Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(storage): configure boot #1808

Merged
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion rust/agama-lib/share/examples/storage/drives.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
"storage": {
"boot": {
"configure": true,
"device": "/dev/vda"
"device": "vda"
},
"drives": [
{
"search": "/dev/vda",
"alias": "vda",
"ptableType": "gpt",
"partitions": [
{
Expand Down
7 changes: 7 additions & 0 deletions rust/agama-lib/share/examples/storage/model.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
{
"boot": {
"configure": true,
"device": {
"default": false,
"name": "/dev/vda"
}
},
"drives": [
{
"name": "/dev/vda",
Expand Down
27 changes: 25 additions & 2 deletions rust/agama-lib/share/storage.model.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,38 @@
"type": "object",
"additionalProperties": false,
"properties": {
"boot": { "$ref": "#/$defs/boot" },
"drives": {
"type": "array",
"items": { "$ref": "#/$defs/drive" }
}
},
"$defs": {
"boot": {
"type": "object",
"additionalProperties": false,
"required": ["configure"],
"properties": {
"configure": { "type": "boolean" },
"device": { "$ref": "#/$defs/bootDevice" }
}
},
"bootDevice": {
"type": "object",
"additionalProperties": false,
"required": ["default"],
"properties": {
"default": { "type": "boolean" },
"name": { "type": "string" }
}
},
"drive": {
"type": "object",
"additionalProperties": false,
"required": ["name"],
"properties": {
"name": { "type": "string" },
"alias": { "type": "string" },
"alias": { "$ref": "#/$defs/alias" },
"mountPath": { "type": "string" },
"filesystem": { "$ref": "#/$defs/filesystem" },
"spacePolicy": { "$ref": "#/$defs/spacePolicy" },
Expand All @@ -32,7 +51,7 @@
"additionalProperties": false,
"properties": {
"name": { "type": "string" },
"alias": { "type": "string" },
"alias": { "$ref": "#/$defs/alias" },
"id": { "$ref": "#/$defs/partitionId" },
"mountPath": { "type": "string" },
"filesystem": { "$ref": "#/$defs/filesystem" },
Expand All @@ -43,6 +62,10 @@
"resizeIfNeeded": { "type": "boolean" }
}
},
"alias": {
"description": "Alias used to reference a device.",
"type": "string"
},
"spacePolicy": {
"enum": ["delete", "resize", "keep", "custom"]
},
Expand Down
6 changes: 1 addition & 5 deletions rust/agama-lib/share/storage.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,7 @@
"description": "Whether to configure partitions for booting.",
"type": "boolean"
},
"device": {
"description": "The target installation device is used by default.",
"type": "string",
"examples": ["/dev/vda"]
}
"device": { "$ref": "#/$defs/alias" }
}
},
"driveElement": {
Expand Down
43 changes: 43 additions & 0 deletions service/lib/agama/storage/boot_settings.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true

# Copyright (c) [2024] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

module Agama
module Storage
# Boot settings.
class BootSettings
# Whether to configure partitions for booting.
#
# @return [Boolean]
attr_accessor :configure
alias_method :configure?, :configure

# Boot device name.
#
# @return [String]
attr_accessor :device

# Constructor
def initialize
@configure = true
end
end
end
end
74 changes: 8 additions & 66 deletions service/lib/agama/storage/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

require "agama/copyable"
require "agama/storage/configs/boot"
require "agama/storage/config_conversions/from_json"

module Agama
module Storage
Expand Down Expand Up @@ -61,11 +60,16 @@ def initialize
@nfs_mounts = []
end

# Name of the device that will presumably be used to boot the target system
# Name of the device that will be used to boot the target system, if any.
#
# @return [String, nil] nil if there is no enough information to infer a possible boot disk
# @note The config has to be solved.
#
# @return [String, nil]
def boot_device
explicit_boot_device || implicit_boot_device
return unless boot.configure? && boot.device.device_alias

boot_drive = drives.find { |d| d.alias?(boot.device.device_alias) }
boot_drive&.found_device&.name
end

# return [Array<Configs::Partition>]
Expand All @@ -77,68 +81,6 @@ def partitions
def logical_volumes
volume_groups.flat_map(&:logical_volumes)
end

private

# Device used for booting the target system
#
# @return [String, nil] nil if no disk is explicitly chosen
def explicit_boot_device
return nil unless boot.configure?

boot.device
end

# Device that seems to be expected to be used for booting, according to the drive definitions
#
# @return [String, nil] nil if the information cannot be inferred from the config
def implicit_boot_device
implicit_drive_boot_device || implicit_lvm_boot_device
end

# @see #implicit_boot_device
#
# @return [String, nil] nil if the information cannot be inferred from the list of drives
def implicit_drive_boot_device
root_drive = drives.find do |drive|
drive.partitions.any? { |p| p.filesystem&.root? }
end

root_drive&.found_device&.name
end

# @see #implicit_boot_device
#
# @return [String, nil] nil if the information cannot be inferred from the list of LVM VGs
def implicit_lvm_boot_device
root_vg = root_volume_group
return nil unless root_vg

root_drives = drives.select { |d| drive_for_vg?(d, root_vg) }
names = root_drives.map { |d| d.found_device&.name }.compact
# Return the first name in alphabetical order
names.min
end

# @see #implicit_lvm_boot_device
#
# @return [Configs::VolumeGroup, nil]
def root_volume_group
volume_groups.find do |vg|
vg.logical_volumes.any? { |lv| lv.filesystem&.root? }
end
end

# @see #implicit_lvm_boot_device
#
# @return [Boolean]
def drive_for_vg?(drive, volume_group)
return true if volume_group.physical_volumes_devices.any? { |d| drive.alias?(d) }

volume_group.physical_volumes.any? do |pv|
drive.partitions.any? { |p| p.alias?(pv) }
end
end
end
end
end
Loading
Loading