168 lines
6 KiB
Ruby
168 lines
6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# Copyright (c) [2024-2026] 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 "y2storage/lv_type"
|
|
require "y2storage/proposal/agama_device_planner"
|
|
|
|
module Y2Storage
|
|
module Proposal
|
|
# Volume group planner for Agama.
|
|
class AgamaVgPlanner < AgamaDevicePlanner
|
|
# @param vg_config [Agama::Storage::Configs::VolumeGroup]
|
|
# @return [Array<Planned::Device>]
|
|
def planned_devices(vg_config)
|
|
return [] if vg_config.search&.skip_device?
|
|
|
|
[planned_vg(vg_config)]
|
|
end
|
|
|
|
private
|
|
|
|
# @return [Hash{String => Planned::Device}] Map with all the new devices that could
|
|
# potentially host automatic physical volumes
|
|
attr_reader :partitionables
|
|
|
|
# @param vg_config [Agama::Storage::Configs::VolumeGroup]
|
|
# @return [Planned::LvmVg]
|
|
def planned_vg(vg_config)
|
|
# TODO: A volume group name is expected. Otherwise, the planned physical volumes cannot
|
|
# be associated to the planned volume group. Should the volume group name be
|
|
# automatically generated if missing?
|
|
#
|
|
# @see AgamaDevicePlanner#configure_pv
|
|
Y2Storage::Planned::LvmVg.new(volume_group_name: vg_config.vg_name).tap do |planned|
|
|
planned.extent_size = vg_config.extent_size
|
|
planned.lvs = planned_lvs(vg_config)
|
|
planned.size_strategy = vg_config.physical_volumes_policy || :use_needed
|
|
planned.pvs_candidate_devices = devices_for_pvs(vg_config)
|
|
configure_pvs_encryption(planned, vg_config)
|
|
configure_reuse(planned, vg_config)
|
|
end
|
|
end
|
|
|
|
# References to the devices that must be used to calculate automatic physical volumes
|
|
# for the given volume group
|
|
#
|
|
# The field Planned::LvmVg#pvs_candidate_devices is designed to use device names, but Agama
|
|
# initializes it using Planned::Device indentifiers instead.
|
|
#
|
|
# @param vg_config [Agama::Storage::Configs::VolumeGroup]
|
|
# @return [Array<String>]
|
|
def devices_for_pvs(vg_config)
|
|
devs = vg_config.physical_volumes_devices.flat_map do |dev_alias|
|
|
partitionables[dev_alias].map(&:planned_id)
|
|
end
|
|
end
|
|
|
|
# Configures the encryption-related fields of the given planned volume group
|
|
#
|
|
# @param planned [Planned::LvmVg]
|
|
# @param config [Agama::Storage::Configs::VolumeGroup]
|
|
def configure_pvs_encryption(planned, config)
|
|
enc = config.physical_volumes_encryption
|
|
return unless enc
|
|
|
|
planned.pvs_encryption_method = enc.method
|
|
planned.pvs_encryption_password = enc.password
|
|
planned.pvs_encryption_pbkdf = enc.pbkd_function
|
|
end
|
|
|
|
# @param config [Agama::Storage::Configs::VolumeGroup]
|
|
# @return [Array<Planned::LvmLv>]
|
|
def planned_lvs(config)
|
|
normal_lvs = planned_normal_lvs(config)
|
|
thin_pool_lvs = planned_thin_pool_lvs(config)
|
|
|
|
normal_lvs + thin_pool_lvs
|
|
end
|
|
|
|
# @param config [Agama::Storage::Configs::VolumeGroup]
|
|
# @return [Array<Planned::LvmLv>]
|
|
def planned_normal_lvs(config)
|
|
valid_lv_configs(config)
|
|
.reject(&:pool?)
|
|
.reject(&:thin_volume?)
|
|
.map { |c| planned_lv(c, LvType::NORMAL) }
|
|
end
|
|
|
|
# @param config [Agama::Storage::Configs::VolumeGroup]
|
|
# @return [Array<Planned::LvmLv>]
|
|
def planned_thin_pool_lvs(config)
|
|
valid_lv_configs(config)
|
|
.select(&:pool?)
|
|
.map { |c| planned_thin_pool_lv(c, config) }
|
|
end
|
|
|
|
# Plan a thin pool logical volume and its thin volumes.
|
|
#
|
|
# @param pool_config [Agama::Storage::Configs::LogicalVolume]
|
|
# @param config [Agama::Storage::Configs::VolumeGroup]
|
|
#
|
|
# @return [Planned::LvmLv]
|
|
def planned_thin_pool_lv(pool_config, config)
|
|
planned_thin_lvs = planned_thin_lvs(config, pool_config.alias)
|
|
|
|
planned_lv(pool_config, LvType::THIN_POOL).tap do |planned|
|
|
planned_thin_lvs.each { |v| planned.add_thin_lv(v) }
|
|
end
|
|
end
|
|
|
|
# @param config [Agama::Storage::Configs::VolumeGroup]
|
|
# @param pool_alias [String]
|
|
#
|
|
# @return [Array<Planned::LvmLv>]
|
|
def planned_thin_lvs(config, pool_alias)
|
|
thin_configs = config.logical_volumes
|
|
.select(&:thin_volume?)
|
|
.select { |c| c.used_pool == pool_alias }
|
|
|
|
thin_configs.map { |c| planned_lv(c, LvType::THIN) }
|
|
end
|
|
|
|
# @param config [Agama::Storage::Configs::LogicalVolume]
|
|
# @param type [LvType]
|
|
#
|
|
# @return [Planned::LvmLv]
|
|
def planned_lv(config, type)
|
|
Planned::LvmLv.new(nil, nil).tap do |planned|
|
|
planned.logical_volume_name = config.name
|
|
planned.lv_type = type
|
|
planned.stripes = config.stripes
|
|
planned.stripe_size = config.stripe_size
|
|
configure_block_device(planned, config)
|
|
configure_size(planned, config.size)
|
|
configure_reuse(planned, config)
|
|
end
|
|
end
|
|
|
|
# Valid logical volume configs to plan for.
|
|
#
|
|
# @param config [Agama::Storage::Configs::VolumeGroup]
|
|
# @return [Array<Agama::Storage::Configs::LogicalVolume>]
|
|
def valid_lv_configs(config)
|
|
config.logical_volumes
|
|
.reject(&:delete?)
|
|
.reject(&:delete_if_needed?)
|
|
.reject { |c| c.search&.skip_device? }
|
|
end
|
|
end
|
|
end
|
|
end
|