agama/service/test/y2storage/agama_proposal_md_lvm_test.rb
2025-11-12 10:34:57 +01:00

285 lines
8.8 KiB
Ruby

# frozen_string_literal: true
# Copyright (c) [2025] 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_relative "../agama/storage/storage_helpers"
require "agama/config"
require "agama/storage/config"
require "agama/storage/config_conversions/from_json"
require "agama/storage/system"
require "y2storage"
require "y2storage/agama_proposal"
describe Y2Storage::AgamaProposal do
using Y2Storage::Refinements::SizeCasts
include Agama::RSpec::StorageHelpers
subject(:proposal) do
described_class.new(config, storage_system, issues_list: issues_list)
end
let(:storage_system) { Agama::Storage::System.new }
let(:config) { config_from_json }
let(:config_from_json) do
Agama::Storage::ConfigConversions::FromJSON
.new(config_json)
.convert
end
let(:issues_list) { [] }
before do
mock_storage(devicegraph: scenario)
# To speed-up the tests
allow(Y2Storage::EncryptionMethod::TPM_FDE).to receive(:possible?).and_return(true)
end
let(:scenario) { "empty-hd-50GiB.yaml" }
describe "#propose" do
context "when the config defines a new LVM using a new RAID as PV" do
let(:scenario) { "disks.yaml" }
let(:config_json) do
{
drives: [
{
partitions: [
{ search: "*", delete: true },
{ alias: "sda1", size: { min: "1 MiB" } }
]
},
{
partitions: [
{ search: "*", delete: true },
{ alias: "sdb1", size: { min: "1 MiB" } }
]
}
],
mdRaids: [
{
level: "raid1",
alias: "md",
devices: ["sda1", "sdb1"]
}
],
volumeGroups: [
{
name: "system",
physicalVolumes: ["md"],
logicalVolumes: [
{ name: "root", filesystem: { path: "/" } },
{ name: "swap", filesystem: { path: "swap" } }
]
}
],
boot: { configure: false }
}
end
it "proposes the expected devices" do
devicegraph = proposal.propose
expect(devicegraph.md_raids).to contain_exactly(
an_object_having_attributes(name: "/dev/md0", md_level: Y2Storage::MdLevel::RAID1)
)
expect(devicegraph.lvm_vgs).to contain_exactly(
an_object_having_attributes(vg_name: "system")
)
vg = devicegraph.lvm_vgs.first
expect(vg.lvm_lvs.map(&:name)).to contain_exactly(
"/dev/system/root", "/dev/system/swap"
)
expect(vg.lvm_pvs.size).to eq 1
expect(vg.lvm_pvs.first.blk_device.name).to eq "/dev/md0"
end
end
context "when the config defines a new LVM generating PVs on a new RAID" do
let(:scenario) { "disks.yaml" }
let(:config_json) do
{
drives: [
{
partitions: [
{ search: "*", delete: true },
{ alias: "sda1", size: { min: "1 MiB" } }
]
},
{
partitions: [
{ search: "*", delete: true },
{ alias: "sdb1", size: { min: "1 MiB" } }
]
}
],
mdRaids: [
{
level: "raid1",
alias: "md",
devices: ["sda1", "sdb1"]
}
],
volumeGroups: [
{
name: "system",
physicalVolumes: [
{ generate: { targetDevices: ["md"] } }
],
logicalVolumes: [
{ name: "root", size: { min: "10 GiB" }, filesystem: { path: "/" } },
{ name: "swap", size: "2 GiB", filesystem: { path: "swap" } }
]
}
],
boot: { configure: false }
}
end
it "proposes the expected devices" do
devicegraph = proposal.propose
expect(devicegraph.md_raids).to contain_exactly(
an_object_having_attributes(name: "/dev/md0", md_level: Y2Storage::MdLevel::RAID1)
)
expect(devicegraph.lvm_vgs).to contain_exactly(
an_object_having_attributes(vg_name: "system")
)
vg = devicegraph.lvm_vgs.first
expect(vg.lvm_lvs.map(&:name)).to contain_exactly(
"/dev/system/root", "/dev/system/swap"
)
expect(vg.lvm_pvs.size).to eq 1
expect(vg.lvm_pvs.first.blk_device.name).to eq "/dev/md0p1"
end
end
context "when the config defines several LVM generating PVs on several new RAIDs" do
let(:scenario) { "disks.yaml" }
let(:config_json) do
{
drives: [
{
partitions: [
{ search: "*", delete: true },
{ alias: "sda1", size: { min: "1 MiB" } },
{ alias: "sda2", size: "10 GiB" }
]
},
{
partitions: [
{ search: "*", delete: true },
{ alias: "sdb1", size: { min: "1 MiB" } },
{ alias: "sdb2", size: "10 GiB" }
]
}
],
mdRaids: [
{
level: "raid1",
alias: "md0",
devices: ["sda1", "sdb1"]
},
{
level: "raid0",
alias: "md1",
devices: ["sdb2", "sda2"],
partitions: [
{ filesystem: { path: "/extra" }, size: "1GiB" }
]
}
],
volumeGroups: [
{
name: "system",
physicalVolumes: [
{ generate: { targetDevices: ["md0", "md1"] } }
],
logicalVolumes: [
{ name: "root", size: { min: "20 GiB" }, filesystem: { path: "/" } },
{ name: "swap", size: "1 GiB", filesystem: { path: "swap" } }
]
},
{
name: "vg1",
physicalVolumes: [
{
generate: {
targetDevices: ["md1"],
encryption: { luks2: { password: "s3cr3t" } }
}
}
],
logicalVolumes: [
{
name: "home",
filesystem: {
path: "/home",
type: "xfs"
},
size: "3 GiB"
}
]
}
],
boot: { configure: false }
}
end
it "proposes the expected devices" do
devicegraph = proposal.propose
expect(devicegraph.md_raids).to contain_exactly(
an_object_having_attributes(name: "/dev/md0", md_level: Y2Storage::MdLevel::RAID1),
an_object_having_attributes(name: "/dev/md1", md_level: Y2Storage::MdLevel::RAID0)
)
md0 = devicegraph.md_raids.find { |r| r.md_level.is?(:raid0) }
md0_formatted = md0.partitions.select(&:formatted?)
expect(md0_formatted.map(&:filesystem).map(&:mount_path)).to include "/extra"
expect(devicegraph.lvm_vgs).to contain_exactly(
an_object_having_attributes(vg_name: "system"),
an_object_having_attributes(vg_name: "vg1")
)
vg_system = devicegraph.find_by_any_name("/dev/system")
expect(vg_system.lvm_lvs.map(&:name)).to contain_exactly(
"/dev/system/root", "/dev/system/swap"
)
pvs_system = vg_system.lvm_pvs.map(&:blk_device)
expect(pvs_system.map(&:partitionable).map(&:name))
.to contain_exactly("/dev/md0", "/dev/md1")
vg1 = devicegraph.find_by_any_name("/dev/vg1")
expect(vg1.lvm_lvs.map(&:name)).to contain_exactly("/dev/vg1/home")
pvs_vg1 = vg1.lvm_pvs.map(&:blk_device)
expect(pvs_vg1.size).to eq 1
pv = pvs_vg1.first
expect(pv.is?(:encryption)).to eq true
expect(pv.blk_device.partitionable).to eq md0
end
end
end
end