From 7e1739bc078677445c0b511e423e371dcb96a10b 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, 10 Feb 2023 13:11:28 +0000 Subject: [PATCH] WIP --- doc/dbus_api.md | 85 +++----- .../lib/dinstaller/dbus/storage/iscsi_node.rb | 33 ++- .../lib/dinstaller/dbus/storage/manager.rb | 71 ++++--- .../dbus/storage/with_iscsi_auth.rb | 44 ++++ service/lib/dinstaller/storage/iscsi.rb | 31 +++ .../lib/dinstaller/storage/iscsi/initiator.rb | 4 +- .../lib/dinstaller/storage/iscsi/manager.rb | 188 ++++++++++++++++++ service/lib/dinstaller/storage/iscsi/node.rb | 9 +- .../lib/dinstaller/storage/iscsi_manager.rb | 178 ----------------- service/lib/dinstaller/storage/manager.rb | 7 +- 10 files changed, 364 insertions(+), 286 deletions(-) create mode 100644 service/lib/dinstaller/dbus/storage/with_iscsi_auth.rb create mode 100644 service/lib/dinstaller/storage/iscsi.rb create mode 100644 service/lib/dinstaller/storage/iscsi/manager.rb delete mode 100644 service/lib/dinstaller/storage/iscsi_manager.rb diff --git a/doc/dbus_api.md b/doc/dbus_api.md index d75e40f189..4404c22f99 100644 --- a/doc/dbus_api.md +++ b/doc/dbus_api.md @@ -128,10 +128,8 @@ Service for managing storage devices. .DInstaller.Storage1.ISCSI.Initiator /DInstaller/Storage1/Proposal .DInstaller.Storage1.Proposal -/DInstaller/Storage1/iscsi/node[0-9]+ +/DInstaller/Storage1/iscsi_nodes/[0-9]+ .DInstaller.Storage1.ISCSI.Node -/DInstaller/Storage1/iscsi/session[0-9]+ - .DInstaller.Storage1.ISCSI.Session ~~~ ### D-Bus Objects @@ -164,23 +162,14 @@ Moreover, it implements interfaces to manipulate the global state (perform insta This object is exported only if a proposal was already calculated (successful or not). It can be used to inspect the result of the calculated proposal. -#### `/org/opensuse/DInstaller/Storage1/iscsi/node[0-9]+` Objects +#### `/org/opensuse/DInstaller/Storage1/iscsi_nodes/[0-9]+` Objects ~~~ -/DInstaller/Storage1/iscsi/node[0-9]+ +/DInstaller/Storage1/iscsi_nodes/[0-9]+ .DInstaller.Storage1.ISCSI.Node ~~~ -Objects representing an iSCSI node are dynamically exported when a successful iSCSI discovery is performed, see `.org.opensuse.DInstaller.Storage1.ISCSI.Initiator` interface. - -#### `/org/opensuse/DInstaller/Storage1/iscsi/session[0-9]+` Objects - -~~~ -/DInstaller/Storage1/iscsi/session[0-9]+ - .DInstaller.Storage1.ISCSI.Session -~~~ - -Objects representing an active iSCSI session are dynamically exported when a iSCSI login is performed, see `.org.opensuse.DInstaller.Storage1.ISCSI.Node` interface. +Objects representing iSCSI nodes are dynamically exported when a successful iSCSI discovery is performed, see `.org.opensuse.DInstaller.Storage1.ISCSI.Initiator` interface. ### D-Bus Interfaces @@ -337,10 +326,12 @@ Provides methods for configuring iSCSI initiator and for discovering nodes. ##### Methods ~~~ -Discover( in s address, - in u port, - in a{sv} options, - out u result) +Discover(in s address, + in u port, + in a{sv} options, + out u result) +Delete(in o iscsi_node_path, + out u result) ~~~ ##### Properties @@ -354,10 +345,10 @@ IniciatorName readable,writable s ###### `Discover` Method ~~~ -Discover( in s address, - in u port, - in a{sv} options, - out u result) +Discover(in s address, + in u port, + in a{sv} options, + out u result) ~~~ Performs nodes discovery. Discovered nodes are exported with the path `/org/opensuse/DInstaller/iscsi/node[0-9]+`. @@ -373,15 +364,30 @@ Arguments: * `TargetPassword s`: Password for outgoing authentication. * `out u result`: `0` on success and `1` on failure. +##### `Delete` Method + +~~~ +Delete(in o iscsi_node_path, + out u result) +~~~ + +Deletes a discovered iSCSI node. The iSCSI node object is unexported. Note that connected nodes cannot be deleted. + +Arguments: + +* `in o iscsi_node_path`: Path of the iSCSI node to delete. +* `out u result`: `0` on success and `1` on failure. + #### `org.opensuse.DInstaller.Storage1.ISCSI.Node` Interface -This interface is implemented by objects exported at `/org/opensuse/DInstaller/Storage1/iscsi/node[0-9]+` path. It provides information about a discovered iSCSI node and allows creating a new session. +This interface is implemented by objects exported at `/org/opensuse/DInstaller/Storage1/iscsi_nodes/[0-9]+` path. It provides information about an iSCSI node and allows to perform login and logout. ##### Methods ~~~ Login(in a{sv} options, out u result) +Logout(out u result) ~~~ ##### Properties @@ -391,6 +397,7 @@ Target readable s Address readable s Port readable u Interface readable s +Startup readable s ~~~ ##### Details @@ -414,42 +421,16 @@ Arguments: * `Startup s`: startup mode (`manual`, `onboot`, `automatic`). * `out u result`: `0` on success and `1` on failure. -#### `org.opensuse.DInstaller.Storage1.ISCSI.Session` Interface - -This interface is implemented by objects exported at `/org/opensuse/DInstaller/Storage1/iscsi/session[0-9]+` path. It allows inspecting and closing an active iSCSI session. - -##### Methods - -~~~ -Logout(in a{sv} options, - out u result) -~~~ - -##### Properties - -~~~ -Node readable o -Startup readable s -~~~ - -##### Details - ###### `Logout` Method ~~~ -Logout(in a{sv} options, - out u result) +Logout(out u result) ~~~ -Closes an iSCSI session. If the session is correctly logged out, then the iSCSI session object is unexported. +Closes an iSCSI session. Arguments: -* `in a{sv} options`: - * `InitiatorUsername s`: Username for incoming authentication. - * `InitiatorPassword s`: Password for incoming authentication. - * `TargetUsername s`: Username for outgoing authentication. - * `TargetPassword s`: Password for outgoing authentication. * `out u result`: `0` on success and `1` on failure. diff --git a/service/lib/dinstaller/dbus/storage/iscsi_node.rb b/service/lib/dinstaller/dbus/storage/iscsi_node.rb index f556e3fbe0..c9f8688712 100644 --- a/service/lib/dinstaller/dbus/storage/iscsi_node.rb +++ b/service/lib/dinstaller/dbus/storage/iscsi_node.rb @@ -21,13 +21,14 @@ require "dbus" require "dinstaller/dbus/base_object" -require "y2iscsi_client/authentication" +require "dinstaller/dbus/storage/with_iscsi_auth" module DInstaller module DBus module Storage class ISCSINode < BaseObject extend Forwardable + include WithISCSIAuth attr_reader :iscsi_manager @@ -55,23 +56,17 @@ def initialize(iscsi_manager, iscsi_node, path, logger: nil) dbus_reader(:connected, "b") dbus_reader(:startup, "s") dbus_method(:Login, "in options:a{sv}, out result:u") { |o| login(o) } - dbus_method(:Logout, "in options:a{sv}, out result:u") { |o| logout(o) } - dbus_method(:Delete, "in options:a{sv}, out result:u") { |o| delete(o) } + dbus_method(:Logout, "out result:u") { logout } end def_delegator :@iscsi_node, :target_name, :target def_delegator :@iscsi_node, :portal_address, :address + def_delegator :@iscsi_node, :portal_port, :port def_delegator :@iscsi_node, :interface def_delegator :@iscsi_node, :connected - def port - @iscsi_node.portal_port.to_i - end - def startup - return "" unless @iscsi_node.connected - - @iscsi_node.startup || "" + iscsi_node.startup.to_s end def iscsi_node=(value) @@ -84,20 +79,16 @@ def iscsi_node=(value) end def login(options) - # TODO - auth = Y2IscsiClient::Authetication.new - - iscsi_manager.login(iscsi_node, auth) - 0 - end + auth = iscsi_auth(options) + startup = options["Startup"] - def logout(options) - iscsi_manager.logout(iscsi_node) - 0 + success = iscsi_manager.login(iscsi_node, auth, startup: startup) + success ? 0 : 1 end - def delete(options) - iscsi_manager.delete(iscsi_node) + def logout + success = iscsi_manager.logout(iscsi_node) + success ? 0 : 1 end end end diff --git a/service/lib/dinstaller/dbus/storage/manager.rb b/service/lib/dinstaller/dbus/storage/manager.rb index 098ac5814c..73642b9ec9 100644 --- a/service/lib/dinstaller/dbus/storage/manager.rb +++ b/service/lib/dinstaller/dbus/storage/manager.rb @@ -28,14 +28,15 @@ require "dinstaller/dbus/storage/proposal_settings_converter" require "dinstaller/dbus/storage/volume_converter" require "dinstaller/dbus/storage/iscsi_node" -require "y2iscsi_client/authentication" require "dinstaller/dbus/with_path_generator" +require "dinstaller/dbus/storage/with_iscsi_auth" module DInstaller module DBus module Storage # D-Bus object to manage storage installation class Manager < BaseObject + include WithISCSIAuth include WithServiceStatus include ::DBus::ObjectManager include DBus::Interfaces::Progress @@ -146,26 +147,28 @@ def initiator_name=(value) backend.iscsi.initiator.name = value end - def iscsi_discovery(address, port, options) - initiator_username = options["InitiatorUsername"] - initiator_password = options["InitiatorPasswor"] - target_username = options["TargetUsername"] - target_password = options["TargetPassword"] + def iscsi_discover(address, port, options) + success = backend.iscsi.discover_send_targets(address, port, iscsi_auth(options)) + success ? 0 : 1 + end + + def iscsi_delete(path) + dbus_node = iscsi_nodes_tree.find(path) + return 1 unless dbus_node - # TODO - auth = Y2IscsiClient::Authentication.new - backend.iscsi.discover_send_targets(address, port, auth) + success = backend.iscsi.delete(dbus_node.iscsi_node) + success ? 0 : 1 end dbus_interface ISCSI_INITIATOR_INTERFACE do dbus_accessor :initiator_name, "s" - # result: 0 success; 1 error dbus_method :Discover, "in address:s, in port:u, in options:a{sv}, out result:u" do |address, port, options| - busy_while { iscsi_discovery(address, port, options) } - 0 + busy_while { iscsi_discover(address, port, options) } end + + dbus_method(:Delete, "in node:o, out result:u") { |n| iscsi_delete(n) } end private @@ -190,7 +193,9 @@ def register_proposal_callbacks end def register_iscsi_callbacks - backend.iscsi.on_refresh do + backend.iscsi.activate + + backend.iscsi.on_probe do refresh_iscsi_nodes end end @@ -207,16 +212,18 @@ def export_proposal end def refresh_iscsi_nodes - @iscsi_nodes_refresher ||= ISCSINodesRefresher.new(service, backend.iscsi, logger: logger) nodes = backend.iscsi.discovered + iscsi_nodes_tree.update(nodes) + end - refresher.refresh(nodes) + def iscsi_nodes_tree + @iscsi_nodes_tree ||= ISCSINodesTree.new(@service, backend.iscsi, logger: logger) end - class ISCSINodesRefresher + class ISCSINodesTree include WithPathGenerator - ROOT_PATH = "/org/opensuse/DInstaller/Storage1/ISCSI/nodes".freeze + ROOT_PATH = "/org/opensuse/DInstaller/Storage1/iscsi_nodes".freeze path_generator ROOT_PATH def initialize(service, iscsi_manager, logger: nil) @@ -225,7 +232,11 @@ def initialize(service, iscsi_manager, logger: nil) @logger = logger end - def refresh(iscsi_nodes) + def find(path) + dbus_nodes.find { |n| n.path == path } + end + + def update(iscsi_nodes) add_new_nodes(iscsi_nodes) update_existing_nodes(iscsi_nodes) delete_old_nodes(iscsi_nodes) @@ -240,13 +251,13 @@ def refresh(iscsi_nodes) attr_reader :logger def add_new_nodes(iscsi_nodes) - new_iscsi_nodes = iscsi_nodes.select { |n| find(n).nil? } - new_iscsi_nodes.each { |n| add(n) } + new_iscsi_nodes = iscsi_nodes.select { |n| find_node(n).nil? } + new_iscsi_nodes.each { |n| add_node(n) } end def update_existing_nodes(iscsi_nodes) - existing_iscsi_nodes = iscsi_nodes.reject { |n| find(n).nil? } - existing_iscsi_nodes.each { |n| update(n) } + existing_iscsi_nodes = iscsi_nodes.reject { |n| find_node(n).nil? } + existing_iscsi_nodes.each { |n| update_node(n) } end def delete_old_nodes(iscsi_nodes) @@ -255,32 +266,34 @@ def delete_old_nodes(iscsi_nodes) iscsi_nodes.none? { |n| same_iscsi_node?(n, current_node) } end - deleted_iscsi_nodes.each { |n| delete(n) } + deleted_iscsi_nodes.each { |n| delete_node(n) } end - def add(iscsi_node) + def add_node(iscsi_node) dbus_node = DBus::Storage::ISCSINode.new( iscsi_manager, iscsi_node, next_path, logger: logger) service.export(dbus_node) dbus_node.path end - def update(iscsi_node) - dbus_node = find(iscsi_node) + def update_node(iscsi_node) + dbus_node = find_node(iscsi_node) dbus_node.iscsi_node = iscsi_node end - def delete(iscsi_node) - dbus_node = find(iscsi_node) + def delete_node(iscsi_node) + dbus_node = find_node(iscsi_node) service.unexport(dbus_node) end - def find(iscsi_node) + def find_node(iscsi_node) dbus_nodes.find { |n| same_iscsi_node?(n.iscsi_node, iscsi_node) } end def dbus_nodes root = service.get_node(ROOT_PATH, create: false) + return [] unless root + root.descendant_objects end diff --git a/service/lib/dinstaller/dbus/storage/with_iscsi_auth.rb b/service/lib/dinstaller/dbus/storage/with_iscsi_auth.rb new file mode 100644 index 0000000000..11a7c1621a --- /dev/null +++ b/service/lib/dinstaller/dbus/storage/with_iscsi_auth.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +# Copyright (c) [2023] 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 "y2iscsi_client/authentication" + +module DInstaller + module DBus + module Storage + module WithISCSIAuth + def iscsi_auth(dbus_options) + target_username = dbus_options["TargetUsername"] + target_password = dbus_options["TargetPassword"] + initiator_username = dbus_options["InitiatorUsername"] + initiator_password = dbus_options["InitiatorPassword"] + + Y2IscsiClient::Authentication.new.tap do |auth| + auth.username = target_username + auth.password = target_password + auth.username_in = initiator_username + auth.password_in = initiator_password + end + end + end + end + end +end diff --git a/service/lib/dinstaller/storage/iscsi.rb b/service/lib/dinstaller/storage/iscsi.rb new file mode 100644 index 0000000000..2467574bd8 --- /dev/null +++ b/service/lib/dinstaller/storage/iscsi.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +# Copyright (c) [2023] 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. + +module DInstaller + module Storage + module ISCSI + end + end +end + +require "dinstaller/storage/iscsi/initiator" +require "dinstaller/storage/iscsi/node" +require "dinstaller/storage/iscsi/manager" diff --git a/service/lib/dinstaller/storage/iscsi/initiator.rb b/service/lib/dinstaller/storage/iscsi/initiator.rb index 3232bde619..10fcf33c35 100644 --- a/service/lib/dinstaller/storage/iscsi/initiator.rb +++ b/service/lib/dinstaller/storage/iscsi/initiator.rb @@ -19,9 +19,11 @@ # To contact SUSE LLC about this file by physical or electronic mail, you may # find current contact information at www.suse.com. +Yast.import "IscsiClientLib" + module DInstaller module Storage - module Iscsi + module ISCSI # The Open-iscsi initiator class Initiator def name diff --git a/service/lib/dinstaller/storage/iscsi/manager.rb b/service/lib/dinstaller/storage/iscsi/manager.rb new file mode 100644 index 0000000000..f3ba996cce --- /dev/null +++ b/service/lib/dinstaller/storage/iscsi/manager.rb @@ -0,0 +1,188 @@ +# frozen_string_literal: true + +# Copyright (c) [2023] 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 "yast" +require "dinstaller/storage/iscsi/node" +require "dinstaller/storage/iscsi/initiator" + +Yast.import "IscsiClientLib" + +module DInstaller + module Storage + module ISCSI + class Manager + # Class methods + class << self + def instance(logger: nil) + return @instance if @instance + + create_instance(logger: logger) + end + + def create_instance(logger: nil) + @instance = new(logger: logger) + end + + # Make sure only .instance can be used to create objects + private :new, :allocate + end + + # Constructor + # + # @param logger [Logger, nil] + def initialize(logger: nil) + @logger = logger || ::Logger.new($stdout) + @on_probe_callbacks = [] + end + + def activate + return if activated? + + # NOTE: check call to IscsiClientLib.load_modules at widgets.rb + + # Why we need to sleep every now and then? We copied that from yast2-iscsi-client + sl = 0.5 + + logger.info "Read information from the iBFT" + Yast::IscsiClientLib.getiBFT + sleep(sl) + + # Check initiatorname, creating one if missing + logger.info "Check initiator name" + # Or maybe add a silent attribute to IscsiClientLib and set it at the beginning of D-Installer + return false unless Yast::IscsiClientLib.checkInitiatorName(silent: true) + sleep(sl) + + Yast::IscsiClientLib.getConfig + + logger.info "Try auto-login to targets configured via iBFT" + Yast::IscsiClientLib.autoLogOn + sleep(sl) + + @activated = true + end + + def probe + read_sessions + read_discovered + + @on_probe_callbacks.each(&:call) + end + + def activated? + !!@activated + end + + def sessions + return [] if @sessions.nil? + + @sessions.values + end + + def read_sessions + logger.info "Read the current iSCSI sessions" + Yast::IscsiClientLib.readSessions + @sessions = {} + Yast::IscsiClientLib.sessions.map do |session_str| + @sessions[session_str] = ISCSI::Node.new_from_yast_session(session_str.split(" ")) + end + end + + def discovered + return [] if @discovered.nil? + + @discovered.values + end + + def read_discovered + logger.info "Read the discovered targets" + @discovered = {} + Yast::IscsiClientLib.getDiscovered.map do |target_str| + node = find_session(target_str) + node ||= ISCSI::Node.new_from_yast_discovered(target_str.split(" ")) + @discovered[target_str] = node + end + end + + def initiator + ISCSI::Initiator.new + end + + # Based on provided address and port, ie. assuming ISNS is not used. + # Since YaST do not offer UI to configure ISNS during installation, we are assuming + # it's not supported. + def discover_send_targets(host, port, authentication) + probe_after do + Yast::IscsiClientLib.discover(host, port, authentication, silent: true) + end + end + + def login(node, authentication, startup: nil) + probe_after do + startup = Yast::IscsiClientLib.detault_startup_status if startup.to_s.empty? + + return false unless ["onboot", "manual", "automatic"].include?(startup) + + Yast::IscsiClientLib.currentRecord = node.to_yast + Yast::IscsiClientLib.login_into_current(authentication, silent: true) && + Yast::IscsiClientLib.setStartupStatus(startup) + end + end + + def logout(node) + probe_after do + Yast::IscsiClientLib.currentRecord = node.to_yast + # Yes, this is the correct method name for logging out + Yast::IscsiClientLib.deleteRecord + end + end + + def delete(node) + probe_after do + Yast::IscsiClientLib.currentRecord = node.to_yast + Yast::IscsiClientLib.removeRecord + end + end + + # Registers a callback to be called when the nodes are probed + # + # @param block [Proc] + def on_probe(&block) + @on_probe_callbacks << block + end + + private + + attr_reader :logger + + def find_session(target_str) + Yast::IscsiClientLib.currentRecord = target_str.split(" ") + session_str = Yast::IscsiClientLib.find_session(true) + session_str ? @sessions[session_str] : nil + end + + def probe_after(&block) + block.call.tap { probe } + end + end + end + end +end diff --git a/service/lib/dinstaller/storage/iscsi/node.rb b/service/lib/dinstaller/storage/iscsi/node.rb index 495a3cb6c3..de5e891def 100644 --- a/service/lib/dinstaller/storage/iscsi/node.rb +++ b/service/lib/dinstaller/storage/iscsi/node.rb @@ -19,9 +19,11 @@ # To contact SUSE LLC about this file by physical or electronic mail, you may # find current contact information at www.suse.com. +Yast.import "IscsiClientLib" + module DInstaller module Storage - module Iscsi + module ISCSI # Class to represent an Open-iscsi node # # Bear in mind Open-iscsi does not use the term node as defined by the iSCSI RFC, where a node @@ -88,7 +90,10 @@ def ibft? private def portal=(string) - @portal_address, @portal_port = string.split(":") + address, port = string.split(":") + + @portal_address = address + @portal_port = port.to_i end end end diff --git a/service/lib/dinstaller/storage/iscsi_manager.rb b/service/lib/dinstaller/storage/iscsi_manager.rb deleted file mode 100644 index 1bb0e92841..0000000000 --- a/service/lib/dinstaller/storage/iscsi_manager.rb +++ /dev/null @@ -1,178 +0,0 @@ -# frozen_string_literal: true - -# Copyright (c) [2023] 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 "yast" -require "dinstaller/storage/iscsi/node" -require "dinstaller/storage/iscsi/initiator" - -Yast.import "IscsiClientLib" - -module DInstaller - module Storage - class IscsiManager - - # Class methods - class << self - def instance(logger: nil) - return @instance if @instance - - create_instance(logger: logger) - end - - def create_instance(logger: nil) - @instance = new(logger: logger) - end - - # Make sure only .instance can be used to create objects - private :new, :allocate - end - - # Constructor - # - # @param logger [Logger, nil] - def initialize(logger: nil) - @logger = logger || ::Logger.new($stdout) - @probed = false - @on_refresh_callbacks = [] - end - - def probe - return if probed? - - # NOTE: check call to IscsiClientLib.load_modules at widgets.rb - - # Why we need to sleep every now and then? We copied that from yast2-iscsi-client - sl = 0.5 - - logger.info "Read information from the iBFT" - Yast::IscsiClientLib.getiBFT - sleep(sl) - - # Check initiatorname, creating one if missing - logger.info "Check initiator name" - # Or maybe add a silent attribute to IscsiClientLib and set it at the beginning of D-Installer - return false unless Yast::IscsiClientLib.checkInitiatorName(silent: true) - sleep(sl) - - logger.info "Try auto-login to targets configured via iBFT" - Yast::IscsiClientLib.autoLogOn - sleep(sl) - - @probed = true - refresh - end - - def probed? - !!@probed - end - - def sessions - raise Whatever if @sessions.nil? - - @sessions.values - end - - def read_sessions - raise Whatever unless probed? - - logger.info "Read the current iSCSI sessions" - Yast::IscsiClientLib.readSessions - @sessions = {} - Yast::IscsiClientLib.sessions.map do |session_str| - @sessions[session_str] = Iscsi::Node.new_from_yast_session(session_str.split(" ")) - end - end - - def discovered - raise Whatever if @discovered.nil? - - @discovered.values - end - - def read_discovered - raise Whatever unless probed? - - logger.info "Read the discovered targets" - @discovered = {} - Yast::IscsiClientLib.getDiscovered.map do |target_str| - node = find_session(target_str) - node ||= Iscsi::Node.new_from_yast_discovered(target_str.split(" "), ) - @discovered[target_str] = node - end - end - - def initiator - Iscsi::Initiator.new - end - - # Based on provided address and port, ie. assuming ISNS is not used. - # Since YaST do not offer UI to configure ISNS during installation, we are assuming - # it's not supported. - def discover_send_targets(host, port, authentication) - Yast::IscsiClientLib.discover(host, port, authentication) - read_discovered - end - - def login(node, authentication) - Yast::IscsiClientLib.currentRecord = node.to_yast - Yast::IscsiClientLib.login_into_current(authentication, silent: true) - refresh - end - - def logout(node) - Yast::IscsiClientLib.currentRecord = node.to_yast - # Yes, this is the correct method name for logging out - Yast::IscsiClientLib.deleteRecord - refresh - end - - def delete(node) - Yast::IscsiClientLib.currentRecord = node.to_yast - Yast::IscsiClientLib.removeRecord - refresh - end - - def refresh - read_sessions - read_discovered - - @on_refresh_callbacks.each(&:call) - end - - # Registers a callback to be called when the nodes are refreshed - # - # @param block [Proc] - def on_refresh(&block) - @on_refresh_callbacks << block - end - - private - - attr_reader :logger - - def find_session(target_str) - Yast::IscsiClientLib.currentRecord = target_str.split(" ") - session_str = Yast::IscsiClientLib.find_session(true) - session_str ? @sessions[session_str] : nil - end - end - end -end diff --git a/service/lib/dinstaller/storage/manager.rb b/service/lib/dinstaller/storage/manager.rb index 819a4d0bf3..06186f736c 100644 --- a/service/lib/dinstaller/storage/manager.rb +++ b/service/lib/dinstaller/storage/manager.rb @@ -28,7 +28,7 @@ require "dinstaller/storage/proposal" require "dinstaller/storage/proposal_settings" require "dinstaller/storage/callbacks" -require "dinstaller/storage/iscsi_manager" +require "dinstaller/storage/iscsi/manager" require "dinstaller/with_progress" require "dinstaller/security" require "dinstaller/dbus/clients/questions" @@ -113,7 +113,7 @@ def proposal end def iscsi - @iscsi = IscsiManager.instance(logger: logger) + @iscsi = ISCSI::Manager.instance(logger: logger) end # Validates the storage configuration @@ -138,13 +138,14 @@ def validate def activate_devices callbacks = Callbacks::Activate.new(questions_client, logger) - iscsi.probe + iscsi.activate Y2Storage::StorageManager.instance.activate(callbacks) end # Probes the devices def probe_devices # TODO: probe callbacks + iscsi.probe Y2Storage::StorageManager.instance.probe end