From 9ee1740bdf36ba121050bdc5d76c3b60ab35a48d Mon Sep 17 00:00:00 2001 From: Ancor Gonzalez Sosa Date: Thu, 14 Nov 2024 13:08:01 +0100 Subject: [PATCH 1/2] AgamaProposal: Honor DiskAnalyzer candidate devices when searching drives --- .../lib/agama/storage/config_search_solver.rb | 23 ++++++++++++--- service/lib/agama/storage/config_solver.rb | 14 +++++++--- service/lib/y2storage/agama_proposal.rb | 2 +- .../test/agama/storage/config_solver_test.rb | 28 ++++++++++++++++++- 4 files changed, 57 insertions(+), 10 deletions(-) diff --git a/service/lib/agama/storage/config_search_solver.rb b/service/lib/agama/storage/config_search_solver.rb index c65d41fe0c..057ec099a7 100644 --- a/service/lib/agama/storage/config_search_solver.rb +++ b/service/lib/agama/storage/config_search_solver.rb @@ -23,10 +23,12 @@ module Agama module Storage # Solver for the search configs. class ConfigSearchSolver - # @param devicegraph [Devicegraph] used to find the corresponding devices that will get - # associated to each search element. - def initialize(devicegraph) + # @param devicegraph [Y2Storage::Devicegraph] used to find the corresponding devices that + # will get associated to each search element. + # @param analyzer [Y2Storage::DiskAnalyzer, nil] optionally used to filter candidate disks + def initialize(devicegraph, analyzer) @devicegraph = devicegraph + @disk_analyzer = analyzer end # Solves all the search configs within a given config. @@ -41,9 +43,12 @@ def solve(config) private - # @return [Devicegraph] + # @return [Y2Storage::Devicegraph] attr_reader :devicegraph + # @return [Y2Storage::DiskAnalyzer, nil] + attr_reader :disk_analyzer + # @return [Array] SIDs of the devices that are already associated to another search. attr_reader :sids @@ -117,9 +122,19 @@ def solve_partition(original_partition, drive_device) def find_drives(search_config) candidates = candidate_devices(search_config, default: devicegraph.blk_devices) candidates.select! { |d| d.is?(:disk_device, :stray_blk_device) } + filter_by_disk_analyzer(candidates) next_unassigned_devices(candidates, search_config) end + # @see #find_drives + # @param devices [Array] this argument is modified + def filter_by_disk_analyzer(devices) + return unless disk_analyzer + + candidate_sids = disk_analyzer.candidate_disks.map(&:sid) + devices.select! { |d| candidate_sids.include?(d.sid) } + end + # Finds the partitions matching the given search config, if any # # @param search_config [Agama::Storage::Configs::Search] diff --git a/service/lib/agama/storage/config_solver.rb b/service/lib/agama/storage/config_solver.rb index 36f8a99954..3ec4084c5c 100644 --- a/service/lib/agama/storage/config_solver.rb +++ b/service/lib/agama/storage/config_solver.rb @@ -32,11 +32,14 @@ module Storage # example, the sizes of a partition config taking into account its fallbacks, assigning a # specific device when a config has a search, etc. class ConfigSolver - # @param devicegraph [Y2Storage::Devicegraph] - # @param product_config [Agama::Config] - def initialize(devicegraph, product_config) + # @param devicegraph [Y2Storage::Devicegraph] initial layout of the system + # @param product_config [Agama::Config] configuration of the product to install + # @param disk_analyzer [Y2Storage::DiskAnalyzer, nil] optional extra information about the + # initial layout of the system + def initialize(devicegraph, product_config, disk_analyzer: nil) @devicegraph = devicegraph @product_config = product_config + @disk_analyzer = disk_analyzer end # Solves the config according to the product and the system. @@ -47,7 +50,7 @@ def initialize(devicegraph, product_config) def solve(config) ConfigEncryptionSolver.new(product_config).solve(config) ConfigFilesystemSolver.new(product_config).solve(config) - ConfigSearchSolver.new(devicegraph).solve(config) + ConfigSearchSolver.new(devicegraph, disk_analyzer).solve(config) # Sizes must be solved once the searches are solved. ConfigSizeSolver.new(devicegraph, product_config).solve(config) end @@ -59,6 +62,9 @@ def solve(config) # @return [Agama::Config] attr_reader :product_config + + # @return [Y2Storage::DiskAnalyzer, nil] + attr_reader :disk_analyzer end end end diff --git a/service/lib/y2storage/agama_proposal.rb b/service/lib/y2storage/agama_proposal.rb index e9f42e78d1..c368386c0c 100644 --- a/service/lib/y2storage/agama_proposal.rb +++ b/service/lib/y2storage/agama_proposal.rb @@ -93,7 +93,7 @@ def fatal_error? # @raise [NoDiskSpaceError] if there is no enough space to perform the installation def calculate_proposal Agama::Storage::ConfigSolver - .new(initial_devicegraph, product_config) + .new(initial_devicegraph, product_config, disk_analyzer: disk_analyzer) .solve(config) issues = Agama::Storage::ConfigChecker diff --git a/service/test/agama/storage/config_solver_test.rb b/service/test/agama/storage/config_solver_test.rb index eb0cc66949..876af8572f 100644 --- a/service/test/agama/storage/config_solver_test.rb +++ b/service/test/agama/storage/config_solver_test.rb @@ -100,6 +100,7 @@ end let(:devicegraph) { Y2Storage::StorageManager.instance.probed } + let(:disk_analyzer) { nil } before do mock_storage(devicegraph: scenario) @@ -109,7 +110,7 @@ .and_return(true) end - subject { described_class.new(devicegraph, product_config) } + subject { described_class.new(devicegraph, product_config, disk_analyzer: disk_analyzer) } describe "#solve" do let(:scenario) { "empty-hd-50GiB.yaml" } @@ -574,6 +575,31 @@ expect(search3.device.name).to eq("/dev/vdc") end + context "and any of the devices are excluded from the list of candidate devices" do + let(:disk_analyzer) { instance_double(Y2Storage::DiskAnalyzer) } + before do + allow(disk_analyzer).to receive(:candidate_disks).and_return [ + devicegraph.find_by_name("/dev/vdb"), devicegraph.find_by_name("/dev/vdc") + ] + end + + it "sets the first unassigned candidate devices to the drive" do + subject.solve(config) + searches = config.drives.map(&:search) + expect(searches[0].solved?).to eq(true) + expect(searches[0].device.name).to eq("/dev/vdb") + expect(searches[1].solved?).to eq(true) + expect(searches[1].device.name).to eq("/dev/vdc") + end + + it "does not set devices that are not installation candidates" do + subject.solve(config) + searches = config.drives.map(&:search) + expect(searches[2].solved?).to eq(true) + expect(searches[2].device).to be_nil + end + end + context "and there is not unassigned device" do let(:drives) do [ From aa8664b50d2bfb43bfc61cb2a4c23b9022b0cd5d Mon Sep 17 00:00:00 2001 From: Ancor Gonzalez Sosa Date: Thu, 14 Nov 2024 14:27:52 +0100 Subject: [PATCH 2/2] Changelog update --- service/package/rubygem-agama-yast.changes | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/service/package/rubygem-agama-yast.changes b/service/package/rubygem-agama-yast.changes index 5a0eb97197..f79db1e9d0 100644 --- a/service/package/rubygem-agama-yast.changes +++ b/service/package/rubygem-agama-yast.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Thu Nov 14 13:26:23 UTC 2024 - Ancor Gonzalez Sosa + +- Storage: honor the candidate devices from DiskAnalyzer when + matching drives (gh#agama-project/agama#1765). + ------------------------------------------------------------------- Wed Nov 13 12:14:06 UTC 2024 - Imobach Gonzalez Sosa