Skip to content
Merged
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