Skip to content

Commit 3143ac1

Browse files
committed
Add available volume groups to the system
1 parent 79f0277 commit 3143ac1

File tree

6 files changed

+273
-22
lines changed

6 files changed

+273
-22
lines changed

service/lib/agama/dbus/storage/manager.rb

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ module Agama
3636
module DBus
3737
module Storage
3838
# D-Bus object to manage storage installation
39-
class Manager < BaseObject
39+
class Manager < BaseObject # rubocop:disable Metrics/ClassLength
4040
extend Yast::I18n
4141
include Yast::I18n
4242
include WithIssues
@@ -384,15 +384,16 @@ def serialize_system
384384
return serialize_nil unless manager.probed?
385385

386386
json = {
387-
devices: devices_json(:probed),
388-
availableDrives: available_drives,
389-
availableMdRaids: available_md_raids,
390-
candidateDrives: candidate_drives,
391-
candidateMdRaids: candidate_md_raids,
392-
issues: system_issues_json,
393-
productMountPoints: product_mount_points,
394-
encryptionMethods: encryption_methods,
395-
volumeTemplates: volume_templates
387+
devices: devices_json(:probed),
388+
availableDrives: available_drives,
389+
availableMdRaids: available_md_raids,
390+
availableVolumeGroups: available_volume_groups,
391+
candidateDrives: candidate_drives,
392+
candidateMdRaids: candidate_md_raids,
393+
issues: system_issues_json,
394+
productMountPoints: product_mount_points,
395+
encryptionMethods: encryption_methods,
396+
volumeTemplates: volume_templates
396397
}
397398
JSON.pretty_generate(json)
398399
end
@@ -510,6 +511,12 @@ def candidate_md_raids
510511
proposal.storage_system.candidate_md_raids.map(&:sid)
511512
end
512513

514+
# @see Storage::System#available_volume_groups
515+
# @return [Array<Integer>]
516+
def available_volume_groups
517+
proposal.storage_system.available_volume_groups.map(&:sid)
518+
end
519+
513520
# Meaningful mount points for the current product.
514521
#
515522
# @return [Array<String>]

service/lib/agama/storage/system.rb

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# frozen_string_literal: true
22

3-
# Copyright (c) [2025] SUSE LLC
3+
# Copyright (c) [2025-2026] SUSE LLC
44
#
55
# All Rights Reserved.
66
#
@@ -66,8 +66,7 @@ def candidate_drives
6666

6767
# All devices that can be referenced by an mdRaid entry at the Agama config
6868
#
69-
# This excludes devices with any mounted filesystem and devices that contain a repository
70-
# for installation.
69+
# This excludes MD RAIDs that are not based on available devices.
7170
#
7271
# @return [Array<Y2Storage::Md>]
7372
def available_md_raids
@@ -92,14 +91,34 @@ def candidate_md_raids
9291
available_md_raids.reject { |r| r.is?(:software_raid) }
9392
end
9493

95-
# Whether the device is usable as drive or mdRaid
94+
# All devices that can be referenced by a volumeGroups entry at the Agama config
9695
#
97-
# See {#available_drives} and {#available_md_raids}
96+
# This excludes volume groups that are not based on available devices.
97+
#
98+
# @return [Array<Y2Storage::LvmVg>]
99+
def available_volume_groups
100+
return [] unless devicegraph
101+
102+
devicegraph.lvm_vgs.select { |v| available?(v) }
103+
end
104+
105+
# Whether the device is usable for the installation.
106+
#
107+
# A device is usable if it contains neither a mounted filesystem nor a repository for the
108+
# installation.
109+
#
110+
# For "compounded" devices like MD RAIDs or volume groups, all the devices used for creating
111+
# it has to be usable for the installation too.
112+
#
113+
# See {#available_drives}, {#available_md_raids} and {#available_volume_groups}
98114
#
99115
# @param device [Y2Storage::Partitionable, Y2Storage::Md]
100116
# @return [Boolean]
101117
def available?(device)
102-
analyzer.available_device?(device)
118+
devices = device.ancestors.select { |a| a.parents.none? }
119+
devices << device if devices.empty?
120+
121+
devices.all? { |d| analyzer.available_device?(d) }
103122
end
104123

105124
# Whether the device can be used for installation, including the boot partitions

service/test/agama/dbus/storage/manager_test.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,12 +209,14 @@ def parse(string)
209209
allow(proposal.storage_system).to receive(:candidate_md_raids).and_return(candidate_raids)
210210
allow(proposal.storage_system).to receive(:candidate_devices)
211211
.and_return(candidate_drives + candidate_raids)
212+
allow(proposal.storage_system).to receive(:available_volume_groups).and_return(available_vgs)
212213
end
213214

214215
let(:available_drives) { [] }
215216
let(:candidate_drives) { [] }
216217
let(:available_raids) { [] }
217218
let(:candidate_raids) { [] }
219+
let(:available_vgs) { [] }
218220

219221
describe "serialized_system[:availableDrives]" do
220222
context "if there is no available drives" do
@@ -306,6 +308,29 @@ def parse(string)
306308
end
307309
end
308310

311+
describe "serialized_system[:availableVolumeGroups]" do
312+
context "if there is no available volume groups" do
313+
let(:available_vgs) { [] }
314+
315+
it "returns an empty list" do
316+
expect(parse(subject.serialized_system)[:availableVolumeGroups]).to eq([])
317+
end
318+
end
319+
320+
context "if there are available volume groups" do
321+
let(:available_vgs) { [vg1, vg2, vg3] }
322+
323+
let(:vg1) { instance_double(Y2Storage::LvmVg, sid: 200) }
324+
let(:vg2) { instance_double(Y2Storage::LvmVg, sid: 201) }
325+
let(:vg3) { instance_double(Y2Storage::LvmVg, sid: 202) }
326+
327+
it "retuns the id of each volume group" do
328+
result = parse(subject.serialized_system)[:availableVolumeGroups]
329+
expect(result).to contain_exactly(200, 201, 202)
330+
end
331+
end
332+
end
333+
309334
describe "serialized_system[:issues]" do
310335
context "if there is no candidate drives" do
311336
let(:candidate_drives) { [] }

service/test/agama/storage/system_test.rb

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# frozen_string_literal: true
22

3-
# Copyright (c) [2025] SUSE LLC
3+
# Copyright (c) [2025-2026] SUSE LLC
44
#
55
# All Rights Reserved.
66
#
@@ -67,14 +67,18 @@
6767
end
6868

6969
describe "#available_md_raids" do
70-
let(:scenario) { "md_raids.yaml" }
70+
let(:scenario) { "available_md_raids.yaml" }
7171

72-
before do
73-
allow(disk_analyzer).to receive(:available_device?) { |d| d.name != "/dev/md0" }
72+
it "includes all software RAIDs that are not in use" do
73+
expect(subject.available_md_raids.map(&:name)).to contain_exactly("/dev/md0", "/dev/md1")
7474
end
7575

76-
it "includes all software RAIDs that are not in use" do
77-
expect(subject.available_md_raids.map(&:name)).to contain_exactly("/dev/md1", "/dev/md2")
76+
it "does not include software RAIDs in use" do
77+
expect(subject.available_md_raids.map(&:name)).to_not include("/dev/md2")
78+
end
79+
80+
it "does not include software RAIDs over devices in use" do
81+
expect(subject.available_md_raids.map(&:name)).to_not include("/dev/md3")
7882
end
7983
end
8084

@@ -85,4 +89,20 @@
8589
expect(subject.candidate_md_raids).to be_empty
8690
end
8791
end
92+
93+
describe "#available_volume_groups " do
94+
let(:scenario) { "available_volume_groups.yaml" }
95+
96+
it "includes all volume groups that are not in use" do
97+
expect(subject.available_volume_groups.map(&:name)).to contain_exactly("/dev/vg0", "/dev/vg1")
98+
end
99+
100+
it "does not include volume groups in use" do
101+
expect(subject.available_volume_groups.map(&:name)).to_not include("/dev/vg2")
102+
end
103+
104+
it "does not include volume groups over devices in use" do
105+
expect(subject.available_volume_groups.map(&:name)).to_not include("/dev/vg3")
106+
end
107+
end
88108
end
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
---
2+
- disk:
3+
name: /dev/vda
4+
size: 500 GiB
5+
partition_table: gpt
6+
partitions:
7+
- partition:
8+
size: 10 GiB
9+
name: /dev/vda1
10+
- partition:
11+
size: 10 GiB
12+
name: /dev/vda2
13+
- disk:
14+
name: /dev/vdb
15+
size: 500 GiB
16+
partition_table: gpt
17+
partitions:
18+
- partition:
19+
size: 10 GiB
20+
name: /dev/vdb1
21+
- partition:
22+
size: 10 GiB
23+
name: /dev/vdb2
24+
- disk:
25+
name: /dev/vdc
26+
size: 500 GiB
27+
partition_table: gpt
28+
partitions:
29+
- partition:
30+
size: 10 GiB
31+
name: /dev/vdc1
32+
- disk:
33+
name: /dev/vdd
34+
size: 500 GiB
35+
partition_table: gpt
36+
partitions:
37+
- partition:
38+
size: 10 GiB
39+
name: /dev/vdd1
40+
- disk:
41+
name: /dev/vde
42+
size: 500 GiB
43+
partition_table: gpt
44+
partitions:
45+
- partition:
46+
size: 10 GiB
47+
name: /dev/vde1
48+
- disk:
49+
name: /dev/vdf
50+
size: 500 GiB
51+
partition_table: gpt
52+
partitions:
53+
- partition:
54+
size: 10 GiB
55+
name: /dev/vdf1
56+
- partition:
57+
size: 10 GiB
58+
name: /dev/vdf2
59+
file_system: ext4
60+
mount_point: /test1
61+
62+
- md:
63+
name: "/dev/md0"
64+
chunk_size: 16 KiB
65+
partition_table: gpt
66+
partitions:
67+
- partition:
68+
size: 1 GiB
69+
name: /dev/md0p1
70+
- partition:
71+
size: 1 GiB
72+
name: /dev/md0p2
73+
md_devices:
74+
- md_device:
75+
blk_device: /dev/vda1
76+
- md_device:
77+
blk_device: /dev/vdb1
78+
- md:
79+
name: "/dev/md1"
80+
chunk_size: 16 KiB
81+
md_devices:
82+
- md_device:
83+
blk_device: /dev/vda2
84+
- md_device:
85+
blk_device: /dev/vdb2
86+
- md:
87+
name: "/dev/md2"
88+
chunk_size: 16 KiB
89+
md_devices:
90+
- md_device:
91+
blk_device: /dev/vdc1
92+
- md_device:
93+
blk_device: /dev/vdd1
94+
partition_table: gpt
95+
partitions:
96+
- partition:
97+
size: 10 GiB
98+
name: /dev/md2p1
99+
file_system: ext4
100+
mount_point: /test1
101+
- md:
102+
name: "/dev/md3"
103+
chunk_size: 16 KiB
104+
md_devices:
105+
- md_device:
106+
blk_device: /dev/vde1
107+
- md_device:
108+
blk_device: /dev/vdf1
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
- disk:
3+
name: /dev/vda
4+
size: 500 GiB
5+
partition_table: gpt
6+
partitions:
7+
- partition:
8+
size: 10 GiB
9+
name: /dev/vda1
10+
- partition:
11+
size: 10 GiB
12+
name: /dev/vda2
13+
- disk:
14+
name: /dev/vdb
15+
size: 500 GiB
16+
partition_table: gpt
17+
partitions:
18+
- partition:
19+
size: 10 GiB
20+
name: /dev/vdb1
21+
- disk:
22+
name: /dev/vdc
23+
size: 500 GiB
24+
partition_table: gpt
25+
partitions:
26+
- partition:
27+
size: 10 GiB
28+
name: /dev/vdc1
29+
- partition:
30+
size: 10 GiB
31+
name: /dev/vdc2
32+
file_system: ext4
33+
mount_point: /test1
34+
- lvm_vg:
35+
vg_name: vg0
36+
lvm_pvs:
37+
- lvm_pv:
38+
blk_device: /dev/vda1
39+
lvm_lvs:
40+
- lvm_lv:
41+
size: 10 GiB
42+
lv_name: lv1
43+
- lvm_vg:
44+
vg_name: vg1
45+
lvm_pvs:
46+
- lvm_pv:
47+
blk_device: /dev/vda2
48+
lvm_lvs:
49+
- lvm_lv:
50+
size: 10 GiB
51+
lv_name: lv1
52+
file_system: btrfs
53+
- lvm_vg:
54+
vg_name: vg2
55+
lvm_pvs:
56+
- lvm_pv:
57+
blk_device: /dev/vdb1
58+
lvm_lvs:
59+
- lvm_lv:
60+
size: 10 GiB
61+
lv_name: lv1
62+
file_system: btrfs
63+
mount_point: /test2
64+
- lvm_vg:
65+
vg_name: vg3
66+
lvm_pvs:
67+
- lvm_pv:
68+
blk_device: /dev/vdc1
69+
lvm_lvs:
70+
- lvm_lv:
71+
size: 10 GiB
72+
lv_name: lv1

0 commit comments

Comments
 (0)