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): initial config support for LVM #1581

Merged
merged 11 commits into from
Sep 17, 2024
71 changes: 71 additions & 0 deletions rust/agama-lib/share/examples/storage_lvm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"storage": {
"drives": [
{
"partitions": [
{
"alias": "pv1",
"id": "lvm",
"size": { "min": "10 GiB" }
}
]
},
{
"partitions": [
{
"alias": "pv2",
"id": "lvm",
"size": { "min": "10 GiB" }
}
]
}
],
"volumeGroups": [
{
"name": "system",
"physicalVolumes": ["pv1", "pv2"],
"extentSize": "8 MiB",
"logicalVolumes": [
{
"name": "root",
"size": {
"min": "10 GiB"
},
"encryption": {
"luks2": {
"password": "notsecret"
}
},
"filesystem": {
"type": "btrfs",
"path": "/"
}
},
{
"name": "home",
"size": "5 GiB",
"filesystem": {
"type": "xfs",
"path": "/home"
}
},
{
"alias": "lvm_thin_pool",
"pool": true,
"name": "pool",
"size": {
"min": "5 GiB"
},
"stripes": 10,
"stripeSize": "4 KiB"
},
{
"name": "data",
"size": "100 GiB",
"usedPool": "lvm_thin_pool"
}
]
}
]
}
}
148 changes: 148 additions & 0 deletions rust/agama-lib/share/profile.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,9 @@
"description": "The search is limited to drives scope.",
"$ref": "#/$defs/search"
},
"alias": {
"$ref": "#/$defs/alias"
},
"encryption": {
"$ref": "#/$defs/encryption"
},
Expand All @@ -489,6 +492,9 @@
"description": "The search is limited to drives scope.",
"$ref": "#/$defs/search"
},
"alias": {
"$ref": "#/$defs/alias"
},
"ptableType": {
"title": "Partition table type",
"description": "The partition table is created only if all the current partitions are deleted.",
Expand All @@ -502,6 +508,140 @@
]
}
},
"volumeGroups": {
"title": "LVM volume groups",
"description": "Section describing the LVM volume groups.",
"type": "array",
"items": {
"title": "LVM volume group",
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"title": "Volume group name",
"type": "string",
"examples": ["vg0"]
},
"extentSize": {
"title": "Extent size",
"$ref": "#/$defs/sizeValue"
},
"physicalVolumes": {
"title": "Physical volumes",
"description": "Devices to use as physical volumes.",
"type": "array",
"items": {
"title": "Device alias",
"type": "string"
}
},
"logicalVolumes": {
"title": "Logical volumes",
"type": "array",
"items": {
"anyOf": [
{
"title": "Logical volume",
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"title": "Logical volume name",
"type": "string",
"examples": ["lv0"]
},
"size": {
"title": "Logical volume size",
"$ref": "#/$defs/size"
},
"stripes": {
"title": "Number of stripes",
"type": "integer",
"minimum": 1,
"maximum": 128
},
"stripeSize": {
"title": "Stripe size",
"$ref": "#/$defs/sizeValue"
},
"encryption": {
"$ref": "#/$defs/encryption"
},
"filesystem": {
"$ref": "#/$defs/filesystem"
}
}
},
{
"title": "Thin pool logical volume",
"type": "object",
"additionalProperties": false,
"properties": {
"pool": {
"title": "LVM thin pool",
"const": true
},
"alias": {
"$ref": "#/$defs/alias"
},
"name": {
"title": "Logical volume name",
"type": "string",
"examples": ["lv0"]
},
"size": {
"title": "Logical volume size",
"$ref": "#/$defs/size"
},
"stripes": {
"title": "Number of stripes",
"type": "integer",
"minimum": 1,
"maximum": 128
},
"stripeSize": {
"title": "Stripe size",
"$ref": "#/$defs/sizeValue"
},
"encryption": {
"$ref": "#/$defs/encryption"
}
}
},
{
"title": "Thin logical volume",
"type": "object",
"additionalProperties": false,
"required": ["usedPool"],
"properties": {
"name": {
"title": "Thin logical volume name",
"type": "string",
"examples": ["lv0"]
},
"size": {
"title": "Thin logical volume size",
"$ref": "#/$defs/size"
},
"usedPool": {
"title": "Used LVM thin pool",
"description": "Alias of a LVM thin pool.",
"type": "string"
},
"encryption": {
"$ref": "#/$defs/encryption"
},
"filesystem": {
"$ref": "#/$defs/filesystem"
}
}
}
]
}
}
}
}
},
"guided": {
"title": "Guided proposal settings",
"$comment": "This guided section will be extracted to a separate schema. Only storage and legacyAutoyastStorage will be offered as valid schemas for the storage config.",
Expand Down Expand Up @@ -859,6 +999,11 @@
}
]
},
"alias": {
"title": "Alias",
"description": "Name used to reference a device.",
"type": "string"
},
"boot": {
"title": "Boot options",
"description": "Allows configuring boot partitions automatically.",
Expand Down Expand Up @@ -1070,6 +1215,9 @@
"description": "The search is limited to the partitions of the selected device scope.",
"$ref": "#/$defs/search"
},
"alias": {
"$ref": "#/$defs/alias"
},
"id": {
"title": "Partition ID",
"enum": ["linux", "swap", "lvm", "raid", "esp", "prep", "bios_boot"]
Expand Down
13 changes: 9 additions & 4 deletions service/lib/agama/storage/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Config
# @return [Array<Configs::Drive>]
attr_accessor :drives

# @return [Array]
# @return [Array<Configs::VolumeGroup>]
attr_accessor :volume_groups

# @return [Array]
Expand Down Expand Up @@ -107,17 +107,22 @@ def calculate_default_sizes(volume_builder)

# return [Array<Configs::Filesystem>]
def filesystems
(drives + partitions).map(&:filesystem).compact
(drives + partitions + logical_volumes).map(&:filesystem).compact
end

# return [Array<Configs::Partition>]
def partitions
drives.flat_map(&:partitions)
end

# return [Array<Configs::Partitions>]
# return [Array<Configs::LogicalVolume>]
def logical_volumes
volume_groups.flat_map(&:logical_volumes)
end

# return [Array<Configs::Partition, Configs::LogicalVolume>]
def default_size_devices
partitions.select { |p| p.size&.default? }
(partitions + logical_volumes).select { |p| p.size&.default? }
end

# Min or max size that should be used for the given partition or logical volume
Expand Down
87 changes: 87 additions & 0 deletions service/lib/agama/storage/config_builder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# 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.

require "agama/storage/configs"
require "agama/storage/proposal_settings_reader"
require "agama/storage/volume_templates_builder"

module Agama
module Storage
# Class for building configs.
class ConfigBuilder
# @todo Replace product_config param by a ProductDefinition.
#
# @param product_config [Agama::Config]
def initialize(product_config)
@product_config = product_config
end

# Default encryption config from the product definition.
#
# @return [Configs::Encryption]
def default_encryption
Configs::Encryption.new.tap do |config|
config.password = settings.encryption.password
config.method = settings.encryption.method
config.pbkd_function = settings.encryption.pbkd_function
end
end

# Default format config from the product definition.
#
# @param path [String, nil]
# @return [Configs::Filesystem]
def default_filesystem(path = nil)
Configs::Filesystem.new.tap do |config|
config.type = default_fstype(path)
end
end

private

# @return [Agama::Config]
attr_reader :product_config

# Default filesystem type config from the product definition.
#
# @param path [String, nil]
# @return [Configs::FilesystemType]
def default_fstype(path = nil)
volume = volume_builder.for(path || "")

Configs::FilesystemType.new.tap do |config|
config.fs_type = volume.fs_type
config.btrfs = volume.btrfs
end
end

# @return [ProposalSettings]
def settings
@settings ||= ProposalSettingsReader.new(product_config).read
end

# @return [VolumeTemplatesBuilder]
def volume_builder
@volume_builder ||= VolumeTemplatesBuilder.new_from_config(product_config)
end
end
end
end
Loading
Loading