From ec4b43243b5ddc248063a599f4d914d1070b3730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Fri, 13 Jun 2025 09:49:18 +0100 Subject: [PATCH 1/5] storage: start iscsi services and add packages to install --- service/lib/agama/storage/iscsi/adapter.rb | 9 +++ service/lib/agama/storage/iscsi/manager.rb | 11 ++- service/lib/agama/storage/manager.rb | 16 ++++- .../test/agama/storage/iscsi/manager_test.rb | 68 ++++++++++++++++--- service/test/agama/storage/manager_test.rb | 40 ++++++++++- 5 files changed, 132 insertions(+), 12 deletions(-) diff --git a/service/lib/agama/storage/iscsi/adapter.rb b/service/lib/agama/storage/iscsi/adapter.rb index 13e3c8913f..a49ba0d907 100644 --- a/service/lib/agama/storage/iscsi/adapter.rb +++ b/service/lib/agama/storage/iscsi/adapter.rb @@ -25,6 +25,7 @@ require "y2iscsi_client/authentication" Yast.import "IscsiClientLib" +Yast.import "Service" module Agama module Storage @@ -33,6 +34,7 @@ module ISCSI class Adapter # Performs actions for activating iSCSI. def activate + start_services Yast::IscsiClientLib.getiBFT # Check initiator name, creating one if missing. return false unless Yast::IscsiClientLib.checkInitiatorName(silent: true) @@ -137,6 +139,13 @@ def update_node(node, startup:) private + # Starts the iSCSI services. + def start_services + Yast::Service.start("iscsi") + Yast::Service.start("iscsid") + Yast::Service.start("iscsiuio") + end + # Creates an iSCSI authentication object. # # @param credentials [Hash] diff --git a/service/lib/agama/storage/iscsi/manager.rb b/service/lib/agama/storage/iscsi/manager.rb index 0064f59bb1..8a1dfd491b 100644 --- a/service/lib/agama/storage/iscsi/manager.rb +++ b/service/lib/agama/storage/iscsi/manager.rb @@ -37,6 +37,7 @@ class Manager include Yast::I18n STARTUP_OPTIONS = ["onboot", "manual", "automatic"].freeze + PACKAGES = ["open-iscsi", "iscsiuio"].freeze # Config according to the JSON schema. # @@ -61,7 +62,15 @@ def initialize(progress_manager: nil, logger: nil) @nodes = [] @on_activate_callbacks = [] @on_probe_callbacks = [] - @on_sessions_change_callbacks = [] + # Sets iSCSI as configured after any change on the sessions. + @on_sessions_change_callbacks = [proc { @configured = true }] + end + + # Whether iSCSI was configured. + # + # @return [Boolean] + def configured? + !!@configured end # Performs actions for activating iSCSI. diff --git a/service/lib/agama/storage/manager.rb b/service/lib/agama/storage/manager.rb index 1815746072..a33230d66b 100644 --- a/service/lib/agama/storage/manager.rb +++ b/service/lib/agama/storage/manager.rb @@ -256,14 +256,28 @@ def probe_devices # Adds the required packages to the list of resolvables to install def add_packages - devicegraph = Y2Storage::StorageManager.instance.staging packages = devicegraph.used_features.pkg_list + packages += ISCSI::Manager::PACKAGES if need_iscsi? return if packages.empty? logger.info "Selecting these packages for installation: #{packages}" Yast::PackagesProposal.SetResolvables(PROPOSAL_ID, :package, packages) end + # Whether iSCSI is needed in the target system. + # + # @return [Boolean] + def need_iscsi? + iscsi.configured? || devicegraph.used_features.any? { |f| f.id == :UF_ISCSI } + end + + # Staging devicegraph + # + # @return [Y2Storage::Devicegraph] + def devicegraph + Y2Storage::StorageManager.instance.staging + end + # Prepares the storage devices for installation # # @return [Boolean] true if the all actions were successful diff --git a/service/test/agama/storage/iscsi/manager_test.rb b/service/test/agama/storage/iscsi/manager_test.rb index bf82acdbf0..19f2bc2d7d 100644 --- a/service/test/agama/storage/iscsi/manager_test.rb +++ b/service/test/agama/storage/iscsi/manager_test.rb @@ -50,6 +50,7 @@ allow(Yast::IscsiClientLib).to receive(:iBFT?) allow(Yast::IscsiClientLib).to receive(:find_session) allow(Yast::IscsiClientLib).to receive(:getStartupStatus) + allow(Yast::Service).to receive(:start) allow(subject).to receive(:adapter).and_return(adapter) allow(subject).to receive(:sleep) end @@ -69,6 +70,14 @@ subject.activate end + it "enables the iSCSI services" do + expect(Yast::Service).to receive(:start).with("iscsi").ordered + expect(Yast::Service).to receive(:start).with("iscsid").ordered + expect(Yast::Service).to receive(:start).with("iscsiuio").ordered + + subject.activate + end + it "runs the callbacks" do callback = proc {} subject.on_activate(&callback) @@ -230,25 +239,20 @@ end describe "#login" do - let(:node) { Agama::Storage::ISCSI::Node.new } - before do allow(Yast::IscsiClientLib).to receive(:default_startup_status).and_return("onboot") - allow(Yast::IscsiClientLib).to receive(:login_into_current) - allow(Yast::IscsiClientLib).to receive(:setStartupStatus) - end - - let(:startup) { "automatic" } - - before do allow(Yast::IscsiClientLib).to receive(:login_into_current).and_return(login_success) allow(Yast::IscsiClientLib).to receive(:setStartupStatus).and_return(startup_success) end + let(:node) { Agama::Storage::ISCSI::Node.new } + let(:login_success) { nil } let(:startup_success) { nil } + let(:startup) { "automatic" } + it "tries to login without credentials" do expect(Yast::IscsiClientLib).to receive(:login_into_current) do |auth, _| expect(auth).to be_a(Y2IscsiClient::Authentication) @@ -685,4 +689,50 @@ end end end + + describe "#configured?" do + context "if no session has been configured yet" do + it "returns false" do + expect(subject.configured?).to eq(false) + end + end + + context "if a session was configured by loading a config" do + let(:config_json) do + { + targets: [ + { + address: "192.168.100.152", + port: 3260, + name: "iqn.2025-01.com.example:becda24e8804c6580bd1", + interface: "default" + } + ] + } + end + + before do + allow(adapter).to receive(:login).and_return(true) + subject.apply_config_json(config_json) + end + + it "returns true" do + expect(subject.configured?).to eq(true) + end + end + + context "if a session was manually configured" do + before do + allow(Yast::IscsiClientLib).to receive(:default_startup_status).and_return("onboot") + allow(Yast::IscsiClientLib).to receive(:login_into_current).and_return(true) + allow(Yast::IscsiClientLib).to receive(:setStartupStatus).and_return(true) + node = Agama::Storage::ISCSI::Node.new + subject.login(node) + end + + it "returns true" do + expect(subject.configured?).to eq(true) + end + end + end end diff --git a/service/test/agama/storage/manager_test.rb b/service/test/agama/storage/manager_test.rb index ede0ba078e..bb9113c56c 100644 --- a/service/test/agama/storage/manager_test.rb +++ b/service/test/agama/storage/manager_test.rb @@ -319,7 +319,11 @@ end let(:used_features) do - instance_double(Y2Storage::StorageFeaturesList, pkg_list: ["btrfsprogs", "snapper"]) + instance_double( + Y2Storage::StorageFeaturesList, + pkg_list: ["btrfsprogs", "snapper"], + any?: false + ) end let(:bootloader_proposal) { instance_double(Bootloader::ProposalClient, make_proposal: nil) } @@ -343,6 +347,40 @@ storage.install end + + context "if iSCSI was configured" do + before do + allow_any_instance_of(Agama::Storage::ISCSI::Manager) + .to receive(:configured?).and_return(true) + end + + it "adds the iSCSI software to install" do + expect(Yast::PackagesProposal).to receive(:SetResolvables) do |_, _, packages| + expect(packages).to include("open-iscsi", "iscsiuio") + end + + storage.install + end + end + + context "if iSCSI was used" do + before do + allow_any_instance_of(Agama::Storage::ISCSI::Manager) + .to receive(:configured?).and_return(false) + end + + let(:used_features) do + instance_double(Y2Storage::StorageFeaturesList, pkg_list: [], any?: true) + end + + it "adds the iSCSI software to install" do + expect(Yast::PackagesProposal).to receive(:SetResolvables) do |_, _, packages| + expect(packages).to include("open-iscsi", "iscsiuio") + end + + storage.install + end + end end describe "#proposal" do From 3c1b9b47af889fa3702084ecb0cb64f30702978e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Mon, 16 Jun 2025 12:51:19 +0100 Subject: [PATCH 2/5] fix(storage): translate finisher steps --- service/lib/agama/storage/finisher.rb | 89 +++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 11 deletions(-) diff --git a/service/lib/agama/storage/finisher.rb b/service/lib/agama/storage/finisher.rb index 6d97f1d88e..b216c1d770 100644 --- a/service/lib/agama/storage/finisher.rb +++ b/service/lib/agama/storage/finisher.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# Copyright (c) [2023] SUSE LLC +# Copyright (c) [2023-2025] SUSE LLC # # All Rights Reserved. # @@ -20,6 +20,7 @@ # find current contact information at www.suse.com. require "yast" +require "yast/i18n" require "yast2/execute" require "yast2/systemd/service" require "bootloader/finish_client" @@ -125,6 +126,8 @@ def wfm_write(function) # Step to copy files from the inst-sys to the target system class CopyFilesStep < Step + include Yast::I18n + UDEV_RULES_DIR = "/etc/udev/rules.d" ROOT_PATH = "/" FILES = [ @@ -136,8 +139,13 @@ class CopyFilesStep < Step { dir: "/etc/nvme", file: "hostid" } ].freeze + def initialize(logger) + super + textdomain "agama" + end + def label - "Copying important installation files to the target system" + _("Copying important installation files to the target system") end def run? @@ -171,14 +179,17 @@ def glob_files # Step to write the security settings class SecurityStep < Step + include Yast::I18n + # Constructor def initialize(logger, security) super(logger) + textdomain "agama" @security = security end def label - "Writing Linux Security Modules configuration" + _("Writing Linux Security Modules configuration") end def run @@ -188,8 +199,15 @@ def run # Step to write the bootloader configuration class BootloaderStep < Step + include Yast::I18n + + def initialize(logger) + super + textdomain "agama" + end + def label - "Installing bootloader" + _("Installing bootloader") end def run @@ -205,8 +223,15 @@ def cio_ignore_finish # Step to finish the Y2Storage configuration class StorageStep < Step + include Yast::I18n + + def initialize(logger) + super + textdomain "agama" + end + def label - "Adjusting storage configuration" + _("Adjusting storage configuration") end def run @@ -216,8 +241,15 @@ def run # Step to configure the file-system snapshots class SnapshotsStep < Step + include Yast::I18n + + def initialize(logger) + super + textdomain "agama" + end + def label - "Configuring file systems snapshots" + _("Configuring file systems snapshots") end def run @@ -227,10 +259,17 @@ def run # Step to copy the installation logs class CopyLogsStep < Step + include Yast::I18n + SCRIPTS_DIR = "/run/agama/scripts" + def initialize(logger) + super + textdomain "agama" + end + def label - "Copying logs" + _("Copying logs") end def run @@ -263,8 +302,15 @@ def logs_dir # Executes post-installation scripts class PostScripts < Step + include Yast::I18n + + def initialize(logger) + super + textdomain "agama" + end + def label - "Running user-defined scripts" + _("Running user-defined scripts") end def run @@ -302,8 +348,15 @@ def enable_init_scripts # Executes post-installation scripts class FilesStep < Step + include Yast::I18n + + def initialize(logger) + super + textdomain "agama" + end + def label - "Deploying user-defined files" + _("Deploying user-defined files") end def run @@ -321,8 +374,15 @@ def deploy_files # Step to unmount the target file-systems class UnmountStep < Step + include Yast::I18n + + def initialize(logger) + super + textdomain "agama" + end + def label - "Unmounting storage devices" + _("Unmounting storage devices") end def run @@ -332,13 +392,20 @@ def run # Step to write the mountlist file for Iguana, if needed class IguanaStep < Step + include Yast::I18n + IGUANA_PATH = "/iguana" private_constant :IGUANA_PATH IGUANA_MOUNTLIST = File.join(IGUANA_PATH, "mountlist").freeze private_constant :IGUANA_MOUNTLIST + def initialize(logger) + super + textdomain "agama" + end + def label - "Configuring Iguana" + _("Configuring Iguana") end def run? From 614fff5acde6b0900e5fdf015c555bee3d6a4a1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Mon, 16 Jun 2025 12:58:41 +0100 Subject: [PATCH 3/5] storage: Add iscsi finisher step --- service/lib/agama/storage/finisher.rb | 19 +++++++++++++++++++ service/test/agama/storage/manager_test.rb | 1 + 2 files changed, 20 insertions(+) diff --git a/service/lib/agama/storage/finisher.rb b/service/lib/agama/storage/finisher.rb index b216c1d770..98007d17a3 100644 --- a/service/lib/agama/storage/finisher.rb +++ b/service/lib/agama/storage/finisher.rb @@ -83,6 +83,7 @@ def possible_steps SecurityStep.new(logger, security), CopyFilesStep.new(logger), StorageStep.new(logger), + IscsiStep.new(logger), BootloaderStep.new(logger), IguanaStep.new(logger), SnapshotsStep.new(logger), @@ -239,6 +240,24 @@ def run end end + # Step to finish the iSCSI configuration + class IscsiStep < Step + include Yast::I18n + + def initialize(logger) + super + textdomain "agama" + end + + def label + _("Adjusting iSCSI configuration") + end + + def run + wfm_write("iscsi-client_finish") + end + end + # Step to configure the file-system snapshots class SnapshotsStep < Step include Yast::I18n diff --git a/service/test/agama/storage/manager_test.rb b/service/test/agama/storage/manager_test.rb index bb9113c56c..744287587a 100644 --- a/service/test/agama/storage/manager_test.rb +++ b/service/test/agama/storage/manager_test.rb @@ -410,6 +410,7 @@ expect(copy_files).to receive(:run) expect(bootloader_finish).to receive(:write) expect(Yast::WFM).to receive(:CallFunction).with("storage_finish", ["Write"]) + expect(Yast::WFM).to receive(:CallFunction).with("iscsi-client_finish", ["Write"]) expect(Yast::WFM).to receive(:CallFunction).with("snapshots_finish", ["Write"]) expect(network).to receive(:link_resolv) expect(scripts_client).to receive(:run).with("post") From e6d635f770e01240072ad4a9a4f878324891c0d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Thu, 19 Jun 2025 10:29:37 +0100 Subject: [PATCH 4/5] storage: remove unnecessary textdomain calls --- service/lib/agama/storage/finisher.rb | 76 ++------------------------- 1 file changed, 3 insertions(+), 73 deletions(-) diff --git a/service/lib/agama/storage/finisher.rb b/service/lib/agama/storage/finisher.rb index 98007d17a3..291ca6d5d0 100644 --- a/service/lib/agama/storage/finisher.rb +++ b/service/lib/agama/storage/finisher.rb @@ -96,8 +96,11 @@ def possible_steps # Base class for the Finisher steps containing some shared logic class Step + include Yast::I18n + # Base constructor def initialize(logger) + textdomain "agama" @logger = logger end @@ -127,8 +130,6 @@ def wfm_write(function) # Step to copy files from the inst-sys to the target system class CopyFilesStep < Step - include Yast::I18n - UDEV_RULES_DIR = "/etc/udev/rules.d" ROOT_PATH = "/" FILES = [ @@ -140,11 +141,6 @@ class CopyFilesStep < Step { dir: "/etc/nvme", file: "hostid" } ].freeze - def initialize(logger) - super - textdomain "agama" - end - def label _("Copying important installation files to the target system") end @@ -180,12 +176,9 @@ def glob_files # Step to write the security settings class SecurityStep < Step - include Yast::I18n - # Constructor def initialize(logger, security) super(logger) - textdomain "agama" @security = security end @@ -200,13 +193,6 @@ def run # Step to write the bootloader configuration class BootloaderStep < Step - include Yast::I18n - - def initialize(logger) - super - textdomain "agama" - end - def label _("Installing bootloader") end @@ -224,13 +210,6 @@ def cio_ignore_finish # Step to finish the Y2Storage configuration class StorageStep < Step - include Yast::I18n - - def initialize(logger) - super - textdomain "agama" - end - def label _("Adjusting storage configuration") end @@ -242,13 +221,6 @@ def run # Step to finish the iSCSI configuration class IscsiStep < Step - include Yast::I18n - - def initialize(logger) - super - textdomain "agama" - end - def label _("Adjusting iSCSI configuration") end @@ -260,13 +232,6 @@ def run # Step to configure the file-system snapshots class SnapshotsStep < Step - include Yast::I18n - - def initialize(logger) - super - textdomain "agama" - end - def label _("Configuring file systems snapshots") end @@ -278,15 +243,8 @@ def run # Step to copy the installation logs class CopyLogsStep < Step - include Yast::I18n - SCRIPTS_DIR = "/run/agama/scripts" - def initialize(logger) - super - textdomain "agama" - end - def label _("Copying logs") end @@ -321,13 +279,6 @@ def logs_dir # Executes post-installation scripts class PostScripts < Step - include Yast::I18n - - def initialize(logger) - super - textdomain "agama" - end - def label _("Running user-defined scripts") end @@ -367,13 +318,6 @@ def enable_init_scripts # Executes post-installation scripts class FilesStep < Step - include Yast::I18n - - def initialize(logger) - super - textdomain "agama" - end - def label _("Deploying user-defined files") end @@ -393,13 +337,6 @@ def deploy_files # Step to unmount the target file-systems class UnmountStep < Step - include Yast::I18n - - def initialize(logger) - super - textdomain "agama" - end - def label _("Unmounting storage devices") end @@ -411,18 +348,11 @@ def run # Step to write the mountlist file for Iguana, if needed class IguanaStep < Step - include Yast::I18n - IGUANA_PATH = "/iguana" private_constant :IGUANA_PATH IGUANA_MOUNTLIST = File.join(IGUANA_PATH, "mountlist").freeze private_constant :IGUANA_MOUNTLIST - def initialize(logger) - super - textdomain "agama" - end - def label _("Configuring Iguana") end From dbf327afe2d658f34fa3e84731cfb884157b35d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Iv=C3=A1n=20L=C3=B3pez=20Gonz=C3=A1lez?= Date: Thu, 19 Jun 2025 11:24:39 +0100 Subject: [PATCH 5/5] service: changelog --- 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 822086afae..38e2abbecb 100644 --- a/service/package/rubygem-agama-yast.changes +++ b/service/package/rubygem-agama-yast.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Thu Jun 19 10:21:13 UTC 2025 - José Iván López González + +- Add missing steps for iSCSI installation + (gh#agama-project/agama#2473). + ------------------------------------------------------------------- Wed Jun 18 12:28:14 UTC 2025 - Ladislav Slezák