From e236bf66f2f8f2c0d86f39316d7dec88e26d1b9d Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Wed, 10 Nov 2021 09:54:00 +0000 Subject: [PATCH 01/31] Added new classes for DASDs management --- .rubocop.yml | 6 +- package/yast2-s390.spec | 1 + src/lib/y2s390.rb | 4 + src/lib/y2s390/base_collection.rb | 88 ++++++++++ src/lib/y2s390/dasd.rb | 170 ++++++++++++++++++++ src/lib/y2s390/dasd_actions.rb | 4 + src/lib/y2s390/dasd_actions/activate.rb | 61 +++++++ src/lib/y2s390/dasd_actions/base.rb | 50 ++++++ src/lib/y2s390/dasd_actions/deactivate.rb | 20 +++ src/lib/y2s390/dasd_actions/diag.rb | 38 +++++ src/lib/y2s390/dasd_actions/format.rb | 84 ++++++++++ src/lib/y2s390/dasds_collection.rb | 13 ++ src/lib/y2s390/dasds_reader.rb | 165 +++++++++++++++++++ src/lib/y2s390/format_process.rb | 129 +++++++++++++++ src/lib/y2s390/formatting_status.rb | 44 +++++ src/lib/y2s390/hwinfo_reader.rb | 54 +++++++ test/dasd_controller_test.rb | 18 ++- test/data/lsdasd.txt | 10 ++ test/data/probe_disk.yml | 52 ++++++ test/y2s390/base_collection_examples.rb | 126 +++++++++++++++ test/y2s390/dasd_actions/activate_test.rb | 138 ++++++++++++++++ test/y2s390/dasd_actions/base_test.rb | 60 +++++++ test/y2s390/dasd_actions/deactivate_test.rb | 35 ++++ test/y2s390/dasd_actions/diag_test.rb | 116 +++++++++++++ test/y2s390/dasd_actions/format_test.rb | 152 +++++++++++++++++ test/y2s390/dasd_test.rb | 72 +++++++++ test/y2s390/dasds_collection_test.rb | 32 ++++ test/y2s390/dasds_reader_test.rb | 58 +++++++ 28 files changed, 1794 insertions(+), 6 deletions(-) create mode 100644 src/lib/y2s390.rb create mode 100644 src/lib/y2s390/base_collection.rb create mode 100644 src/lib/y2s390/dasd.rb create mode 100644 src/lib/y2s390/dasd_actions.rb create mode 100644 src/lib/y2s390/dasd_actions/activate.rb create mode 100644 src/lib/y2s390/dasd_actions/base.rb create mode 100644 src/lib/y2s390/dasd_actions/deactivate.rb create mode 100644 src/lib/y2s390/dasd_actions/diag.rb create mode 100644 src/lib/y2s390/dasd_actions/format.rb create mode 100644 src/lib/y2s390/dasds_collection.rb create mode 100644 src/lib/y2s390/dasds_reader.rb create mode 100644 src/lib/y2s390/format_process.rb create mode 100644 src/lib/y2s390/formatting_status.rb create mode 100644 src/lib/y2s390/hwinfo_reader.rb create mode 100644 test/data/lsdasd.txt create mode 100644 test/y2s390/base_collection_examples.rb create mode 100644 test/y2s390/dasd_actions/activate_test.rb create mode 100644 test/y2s390/dasd_actions/base_test.rb create mode 100644 test/y2s390/dasd_actions/deactivate_test.rb create mode 100644 test/y2s390/dasd_actions/diag_test.rb create mode 100644 test/y2s390/dasd_actions/format_test.rb create mode 100644 test/y2s390/dasd_test.rb create mode 100644 test/y2s390/dasds_collection_test.rb create mode 100644 test/y2s390/dasds_reader_test.rb diff --git a/.rubocop.yml b/.rubocop.yml index a2441ff9..c8b52025 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -75,10 +75,8 @@ Metrics/BlockLength: - 'src/include/s390/iucvterminal/ui.rb' - 'src/include/s390/onpanic/ui.rb' - 'src/modules/DASDController.rb' - - 'test/dasd_controller_test.rb' - - 'test/ui_include_test.rb' - - 'test/ui_onpanic_include_test.rb' - - 'test/zfcp_controller_test.rb' + # RSpec is known as DSL with big blocks + - 'test/**/*' # Offense count: 3 Naming/AccessorMethodName: diff --git a/package/yast2-s390.spec b/package/yast2-s390.spec index 4d985046..add45c87 100644 --- a/package/yast2-s390.spec +++ b/package/yast2-s390.spec @@ -63,6 +63,7 @@ S/390-specific features. %files %{yast_yncludedir} %{yast_clientdir} +%{yast_libdir} %{yast_moduledir} %{yast_scrconfdir} %{yast_desktopdir} diff --git a/src/lib/y2s390.rb b/src/lib/y2s390.rb new file mode 100644 index 00000000..51ac23fd --- /dev/null +++ b/src/lib/y2s390.rb @@ -0,0 +1,4 @@ +require "y2s390/dasd" +require "y2s390/dasds_reader" +require "y2s390/dasds_collection" +require "y2s390/hwinfo_reader" diff --git a/src/lib/y2s390/base_collection.rb b/src/lib/y2s390/base_collection.rb new file mode 100644 index 00000000..a89b70d7 --- /dev/null +++ b/src/lib/y2s390/base_collection.rb @@ -0,0 +1,88 @@ +# Copyright (c) [2021] 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 "forwardable" + +module Y2S390 + # Base class for collection of config elements (e.g., {Dasd}). + class BaseCollection + extend Forwardable + + def_delegators :@elements, :each, :each_with_index, :select, :find, :reject, :map, + :any?, :size, :empty?, :first + + # Constructor + # + # @param elements [Array] + def initialize(elements = []) + @elements = elements + end + + # Adds an element to the collection + # + # @param element [Object] + # @return [self] + def add(element) + @elements << element + + self + end + + # Deletes the element with the given id from the collection + # + # @param id [String] + # @return [self] + def delete(id) + @elements.reject! { |e| e.id == id } + + self + end + + # List with all the elements + # + # @return [Array] + def all + @elements.dup + end + + alias_method :to_a, :all + + # Element with the given id + # + # @return [Object, nil] nil if the collection does not include an element with + # such an id. + def by_id(value) + @elements.find { |e| e.id == value } + end + + # Elements included in the given id's list + # + # @return [BaseCollection] A new collection with the elements included in the list given + def by_ids(ids) + self.class.new(@elements.select { |d| ids.include?(d.id) }) + end + + # All element ids + # + # @return [Array] + def ids + map(&:id) + end + end +end diff --git a/src/lib/y2s390/dasd.rb b/src/lib/y2s390/dasd.rb new file mode 100644 index 00000000..e56fbc57 --- /dev/null +++ b/src/lib/y2s390/dasd.rb @@ -0,0 +1,170 @@ +# Copyright (c) [2021] 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 "yast2/execute" +require "y2s390/formatting_status" + +module Y2S390 + # This class represents a direct-access storage device (DASD) + class Dasd + # Command for configuring z Systems specific devices + CONFIGURE_CMD = "/sbin/dasd_configure".freeze + # # Command for displaying configuration of z Systems DASD devices + LIST_CMD = "/sbin/lsdasd".freeze + + # @return [String] dasd type (EKCD, FBA) + attr_accessor :type + + # @return [String] dasd device type, cpu model... + attr_accessor :device_type + + # @return [String] the device id or channel + attr_accessor :id + + # @return [String, nil) associated device name + attr_accessor :device_name + + # @return [Symbol] device status (:offline, :active) + attr_reader :status + + # @return [Integer] number of cylinders + attr_accessor :cylinders + + # @return [FormattingStatus] status of the last formatting process + attr_accessor :formatting_status + + # @return [Boolean] + attr_accessor :format_wanted + + # @return [Boolean] + attr_accessor :diag_wanted + + # @return [Boolean] + attr_accessor :formatted + + # @return [Boolean] + attr_accessor :use_diag + + KNOWN_STATUS = { + "offline" => :offline, "active" => :active, "active(ro)" => :read_only, "n/f" => :no_format + }.freeze + + # Constructor + # + # @param id [String] + # @param status [String] + # @param device_name [String] + # @param type [String] + def initialize(id, status: nil, device_name: nil, type: nil) + @id = id + @device_name = device_name + @type = type + self.status = status + end + + def hex_id + @id.gsub(".", "").hex + end + + # Sets the device status if known or :unknown if not + # + # @param value [String] device current status according to lsdasd output + # @return [Symbol] device status (:active, :read_only, :offline or :unknown) + def status=(value) + @status = KNOWN_STATUS[value.to_s.downcase] || :unknown + end + + # @return [Boolean] whether the DASD device is active or not + def active? + status == :active || status == :read_only + end + + # @return [Boolean] whether the DASD device is formatted or not + def offline? + status == :offline + end + + # @return [Boolean] whether the DASD device is formatted or not + def formatted? + @formatted || false + end + + # Return the partitions information + # + # @return [String] + def partition_info + return "/dev/#{device_name}1" if type != "ECKD" + + out = Yast::Execute.stdout.on_target!("/sbin/fdasd", "-p", "/dev/#{device_name}") + return out if out.empty? + + regexp = Regexp.new("^[ \t]*([^ \t]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)" \ + "[ \t]+([^ \t]+)[ \t]+([^ \t]+([ \t]+[^ \t]+))*[ \t]*$") + + lines = out.split("\n").select { |s| s.match?(regexp) } + lines.map { |line| r = line.match(regexp); "#{r[1]} (#{r[6]})" }.join(", ") + end + + def hwinfo + Y2S390::HwinfoReader.instance.for_device(id) + end + + # Returns whether the device can be formatted or not + # + # @return [Boolean] + def can_be_formatted? + active? && type == "ECKD" + end + + # Returns whether the device is active according to the IO hwinfo + # + # @return [Boolean] true if it is active; false otherwise + def io_active? + hwinfo&.resource&.io&.first&.active + end + + # Returns the access type ('rw', 'ro') according to the hwinfo + # + # @return [Boolean] true if it is active; false otherwise + def access_type + hwinfo&.resource&.io&.first&.mode + end + + # @return [Integer] + def sysfs_id + hwinfo&.sysfs_id + end + + def sys_device_name + cmd = ["ls", "/sys/bus/ccw/devices/#{id}/block/"] + disk = Yast::Execute.stdout.on_target!(cmd).strip + disk.to_s.empty? ? nil : "/dev/#{disk}" + end + + def refresh_data! + cmd = [LIST_CMD, id] + data = Yast::Execute.stdout.locally!(*cmd).split("\n").find { |l| l.start_with? /\d/ } + + return if data.to_s.empty? + + _id, @status, @device_name, _, @type, = data.split(" ") + end + end +end diff --git a/src/lib/y2s390/dasd_actions.rb b/src/lib/y2s390/dasd_actions.rb new file mode 100644 index 00000000..4631bc80 --- /dev/null +++ b/src/lib/y2s390/dasd_actions.rb @@ -0,0 +1,4 @@ +require "y2s390/dasd_actions/activate" +require "y2s390/dasd_actions/deactivate" +require "y2s390/dasd_actions/format" +require "y2s390/dasd_actions/diag" diff --git a/src/lib/y2s390/dasd_actions/activate.rb b/src/lib/y2s390/dasd_actions/activate.rb new file mode 100644 index 00000000..553c6eec --- /dev/null +++ b/src/lib/y2s390/dasd_actions/activate.rb @@ -0,0 +1,61 @@ +require "y2s390/dasd_actions/base" + +module Y2S390 + module DasdActions + class Activate < Base + def run + unformatted_disks = [] + + selected.each do |dasd| + unformatted_disks << dasd if activate(dasd) == 8 # 8 means disk is not formatted + end + + # for autoinst, format unformatted disks later + if format_now?(unformatted_disks) + devices = unformatted_disks.each_with_object([]) { |d, arr| arr << d if device_for!(d) } + controller.FormatDisks(devices) + devices.each { |d| activate(d) } + end + + controller.ProbeDisks + + true + end + + private + + # Convenience method for checking if the activated DASD without format need to be formatted + # now or not. + # + # @param unformatted_disks [Array] + def format_now?(unformatted_disks) + return false if auto_mode? || unformatted_disks.empty? + + popup = if unformatted_disks.size == 1 + format(_("Device %s is not formatted. Format device now?"), unformatted_disks.first.id) + else + format(_("There are %s unformatted devices. Format them now?"), + unformatted_disks.size) + end + + Yast::Popup.ContinueCancel(popup) + end + + def device_for!(dasd) + # We need to set it before format the disk + name = dasd.device_name = dasd.sys_device_name + Yast::Popup.Error(format(_("Couldn't find device for channel %s."), dasd.id)) if !name + + name + end + + # Convenience method for activating a DASD device + # + # @param dasd [Dasd] device to be activated + # @return [Boolean] whether the device was activated or not + def activate(dasd) + controller.ActivateDisk(dasd.id, !!dasd.diag_wanted) + end + end + end +end diff --git a/src/lib/y2s390/dasd_actions/base.rb b/src/lib/y2s390/dasd_actions/base.rb new file mode 100644 index 00000000..cc4e93d0 --- /dev/null +++ b/src/lib/y2s390/dasd_actions/base.rb @@ -0,0 +1,50 @@ +require "yast" +require "abstract_method" + +Yast.import "DASDController" +Yast.import "Mode" +Yast.import "Popup" + +module Y2S390 + module DasdActions + # Base class for all the DASD actions that can be performed over a collection of DASDs + class Base + include Yast::I18n + + # @return [Boolean] + abstract_method :run + # @return [Y2S390::DasdsCollection] + attr_accessor :selected + + # Constructor + # + # @param selected [Y2S390::DasdsCollection] the collection of DASDs to which the action + # has to be applied + def initialize(selected) + textdomain "s390" + @selected = selected + end + + # @params selected [Y2S390::DasdsCollection] the collection of DASDs to which the action + # has to be applied + def self.run(selected) + new(selected).run + end + + # @return [Boolean] true in config mode; false otherwise + def config_mode? + Yast::Mode.config + end + + # @return [Boolean] true in autoinst mode; false otherwise + def auto_mode? + Yast::Mode.autoinst + end + + # Convenience method + def controller + Yast::DASDController + end + end + end +end diff --git a/src/lib/y2s390/dasd_actions/deactivate.rb b/src/lib/y2s390/dasd_actions/deactivate.rb new file mode 100644 index 00000000..9643214f --- /dev/null +++ b/src/lib/y2s390/dasd_actions/deactivate.rb @@ -0,0 +1,20 @@ +require "y2s390/dasd_actions/base" + +module Y2S390 + module DasdActions + class Deactivate < Base + def run + selected.each { |d| deactivate(d) } + controller.ProbeDisks + + true + end + + private + + def deactivate(dasd) + controller.DeactivateDisk(dasd.id, dasd.diag_wanted) + end + end + end +end diff --git a/src/lib/y2s390/dasd_actions/diag.rb b/src/lib/y2s390/dasd_actions/diag.rb new file mode 100644 index 00000000..a82bfeb9 --- /dev/null +++ b/src/lib/y2s390/dasd_actions/diag.rb @@ -0,0 +1,38 @@ +require "y2s390/dasd_actions/base" + +module Y2S390 + module DasdActions + class Diag < Base + attr_accessor :use_diag + + def run + if Yast::Mode.config + selected.each { |dasd| dasd.diag_wanted = !!use_diag } + else + selected.each do |dasd| + controller.ActivateDiag(dasd.id, !!use_diag) if dasd.io_active? + dasd.diag_wanted = !!use_diag + end + + controller.ProbeDisks + end + + true + end + end + + class DiagOff < Diag + def initialize(selected) + super(selected) + @use_diag = false + end + end + + class DiagOn < Diag + def initialize(selected) + super(selected) + @use_diag = true + end + end + end +end diff --git a/src/lib/y2s390/dasd_actions/format.rb b/src/lib/y2s390/dasd_actions/format.rb new file mode 100644 index 00000000..83050331 --- /dev/null +++ b/src/lib/y2s390/dasd_actions/format.rb @@ -0,0 +1,84 @@ +require "y2s390/dasd_actions/base" + +module Y2S390 + module DasdActions + class FormatOff < Base + def run + selected.each { |dasd| dasd.format_wanted = false } + true + end + end + + class FormatOn < Base + def run + selected.each { |dasd| dasd.format_wanted = true } + true + end + end + + class Format < Base + def run + return false unless can_be_formatted? + return false unless really_format? + + controller.FormatDisks(selected) + + # We used to explicitly activate the DASD devices here, don't do + # it - see bsc#1187012. + + controller.ProbeDisks + + true + end + + private + + def can_be_formatted? + # check if disks are R/W and active + problem = nil + + selected.each do |dasd| + if !dasd.io_active? + # error report, %s is device identification + problem = format(_("Disk %s is not active."), dasd.id) + elsif dasd.access_type != "rw" + # error report, %s is device identification + problem = format(_("Disk %s is not accessible for writing."), dasd.id) + elsif !dasd.can_be_formatted? + problem = + # TRANSLATORS %s is device idetification + format(_("Disk %s cannot be formatted. Only ECKD disks can be formatted."), dasd.id) + end + end + + if problem + Yast::Popup.Message(problem) + return false + end + + true + end + + def really_format? + channels_str = selected.map(&:id).join(", ") + + Yast::Popup.AnyQuestionRichText( + Yast::Popup.NoHeadline, + # popup question + format( + _( + "Formatting these disks destroys all data on them.
\n" \ + "Really format the following disks?
\n" \ + "%s" + ), channels_str + ), + 60, + 20, + Yast::Label.YesButton, + Yast::Label.NoButton, + :focus_no + ) + end + end + end +end diff --git a/src/lib/y2s390/dasds_collection.rb b/src/lib/y2s390/dasds_collection.rb new file mode 100644 index 00000000..c42bec0f --- /dev/null +++ b/src/lib/y2s390/dasds_collection.rb @@ -0,0 +1,13 @@ +require "y2s390/base_collection" + +module Y2S390 + class DasdsCollection < BaseCollection + def filter(&block) + self.class.new(@elements.select(&block)) + end + + def active + filter(&:active?) + end + end +end diff --git a/src/lib/y2s390/dasds_reader.rb b/src/lib/y2s390/dasds_reader.rb new file mode 100644 index 00000000..2a17d13a --- /dev/null +++ b/src/lib/y2s390/dasds_reader.rb @@ -0,0 +1,165 @@ +# Copyright (c) [2021] 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 "y2s390/dasd" +require "yast2/execute" +require "y2s390/dasds_collection" +require "y2s390/hwinfo_reader" + +Yast.import "Mode" + +module Y2S390 + # This class is reponsible of reading the information about DASD devices + class DasdsReader + attr_accessor :disks + + # Command for displaying configuration of z Systems DASD devices + LIST_CMD = "/sbin/lsdasd".freeze + + # Initializes a collection of DASDs based on the information read using lsdasd output and also + # the hardware information (hwinfo). + # + # @param offline [Boolean] whether it should obtain the offline devices too or not + # @param force_probing [Boolean] in case of probing it will fetch the hwinfo if not will use the + # information cached when exist + # @return [Array] a collection of Dasds read from the system using a + # comination + def list(offline: true, force_probing: false) + HwinfoReader.instance.reset if force_probing + + a = dasd_entries(offline: offline).each_with_object([]) do |entry, arr| + next unless entry.start_with?(/\d/) + + id, offline, name, _, type, = entry.split(" ") + attrs = Yast::Mode.config ? {} : { status: offline, device_name: name, type: type } + dasd = Y2S390::Dasd.new(id, **attrs).tap do |d| + if Yast::Mode.config + d.diag = d.use_diag = use_diag?(d) + d.format = false + else + update_additional_info(d) + end + end + + arr << dasd + end + + Y2S390::DasdsCollection.new(a) + end + + def update_info(dasd, extended: false) + data = dasd_entries(dasd: dasd).find { |e| e.start_with?(/\d/) } + return false if data.to_s.empty? + + _, status, name, _, type, = data.split(" ") + dasd.status = status + dasd.device_name = name + dasd.type = type + update_additional_info(dasd) if extended + end + + def update_additional_info(dasd) + refresh_extended_data!(dasd) + end + + private + + # In production, call SCR.Read(.probe.disk). + # For testing, point YAST2_S390_PROBE_DISK to a YAML file + # with the mock value. + # Suggesstion: + # YAST2_S390_PROBE_DISK=test/data/probe_disk_dasd.yml rake run"[dasd]" + # @return [Array] .probe.disk output + def dasd_entries(offline: true, dasd: nil) + if ENV["S390_MOCKING"] + File.read("test/data/lsdasd.txt") + else + cmd = cmd_for(offline: offline) + Yast::Execute.stdout.locally!(cmd) + end.split("\n") + end + + def cmd_for(offline: true, dasd: nil) + cmd = [LIST_CMD] + cmd << "-a" if offline + cmd << dasd if dasd + cmd + end + + def refresh_extended_data!(dasd) + reset_extended_data!(dasd) if dasd.offline? + dasd.use_diag = use_diag?(dasd) + dasd.formatted = formatted?(dasd) + dasd.device_type = device_type_for(dasd) + end + + def reset_extended_data!(dasd) + dasd.cylinders = nil + dasd.formatting_status = nil + end + + # Determines whether a given DASD is formatted or not + # + # @param dasd [DASD] + # @return [Boolean] + def formatted?(dasd) + return false if dasd.offline? + + fmt_out = Yast::Execute.stdout.locally!( + ["/sbin/dasdview", "--extended", "/dev/#{dasd.device_name}"], ["grep", "formatted"] + ) + fmt_out.empty? ? false : !fmt_out.upcase.match?(/NOT[ \t]*FORMATTED/) + end + + # Determines whether the given DASD has the DIAG access enabled or not + # + # @param dasd [DASD] + # @return [Boolean] + def use_diag?(dasd) + diag_file = "/sys/#{dasd.sysfs_id}/device/use_diag" + use_diag = Yast::SCR.Read(Yast.path(".target.string"), diag_file) if File.exist?(diag_file) + use_diag.to_i == 1 + end + + # Get partitioninfo + # @param [String] disk string Disk to read info from + # @return GetPartitionInfo string The info + def partition_info(dasd) + return "#{dasd.device_name}1" if dasd.type != "ECKD" + + out = Yast::Execute.stdout.on_target!("/sbin/fdasd", "-p", "/dev/#{dasd.device_name}") + return out if out.empty? + + regexp = Regexp.new("^[ \t]*([^ \t]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)" \ + "[ \t]+([^ \t]+)[ \t]+([^ \t]+([ \t]+[^ \t]+))*[ \t]*$") + + lines = out.split("\n").select { |s| s.match?(regexp) } + lines.map { |line| r = line.match(regexp); "#{r[1]} (#{r[6]})" }.join(", ") + end + + def device_type_for(dasd) + device_type = (dasd&.hwinfo&.device_id.to_i & 65535).to_s(16) + cu_model = dasd&.hwinfo&.detail&.cu_model.to_i.to_s(16).rjust(2, "0") + sub_device_id = (dasd&.hwinfo&.sub_device_id.to_i & 65535).to_s(16) + dev_model = dasd&.hwinfo&.detail&.dev_model.to_i.to_s(16).rjust(2, "0") + + "#{device_type}/#{cu_model} #{sub_device_id}/#{dev_model}".upcase + end + end +end diff --git a/src/lib/y2s390/format_process.rb b/src/lib/y2s390/format_process.rb new file mode 100644 index 00000000..327d06e3 --- /dev/null +++ b/src/lib/y2s390/format_process.rb @@ -0,0 +1,129 @@ +require "yast" +require "yast2/execute" + +module Y2S390 + class FormatStatus + attr_accessor :progress, :cylinders, :dasd + # Constructor + # + # @param dasd [Dasd] + # @param cylinders [Ingeger] + # @param format_size [Integer] + def initialize(dasd, cylinders, format_size = 10) + @dasd = dasd + @cylinders = cylinders + @progress = 0 + @size = format_size + end + + def update_progress + @progress += @size + end + + def done? + @cylinders <= @progress + end + + def step! + update_progress + end + end + + # This class is responsible of formatting a set of DASD volumes maintaining also the status of the + # progress. + class FormatProcess + include Yast::Logger + attr_accessor :id, :dasds, :summary, :updated + + SIZE = 10 + + # Constructor + # + # @param dasds [Integer] + def initialize(dasds) + @dasds = dasds + @summary = {} + @updated = {} + end + + def disks_params + dasds.map { |d| "-f /dev/#{d.device_name}" }.join(" ") + end + + # Convenience method to start with the formatting process + def start + cmd = "/sbin/dasdfmt -Y -P #{dasds.size} -b 4096 -y -r #{SIZE} -m #{SIZE} #{disks_params}" + + @id = Yast::SCR.Execute(Yast.path(".process.start_shell"), cmd) + end + + # Checks whether the formatting process is still running or not + # + # @return [Boolean] true when running; false otherwise + def running? + return false unless @id + + Yast::SCR.Read(Yast.path(".process.running"), @id) + end + + def read_line + return "" unless @id + + Yast::SCR.Read(Yast.path(".process.read_line"), @id) + end + + def read + Yast::SCR.Read(Yast.path(".process.read"), @id) + end + + def status + Yast::SCR.Read(Yast.path(".process.status"), @id) + end + + def error + stderr = "" + loop do + line = Yast::SCR.Read(Yast.path(".process.read_line_stderr")) + break unless line + + stderr << line + end + + stderr + end + + def initialize_summary + dasds.each_with_index { |d, i| @summary[i] = FormatStatus.new(d, read_line.to_i) } + end + + def update_summary + @updated = {} + + line = read + + return unless line + + log.info "Updating Summary" + progress = line.split("|") + progress.each do |d| + next if d.to_s.empty? + + summary[d.to_i]&.update_progress + @updated[d.to_i] = summary[d.to_i] + end + log.info("The summary is #{summary.inspect}") + log.info("Updated #{updated.inspect}") + + updated + end + + def cylinders + log.info("The summary is #{summary.values.inspect}") + summary.values.inject(0) { |sum, v| sum + v.cylinders } + end + + def progress + @summary.values.inject(0) { |sum, v| sum + v.progress } + end + end +end diff --git a/src/lib/y2s390/formatting_status.rb b/src/lib/y2s390/formatting_status.rb new file mode 100644 index 00000000..a351649b --- /dev/null +++ b/src/lib/y2s390/formatting_status.rb @@ -0,0 +1,44 @@ +module Y2S390 + class FormattingStatus + # @return [Symbol] + attr_accessor :status + # return [Integer, nil] + attr_accessor :cylinders + + # return [Integer] + attr_accessor :cylinders_formatted + + # return [String] + attr_accessor :error_details + + # Constructor + def initialize(cylinders = nil) + @cylinders = cylinders + end + + def format! + @cylinders_formatted = 0 + @status = :formatting + end + + def step!(cyl = 10) + return if done? + + @cylinders_formatted += cyl + done! if done? + end + + def done? + @cylinders_formatted >= @cylinders + end + + def done! + @status = :done + end + + def error!(error) + @status = :error + @error_details = error + end + end +end diff --git a/src/lib/y2s390/hwinfo_reader.rb b/src/lib/y2s390/hwinfo_reader.rb new file mode 100644 index 00000000..b54563c9 --- /dev/null +++ b/src/lib/y2s390/hwinfo_reader.rb @@ -0,0 +1,54 @@ +require "yaml" + +module Y2S390 + class HwinfoReader + include Singleton + + def for_device(id, force_probing: false) + reset if force_probing + + data[id] + end + + def reset + @data = nil + end + + def data + @data ||= data_from_hwinfo + end + + private + + def disks + if ENV["S390_MOCKING"] + load_data("test/data/probe_disk_dasd.yml") + else + Yast::SCR.Read(Yast.path(".probe.disk")) || [] + end + end + + def data_from_hwinfo + disks.each_with_object({}) do |disk, hash| + hw_data = struct_for(disk) + hash[hw_data.sysfs_bus_id] = hw_data + end + end + + def struct_for(hash_value) + hash_value.each_with_object(OpenStruct.new) do |(k, v), data| + value = if k == "io" && v.is_a?(Array) + v.first.is_a?(Hash) ? v.map { |e| struct_for(e) } : v + else + v.is_a?(Hash) ? struct_for(v) : v + end + + data.public_send("#{k}=", value) + end + end + + def load_data(name) + YAML.safe_load(File.read(name)) + end + end +end diff --git a/test/dasd_controller_test.rb b/test/dasd_controller_test.rb index c84ff073..18b7a74c 100755 --- a/test/dasd_controller_test.rb +++ b/test/dasd_controller_test.rb @@ -7,6 +7,20 @@ describe Yast::DASDController do subject { Yast::DASDController } + describe "#GetDeviceName" do + let(:channel) { "0.0.0150" } + let(:device_block_path) { "/sys/bus/ccw/devices/#{channel}/block/" } + + before do + allow(Yast::SCR).to receive(:Read).with(Yast.path(".target.dir"), device_block_path) + .once.and_return(["dasda"]) + end + + it "returns the associated device name" do + expect(subject.GetDeviceName(channel)).to eq("/dev/dasda") + end + end + describe "#ActivateDisk" do let(:exit_code) { 8 } let(:channel) { "0.0.0100" } @@ -436,7 +450,7 @@ end before do - allow(Yast::FileUtils).to receive(:Exists).and_return(false) + allow(File).to receive(:exist?).and_return(false) end it "is added to devices with formatted info" do @@ -454,7 +468,7 @@ let(:diag_path) { "/sys//class/block/dasda/device/use_diag" } before do - allow(Yast::FileUtils).to receive(:Exists).with(diag_path) + allow(File).to receive(:exist?).with(diag_path) .and_return(true) allow(Yast::SCR).to receive(:Read) .with(Yast::Path.new(".target.string"), diag_path) diff --git a/test/data/lsdasd.txt b/test/data/lsdasd.txt new file mode 100644 index 00000000..422b8f05 --- /dev/null +++ b/test/data/lsdasd.txt @@ -0,0 +1,10 @@ +Bus-ID Status Name Device Type BlkSz Size Blocks +================================================================================ +0.0.0190 offline +0.0.0191 offline +0.0.0192 offline +0.0.019d offline +0.0.0160 active dasda 94:0 ECKD 4096 21127MB 5408640 +0.0.0150 active dasdb 94:4 ECKD 4096 7042MB 1802880 +0.0.0592 active(ro) dasdc 94:8 ECKD 4096 168MB 43200 +0.0.019e active(ro) dasdd 94:12 ECKD 4096 351MB 90000 diff --git a/test/data/probe_disk.yml b/test/data/probe_disk.yml index 31ca9f3e..6419c8bc 100644 --- a/test/data/probe_disk.yml +++ b/test/data/probe_disk.yml @@ -129,3 +129,55 @@ sysfs_id: "/class/block/sdc" unique_key: _R2u.eVSycZhnQ60 vendor: IET +- bus: None + bus_hwcfg: none + class_id: 262 + detail: + cu_model: 233 + dev_model: 12 + lcss: 0 + dev_name: \"/dev/dasda\" + dev_names: + - "/dev/dasda" + - "/dev/disk/by-path/ccw-0.0.0160" + - "/dev/disk/by-id/ccw-IBM.750000000FRK11.1192.4b.00000001000075600000000000000000" + - "/dev/disk/by-id/ccw-0X0160" + - "/dev/disk/by-id/ccw-IBM.750000000FRK11.1192.4b" + dev_num: + major: 94 + minor: 0 + range: 4 + type: b + device: DASD + device_id: 276880 + driver: io_subchannel + drivers: + - active: true + modprobe: true + modules: + - - dasd_eckd_mod + - '' + model: IBM DASD + old_unique_key: N5EP.J4gQoPlOYuE + prog_if: 1 + resource: + disk_log_geo: + - cylinders: 30048 + heads: 15 + sectors: 12 + io: + - active: true + length: 1 + mode: rw + start: 352 + size: + - unit: sectors + x: 5408640 + y: 4096 + sub_class_id: 0 + sub_device_id: 275344 + sysfs_bus_id: 0.0.0160 + sysfs_id: "/class/block/dasda" + unique_key: 5czR.ALFATSt_U8F + vendor: IBM + vendor_id: 286721 diff --git a/test/y2s390/base_collection_examples.rb b/test/y2s390/base_collection_examples.rb new file mode 100644 index 00000000..967fba2f --- /dev/null +++ b/test/y2s390/base_collection_examples.rb @@ -0,0 +1,126 @@ +# Copyright (c) [2021] 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 "../test_helper" +require "y2s390" + +shared_examples "config base collection" do + subject { described_class.new(elements) } + + let(:elements) { [element1, element2, element3] } + + let(:element1) { element_class.new("test1") } + + let(:element2) { element_class.new("test2") } + + let(:element3) { element_class.new("test3") } + + let(:element_class) { Y2S390::Dasd } + + describe "#add" do + let(:element) { element_class.new("test") } + + it "adds the given element to the collection" do + expect(subject.any? { |e| e.id == element.id }).to eq(false) + + size = subject.size + subject.add(element) + + expect(subject.size).to eq(size + 1) + expect(subject.any? { |e| e.id == element.id }).to eq(true) + end + + it "returns the collection" do + expect(subject.add(element)).to eq(subject) + end + end + + describe "#delete" do + context "if the collection includes an element with the given id" do + let(:id) { elements.first.id } + + it "deletes the element from the collection" do + expect(subject.any? { |e| e.id == id }).to eq(true) + + size = subject.size + subject.delete(id) + + expect(subject.size).to eq(size - 1) + expect(subject.any? { |e| e.id == id }).to eq(false) + end + + it "returns the collection" do + expect(subject.delete(id)).to eq(subject) + end + end + + context "if the collection does not include an element with the given id" do + let(:id) { element_class.new("test").id } + + it "does not modify the collection" do + size = subject.size + subject.delete(id) + + expect(subject.size).to eq(size) + end + + it "returns the collection" do + expect(subject.delete(id)).to eq(subject) + end + end + + end + + describe "#all" do + it "returns the list of elements" do + all = subject.all + + expect(all).to eq(elements) + end + end + + describe "#by_id" do + context "if the collection contains an element with the given id" do + let(:id) { element2.id } + + it "returns the element" do + result = subject.by_id(id) + + expect(result).to be_a(element_class) + expect(result.id).to eq(element2.id) + end + end + + context "if the collection does not contain an element with the given id" do + let(:id) { element_class.new("test").id } + + it "returns nil" do + expect(subject.by_id(id)).to be_nil + end + end + end + + describe "#ids" do + it "returns the ids of all the elements" do + ids = elements.map(&:id) + + expect(subject.ids).to contain_exactly(*ids) + end + end +end diff --git a/test/y2s390/dasd_actions/activate_test.rb b/test/y2s390/dasd_actions/activate_test.rb new file mode 100644 index 00000000..a8699c46 --- /dev/null +++ b/test/y2s390/dasd_actions/activate_test.rb @@ -0,0 +1,138 @@ +require_relative "../../test_helper.rb" +require "y2s390/dasd_actions/activate" + +describe Y2S390::DasdActions::Activate do + let(:action) { described_class.new(selected) } + let(:selected) { Y2S390::DasdsCollection.new([dasd_0150, dasd_0160, dasd_0fff]) } + let(:dasd_0150) { Y2S390::Dasd.new("0.0.0150", status: "offline") } + let(:dasd_0160) { Y2S390::Dasd.new("0.0.0160", status: "offline") } + let(:dasd_0fff) { Y2S390::Dasd.new("0.0.0fff", status: "offline") } + let(:controller) { Yast::DASDController } + + describe "#run" do + let(:format_now) { false } + + before do + allow(controller).to receive(:ProbeDisks) + allow(controller).to receive(:FormatDisks) + allow(action).to receive(:format_now?).and_return(format_now) + allow(action).to receive(:activate) + end + + it "iterates over the the selected DASDs trying to active them" do + expect(action).to receive(:activate).with(dasd_0160) + expect(action).to receive(:activate).with(dasd_0fff) + # test method call through activate + allow(action).to receive(:activate).with(dasd_0150).and_call_original + expect(controller).to receive(:ActivateDisk).with(dasd_0150.id, false) + + action.run + end + + context "when some of the the activated DASD is unformatted" do + let(:to_format) { [dasd_0150] } + + before do + allow(action).to receive(:activate).with(dasd_0150).and_return(8) + allow(action).to receive(:activate).with(dasd_0160).and_return(0) + allow(action).to receive(:activate).with(dasd_0fff).and_return(0) + end + + it "asks for formatting the unformatted devices" do + expect(action).to receive(:format_now?).with(to_format) + action.run + end + + context "when the user approve to format the unformatted disks" do + let(:format_now) { true } + + before do + allow(action).to receive(:device_for!).with(dasd_0150).and_return("dasda") + end + + it "formats the unformatted disks wich has a device name and activates them" do + expect(controller).to receive(:FormatDisks).with(to_format) + expect(action).to receive(:activate).with(dasd_0150) + action.run + end + end + + context "when the user does not approve to format the unformatted disks" do + it "reloads the DASDs configuration forcing a probe of the disks" do + expect(controller).to receive(:ProbeDisks) + action.run + end + end + + it "returns true" do + expect(action.run).to eql(true) + end + end + end + + describe "#format_now?" do + let(:to_format) { [dasd_0150] } + let(:auto) { false } + + before do + allow(action).to receive(:auto_mode?).and_return(auto) + end + + context "during Autoinstallation" do + let(:auto) { true } + + it "returns false" do + expect(action.send(:format_now?, to_format)).to eql(false) + end + end + + context "when the unformatted disk list is empty?" do + it "returns false" do + expect(action.send(:format_now?, [])).to eql(false) + end + end + + context "when the unformatted disk list only has one disk" do + + it "shows a popup asking for formatting that specific disk" do + expect(Yast::Popup).to receive(:ContinueCancel) + .with("Device 0.0.0150 is not formatted. Format device now?") + + action.send(:format_now?, to_format) + end + end + + context "when the unformatted disk list only has more than one disk" do + let(:to_format) { [dasd_0150, dasd_0160] } + + it "shows a popup asking for formatting all of them" do + expect(Yast::Popup).to receive(:ContinueCancel) + .with("There are 2 unformatted devices. Format them now?") + + action.send(:format_now?, to_format) + end + end + end + + describe "#device_for!" do + let(:device_name) { "dasda" } + + before do + allow(dasd_0150).to receive(:sys_device_name).and_return(device_name) + end + + it "sets the dasd device name obtained from the sysfs" do + expect { action.send(:device_for!, dasd_0150) } + .to change { dasd_0150.device_name }.from(nil).to(device_name) + end + + context "when there is no device associated with the given DASD" do + let(:device_name) { nil } + + it "shows a popup error" do + expect(Yast::Popup).to receive(:Error).with("Couldn't find device for channel 0.0.0150.") + action.send(:device_for!, dasd_0150) + end + end + end +end diff --git a/test/y2s390/dasd_actions/base_test.rb b/test/y2s390/dasd_actions/base_test.rb new file mode 100644 index 00000000..8d691bc6 --- /dev/null +++ b/test/y2s390/dasd_actions/base_test.rb @@ -0,0 +1,60 @@ +require_relative "../../test_helper.rb" +require "y2s390/dasd_actions/base" + +describe Y2S390::DasdActions::Base do + subject { described_class.new(selected) } + let(:selected) { Y2S390::DasdsCollection.new([]) } + + describe ".run" do + it "creates a new object of the class and call its run method" do + expect(described_class).to receive(:new).with(selected).and_return(subject) + expect(subject).to receive(:run) + + described_class.run(selected) + end + end + + describe "#config_mode?" do + let(:config_mode) { true } + + before do + allow(Yast::Mode).to receive(:config).and_return(config_mode) + end + + context "in Mode.config" do + it "returns true" do + expect(subject.config_mode?).to eq(true) + end + end + + context "in other Mode" do + let(:config_mode) { false } + + it "returns false" do + expect(subject.config_mode?).to eq(false) + end + end + end + + describe "#auto_mode?" do + let(:auto_mode) { true } + + before do + allow(Yast::Mode).to receive(:autoinst).and_return(auto_mode) + end + + context "in Mode.autoinst" do + it "returns true" do + expect(subject.auto_mode?).to eq(true) + end + end + + context "in other Mode" do + let(:auto_mode) { false } + + it "returns false" do + expect(subject.auto_mode?).to eq(false) + end + end + end +end diff --git a/test/y2s390/dasd_actions/deactivate_test.rb b/test/y2s390/dasd_actions/deactivate_test.rb new file mode 100644 index 00000000..13017c89 --- /dev/null +++ b/test/y2s390/dasd_actions/deactivate_test.rb @@ -0,0 +1,35 @@ +require_relative "../../test_helper.rb" +require "y2s390/dasd_actions/deactivate" + +describe Y2S390::DasdActions::Deactivate do + let(:action) { described_class.new(selected) } + let(:selected) { Y2S390::DasdsCollection.new([dasd_0150, dasd_0fff]) } + let(:dasd_0150) { Y2S390::Dasd.new("0.0.0150", status: "offline") } + let(:dasd_0fff) { Y2S390::Dasd.new("0.0.0fff", status: "offline") } + let(:controller) { Yast::DASDController } + + describe "#run" do + let(:format_now) { false } + + before do + allow(controller).to receive(:ProbeDisks) + allow(action).to receive(:deactivate) + end + + it "iterates over the the selected DASDs deactivating them" do + expect(action).to receive(:deactivate).with(dasd_0150) + expect(action).to receive(:deactivate).with(dasd_0fff) + + action.run + end + + it "reloads the DASDs configuration forcing a probe of the disks" do + expect(controller).to receive(:ProbeDisks) + action.run + end + + it "returns true" do + expect(action.run).to eql(true) + end + end +end diff --git a/test/y2s390/dasd_actions/diag_test.rb b/test/y2s390/dasd_actions/diag_test.rb new file mode 100644 index 00000000..90eb958b --- /dev/null +++ b/test/y2s390/dasd_actions/diag_test.rb @@ -0,0 +1,116 @@ +require_relative "../../test_helper.rb" +require "y2s390/dasd_actions/diag" + +describe Y2S390::DasdActions::DiagOn do + let(:action) { described_class.new(selected) } + let(:selected) { Y2S390::DasdsCollection.new([dasd_0150, dasd_0fff]) } + let(:dasd_0150) { Y2S390::Dasd.new("0.0.0150", status: "offline") } + let(:dasd_0fff) { Y2S390::Dasd.new("0.0.0fff", status: "offline") } + let(:controller) { Yast::DASDController } + + describe "#run" do + let(:format_now) { false } + let(:config_mode) { false } + + before do + allow(controller).to receive(:ProbeDisks) + allow(Yast::Mode).to receive(:config).and_return(config_mode) + allow(dasd_0150).to receive(:io_active?).and_return(false) + allow(dasd_0fff).to receive(:io_active?).and_return(false) + end + + context "when running in config Mode" do + let(:config_mode) { true } + + it "iterates over the the selected DASDs setting the diag wanted to true" do + expect { action.run }.to change { dasd_0150.diag_wanted }.from(nil).to(true) + .and change { dasd_0fff.diag_wanted }.from(nil).to(true) + end + end + + context "when not running in config Mode" do + it "iterates over the selected DASDs setting the diag wanted to true" do + expect { action.run }.to change { dasd_0150.diag_wanted }.from(nil).to(true) + .and change { dasd_0fff.diag_wanted }.from(nil).to(true) + end + + context "when the DASD is active according to sysfs" do + before do + allow(dasd_0150).to receive(:io_active?).and_return(true) + end + + it "activates the DIAG" do + expect(controller).to receive(:ActivateDiag).with("0.0.0150", true) + + action.run + end + end + + it "reloads the DASDs configuration forcing a probe of the disks" do + expect(controller).to receive(:ProbeDisks) + action.run + end + end + + it "returns true" do + expect(action.run).to eql(true) + end + end +end + +describe Y2S390::DasdActions::DiagOff do + let(:action) { described_class.new(selected) } + let(:selected) { Y2S390::DasdsCollection.new([dasd_0150, dasd_0fff]) } + let(:dasd_0150) { Y2S390::Dasd.new("0.0.0150", status: "offline") } + let(:dasd_0fff) { Y2S390::Dasd.new("0.0.0fff", status: "offline") } + let(:controller) { Yast::DASDController } + + describe "#run" do + let(:format_now) { false } + let(:config_mode) { false } + + before do + allow(controller).to receive(:ProbeDisks) + allow(Yast::Mode).to receive(:config).and_return(config_mode) + allow(dasd_0150).to receive(:io_active?).and_return(false) + allow(dasd_0fff).to receive(:io_active?).and_return(false) + end + + context "when running in config Mode" do + let(:config_mode) { true } + + it "iterates over the the selected DASDs setting the diag wanted to false" do + expect { action.run }.to change { dasd_0150.diag_wanted }.from(nil).to(false) + .and change { dasd_0fff.diag_wanted }.from(nil).to(false) + end + end + + context "when not running in config Mode" do + it "iterates over the selected DASDs setting the diag wanted to false" do + expect { action.run }.to change { dasd_0150.diag_wanted }.from(nil).to(false) + .and change { dasd_0fff.diag_wanted }.from(nil).to(false) + end + + context "when the DASD is active according to sysfs" do + before do + allow(dasd_0150).to receive(:io_active?).and_return(true) + end + + it "deactivates the DIAG" do + expect(controller).to receive(:ActivateDiag).with("0.0.0150", false) + + action.run + end + end + + it "reloads the DASDs configuration forcing a probe of the disks" do + expect(controller).to receive(:ProbeDisks) + action.run + end + end + + it "returns true" do + expect(action.run).to eql(true) + end + end +end diff --git a/test/y2s390/dasd_actions/format_test.rb b/test/y2s390/dasd_actions/format_test.rb new file mode 100644 index 00000000..f85d57ac --- /dev/null +++ b/test/y2s390/dasd_actions/format_test.rb @@ -0,0 +1,152 @@ +require_relative "../../test_helper.rb" +require "y2s390/dasd_actions/format" + +describe Y2S390::DasdActions::Format do + let(:action) { described_class.new(selected) } + let(:selected) { Y2S390::DasdsCollection.new([dasd_0150, dasd_0fff]) } + let(:dasd_0150) { Y2S390::Dasd.new("0.0.0150", status: "active", type: "ECKD") } + let(:dasd_0fff) { Y2S390::Dasd.new("0.0.0fff", status: "active(ro)", type: "FBA") } + let(:controller) { Yast::DASDController } + + describe "#run" do + let(:format_now) { false } + let(:config_mode) { false } + let(:io_active) { false } + + before do + allow(controller).to receive(:ProbeDisks) + allow(controller).to receive(:FormatDisks) + allow(Yast::Mode).to receive(:config).and_return(config_mode) + allow(dasd_0150).to receive(:io_active?).and_return(io_active) + allow(dasd_0fff).to receive(:io_active?).and_return(io_active) + allow(dasd_0150).to receive(:access_type).and_return("rw") + allow(dasd_0fff).to receive(:access_type).and_return("ro") + end + + context "when at least one of the DASD devices is not active" do + it "reports the problem" do + expect(Yast::Popup).to receive(:Message).with(/Disk 0.0.0fff is not active/) + + action.run + end + + it "does not format any disk" do + expect(controller).to_not receive(:FormatDisks) + action.run + end + + it "returns false" do + expect(action.run).to eql(false) + end + end + + context "when at least one of the DASD devices is not accessible for writing" do + let(:io_active) { true } + + it "reports the problem" do + expect(Yast::Popup).to receive(:Message).with(/Disk 0.0.0fff is not accessible for writing/) + + action.run + end + + it "does not format any disk" do + expect(controller).to_not receive(:FormatDisks) + action.run + end + + it "returns false" do + expect(action.run).to eql(false) + end + end + + context "when at least one of the DASD devices is not a ECKD one" do + let(:io_active) { true } + before do + dasd_0fff.status = "active" + allow(dasd_0fff).to receive(:access_type).and_return("rw") + end + + it "reports the problem" do + expect(Yast::Popup).to receive(:Message).with(/Disk 0.0.0fff cannot be formatted/) + + action.run + end + + it "does not format any disk" do + expect(controller).to_not receive(:FormatDisks) + action.run + end + + it "returns false" do + expect(action.run).to eql(false) + end + end + + context "when all the DASDs can be formatted" do + before do + allow(action).to receive(:can_be_formatted?).and_return(true) + allow(action).to receive(:really_format?).and_return(true) + end + + it "asks the user to confirm the format of the selected disks" do + allow(action).to receive(:really_format?).and_call_original + expect(Yast::Popup).to receive(:AnyQuestionRichText) + action.run + end + + context "and the user accepts to procceed with the format of the selected disks" do + it "formats the selected DASDs" do + expect(controller).to receive(:FormatDisks).with(selected) + action.run + end + + it "reloads the DASDs configuration forcing a probe of the disks" do + expect(controller).to receive(:ProbeDisks) + action.run + end + + it "returns true" do + expect(action.run).to eql(true) + end + end + + context "and the user does not accept to procceed with the format of the selected disks" do + it "returns false" do + allow(action).to receive(:really_format?).and_return(false) + expect(action.run).to eql(false) + end + end + + end + end +end + +describe Y2S390::DasdActions::FormatOn do + let(:action) { described_class.new(selected) } + let(:selected) { Y2S390::DasdsCollection.new([dasd_0150, dasd_0fff]) } + let(:dasd_0150) { Y2S390::Dasd.new("0.0.0150", status: "offline") } + let(:dasd_0fff) { Y2S390::Dasd.new("0.0.0fff", status: "offline") } + let(:controller) { Yast::DASDController } + + describe "#run" do + it "iterates over the the selected DASDs setting the format wanted to true" do + expect { action.run }.to change { dasd_0150.format_wanted }.from(nil).to(true) + .and change { dasd_0fff.format_wanted }.from(nil).to(true) + end + end +end + +describe Y2S390::DasdActions::FormatOff do + let(:action) { described_class.new(selected) } + let(:selected) { Y2S390::DasdsCollection.new([dasd_0150, dasd_0fff]) } + let(:dasd_0150) { Y2S390::Dasd.new("0.0.0150", status: "offline") } + let(:dasd_0fff) { Y2S390::Dasd.new("0.0.0fff", status: "offline") } + let(:controller) { Yast::DASDController } + + describe "#run" do + it "iterates over the the selected DASDs setting the format wanted to true" do + expect { action.run }.to change { dasd_0150.format_wanted }.from(nil).to(false) + .and change { dasd_0fff.format_wanted }.from(nil).to(false) + end + end +end diff --git a/test/y2s390/dasd_test.rb b/test/y2s390/dasd_test.rb new file mode 100644 index 00000000..a4a22d5d --- /dev/null +++ b/test/y2s390/dasd_test.rb @@ -0,0 +1,72 @@ +require_relative "../test_helper" +require "y2s390" + +describe Y2S390::Dasd do + subject { described_class.new("0.0.0150") } + let(:dasda) { described_class.new("0.0.0150", status: "active", device_name: "dasda") } + + describe "#hex_id" do + it "returns an integer representation of the channel ID" do + expect(subject.hex_id).to be_a(Integer) + expect(subject.hex_id).to eql("000150".hex) + end + end + + describe "#active?" do + it "returns true if the DASD status is :active or :read_only" do + expect(dasda.active?).to eql(true) + end + + it "returns false if it is offline" do + expect(subject.active?).to eql(false) + end + end + + describe "#offline?" do + subject { described_class.new("0.0.0190", status: "offline") } + + it "returns true if the DASD status is offline" do + expect(subject.offline?).to eql(true) + end + + it "returns false if the DASD status is not offline" do + expect(dasda.offline?).to eql(false) + end + end + + describe "#status=" do + context "when given a known status" do + it "sets the corresponding one" do + expect { subject.status = "offline" }.to change { subject.status } + .from(:unknown).to(:offline) + expect { subject.status = "active" }.to change { subject.status } + .from(:offline).to(:active) + expect { subject.status = "active(ro)" }.to change { subject.status } + .from(:active).to(:read_only) + end + end + + context "when the given status is not known" do + subject { described_class.new("0.0.0190", status: "offline") } + + it "sets the status as :unknown" do + expect { subject.status = "another" }.to change { subject.status } + .from(:offline).to(:unknown) + end + end + end + + describe "#formatted?" do + it "returns true if the DASD device is formmated according to internal state" do + subject.formatted = true + expect(subject.formatted?).to eql(true) + end + + it "returns false otherwise" do + subject.formatted = nil + expect(subject.formatted?).to eql(false) + subject.formatted = false + expect(subject.formatted?).to eql(false) + end + end +end diff --git a/test/y2s390/dasds_collection_test.rb b/test/y2s390/dasds_collection_test.rb new file mode 100644 index 00000000..140f417b --- /dev/null +++ b/test/y2s390/dasds_collection_test.rb @@ -0,0 +1,32 @@ +require_relative "../test_helper" +require_relative "base_collection_examples" +require "y2s390" + +describe Y2S390::DasdsCollection do + include_examples "config base collection" + + describe "#filter" do + let(:elements) { [element1, element2, element3] } + let(:element1) { Y2S390::Dasd.new("0.0.0150", status: "active", type: "EKCD") } + let(:element2) { Y2S390::Dasd.new("0.0.0160", status: "offline", type: "EKCD") } + let(:element3) { Y2S390::Dasd.new("0.0.0190", status: "active(ro)", type: "EKCD") } + + it "returns a new collection with the elements which the block returns true" do + expect(subject.size).to eq(3) + collection = subject.filter(&:offline?) + expect(collection.size).to eq(1) + expect(collection.by_id("0.0.0160")).to eq(element2) + end + end + + describe "#active" do + let(:elements) { [element1, element2, element3] } + let(:element1) { Y2S390::Dasd.new("0.0.0150", status: "active", type: "EKCD") } + let(:element2) { Y2S390::Dasd.new("0.0.0160", status: "offline", type: "EKCD") } + let(:element3) { Y2S390::Dasd.new("0.0.0190", status: "active(ro)", type: "EKCD") } + + it "returns a new collection with only the active elements" do + expect(subject.active.ids).to eql(["0.0.0150", "0.0.0190"]) + end + end +end diff --git a/test/y2s390/dasds_reader_test.rb b/test/y2s390/dasds_reader_test.rb new file mode 100644 index 00000000..e2e44691 --- /dev/null +++ b/test/y2s390/dasds_reader_test.rb @@ -0,0 +1,58 @@ +require_relative "../test_helper" + +require "y2s390/dasds_reader" + +describe Y2S390::DasdsReader do + let(:reader) { described_class.new } + let(:config_mode) { true } + let(:execute) { instance_double("Yast::Execute", on_target: true) } + + before do + allow(reader).to receive(:dasd_entries).and_return(load_file("lsdasd.txt").split("\n")) + allow(ENV).to receive(:[]).with("S390_MOCKING").and_return(true) + end + + describe "#list" do + before do + allow(Yast::Mode).to receive(:config).and_return(config_mode) + end + + it "reads and parses the DASD devices using lsdasd" do + allow(ENV).to receive(:[]).with("S390_MOCKING").and_return(false) + allow(Yast::Execute).to receive(:stdout).and_return(execute) + expect(reader).to receive(:dasd_entries).and_call_original + expect(execute).to receive(:locally!).with(["/sbin/lsdasd", "-a"]).and_return("") + + reader.list + end + + it "returns a collection of DASD devices" do + expect(reader.list).to be_a(Y2S390::DasdsCollection) + end + + context "when called in 'normal' Mode" do + let(:config_mode) { false } + + it "it fetchs all the DASD information" do + devices = reader.list + dasd = devices.by_id("0.0.0160") + expect(dasd.type).to eq("ECKD") + expect(dasd.device_name).to eq("dasda") + expect(dasd.offline?).to eq(false) + expect(dasd.device_type).to eq("3990/E9 3390/0A") + end + end + + context "when called in 'config' Mode" do + it "it fetchs only the 'id' and 'diag' information and initializes 'format' as false" do + expect(reader).to_not receive(:update_additional_info) + devices = reader.list + dasd = devices.by_id("0.0.0150") + expect(dasd.format).to eq(false) + expect(dasd.use_diag).to eq(false) + expect(dasd.type).to be_nil + expect(dasd.device_name).to be_nil + end + end + end +end From b939ffc0701425b293591fdef619ea98f44b8298 Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Wed, 17 Nov 2021 09:51:19 +0000 Subject: [PATCH 02/31] Added format dialogs --- src/lib/y2s390/dialogs/dasd_format.rb | 129 ++++++++++++++++++++++++ src/lib/y2s390/dialogs/format.rb | 3 + src/lib/y2s390/dialogs/format_dialog.rb | 70 +++++++++++++ src/lib/y2s390/dialogs/format_disks.rb | 36 +++++++ 4 files changed, 238 insertions(+) create mode 100644 src/lib/y2s390/dialogs/dasd_format.rb create mode 100644 src/lib/y2s390/dialogs/format.rb create mode 100644 src/lib/y2s390/dialogs/format_dialog.rb create mode 100644 src/lib/y2s390/dialogs/format_disks.rb diff --git a/src/lib/y2s390/dialogs/dasd_format.rb b/src/lib/y2s390/dialogs/dasd_format.rb new file mode 100644 index 00000000..18d9d598 --- /dev/null +++ b/src/lib/y2s390/dialogs/dasd_format.rb @@ -0,0 +1,129 @@ +require "yast" +require "y2s390/dialogs/format_dialog" + +module Y2S390 + module Dialogs + # Class for displaying progress while formatting one or several DASDs. + class DasdFormat < FormatDialog + def dialog_content + textdomain "s390" + + MarginBox( + 1, # left and right margin + 0.45, # top and bottom margin; NCurses rounds this down to 0 + VBox( + Heading(_("Formatting DASDs")), + MinHeight(7, tables), + VSpacing(1), + ProgressBar(Id(:progress_bar), _("Total Progress"), 100, 0), + VSpacing(1) + ) + ) + end + + private + + def tables + HBox( + MinWidth( + 38, + VBox( + Left(Label(_("In Progress"))), + in_progress_table + ) + ), + HSpacing(4), + MinWidth( + 26, + VBox( + Left(Label(_("Done"))), + done_table + ) + ) + ) + end + + def in_progress_table + Table( + Id(:in_progress_table), + Header( + Right(_("Channel ID")), + "Device", + Right(_("Cyl.") + " " * 6) # reserve some space for more digits + ), + in_progress_items + ) + end + + def in_progress_items + @fmt_process.summary.values.reject(&:done?).map { |s| in_progress_item_for(s) } + end + + def id_for(dasd) + Id(dasd.device_name.to_sym) + end + + def in_progress_item_for(status) + d = status.dasd + Item(id_for(d), d.id, d.device_name, format_cyl(status.progress, status.cylinders)) + end + + def done_item_for(status) + d = status.dasd + Item(id_for(d), d.id, "/dev/#{d.device_name}") + end + + def format_cyl(current_cyl, total_cyl) + "#{current_cyl}/#{total_cyl}" + end + + def done_table + Table( + Id(:done_table), + Header(Right(_("Channel ID")), _("Device")), + done_items + ) + end + + def done_items + fmt_process.summary.values.select(&:done?).map { |s| done_item_for(s) } + end + + def update_progress + fmt_process.update_summary + sleep(0.2) + progress = fmt_process.progress + cylinders = fmt_process.cylinders + update_progress_percent(100 * progress / cylinders) if cylinders > 0 + fmt_process.updated.values.each { |s| s.done? ? refresh_tables : update_cyl_cell(s) } + + fmt_process.running? ? :continue : :break + end + + def refresh_tables + Yast::UI.ChangeWidget(Id(:in_progress_table), :Items, in_progress_items) + Yast::UI.ChangeWidget(Id(:done_table), :Items, done_items) + end + + def update_progress_percent(percent) + @progress = percent + Yast::UI.ChangeWidget(Id(:progress_bar), :Value, @progress) + end + + # Update the cylinder cell for one item of the "In Progress" table. + # + # @param item_id [Term] ID of the table item to update + # @param cyl [Integer] Current cylinder of that DASD + # @param total_cyl [Integer] Total number of cylinders of that DASD + # + def update_cyl_cell(status) + item_id = id_for(status.dasd) + cyl = status.progress + total_cyl = status.cylinders + return if cyl <= 0 || cyl > total_cyl + + Yast::UI.ChangeWidget(Id(:in_progress_table), Cell(item_id, 2), format_cyl(cyl, total_cyl)) + end + end + end +end diff --git a/src/lib/y2s390/dialogs/format.rb b/src/lib/y2s390/dialogs/format.rb new file mode 100644 index 00000000..7d6fd3d2 --- /dev/null +++ b/src/lib/y2s390/dialogs/format.rb @@ -0,0 +1,3 @@ +require "y2s390/format_process" +require "y2s390/dialogs/dasd_format" +require "y2s390/dialogs/format_disks" diff --git a/src/lib/y2s390/dialogs/format_dialog.rb b/src/lib/y2s390/dialogs/format_dialog.rb new file mode 100644 index 00000000..d2a4697c --- /dev/null +++ b/src/lib/y2s390/dialogs/format_dialog.rb @@ -0,0 +1,70 @@ +require "yast" +require "y2s390/format_process" +require "ui/dialog" +require "ui/event_dispatcher" + +Yast.import "UI" +Yast.import "Label" +Yast.import "Report" + +module Y2S390 + module Dialogs + # Class for displaying progress while formatting one or several DASDs. + class FormatDialog < ::UI::Dialog + include Yast::Logger + include ::UI::EventDispatcher + attr_accessor :fmt_process + attr_accessor :progress + attr_accessor :cylinders + attr_accessor :dasds + + abstract_method :dialog_content, :update_progress + + TIMEOUT_MILLISEC = 10 + + # Constructor + # + # @param dasds [Array] list of DASDs to be formatted + def initialize(dasds) + textdomain "s390" + @dasds = dasds + @fmt_process = FormatProcess.new(dasds) + end + + def should_open_dialog? + true + end + + def run + fmt_process.start + sleep(0.2) + return report_format_failed(fmt_process) unless fmt_process.running? + + fmt_process.initialize_summary + create_dialog + while fmt_process.running? + fmt_process.update_summary + sleep(0.2) + update_progress + end + close_dialog + return report_format_failed(fmt_process) if fmt_process.status.to_i != 0 + + :refresh + end + + def user_input + Yast::UI.TimeoutUserInput(1000) + end + + private + + def report_format_failed(process) + Yast::Report.Error(format(_("Disks formatting failed. Exit code: %s.\nError output:%s"), + process.status, process.error)) + + nil + end + end + end +end diff --git a/src/lib/y2s390/dialogs/format_disks.rb b/src/lib/y2s390/dialogs/format_disks.rb new file mode 100644 index 00000000..8a4088d6 --- /dev/null +++ b/src/lib/y2s390/dialogs/format_disks.rb @@ -0,0 +1,36 @@ +require "y2s390/dialogs/format_dialog" + +module Y2S390 + module Dialogs + class FormatDisks < FormatDialog + def dialog_content + VBox( + HSpacing(70), + *dasds_progress_bars + ) + end + + private + + def dasds_progress_bars + dasds.map.with_index { |d, i| ProgressBar(Id(i), format(_("Formatting %s:"), d), 100, 0) } + end + + def update_progress + fmt_process.updated.each do |index, status| + Yast::UI.ChangeWidget( + Id(index), + :Label, + # progress bar, %1 is device name, %2 and %3 + # integers, + # eg. Formatting /dev/dasda: cylinder 123 of 12334 done + format(_("Formatting %s: cylinder %s of %s done"), + status.dasd.id, status.progress, status.cylinders) + ) + Yast::UI.ChangeWidget(Id(index), :Value, (100 * status.progress) / status.cylinders) + Yast::UI.ChangeWidget(Id(index), :Enabled, true) + end + end + end + end +end From 8e3b7f05397acb53f72206a41ed452a062acb2b6 Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Thu, 18 Nov 2021 09:24:04 +0000 Subject: [PATCH 03/31] Changed the way the DASD data is refreshed --- src/lib/y2s390/dasd.rb | 14 ++++---------- src/lib/y2s390/dasds_reader.rb | 28 ++++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/lib/y2s390/dasd.rb b/src/lib/y2s390/dasd.rb index e56fbc57..73091ee8 100644 --- a/src/lib/y2s390/dasd.rb +++ b/src/lib/y2s390/dasd.rb @@ -119,7 +119,10 @@ def partition_info "[ \t]+([^ \t]+)[ \t]+([^ \t]+([ \t]+[^ \t]+))*[ \t]*$") lines = out.split("\n").select { |s| s.match?(regexp) } - lines.map { |line| r = line.match(regexp); "#{r[1]} (#{r[6]})" }.join(", ") + lines.map do |line| + r = line.match(regexp) + "#{r[1]} (#{r[6]})" + end.join(", ") end def hwinfo @@ -157,14 +160,5 @@ def sys_device_name disk = Yast::Execute.stdout.on_target!(cmd).strip disk.to_s.empty? ? nil : "/dev/#{disk}" end - - def refresh_data! - cmd = [LIST_CMD, id] - data = Yast::Execute.stdout.locally!(*cmd).split("\n").find { |l| l.start_with? /\d/ } - - return if data.to_s.empty? - - _id, @status, @device_name, _, @type, = data.split(" ") - end end end diff --git a/src/lib/y2s390/dasds_reader.rb b/src/lib/y2s390/dasds_reader.rb index 2a17d13a..c8f63009 100644 --- a/src/lib/y2s390/dasds_reader.rb +++ b/src/lib/y2s390/dasds_reader.rb @@ -46,8 +46,8 @@ def list(offline: true, force_probing: false) a = dasd_entries(offline: offline).each_with_object([]) do |entry, arr| next unless entry.start_with?(/\d/) - id, offline, name, _, type, = entry.split(" ") - attrs = Yast::Mode.config ? {} : { status: offline, device_name: name, type: type } + id, status, name, _, type, = entry.split(" ") + attrs = Yast::Mode.config ? {} : { status: status, device_name: name, type: type } dasd = Y2S390::Dasd.new(id, **attrs).tap do |d| if Yast::Mode.config d.diag = d.use_diag = use_diag?(d) @@ -63,6 +63,23 @@ def list(offline: true, force_probing: false) Y2S390::DasdsCollection.new(a) end + def refresh_data!(dasds) + dasd_entries(offline: true).each do |entry| + next unless entry.start_with?(/\d/) + + id, status, name, _, type, = entry.split(" ") + dasd = dasds.by_id(id) + next unless dasd + + dasd.status = status + dasd.device_name = name + dasd.type = type + update_additional_info(dasd) + end + + true + end + def update_info(dasd, extended: false) data = dasd_entries(dasd: dasd).find { |e| e.start_with?(/\d/) } return false if data.to_s.empty? @@ -90,7 +107,7 @@ def dasd_entries(offline: true, dasd: nil) if ENV["S390_MOCKING"] File.read("test/data/lsdasd.txt") else - cmd = cmd_for(offline: offline) + cmd = cmd_for(offline: offline, dasd: dasd) Yast::Execute.stdout.locally!(cmd) end.split("\n") end @@ -150,7 +167,10 @@ def partition_info(dasd) "[ \t]+([^ \t]+)[ \t]+([^ \t]+([ \t]+[^ \t]+))*[ \t]*$") lines = out.split("\n").select { |s| s.match?(regexp) } - lines.map { |line| r = line.match(regexp); "#{r[1]} (#{r[6]})" }.join(", ") + lines.map do |line| + r = line.match(regexp) + "#{r[1]} (#{r[6]})" + end.join(", ") end def device_type_for(dasd) From c9c2d882bfd098cb9fa2b7c5c996b6bcec9d032a Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Thu, 18 Nov 2021 09:25:42 +0000 Subject: [PATCH 04/31] Start using the new classes for managing DASDs --- src/include/s390/dasd/dialogs.rb | 334 +++-------------- src/modules/DASDController.rb | 593 +++++++------------------------ test/dasd_controller_test.rb | 264 ++++---------- test/data/lsdasd.txt | 1 + test/data/probe_disk_dasd.yml | 50 +++ 5 files changed, 299 insertions(+), 943 deletions(-) diff --git a/src/include/s390/dasd/dialogs.rb b/src/include/s390/dasd/dialogs.rb index 81f69df4..f67b5b91 100644 --- a/src/include/s390/dasd/dialogs.rb +++ b/src/include/s390/dasd/dialogs.rb @@ -23,6 +23,10 @@ # Authors: Jiri Srain # # $Id$ +# +require "y2s390/dialogs/dasd_read" +require "y2s390/dasd_actions" + module Yast module S390DasdDialogsInclude def initialize_s390_dasd_dialogs(include_target) @@ -48,12 +52,8 @@ def initialize_s390_dasd_dialogs(include_target) # List DASD devices that are currently being selected # @return [Array] list of IDs of selected DASD devices def ListSelectedDASD - selected = Convert.convert( - UI.QueryWidget(Id(:table), :SelectedItems), - from: "any", - to: "list " - ) - Builtins.y2milestone("selected %1", selected) + selected = UI.QueryWidget(Id(:table), :SelectedItems) || [] + log.info("selected #{selected}") deep_copy(selected) end @@ -73,6 +73,24 @@ def WriteDialog ret ? :next : :abort end + def yes_no(value) + String.YesNo(value) + end + + def item_elements_for(dasd) + item_id = Id(dasd.id) + diag = yes_no(Mode.config ? dasd.diag_wanted : dasd.use_diag) + formatted = yes_no(dasd.formatted?) + + return [item_id, dasd.id, d.format, diag] if Mode.config + return [item_id, dasd.id, "--", "--", "--", diag, "--", "--"] unless dasd.active? + + [ + item_id, dasd.id, dasd.device_name, dasd.access_type.to_s.upcase, + dasd.device_type, diag, formatted, dasd.partition_info + ] + end + # Get the list of items for the table of DASD devices # @param min_chan integer minimal channel number # @param max_chan integer maximal channel number @@ -80,78 +98,7 @@ def WriteDialog def GetDASDDiskItems devices = DASDController.GetFilteredDevices - items = if Mode.config - Builtins.maplist(devices) do |k, d| - channel = Ops.get_string(d, "channel", "") - diag = String.YesNo(Ops.get_boolean(d, "diag", false)) - format = String.YesNo(Ops.get_boolean(d, "format", false)) - Item(Id(k), channel, format, diag) - end - else - Builtins.maplist(devices) do |k, d| - active = Ops.get_boolean(d, ["resource", "io", 0, "active"], false) - channel = Ops.get_string(d, "channel", "") - access = Builtins.toupper( - Ops.get_string(d, ["resource", "io", 0, "mode"], "RO") - ) - diag = String.YesNo(Ops.get(DASDController.diag, channel, false)) - device = Ops.get_string(d, "dev_name", "") - type = Builtins.toupper( - Builtins.sformat( - "%1/%2, %3/%4", - Builtins.substring( - Builtins.tohexstring( - Ops.bitwise_and(Ops.get_integer(d, "device_id", 0), 65535), - 4 - ), - 2 - ), - Builtins.substring( - Builtins.tohexstring( - Ops.get_integer(d, ["detail", "cu_model"], 0), - 4 - ), - 4 - ), - Builtins.substring( - Builtins.tohexstring( - Ops.bitwise_and(Ops.get_integer(d, "sub_device_id", 0), 65535), - 4 - ), - 2 - ), - Builtins.substring( - Builtins.tohexstring( - Ops.get_integer(d, ["detail", "dev_model"], 0), - 4 - ), - 4 - ) - ) - ) - formatted = String.YesNo(Ops.get_boolean(d, "formatted", false)) - partition_info = Ops.get_string(d, "partition_info", "--") - if !active - type = "--" - access = "--" - formatted = "--" - partition_info = "--" - device = "--" - end - Item( - Id(k), - channel, - device, - type, - access, - diag, - formatted, - partition_info - ) - end - end - - deep_copy(items) + devices.map { |d| Item(*item_elements_for(d)) } end def PossibleActions @@ -182,217 +129,25 @@ def PossibleActions end end - def AskNumParallel(max_num_parallel) - UI.OpenDialog( - VBox( - IntField( - # integer field (count of disks formatted parallel) - Id(:num_parallel), _("&Parallel Formatted Disks"), - 1, max_num_parallel, max_num_parallel - ), - ButtonBox( - PushButton(Id(:ok), Label.OKButton), - PushButton(Id(:cancel), Label.CancelButton) - ) - ) - ) - - ret = UI.UserInput() - num_parallel = UI.QueryWidget(Id(:num_parallel), :Value).to_i - - UI.CloseDialog() + def action_class_for(action) + name = action.to_s.split("_").map(&:capitalize).join + "Y2S390::DasdActions::#{name}" + end - (ret == :ok) ? num_parallel : 0 + def run(action, selected) + Object.const_get(action_class_for(action)).run(selected) end def PerformAction(action) - selected = ListSelectedDASD() - if Builtins.isempty(selected) + selected = DASDController.devices.by_ids(ListSelectedDASD()) + + if selected.empty? # error popup message Popup.Message(_("No disk selected.")) return false end - if !Mode.config - case action - when :activate, :deactivate - value = action == :activate - unformatted_disks = [] - - Builtins.foreach(selected) do |id| - channel = Ops.get_string( - DASDController.devices, - [id, "channel"], - "" - ) - act_ret = 0 - diag = Ops.get(DASDController.diag, channel, false) - if value - act_ret = DASDController.ActivateDisk(channel, diag) - else - DASDController.DeactivateDisk(channel, diag) - end - unformatted_disks << channel if act_ret == 8 # 8 means disk is not formatted - end - if !unformatted_disks.empty? - popup = if unformatted_disks.size == 1 - Builtins.sformat(_("Device %1 is not formatted. Format device now?"), - unformatted_disks[0]) - else - Builtins.sformat(_("There are %1 unformatted devices. Format them now?"), - unformatted_disks.size) - end - # for autoinst, format unformatted disks later - if !Mode.autoinst && Popup.ContinueCancel(popup) - devices = unformatted_disks.map do |channel| - device = nil - cmd = "ls '/sys/bus/ccw/devices/#{channel}/block/' | tr -d '\n'" - disk = SCR.Execute(path(".target.bash_output"), cmd) - if disk["exit"] == 0 && !disk["stdout"].empty? - device = "/dev/#{disk["stdout"]}" - else - Popup.Error(Builtins.sformat(_("Couldn't find device for channel %1."), channel)) - end - device - end - devices.reject!(&:nil?) - DASDController.FormatDisks(devices, 8) # don't format more than 8 disks in parallel - unformatted_disks.each do |channel| - diag = !!DASDController.diag[channel] - DASDController.ActivateDisk(channel, diag) - end - end - end - DASDController.ProbeDisks - - return true - - when :diag_off, :diag_on - value = action == :diag_on - - Builtins.foreach(selected) do |id| - channel = Ops.get_string( - DASDController.devices, - [id, "channel"], - "" - ) - active = Ops.get_boolean( - DASDController.devices, - [id, "resource", "io", 0, "active"], - false - ) - DASDController.ActivateDiag(channel, value) if active - Ops.set(DASDController.diag, channel, value) - end - DASDController.ProbeDisks - - return true - - when :format - # check if disks are R/W and active - problem = "" - Builtins.foreach(selected) do |id| - active = Ops.get_boolean( - DASDController.devices, - [id, "resource", "io", 0, "active"], - false - ) - access = Ops.get_string( - DASDController.devices, - [id, "resource", "io", 0, "mode"], - "ro" - ) - channel = Ops.get_string(DASDController.devices, [id, "channel"], "") - if !active - # error report, %1 is device identification - problem = Builtins.sformat( - _("Disk %1 is not active."), - channel - ) - elsif access != "rw" - # error report, %1 is device identification - problem = Builtins.sformat( - _("Disk %1 is not accessible for writing."), - channel - ) - elsif !DASDController.can_be_formatted?(DASDController.devices[id]) - problem = - # TRANSLATORS %s is device idetification - format( - _("Disk %s cannot be formatted. Only ECKD disks can be formatted."), - channel - ) - end - end - if !Builtins.isempty(problem) - Popup.Message(problem) - return false - end - - num_parallel = [selected.size, 8].min - num_parallel = AskNumParallel(num_parallel) if num_parallel > 1 - - return false if num_parallel == 0 - - # final confirmation before formatting the discs - channels = Builtins.maplist(selected) do |id| - Ops.get_string(DASDController.devices, [id, "channel"], "") - end - channels_str = Builtins.mergestring(channels, ", ") - if !Popup.AnyQuestionRichText( - Popup.NoHeadline, - # popup question - Builtins.sformat( - _( - "Formatting these disks destroys all data on them.
\n" \ - "Really format the following disks?
\n" \ - "%1" - ), - channels_str - ), - 60, - 20, - Label.YesButton, - Label.NoButton, - :focus_no - ) - return false - end - - devices = Builtins.maplist(selected) do |id| - Ops.get_string(DASDController.devices, [id, "dev_name"], "") - end - DASDController.FormatDisks(devices, num_parallel) - - # We used to explicitly activate the DASD devices here, don't do - # it - see bsc#1187012. - - DASDController.ProbeDisks - - return true - end - else - case action - when :diag_off, :diag_on - value = action == :diag_on - - Builtins.foreach(selected) do |id| - Ops.set(DASDController.devices, [id, "diag"], value) - end - - return true - when :format_off, :format_on - value = action == :format_on - - Builtins.foreach(selected) do |id| - Ops.set(DASDController.devices, [id, "format"], value) - end - - return true - end - end - - false + run(action, selected) end # Draw the DASD dialog @@ -400,7 +155,7 @@ def DisplayDASDDialog help_key = Mode.config ? "disk_selection_config" : "disk_selection" # Minimal text for the help - help = Ops.get_string(@DASD_HELPS, help_key, "") + help = @DASD_HELPS.fetch(help_key, "") # Dialog caption caption = _("DASD Disk Management") @@ -491,11 +246,7 @@ def DisplayDASDDialog def ReloadDASDDialog items = GetDASDDiskItems() - selected = Convert.convert( - UI.QueryWidget(Id(:table), :SelectedItems), - from: "any", - to: "list " - ) + selected = UI.QueryWidget(Id(:table), :SelectedItems) || [] UI.ChangeWidget(Id(:table), :Items, items) UI.ChangeWidget(Id(:table), :SelectedItems, selected) UI.SetFocus(:table) @@ -656,9 +407,12 @@ def AddDASDDiskDialog channel = DASDController.FormatChannel(channel) - d = { "channel" => channel, "format" => format, "diag" => diag } + dasd_new = Y2S390::Dasd.new(channel).tap do |dasd| + dasd.format_watend = format + dasd.diag_wanted = diag + end - DASDController.AddDevice(d) + DASDController.devices.add(dasd_new) end ret @@ -668,11 +422,11 @@ def AddDASDDiskDialog # @return [Symbol] from DeleteDASDDiskDialog def DeleteDASDDiskDialog selected = ListSelectedDASD() - if Builtins.isempty(selected) + if selected.empty? # error popup message Popup.Message(_("No disk selected.")) else - Builtins.foreach(selected) { |index| DASDController.RemoveDevice(index) } + selected { |id| DASDController.devices.delete(id) } end :next diff --git a/src/modules/DASDController.rb b/src/modules/DASDController.rb index 82afaea9..d30659a3 100644 --- a/src/modules/DASDController.rb +++ b/src/modules/DASDController.rb @@ -1,4 +1,4 @@ -# Copyright (c) [2012-2014] Novell, Inc. +# Copyright (c) [2021] SUSE LLC # # All Rights Reserved. # @@ -12,26 +12,20 @@ # more details. # # You should have received a copy of the GNU General Public License along -# with this program; if not, contact Novell, Inc. +# with this program; if not, contact SUSE LLC. # -# To contact Novell about this file by physical or electronic mail, you may -# find current contact information at www.novell.com. - -# File: modules/DASDController.ycp -# Package: Configuration of controller -# Summary: Controller settings, input and output functions -# Authors: Jiri Srain -# -# $Id$ +# To contact SUSE LLC about this file by physical or electronic mail, you may +# find current contact information at www.suse.com. # -# Representation of the configuration of controller. -# Input and output routines. require "yast" require "yast2/popup" +require "yast2/execute" require "shellwords" -require "yaml" +require "y2s390/dialogs/format" +require "y2s390/dasds_reader" module Yast + # Dasd controller settings class DASDControllerClass < Module include Yast::Logger @@ -45,7 +39,7 @@ def main Yast.import "Popup" Yast.import "String" - @devices = {} + @devices = Y2S390::DasdsCollection.new([]) @filter_min = "0.0.0000" @filter_max = "ff.f.ffff" @@ -65,38 +59,33 @@ def main end # Data was modified? - # @return true if modified + # @return [Boolean] true if modified def GetModified @modified end + # Set the data as modified or not according to the given parameter + # + # @param value [Boolean] def SetModified(value) @modified = value nil end - def GetDeviceName(channel) - dir = Builtins.sformat("/sys/bus/ccw/devices/%1/block/", channel) - files = Convert.convert( - SCR.Read(path(".target.dir"), dir), - from: "any", - to: "list " - ) - return Ops.add("/dev/", Ops.get(files, 0, "")) if Builtins.size(files) == 1 - - nil - end - + # Returns whether the DASD channel ID is valid or not + # @param channel [String] + # @return [Boolean] def IsValidChannel(channel) - regexp = "^([[:xdigit:]]{1,2}).([[:xdigit:]]{1}).([[:xdigit:]]{4})$" - Builtins.regexpmatch(channel, regexp) + regexp = /^([[:xdigit:]]{1,2}).([[:xdigit:]]{1}).([[:xdigit:]]{4})$/ + channel.match?(regexp) end + # @param channel [Boolean] def FormatChannel(channel) return channel if !IsValidChannel(channel) - Builtins.tolower(channel) + channel.downcase end # Read all controller settings @@ -104,31 +93,10 @@ def FormatChannel(channel) def Read ProbeDisks() - if !Mode.normal - @devices = Builtins.mapmap(@devices) do |index, d| - Ops.set(d, "format", Ops.get_boolean(d, "format", false)) - Ops.set(d, "diag", Ops.get_boolean(d, "diag", false)) - { index => d } - end - end - @disk_configured = false true end - # Returns if device can be formatted - # - # @param [Hash] device one of the #devices values - # @return [Boolean] - def can_be_formatted?(device) - device_name = device["dev_name"] || GetDeviceName(device["channel"]) - command = "/sbin/dasdview --extended #{device_name.shellescape}" - res = SCR.Execute(path(".target.bash_output"), command) - Builtins.y2milestone("Command %1 result in %2", command, res) - # allow to format only ECKD bsc#1070265 - !res["stdout"].lines.grep(/^type\s.*ECKD/).empty? - end - # Write all controller settings # @return true on success def Write @@ -136,23 +104,23 @@ def Write to_format = [] to_reactivate = [] unformatted_devices = [] + reader.refresh_data!(@devices) - Builtins.foreach(@devices) do |_index, device| - channel = Ops.get_string(device, "channel", "") - format = Ops.get_boolean(device, "format", false) - do_diag = Ops.get_boolean(device, "diag", false) - act_ret = activate_disk_if_needed(channel, do_diag) + @devices.each do |dasd| + act_ret = activate_if_needed(dasd) + format = !!dasd.format_wanted # FIXME: general activation error handling - also in sync with below # for AutoInstall, format unformatted disks later at once # even disks manually selected for formatting must be reactivated if Mode.autoinst && act_ret == 8 && (@format_unformatted || format) format = true - to_reactivate << device + to_reactivate << dasd end - device_name = device["dev_name"] || GetDeviceName(channel) + + device_name = dasd.device_name || dasd.sys_device_name if format - if can_be_formatted?(device) - to_format << device_name + if dasd.can_be_formatted? + to_format << dasd else Report.Error( # TRANSLATORS %s is device name @@ -164,50 +132,39 @@ def Write end # unformatted disk, manual (not AutoYaST) elsif act_ret == 8 - unformatted_devices << device_name + unformatted_devices << dasd end end if !unformatted_devices.empty? message = if unformatted_devices.size == 1 - Builtins.sformat(_("Device %1 is not formatted. Format device now?"), - unformatted_devices[0]) + format(_("Device %s is not formatted. Format device now?"), + unformatted_devices.first.device_name) else - Builtins.sformat(_("There are %1 unformatted devices. Format them now?"), + format(_("There are %s unformatted devices. Format them now?"), unformatted_devices.size) end if Popup.ContinueCancel(message) - unformatted_devices.each do |device| - to_format << device - to_reactivate << device + unformatted_devices.each do |dasd| + to_format << dasd + to_reactivate << dasd end end end - Builtins.y2milestone("Disks to format: %1", to_format) + log.info "Disks to format: #{to_format}" - FormatDisks(to_format, 8) if !Builtins.isempty(to_format) + FormatDisks(to_format) unless to_format.empty? - to_reactivate.each do |device| - channel = device["channel"] || "" - do_diag = device["diag"] || false + to_reactivate.each do |dasd| # FIXME: general activation error handling - also in sync with above - ActivateDisk(channel, do_diag) + ActivateDisk(dasd.id, !!dasd.diag_wanted) end end if !Mode.installation if @disk_configured - # popup label - UI.OpenDialog(Label(_("Running mkinitrd."))) - - command = "/sbin/mkinitrd" - Builtins.y2milestone("Running command %1", command) - ret = SCR.Execute(path(".target.bash"), command) - Builtins.y2milestone("Exit code: %1", ret) - - UI.CloseDialog - + Y2S390::Dialogs::Mkinitrd.new.run @disk_configured = false end end @@ -221,16 +178,16 @@ def Write # @return [Boolean] True on success def Import(settings) settings = deep_copy(settings) - index = -1 - @devices = Builtins.listmap(Ops.get_list(settings, "devices", [])) do |d| - index = Ops.add(index, 1) - Ops.set(d, "channel", FormatChannel(Ops.get_string(d, "channel", ""))) - d = Builtins.filter(d) do |k, _v| - Builtins.contains(["channel", "format", "diag"], k) - end - { index => d } + imported_devices = settings.fetch("devices", []).map do |device| + channel = FormatChannel(device.fetch("channel", "")) + d = Y2S390::Dasd.new(channel) + d.format_wanted = device.fetch("format", false) + d.diag_wanted = device.fetch("diag", false) + d end + @devices = Y2S390::DasdsCollection.new(imported_devices) + @format_unformatted = settings["format_unformatted"] || false true @@ -242,24 +199,17 @@ def Import(settings) def Export # Exporting active DASD only. # (bnc#887407) - active_devices = @devices.select do |_nr, device| - device.key?("resource") && - device["resource"].key?("io") && - !device["resource"]["io"].empty? && - device["resource"]["io"].first["active"] - end + active_devices = @devices.active if active_devices.empty? # If no device is active we are exporting all. So the admin # can patch this manually. - Builtins.y2milestone("No active DASD found. --> Taking all") + log.info("No active DASD found. --> Taking all") active_devices = @devices end - l = Builtins.maplist(active_devices) do |_i, d| - Builtins.filter(d) do |k, _v| - Builtins.contains(["channel", "format", "diag"], k) - end + l = active_devices.map do |d| + { "channel" => d.id, "diag" => d.diag_wanted, "format" => d.format_wanted }.compact end { @@ -269,7 +219,7 @@ def Export end def GetDevices - deep_copy(@devices) + @devices end # @param channel [String] "0.0.0000" "ab.c.Def0" @@ -281,71 +231,17 @@ def channel_sort_key(channel) # @return {GetDevices} but filtered by filter_min and filter_max def GetFilteredDevices - min = channel_sort_key(@filter_min) - max = channel_sort_key(@filter_max) - - ret = GetDevices() - Builtins.filter(ret) do |_k, d| - channel = d.fetch("channel", "") - key = channel_sort_key(channel) - min <= key && key <= max - end - end - - def AddDevice(device) - device = deep_copy(device) - index = 0 - index = Ops.add(index, 1) while Builtins.haskey(@devices, index) - Ops.set(@devices, index, device) + min = channel_sort_key(@filter_min).hex + max = channel_sort_key(@filter_max).hex - nil - end - - def RemoveDevice(index) - @devices = Builtins.remove(@devices, index) - - nil - end - - def GetDeviceIndex(channel) - ret = nil - Builtins.foreach(@devices) do |index, d| - ret = index if Ops.get_string(d, "channel", "") == channel - end - ret + GetDevices().filter { |d| min <= d.hex_id && d.hex_id <= max } end # Create a textual summary and a list of configured devices # @return summary of the current configuration def Summary - ret = [] - - if Mode.config - ret = Builtins.maplist(@devices) do |_index, d| - Builtins.sformat( - _("Channel ID: %1, Format: %2, DIAG: %3"), - Ops.get_string(d, "channel", ""), - String.YesNo(Ops.get_boolean(d, "format", false)), - String.YesNo(Ops.get_boolean(d, "diag", false)) - ) - end - else - active_devices = Builtins.filter(@devices) do |_index, device| - Ops.get_boolean(device, ["resource", "io", 0, "active"], false) - end - - ret = Builtins.maplist(active_devices) do |_index, d| - Builtins.sformat( - _("Channel ID: %1, Device: %2, DIAG: %3"), - Ops.get_string(d, "channel", ""), - Ops.get_string(d, "dev_name", ""), - String.YesNo(Ops.get_boolean(d, "diag", false)) - ) - end - end - - Builtins.y2milestone("Summary: %1", ret) - deep_copy(ret) + require "y2s390/presenters/summary" + Y2S390::Presenters::DasdsSummary.new(Yast::Mode.config ? @devices : @devices.active).text end # In production, call SCR.Read(.probe.disk). @@ -374,30 +270,23 @@ def AutoPackages # Check if DASD subsystem is available # @return [Boolean] True if more than one disk def IsAvailable - disks = probe_or_mock_disks - count = disks.count { |d| d["device"] == "DASD" } + disks = find_disks(force_probing: true) + count = disks.size log.info("number of probed DASD devices #{count}") count > 0 end + def reader + @reader ||= Y2S390::DasdsReader.new + end + # Probe for DASD disks def ProbeDisks # popup label UI.OpenDialog(Label(_("Reading Configured DASD Disks"))) - disks = find_disks(force_probing: true) - - index = -1 - @devices = Builtins.listmap(disks) do |d| - index = Ops.add(index, 1) - { index => d } - end - - disks.each do |dev| - @diag[dev["channel"]] = dev["diag"] if dev["diag"] - end - - Builtins.y2milestone("probed DASD devices %1", @devices) + @devices = reader.list(force_probing: true) + log.info("probed DASD devices #{@devices.inspect}") UI.CloseDialog @@ -408,9 +297,9 @@ def ProbeDisks # @param [String] channel string channel of the device # @param [Hash] ret output of bash_output agent run def ReportActivationError(channel, ret) - case ret["exit"] - when 0 + return if ret["exit"] == 0 + case ret["exit"] when 1 # error report, %1 is device identification Report.Error(Builtins.sformat(_("%1: sysfs not mounted."), channel)) @@ -458,24 +347,16 @@ def ReportActivationError(channel, ret) # @param [Boolean] diag boolean Activate DIAG or not # @return [Integer] exit code of the activation command def ActivateDisk(channel, diag) - command = Builtins.sformat( - "/sbin/dasd_configure '%1' %2 %3", - channel, - 1, - diag ? 1 : 0 - ) + command = "/sbin/dasd_configure '#{channel}' 1 #{diag ? 1 : 0}" Builtins.y2milestone("Running command \"%1\"", command) ret = SCR.Execute(path(".target.bash_output"), command) - Builtins.y2milestone( - "Command \"%1\" returned %2", - command, - ret - ) + Builtins.y2milestone("Command \"#{command}\" returned #{command}") case ret["exit"] when 8 # unformatted disk is now handled now outside this function # however, don't issue any error + log.info("Unformatted disk #{channel}, nothing to do") when 7 # when return code is 7, set DASD offline # https://bugzilla.novell.com/show_bug.cgi?id=561876#c9 @@ -496,32 +377,23 @@ def ActivateDisk(channel, diag) # the same API than ActivateDisk. # # @return [Integer] Returns an error code (8 means 'unformatted'). - def activate_disk_if_needed(channel, diag) - disk = find_disks.find { |d| d["channel"] == channel } - if disk && active_disk?(disk) - log.info "Disk #{disk.inspect} is already active. Skipping the activation." - return disk["formatted"] ? 0 : 8 + def activate_if_needed(dasd) + if dasd.io_active? + log.info "Dasd #{dasd.inspect} is already active. Skipping the activation." + return dasd.formatted? ? 0 : 8 end - ActivateDisk(channel, diag) + + ActivateDisk(dasd.id, !!dasd.diag_wanted) end # Deactivate disk # @param [String] channel string Name of the disk to deactivate # @param [Boolean] diag boolean Activate DIAG or not def DeactivateDisk(channel, diag) - command = Builtins.sformat( - "/sbin/dasd_configure '%1' %2 %3 < /dev/null", - channel, - 0, - diag ? 1 : 0 - ) - Builtins.y2milestone("Running command \"%1\"", command) + command = "/sbin/dasd_configure '#{channel}' 0 #{diag ? 1 : 0} < /dev/null" + log.info("Running command \"#{command}\"") ret = SCR.Execute(path(".target.bash_output"), command) - Builtins.y2milestone( - "Command \"%1\" returned with exit code %2", - command, - ret - ) + log.info("Command \"#{command}\" returned with exit code #{ret}") ReportActivationError(channel, ret) @@ -532,183 +404,28 @@ def DeactivateDisk(channel, diag) # Activate or deactivate diag on active disk # @param [String] channel string Name of the disk to operate on - # @param [Boolean] diag boolean Activate DIAG or not - def ActivateDiag(channel, diag) - old_diag = DASDController.diag.fetch(channel, false) - return if diag == old_diag - - DeactivateDisk(channel, old_diag) - ActivateDisk(channel, diag) - end - - # Format disks - # @param [Array] disks_list list List of disks to be formatted - # @param [Fixnum] par integer Number of disks that can be formated in parallel - def FormatDisks(disks_list, par) - disks_list = deep_copy(disks_list) - par = Builtins.size(disks_list) if Ops.greater_than(par, Builtins.size(disks_list)) - - disks = {} - disks_cmd = [] - index = -1 - reqsize = 10 # The default request size for dasdfmt is 10 - msize = 10 # The "cylinders per hashmark" value must be >= the request size - msize = reqsize if msize < reqsize - Builtins.foreach(disks_list) do |device| - index = Ops.add(index, 1) - Ops.set(disks, index, device) - disks_cmd = Builtins.add(disks_cmd, Builtins.sformat("-f '%1'", device)) - end - disks_param = Builtins.mergestring(disks_cmd, " ") - command = Builtins.sformat( - "/sbin/dasdfmt -Y -P %1 -b 4096 -y -r %2 -m %3 %4", - par, - reqsize, - msize, - disks_param - ) - - Builtins.y2milestone("Running command %1", command) - contents = VBox(HSpacing(70)) - index = 0 - while Ops.less_than(index, par) - # progress bar - contents = Builtins.add( - contents, - ProgressBar( - Id(index), - Builtins.sformat(_("Formatting %1:"), Ops.get(disks, index, "")), - 100, - 0 - ) - ) - index = Ops.add(index, 1) - end - UI.OpenDialog(contents) - cylinders = {} - done = {} - # start formatting on background - process_id = Convert.to_integer( - SCR.Execute(path(".process.start_shell"), command) - ) - Builtins.y2milestone("Process start returned %1", process_id) - # get the sizes of all disks - index = 0 - while Ops.less_than(index, Builtins.size(disks)) - Builtins.y2milestone("Running first formatting cycle") - Builtins.sleep(500) - - if !Convert.to_boolean(SCR.Read(path(".process.running"), process_id)) - UI.CloseDialog - iret2 = Convert.to_integer( - SCR.Read(path(".process.status"), process_id) - ) - # error report, %1 is exit code of the command (integer) - Report.Error( - Builtins.sformat( - _("Disks formatting failed. Exit code: %1.\nError output:%2"), - iret2, - stderr_from_proccess - ) - ) - return - end + # @param [Boolean] value boolean Activate DIAG or not + def ActivateDiag(channel, value) + dasd = devices.by_id(channel) + return if !dasd || value == dasd.diag_wanted - while Ops.less_than(index, Builtins.size(disks)) - line = Convert.to_string( - SCR.Read(path(".process.read_line"), process_id) - ) - break if line.nil? + DeactivateDisk(dasd.id, dasd.diag_wanted) + ActivateDisk(dasd.id, value) + end - siz = Builtins.tointeger(line) - siz = 999999999 if siz == 0 - Ops.set(cylinders, index, siz) - index = Ops.add(index, 1) - end - end - Builtins.y2milestone("Sizes of disks: %1", cylinders) - Builtins.y2milestone("Disks to format: %1", disks) - last_step = [] - last_rest = "" - while Convert.to_boolean(SCR.Read(path(".process.running"), process_id)) - Builtins.sleep(1000) - buffer = Convert.to_string(SCR.Read(path(".process.read"), process_id)) - buffer = Ops.add(last_rest, buffer) - progress = Builtins.splitstring(buffer, "|") - this_step = {} - if Convert.to_boolean(SCR.Read(path(".process.running"), process_id)) - last = Ops.subtract(Builtins.size(progress), 1) - last_rest = Ops.get(progress, last, "") - progress = Builtins.remove(progress, last) - end - Builtins.foreach(progress) do |d| - if d != "" - i = Builtins.tointeger(d) - Ops.set(this_step, i, Ops.add(Ops.get(this_step, i, 0), msize)) - end - end - Builtins.foreach(this_step) do |k, v| - Ops.set(done, k, Ops.add(Ops.get(done, k, 0), v)) - end - this_step = Builtins.filter(this_step) do |k, _v| - Ops.less_than(Ops.get(done, k, 0), Ops.get(cylinders, k, 0)) - end - difference = Ops.subtract( - Builtins.size(last_step), - Builtins.size(this_step) - ) - index = -1 - while Ops.greater_than(difference, 0) - index = Ops.add(index, 1) - if !Builtins.haskey(this_step, Ops.get(last_step, index, 0)) - difference = Ops.subtract(difference, 1) - Ops.set(this_step, Ops.get(last_step, index, 0), 0) - end - end - index = 0 - Builtins.foreach(this_step) do |k, _v| - UI.ChangeWidget( - Id(index), - :Label, - Builtins.sformat( - # progress bar, %1 is device name, %2 and %3 - # integers, - # eg. Formatting /dev/dasda: cylinder 123 of 12334 done - _("Formatting %1: cylinder %2 of %3 done"), - Ops.get(disks, k, ""), - Ops.get(done, k, 0), - Ops.get(cylinders, k, 0) - ) - ) - UI.ChangeWidget( - Id(index), - :Value, - Ops.divide( - Ops.multiply(100, Ops.get(done, k, 0)), - Ops.get(cylinders, k, 1) - ) - ) - UI.ChangeWidget(Id(index), :Enabled, true) - index = Ops.add(index, 1) - end - while Ops.less_than(index, par) - UI.ChangeWidget(Id(index), :Label, "") - UI.ChangeWidget(Id(index), :Value, 0) - UI.ChangeWidget(Id(index), :Enabled, false) - index = Ops.add(index, 1) - end - end - UI.CloseDialog - iret = Convert.to_integer(SCR.Read(path(".process.status"), process_id)) - if iret != 0 - # error report, %1 is exit code of the command (integer), %2 output of command - Report.Error( - Builtins.sformat(_("Disks formatting failed. Exit code: %1.\nError output: %2"), - iret, stderr_from_proccess) - ) - end + def format_dialog_for(disks_list) + if ENV["NEW_FORMAT"] + Y2S390::Dialogs::DasdFormat + else + Y2S390::Dialogs::FormatDisks + end.new(disks_list) + end - nil + # It formats the given disks showing the progress in a separate dialog + # + # @param [S390::DasdsCollection] collection of dasds to be be formatted + def FormatDisks(disks_list) + format_dialog_for(disks_list).run end # Get partitioninfo @@ -763,25 +480,19 @@ def GetPartitionInfo(disk) publish function: :Export, type: "map ()" publish function: :GetDevices, type: "map > ()" publish function: :GetFilteredDevices, type: "map > ()" - publish function: :AddDevice, type: "void (map )" - publish function: :RemoveDevice, type: "void (integer)" - publish function: :GetDeviceIndex, type: "integer (string)" publish function: :Summary, type: "list ()" publish function: :AutoPackages, type: "map ()" publish function: :IsAvailable, type: "boolean ()" private - def stderr_from_proccess - stderr = "" - loop do - line = SCR.Read(path(".process.read_line_stderr")) - break unless line - - stderr << line - end - - stderr + # Convenience method to convert the device ID to integers for filtering purposes + # + # @param [String] the DASD id + # @return [Array] the css, lcss and channel in integer format + def int_channels(channel_id) + css, lcss, chan = channel_id.split(".") + [css, lcss, chan].map { |c| "0x#{c}".to_i } end # Returns an string containing the available stdout and/or stderr @@ -822,6 +533,31 @@ def active_disk?(disk) io.any? { |i| i["active"] } end + # Determines whether the disk is formatted or not + # + # @param disk [Hash] + # @return [Boolean] + def formatted?(disk) + device = disk.fetch("dev_name", "") + fmt_out = Yast::Execute.stdout.locally!( + ["/sbin/dasdview", "--extended", device], ["grep", "formatted"] + ) + fmt_out.empty? ? false : !fmt_out.upcase.match?(/NOT[ \t]*FORMATTED/) + end + + # Determines whether the disk has the DIAG access enabled or not + # + # @param disk [Hash] + # @return [Boolean] + def use_diag?(disk) + diag_file = "/sys/#{disk["sysfs_id"]}/device/use_diag" + use_diag = SCR.Read(path(".target.string"), diag_file) if File.exist?(diag_file) + use_diag.to_i == 1 + end + + DASD_ATTRS = ["channel", "diag", "resource", "formatted", "partition_info", "dev_name", + "detail", "device_id", "sub_device_id"].freeze + # Returns the DASD disks # # Probes and returns the found DASD disks ordered by channel. @@ -830,68 +566,9 @@ def active_disk?(disk) # @param force_probing [Boolean] Ignore the cached values and probes again. # @return [Array] Found DASD disks def find_disks(force_probing: false) - return @disks if @disks && !force_probing - - disks = probe_or_mock_disks - disks = Builtins.filter(disks) do |d| - Builtins.tolower(Ops.get_string(d, "device", "")) == "dasd" - end - - disks.sort_by! { |disk| FormatChannel(disk.fetch("sysfs_bus_id", "0.0.0000")) } - - @disks = Builtins.maplist(disks) do |d| - channel = Ops.get_string(d, "sysfs_bus_id", "") - Ops.set(d, "channel", channel) - active = Ops.get_boolean(d, ["resource", "io", 0, "active"], false) - if active - device = Ops.get_string(d, "dev_name", "") - scr_out = Convert.to_map( - SCR.Execute( - path(".target.bash_output"), - Builtins.sformat("/sbin/dasdview --extended '%1' | grep formatted", device) - ) - ) - formatted = false - if Ops.get_integer(scr_out, "exit", 0) == 0 - out = Ops.get_string(scr_out, "stdout", "") - formatted = !Builtins.regexpmatch( - Builtins.toupper(out), - "NOT[ \t]*FORMATTED" - ) - end - Ops.set(d, "formatted", formatted) - - Ops.set(d, "partition_info", GetPartitionInfo(device)) if formatted - - diag_file = Builtins.sformat( - "/sys/%1/device/use_diag", - Ops.get_string(d, "sysfs_id", "") - ) - if FileUtils.Exists(diag_file) - use_diag = Convert.to_string( - SCR.Read(path(".target.string"), diag_file) - ) - Ops.set(d, "diag", Builtins.substring(use_diag, 0, 1) == "1") - end - end - d = Builtins.filter(d) do |k, _v| - Builtins.contains( - [ - "channel", - "diag", - "resource", - "formatted", - "partition_info", - "dev_name", - "detail", - "device_id", - "sub_device_id" - ], - k - ) - end - deep_copy(d) - end + reader = Y2S390::HwinfoReader.instance + reader.reset if force_probing + reader.data end end diff --git a/test/dasd_controller_test.rb b/test/dasd_controller_test.rb index 18b7a74c..a43a337f 100755 --- a/test/dasd_controller_test.rb +++ b/test/dasd_controller_test.rb @@ -6,19 +6,11 @@ describe Yast::DASDController do subject { Yast::DASDController } + let(:mock_disks) { true } - describe "#GetDeviceName" do - let(:channel) { "0.0.0150" } - let(:device_block_path) { "/sys/bus/ccw/devices/#{channel}/block/" } - - before do - allow(Yast::SCR).to receive(:Read).with(Yast.path(".target.dir"), device_block_path) - .once.and_return(["dasda"]) - end - - it "returns the associated device name" do - expect(subject.GetDeviceName(channel)).to eq("/dev/dasda") - end + before do + allow(ENV).to receive(:[]).and_call_original + allow(ENV).to receive(:[]).with("S390_MOCKING").and_return(mock_disks) end describe "#ActivateDisk" do @@ -61,43 +53,35 @@ end end - describe "#activate_disk_if_needed" do + describe "#activate_if_needed" do + let(:dasd) { subject.devices.by_id(channel) } let(:channel) { "0.0.0150" } - let(:formatted) { true } let(:active) { true } - - let(:disk) do - { - "dev_name" => "/dev/dasda", - "formatted" => formatted, - "channel" => channel, - "resource" => { - "io" => [{ "active" => active }] - } - } - end + let(:formatted) { true } before do - allow(subject).to receive(:find_disks).and_return([disk]) + subject.ProbeDisks() + allow(dasd).to receive(:io_active?).and_return(active) + dasd.formatted = formatted end context "when the disk is already active" do it "does not activate the disk" do expect(subject).to_not receive(:ActivateDisk) - subject.activate_disk_if_needed(channel, false) + subject.activate_if_needed(dasd) end context "and it is not formatted" do let(:formatted) { false } it "returns 8" do - expect(subject.activate_disk_if_needed(channel, false)).to eq(8) + expect(subject.activate_if_needed(dasd)).to eq(8) end end context "and it is formatted" do it "returns 0" do - expect(subject.activate_disk_if_needed(channel, false)).to eq(0) + expect(subject.activate_if_needed(dasd)).to eq(0) end end end @@ -108,7 +92,7 @@ it "activates the disk" do expect(subject).to receive(:ActivateDisk).with(channel, false) .and_return(0) - expect(subject.activate_disk_if_needed(channel, false)).to eq(0) + expect(subject.activate_if_needed(dasd)).to eq(0) end end end @@ -213,49 +197,37 @@ end describe "#IsAvailable" do + context "when .probe.disk does not contain DASDS" do + let(:mock_disks) { false } + + before do + allow(Yast::SCR).to receive(:Read).with(Yast.path(".probe.disk")).and_return({}) + end + + it "returns false" do + expect(subject.IsAvailable()).to eq(false) + end + end + it "returns true if .probe.disk contains DASDs" do - expect(Yast::SCR).to receive(:Read).with(Yast.path(".probe.disk")).once - .and_return(load_data("probe_disk_dasd.yml")) expect(subject.IsAvailable()).to eq(true) end end describe "#GetDevices" do - it "returns DASDs" do - expect(Yast::SCR).to receive(:Read).with(Yast.path(".probe.disk")).once - .and_return(load_data("probe_disk_dasd.yml")) - expect(subject.ProbeDisks()).to eq(nil) - expect(subject.GetDevices()).to eq( - 0 => { "detail" => { "cu_model" => 233, "dev_model" => 10, "lcss" => 0 }, - "device_id" => 276880, - "resource" => { "io" => [{ "active" => false, - "length" => 1, - "mode" => "rw", - "start" => 352 }] }, - "sub_device_id" => 275344, - "channel" => "0.0.0150" }, - 1 => { "detail" => { "cu_model" => 233, "dev_model" => 10, "lcss" => 0 }, - "device_id" => 276880, - "resource" => { "io" => [{ "active" => false, - "length" => 1, - "mode" => "rw", - "start" => 352 }] }, - "sub_device_id" => 275344, - "channel" => "0.0.0160" } - ) + it "returns cached DASDs" do + expect(subject.GetDevices).to be_a(Y2S390::DasdsCollection) end end describe "#FormatDisks" do - it "formats the given disks using dasdfmt" do - allow(Yast::SCR).to receive(:Read).with(path(".process.running"), 100).and_return(true, false) - allow(Yast::SCR).to receive(:Read).with(path(".process.status"), 100).and_return(0) - allow(Yast::SCR).to receive(:Read).with(path(".process.read_line"), 100).and_return("0") - allow(Yast::SCR).to receive(:Read).with(path(".process.read_line_stderr")).and_return(nil) - expect(Yast::SCR).to receive(:Execute).with( - path(".process.start_shell"), "/sbin/dasdfmt -Y -P 1 -b 4096 -y -r 10 -m 10 -f '/dev/dasda'" - ).and_return(100) - subject.FormatDisks(["/dev/dasda"], 8) + let(:disks) { Yast::DASDController.devices.by_ids(["0.0.0150"]) } + let(:dialog) { Y2S390::Dialogs::FormatDisks } + + it "runs a Format Disk dialog for the given disks" do + expect_any_instance_of(dialog).to receive(:run) + + subject.FormatDisks(disks) end end @@ -276,18 +248,21 @@ allow(Yast::Mode).to receive(:installation).and_return(true) allow(Yast::Mode).to receive(:autoinst).and_return(true) # speed up the test a bit - allow(Yast::Builtins).to receive(:sleep) allow(subject).to receive(:ActivateDisk).and_return(0) - allow(subject).to receive(:GetDeviceName).and_return("/dev/dasda") + allow(subject).to receive(:FormatDisks) end context "during autoinstallation" do + let(:channel) { "0.0.0100" } + let(:dasd) { Yast::DASDController.devices.by_id(channel) } + let(:can_format) { true } + before do subject.Import(data) + allow(dasd).to receive(:can_be_formatted?).and_return(can_format) if dasd end it "activates the disk" do - allow(subject).to receive(:FormatDisks) expect(subject).to receive(:ActivateDisk).with("0.0.0100", false) subject.Write end @@ -295,9 +270,11 @@ context "when 'format' is sets to true" do let(:format) { true } - it "formats the disk" do - expect(subject).to receive(:FormatDisks).with(["/dev/dasda"], 8) - expect(subject.Write).to eq(true) + context "and the disk can be formatted" do + it "formats the disk" do + expect(subject).to receive(:FormatDisks).with([dasd]) + expect(subject.Write).to eq(true) + end end end @@ -316,7 +293,7 @@ let(:format) { false } before do - allow(subject).to receive(:activate_disk_if_needed).with(channel, false) + allow(subject).to receive(:activate_if_needed).with(dasd) .and_return(NOT_FORMATTED_CODE) end @@ -324,7 +301,7 @@ let(:format_unformatted) { true } it "formats the device" do - expect(subject).to receive(:FormatDisks).with(["/dev/dasda"], anything) + expect(subject).to receive(:FormatDisks).with([dasd]) subject.Write end @@ -354,7 +331,7 @@ let(:format_unformatted) { false } it "formats the device" do - expect(subject).to receive(:FormatDisks).with(["/dev/dasda"], anything) + expect(subject).to receive(:FormatDisks).with([dasd]) subject.Write end @@ -366,122 +343,24 @@ end end - it "does not format disk for FBA disk and report error" do - allow(Yast::SCR).to receive(:Execute).with(path(".target.bash_output"), - /\/sbin\/dasdview/) - .and_return("exitstatus" => 0, "stdout" => load_file("dasdview_fba.txt"), "stderr" => "") - - expect(Yast::SCR).to_not receive(:Execute).with(path(".process.start_shell"), - /dasdfmt.*\/dev\/dasda/) + context "when the imported disk is a FBA one" do + let(:channel) { "0.0.ffff" } - expect(Yast::Report).to receive(:Error) + it "does not format the disk and report an error" do + subject.Import(data) + expect(subject).to_not receive(:FormatDisks) + expect(Yast::Report).to receive(:Error) - expect(subject.Import(data)).to eq(true) - expect(subject.Write).to eq(true) + expect(subject.Write).to eq(true) + end end end end describe "#ProbeDisks" do - let(:disks) { [disk] } - - let(:disk) do - { - "device" => "DASD", - "sysfs_bus_id" => "0.0.0150", - "resource" => { - "io" => [] - } - } - end - - before do - allow(Yast::SCR).to receive(:Read).with(path(".probe.disk")).and_return(disks) - end - - context "there is non-dasd disk" do - let(:disk) do - { - "device" => "ZFCP", - "sysfs_bus_id" => "0.0.0150", - "resource" => { - "io" => [] - } - } - end - - it "is not added to devices" do - subject.ProbeDisks - - expect(subject.devices).to be_empty - end - end - - context "there is not activated dasd disk" do - let(:disk) do - { - "device" => "DASD", - "sysfs_bus_id" => "0.0.0150", - "resource" => { - "io" => [] - } - } - end - - it "is added to devices with channel entry" do - subject.ProbeDisks - - expect(subject.devices.size).to eq 1 - expect(subject.devices.values.first["channel"]).to eq "0.0.0150" - end - end - - context "there is activated dasd disk" do - let(:disk) do - { - "device" => "DASD", - "dev_name" => "/dev/dasda", - "sysfs_bus_id" => "0.0.0150", - "sysfs_id" => "/class/block/dasda", - "resource" => { - "io" => ["active" => true] - } - } - end - - before do - allow(File).to receive(:exist?).and_return(false) - end - - it "is added to devices with formatted info" do - allow(Yast::SCR).to receive(:Execute).with(path(".target.bash_output"), - /\/sbin\/dasdview/) - .and_return("exitstatus" => 0, "stdout" => load_file("dasdview_unformatted.txt"), "stderr" => "") - - subject.ProbeDisks - - expect(subject.devices.size).to eq 1 - expect(subject.devices.values.first["formatted"]).to eq false - end - - context "when the 'use_diag' file exists" do - let(:diag_path) { "/sys//class/block/dasda/device/use_diag" } - - before do - allow(File).to receive(:exist?).with(diag_path) - .and_return(true) - allow(Yast::SCR).to receive(:Read) - .with(Yast::Path.new(".target.string"), diag_path) - .and_return("1") - end - - it "reads its value" do - subject.ProbeDisks - device = subject.devices.values.first - expect(device["diag"]).to eq(true) - expect(subject.diag).to eq("0.0.0150" => true) - end - end + it "forces a read of the DASDs information from the system" do + expect(subject.reader).to receive(:list).with(force_probing: true).and_call_original + subject.ProbeDisks end end @@ -489,27 +368,22 @@ it "deactivates and reactivates dasd" do expect(subject).to receive(:DeactivateDisk).ordered expect(subject).to receive(:ActivateDisk).ordered - expect(subject.ActivateDiag("0.0.3333", true)).to eq(nil) + expect(subject.ActivateDiag("0.0.0150", true)).to eq(nil) end end describe "#GetFilteredDevices" do - it "Filters the devices (as a single large number)" do - import_data = { "devices" => [{ "channel" => "0.4.fa00" }, - { "channel" => "0.0.fb00" }, - { "channel" => "0.0.fc00" }, - { "channel" => "0.0.f800" }, - { "channel" => "0.0.f900" }] } + let(:imported_ids) { ["0.4.fa00", "0.0.fb00", "0.0.fc00", "0.0.f800", "0.0.f900"] } - expect(subject.Import(import_data)).to eq(true) + it "Filters the devices (as a single large number)" do + import_data = { "devices" => imported_ids.map { |id| { "channel" => id } } } + subject.Import(import_data) subject.filter_max = subject.FormatChannel("10.0.FA00") subject.filter_min = subject.FormatChannel("0.0.f900") - expect(subject.GetFilteredDevices()).to eq( - 0 => { "channel" => "0.4.fa00" }, - 1 => { "channel" => "0.0.fb00" }, - 2 => { "channel" => "0.0.fc00" }, - 4 => { "channel" => "0.0.f900" } - ) + devices = subject.GetFilteredDevices() + + expect(devices.size).to eq(4) + expect(devices.ids).to eq(imported_ids.reject { |id| id == "0.0.f800" }) end end end diff --git a/test/data/lsdasd.txt b/test/data/lsdasd.txt index 422b8f05..f9e30c93 100644 --- a/test/data/lsdasd.txt +++ b/test/data/lsdasd.txt @@ -8,3 +8,4 @@ Bus-ID Status Name Device Type BlkSz Size Blocks 0.0.0150 active dasdb 94:4 ECKD 4096 7042MB 1802880 0.0.0592 active(ro) dasdc 94:8 ECKD 4096 168MB 43200 0.0.019e active(ro) dasdd 94:12 ECKD 4096 351MB 90000 +0.0.ffff active dasdc 94:8 FBA 512 97MB 200000 diff --git a/test/data/probe_disk_dasd.yml b/test/data/probe_disk_dasd.yml index 33411fa6..0c445c3c 100644 --- a/test/data/probe_disk_dasd.yml +++ b/test/data/probe_disk_dasd.yml @@ -63,3 +63,53 @@ sysfs_id: "/devices/css0/0.0.0001/0.0.0150" vendor: IBM vendor_id: 286721 +- bus: None + bus_hwcfg: none + class_id: 262 + detail: + cu_model: 128 + dev_model: 16 + lcss: 0 + dev_name: "/dev/dasdc" + dev_names: + - "/dev/dasdc" + - "/dev/disk/by-id/ccw-TMPDSK" + - "/dev/disk/by-path/ccw-0.0.ffff" + dev_num: + major: 94 + minor: 8 + range: 4 + type: b + device: DASD + device_id: 287504 + driver: io_subchannel + drivers: + - active: true + modprobe: true + modules: + - - dasd_fba_mod + - '' + model: IBM DASD + old_unique_key: bWb9.SmaKL6WXMRD + prog_if: 2 + resource: + disk_log_geo: + - cylinders: 97 + heads: 16 + sectors: 128 + io: + - active: true + length: 1 + mode: rw + start: 65535 + size: + - unit: sectors + x: 200000 + y: 512 + sub_class_id: 0 + sub_device_id: 299830 + sysfs_bus_id: 0.0.ffff + sysfs_id: "/class/block/dasdc" + unique_key: "+yTa.QXpeV9WJ_32" + vendor: IBM + vendor_id: 286721 From 3732ecb4a24427c29ab969e4db731da47c9f9dd0 Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Wed, 17 Nov 2021 10:09:41 +0000 Subject: [PATCH 05/31] Added Summary presenter --- src/lib/y2s390/presenters/summary.rb | 73 ++++++++++++++++++++++++++ src/modules/DASDController.rb | 5 +- test/test_helper.rb | 4 ++ test/y2s390/presenters/summary_test.rb | 26 +++++++++ 4 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 src/lib/y2s390/presenters/summary.rb create mode 100644 test/y2s390/presenters/summary_test.rb diff --git a/src/lib/y2s390/presenters/summary.rb b/src/lib/y2s390/presenters/summary.rb new file mode 100644 index 00000000..46f4ea51 --- /dev/null +++ b/src/lib/y2s390/presenters/summary.rb @@ -0,0 +1,73 @@ +# Copyright (c) [2021] 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" + +Yast.import "Mode" +Yast.import "String" + +module Y2S390 + module Presenters + # This class is responsible of returning a configuration summary of the given devices + class DasdSummary + include Yast::Logger + include Yast::I18n + + # @return [Y2S390::DasdsCollection] + attr_accessor :devices + + # Constructor + # + # @param devices [Y2S390::DasdsCollection] + def initialize(devices) + @devices = devices + end + + # Return a list with the configuration summary for all the devices given in text plain + # + # @return [Array] + def list + ret = devices.map { |d| format(template, *params(d)) } + log.info("Summary: #{ret}") + ret + end + + private + + # Convenience method to obtain the arguments needed by the configuration template to be used + # depending on the {Yast::Mode} + # + # @param device [Y2S390::Dasd] + def params(device) + return [device.id, device.format, Yast::String.YesNo(device.use_diag)] if Yast::Mode.config + + [device.id, device.device_name, Yast::String.YesNo(device.use_diag)] + end + + # Return the configuration summary template to be used depending on the {Yast::Mode} + # + # @return [String] + def template + return _("Channel ID: %s, Format: %s, DIAG: %s") if Yast::Mode.config + + _("Channel ID: %s, Device: %s, DIAG: %s") + end + end + end +end diff --git a/src/modules/DASDController.rb b/src/modules/DASDController.rb index d30659a3..ca371768 100644 --- a/src/modules/DASDController.rb +++ b/src/modules/DASDController.rb @@ -237,11 +237,12 @@ def GetFilteredDevices GetDevices().filter { |d| min <= d.hex_id && d.hex_id <= max } end - # Create a textual summary and a list of configured devices + # Returns a text list with the summary of the configured devices + # # @return summary of the current configuration def Summary require "y2s390/presenters/summary" - Y2S390::Presenters::DasdsSummary.new(Yast::Mode.config ? @devices : @devices.active).text + Y2S390::Presenters::DasdsSummary.new(Yast::Mode.config ? @devices : @devices.active).list end # In production, call SCR.Read(.probe.disk). diff --git a/test/test_helper.rb b/test/test_helper.rb index 72072e78..135a6b75 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -56,3 +56,7 @@ def load_file(name) path = File.join(File.dirname(__FILE__), "data", name) File.read(path) end + +def mock_entries + ENV["S390_MOCKING"] = "1" +end diff --git a/test/y2s390/presenters/summary_test.rb b/test/y2s390/presenters/summary_test.rb new file mode 100644 index 00000000..c0f20bc7 --- /dev/null +++ b/test/y2s390/presenters/summary_test.rb @@ -0,0 +1,26 @@ +require_relative "../../test_helper" + +require "cwm/rspec" +require "y2s390/presenters/summary" + +describe Y2S390::Presenters::DasdSummary do + subject { described_class.new(devices) } + let(:devices) { Yast::DASDController.devices.by_ids(["0.0.0150", "0.0.0160"]) } + + mock_entries + + describe "#list" do + before do + Yast.import "DASDController" + Yast::DASDController.ProbeDisks() + end + + it "returns a summary of the dasds configuration" do + dasd0160 = "Channel ID: 0.0.0160, Device: dasda, DIAG: No" + dasd0150 = "Channel ID: 0.0.0150, Device: dasdb, DIAG: No" + + expect(subject.list).to include(dasd0150) + expect(subject.list).to include(dasd0160) + end + end +end From 0034800148260bcb4f23597a5f9e77e60f772ba5 Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Thu, 18 Nov 2021 10:25:11 +0000 Subject: [PATCH 06/31] Fixing reads for config Mode. --- src/lib/y2s390/dasds_reader.rb | 4 ++-- test/y2s390/dasds_reader_test.rb | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lib/y2s390/dasds_reader.rb b/src/lib/y2s390/dasds_reader.rb index c8f63009..6c00a1f9 100644 --- a/src/lib/y2s390/dasds_reader.rb +++ b/src/lib/y2s390/dasds_reader.rb @@ -50,8 +50,8 @@ def list(offline: true, force_probing: false) attrs = Yast::Mode.config ? {} : { status: status, device_name: name, type: type } dasd = Y2S390::Dasd.new(id, **attrs).tap do |d| if Yast::Mode.config - d.diag = d.use_diag = use_diag?(d) - d.format = false + d.diag_wanted = d.use_diag = use_diag?(d) + d.format_wanted = false else update_additional_info(d) end diff --git a/test/y2s390/dasds_reader_test.rb b/test/y2s390/dasds_reader_test.rb index e2e44691..98f031ec 100644 --- a/test/y2s390/dasds_reader_test.rb +++ b/test/y2s390/dasds_reader_test.rb @@ -48,8 +48,9 @@ expect(reader).to_not receive(:update_additional_info) devices = reader.list dasd = devices.by_id("0.0.0150") - expect(dasd.format).to eq(false) + expect(dasd.format_wanted).to eq(false) expect(dasd.use_diag).to eq(false) + expect(dasd.diag_wanted).to eq(false) expect(dasd.type).to be_nil expect(dasd.device_name).to be_nil end From 5b5db79ca8428025b007df51f5e6dfeecd394e17 Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Wed, 24 Nov 2021 11:05:52 +0000 Subject: [PATCH 07/31] Added test for the format dialog --- src/lib/y2s390/dialogs/format_dialog.rb | 14 ++- test/y2s390/dialogs/format_dialog_test.rb | 121 ++++++++++++++++++++++ 2 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 test/y2s390/dialogs/format_dialog_test.rb diff --git a/src/lib/y2s390/dialogs/format_dialog.rb b/src/lib/y2s390/dialogs/format_dialog.rb index d2a4697c..4001abb0 100644 --- a/src/lib/y2s390/dialogs/format_dialog.rb +++ b/src/lib/y2s390/dialogs/format_dialog.rb @@ -11,8 +11,6 @@ module Y2S390 module Dialogs # Class for displaying progress while formatting one or several DASDs. class FormatDialog < ::UI::Dialog - include Yast::Logger - include ::UI::EventDispatcher attr_accessor :fmt_process attr_accessor :progress attr_accessor :cylinders @@ -31,20 +29,16 @@ def initialize(dasds) @fmt_process = FormatProcess.new(dasds) end - def should_open_dialog? - true - end - def run fmt_process.start - sleep(0.2) + wait_for_update return report_format_failed(fmt_process) unless fmt_process.running? fmt_process.initialize_summary create_dialog while fmt_process.running? fmt_process.update_summary - sleep(0.2) + wait_for_update update_progress end close_dialog @@ -59,6 +53,10 @@ def user_input private + def wait_for_update + sleep(0.2) + end + def report_format_failed(process) Yast::Report.Error(format(_("Disks formatting failed. Exit code: %s.\nError output:%s"), process.status, process.error)) diff --git a/test/y2s390/dialogs/format_dialog_test.rb b/test/y2s390/dialogs/format_dialog_test.rb new file mode 100644 index 00000000..5e53f31a --- /dev/null +++ b/test/y2s390/dialogs/format_dialog_test.rb @@ -0,0 +1,121 @@ +require_relative "../../test_helper.rb" + +require "y2s390" +require "y2s390/dialogs/format_dialog" + +describe Y2S390::Dialogs::FormatDialog do + subject { described_class.new(selected) } + + let(:selected) { Y2S390::DasdsCollection.new([dasd0150]) } + let(:dasd0150) { Y2S390::Dasd.new("0.0.0150") } + + def mock_ui_events(*events) + allow(Yast::UI).to receive(:UserInput).and_return(*events) + end + + before do + mock_ui_events(:timeout) + end + + describe "#user_input" do + it "waits 1 second for input" do + expect(Yast::UI).to receive(:TimeoutUserInput).with(1000) + + subject.user_input + end + end + + describe "#.new" do + it "initializes the dasds with the given DasdsCollection" do + expect(subject.dasds).to eq(selected) + end + + it "initializes a FormatProcess with the given dasds" do + expect(Y2S390::FormatProcess).to receive(:new).with(selected) + subject + end + end + + describe "#run" do + let(:running) { true } + let(:status) { 0 } + let(:fmt_process) do + instance_double("Y2S390::FmtProcess", running?: running, start: true, status: status, + initialize_summary: true, update_summary: true) + end + + before do + allow(subject).to receive(:create_dialog) + allow(subject).to receive(:close_dialog) + allow(subject).to receive(:update_progress) + allow(subject).to receive(:wait_for_update) + + allow(fmt_process).to receive(:running?).and_return(true, true, true, false) + subject.fmt_process = fmt_process + end + + it "starts a format process with the selected DASDs" do + expect(fmt_process).to receive(:start) + + subject.run + end + + context "when the process is not running after 0.2 seconds of waiting" do + before do + allow(fmt_process).to receive(:running?).and_return(false) + end + + it "reports a format failed error" do + expect(subject).to receive(:report_format_failed).with(subject.fmt_process) + + subject.run + end + + it "returns nil" do + end + end + + context "when the process is started correctly" do + it "creates the format dialogs" do + expect(subject).to receive(:create_dialog) + subject.run + end + + it "initializes the FmtProcess summary" do + expect(fmt_process).to receive(:initialize_summary) + subject.run + end + + context "while the process is running" do + it "update the fmt process summary according to the dasdfmt output" do + expect(fmt_process).to receive(:update_summary).twice + subject.run + end + + it "updates the dialog progress" do + expect(subject).to receive(:update_progress).twice + subject.run + end + end + + it "closes the format dialogs" do + expect(subject).to receive(:close_dialog) + subject.run + end + + context "when the FmtProcess finishs" do + let(:status) { 1 } + + it "reports a format failed error if the status of the process is not 0" do + expect(subject).to receive(:report_format_failed).with(subject.fmt_process) + + subject.run + end + end + + it "returns :refresh" do + expect(subject.run).to eq(:refresh) + end + end + end +end From 56778c45ec714a68363a490f91e7980b3747ad1d Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Wed, 24 Nov 2021 11:17:47 +0000 Subject: [PATCH 08/31] Add missing textdomain --- src/lib/y2s390/dasd_actions/activate.rb | 2 ++ src/lib/y2s390/dasd_actions/format.rb | 2 ++ src/lib/y2s390/dialogs/format_disks.rb | 2 ++ src/lib/y2s390/presenters/summary.rb | 1 + 4 files changed, 7 insertions(+) diff --git a/src/lib/y2s390/dasd_actions/activate.rb b/src/lib/y2s390/dasd_actions/activate.rb index 553c6eec..bc4722e6 100644 --- a/src/lib/y2s390/dasd_actions/activate.rb +++ b/src/lib/y2s390/dasd_actions/activate.rb @@ -4,6 +4,8 @@ module Y2S390 module DasdActions class Activate < Base def run + textdomain "s390" + unformatted_disks = [] selected.each do |dasd| diff --git a/src/lib/y2s390/dasd_actions/format.rb b/src/lib/y2s390/dasd_actions/format.rb index 83050331..dd290ddf 100644 --- a/src/lib/y2s390/dasd_actions/format.rb +++ b/src/lib/y2s390/dasd_actions/format.rb @@ -18,6 +18,8 @@ def run class Format < Base def run + textdomain "s390" + return false unless can_be_formatted? return false unless really_format? diff --git a/src/lib/y2s390/dialogs/format_disks.rb b/src/lib/y2s390/dialogs/format_disks.rb index 8a4088d6..4d793813 100644 --- a/src/lib/y2s390/dialogs/format_disks.rb +++ b/src/lib/y2s390/dialogs/format_disks.rb @@ -4,6 +4,8 @@ module Y2S390 module Dialogs class FormatDisks < FormatDialog def dialog_content + textdomain "s390" + VBox( HSpacing(70), *dasds_progress_bars diff --git a/src/lib/y2s390/presenters/summary.rb b/src/lib/y2s390/presenters/summary.rb index 46f4ea51..c4c035e0 100644 --- a/src/lib/y2s390/presenters/summary.rb +++ b/src/lib/y2s390/presenters/summary.rb @@ -36,6 +36,7 @@ class DasdSummary # # @param devices [Y2S390::DasdsCollection] def initialize(devices) + textdomain "s390" @devices = devices end From 0cb8c73f96f80c6f42071bf736dfda9344fe9cf4 Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Wed, 19 Jan 2022 09:57:08 +0000 Subject: [PATCH 09/31] Remove FormattingStatus class by now --- src/lib/y2s390/dasd.rb | 4 --- src/lib/y2s390/dasds_reader.rb | 1 - src/lib/y2s390/formatting_status.rb | 44 ----------------------------- 3 files changed, 49 deletions(-) delete mode 100644 src/lib/y2s390/formatting_status.rb diff --git a/src/lib/y2s390/dasd.rb b/src/lib/y2s390/dasd.rb index 73091ee8..f23089ff 100644 --- a/src/lib/y2s390/dasd.rb +++ b/src/lib/y2s390/dasd.rb @@ -19,7 +19,6 @@ require "yast" require "yast2/execute" -require "y2s390/formatting_status" module Y2S390 # This class represents a direct-access storage device (DASD) @@ -47,9 +46,6 @@ class Dasd # @return [Integer] number of cylinders attr_accessor :cylinders - # @return [FormattingStatus] status of the last formatting process - attr_accessor :formatting_status - # @return [Boolean] attr_accessor :format_wanted diff --git a/src/lib/y2s390/dasds_reader.rb b/src/lib/y2s390/dasds_reader.rb index 6c00a1f9..4e684f65 100644 --- a/src/lib/y2s390/dasds_reader.rb +++ b/src/lib/y2s390/dasds_reader.rb @@ -128,7 +128,6 @@ def refresh_extended_data!(dasd) def reset_extended_data!(dasd) dasd.cylinders = nil - dasd.formatting_status = nil end # Determines whether a given DASD is formatted or not diff --git a/src/lib/y2s390/formatting_status.rb b/src/lib/y2s390/formatting_status.rb deleted file mode 100644 index a351649b..00000000 --- a/src/lib/y2s390/formatting_status.rb +++ /dev/null @@ -1,44 +0,0 @@ -module Y2S390 - class FormattingStatus - # @return [Symbol] - attr_accessor :status - # return [Integer, nil] - attr_accessor :cylinders - - # return [Integer] - attr_accessor :cylinders_formatted - - # return [String] - attr_accessor :error_details - - # Constructor - def initialize(cylinders = nil) - @cylinders = cylinders - end - - def format! - @cylinders_formatted = 0 - @status = :formatting - end - - def step!(cyl = 10) - return if done? - - @cylinders_formatted += cyl - done! if done? - end - - def done? - @cylinders_formatted >= @cylinders - end - - def done! - @status = :done - end - - def error!(error) - @status = :error - @error_details = error - end - end -end From e2b1894068ae8a408377ebbb11a73addc8d2a1a4 Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Wed, 19 Jan 2022 10:49:19 +0000 Subject: [PATCH 10/31] Small fixes/changes --- src/include/s390/dasd/dialogs.rb | 4 +- src/lib/y2s390/dasds_reader.rb | 34 ++++++------ src/lib/y2s390/format_process.rb | 61 +++++++++++++++------ src/lib/y2s390/hwinfo_reader.rb | 8 ++- test/y2s390/dasd_test.rb | 19 +++++++ test/y2s390/dasds_reader_test.rb | 1 + test/y2s390/format_process_test.rb | 86 ++++++++++++++++++++++++++++++ 7 files changed, 178 insertions(+), 35 deletions(-) create mode 100644 test/y2s390/format_process_test.rb diff --git a/src/include/s390/dasd/dialogs.rb b/src/include/s390/dasd/dialogs.rb index f67b5b91..9fb2cbd9 100644 --- a/src/include/s390/dasd/dialogs.rb +++ b/src/include/s390/dasd/dialogs.rb @@ -86,8 +86,8 @@ def item_elements_for(dasd) return [item_id, dasd.id, "--", "--", "--", diag, "--", "--"] unless dasd.active? [ - item_id, dasd.id, dasd.device_name, dasd.access_type.to_s.upcase, - dasd.device_type, diag, formatted, dasd.partition_info + item_id, dasd.id, dasd.device_name, dasd.device_type, + dasd.access_type.to_s.upcase, diag, formatted, dasd.partition_info ] end diff --git a/src/lib/y2s390/dasds_reader.rb b/src/lib/y2s390/dasds_reader.rb index 4e684f65..53f54f6c 100644 --- a/src/lib/y2s390/dasds_reader.rb +++ b/src/lib/y2s390/dasds_reader.rb @@ -38,7 +38,7 @@ class DasdsReader # @param offline [Boolean] whether it should obtain the offline devices too or not # @param force_probing [Boolean] in case of probing it will fetch the hwinfo if not will use the # information cached when exist - # @return [Array] a collection of Dasds read from the system using a + # @return [Y2S390::DasdsCollection] a collection of Dasds read from the system using a # comination def list(offline: true, force_probing: false) HwinfoReader.instance.reset if force_probing @@ -91,27 +91,33 @@ def update_info(dasd, extended: false) update_additional_info(dasd) if extended end - def update_additional_info(dasd) - refresh_extended_data!(dasd) - end - private # In production, call SCR.Read(.probe.disk). - # For testing, point YAST2_S390_PROBE_DISK to a YAML file - # with the mock value. + # + # For testing, use S390_MOCKING=1 ENV variable or point YAST2_S390_LSDASD to a txt file + # with the mock value with a lsdasd's command output format. + # # Suggesstion: - # YAST2_S390_PROBE_DISK=test/data/probe_disk_dasd.yml rake run"[dasd]" + # S390_MOCKING=1 rake run"[dasd]" + # # @return [Array] .probe.disk output def dasd_entries(offline: true, dasd: nil) - if ENV["S390_MOCKING"] - File.read("test/data/lsdasd.txt") + if mock_filename + File.read(mock_filename) else cmd = cmd_for(offline: offline, dasd: dasd) Yast::Execute.stdout.locally!(cmd) end.split("\n") end + # Mock filenam if defined supported environment variables + # + # @return [String,nil] + def mock_filename + ENV["S390_MOCKING"] ? "test/data/lsdasd.txt" : ENV["YAST2_S390_LSDASD"] + end + def cmd_for(offline: true, dasd: nil) cmd = [LIST_CMD] cmd << "-a" if offline @@ -119,17 +125,13 @@ def cmd_for(offline: true, dasd: nil) cmd end - def refresh_extended_data!(dasd) - reset_extended_data!(dasd) if dasd.offline? + def update_additional_info(dasd) + dasd.cylinders = nil if dasd.offline? dasd.use_diag = use_diag?(dasd) dasd.formatted = formatted?(dasd) dasd.device_type = device_type_for(dasd) end - def reset_extended_data!(dasd) - dasd.cylinders = nil - end - # Determines whether a given DASD is formatted or not # # @param dasd [DASD] diff --git a/src/lib/y2s390/format_process.rb b/src/lib/y2s390/format_process.rb index 327d06e3..87465599 100644 --- a/src/lib/y2s390/format_process.rb +++ b/src/lib/y2s390/format_process.rb @@ -1,7 +1,27 @@ +# Copyright (c) [2022] 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 "yast2/execute" module Y2S390 + # This class is responsible for maintaining an specific DASD format progress class FormatStatus attr_accessor :progress, :cylinders, :dasd # Constructor @@ -16,17 +36,17 @@ def initialize(dasd, cylinders, format_size = 10) @size = format_size end - def update_progress + # It increments the progress status based on the configured format size + def update_progress! @progress += @size end + # Return whether the format progress has been completed according to the number of cylinders + # + # @return [Boolean] whether the format progress has been completed or not def done? @cylinders <= @progress end - - def step! - update_progress - end end # This class is responsible of formatting a set of DASD volumes maintaining also the status of the @@ -39,22 +59,16 @@ class FormatProcess # Constructor # - # @param dasds [Integer] + # @param dasds [Array] def initialize(dasds) @dasds = dasds @summary = {} @updated = {} end - def disks_params - dasds.map { |d| "-f /dev/#{d.device_name}" }.join(" ") - end - # Convenience method to start with the formatting process def start - cmd = "/sbin/dasdfmt -Y -P #{dasds.size} -b 4096 -y -r #{SIZE} -m #{SIZE} #{disks_params}" - - @id = Yast::SCR.Execute(Yast.path(".process.start_shell"), cmd) + @id = Yast::SCR.Execute(Yast.path(".process.start_shell"), fmt_cmd) end # Checks whether the formatting process is still running or not @@ -92,10 +106,12 @@ def error stderr end + # Initializes the summary for the DASDs given in the constructor def initialize_summary dasds.each_with_index { |d, i| @summary[i] = FormatStatus.new(d, read_line.to_i) } end + # Update the summary of the formatting progress reading the output of the format process def update_summary @updated = {} @@ -108,7 +124,7 @@ def update_summary progress.each do |d| next if d.to_s.empty? - summary[d.to_i]&.update_progress + summary[d.to_i]&.update_progress! @updated[d.to_i] = summary[d.to_i] end log.info("The summary is #{summary.inspect}") @@ -117,13 +133,28 @@ def update_summary updated end + # Total number of cylinders to be formatted + # + # @return [Integer] def cylinders - log.info("The summary is #{summary.values.inspect}") summary.values.inject(0) { |sum, v| sum + v.cylinders } end + # Current progress according to the cylinders formatted + # + # @return [Integer] def progress @summary.values.inject(0) { |sum, v| sum + v.progress } end + + private + + def fmt_cmd + "/sbin/dasdfmt -Y -P #{dasds.size} -b 4096 -y -r #{SIZE} -m #{SIZE} #{disks_params}" + end + + def disks_params + dasds.map { |d| "-f /dev/#{d.device_name}" }.join(" ") + end end end diff --git a/src/lib/y2s390/hwinfo_reader.rb b/src/lib/y2s390/hwinfo_reader.rb index b54563c9..48ef31a1 100644 --- a/src/lib/y2s390/hwinfo_reader.rb +++ b/src/lib/y2s390/hwinfo_reader.rb @@ -21,13 +21,17 @@ def data private def disks - if ENV["S390_MOCKING"] - load_data("test/data/probe_disk_dasd.yml") + if mock_filename + load_data(mock_filename) else Yast::SCR.Read(Yast.path(".probe.disk")) || [] end end + def mock_filename + ENV["S390_MOCKING"] ? "test/data/probe_disk_dasd.yml" : ENV["YAST2_S390_PROBE_DISK"] + end + def data_from_hwinfo disks.each_with_object({}) do |disk, hash| hw_data = struct_for(disk) diff --git a/test/y2s390/dasd_test.rb b/test/y2s390/dasd_test.rb index a4a22d5d..63db8006 100644 --- a/test/y2s390/dasd_test.rb +++ b/test/y2s390/dasd_test.rb @@ -1,3 +1,22 @@ +# Copyright (c) [2022] 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 "../test_helper" require "y2s390" diff --git a/test/y2s390/dasds_reader_test.rb b/test/y2s390/dasds_reader_test.rb index 98f031ec..4c34d3c1 100644 --- a/test/y2s390/dasds_reader_test.rb +++ b/test/y2s390/dasds_reader_test.rb @@ -10,6 +10,7 @@ before do allow(reader).to receive(:dasd_entries).and_return(load_file("lsdasd.txt").split("\n")) allow(ENV).to receive(:[]).with("S390_MOCKING").and_return(true) + allow(ENV).to receive(:[]).with("YAST2_S390_LSDASD").and_return(nil) end describe "#list" do diff --git a/test/y2s390/format_process_test.rb b/test/y2s390/format_process_test.rb new file mode 100644 index 00000000..560a561a --- /dev/null +++ b/test/y2s390/format_process_test.rb @@ -0,0 +1,86 @@ +# Copyright (c) [2022] 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 "../test_helper" +require "y2s390" +require "y2s390/format_process" + +describe Y2S390::FormatStatus do + let(:dasd) { Y2S390::Dasd.new("0.0.0150", status: "active", type: "ECKD") } + + subject { described_class.new(dasd, 1500) } + + describe "#update_progress!" do + it "increases the progress by the format size" do + expect { subject.update_progress! }.to change { subject.progress }.from(0).to(10) + expect { subject.update_progress! }.to change { subject.progress }.from(10).to(20) + end + end + + describe "#done?" do + it "returns true when all the cylinders have been formatted" do + expect(subject.done?).to eql(false) + 150.times { subject.update_progress! } + expect(subject.done?).to eql(true) + end + + it "returns false otherwise" do + expect(subject.done?).to eql(false) + end + end +end + +describe Y2S390::FormatProcess do + let(:subject) { described_class.new(dasds) } + let(:dasd_0150) do + Y2S390::Dasd.new("0.0.0150", status: "active", type: "ECKD", device_name: "dasda") + end + let(:dasd_0160) do + Y2S390::Dasd.new("0.0.0160", status: "active", type: "ECKD", device_name: "dasdb") + end + + let(:dasds) { [dasd_0150, dasd_0160] } + + describe "#start" do + it "starts a dasdfmt process in parallel with the disks given" do + expect(Yast::SCR).to receive(:Execute).with( + Yast.path(".process.start_shell"), + "/sbin/dasdfmt -Y -P 2 -b 4096 -y -r 10 -m 10 -f /dev/dasda -f /dev/dasdb" + ) + subject.start + end + + it "returns the process id" do + expect(Yast::SCR).to receive(:Execute).with(anything, anything).and_return(3200) + expect(subject.start).to eql(3200) + end + end + + describe "#running?" do + it "returns false if the process has not started" do + expect(subject.running?).to eql(false) + end + end + + describe "#initialize_summary" do + end + + describe "#update_summary" do + end +end From 6279a2f1882332f326e962846af05edfe7a82289 Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Thu, 20 Jan 2022 19:10:00 +0000 Subject: [PATCH 11/31] Added more unit test for the FormatProcess class --- src/lib/y2s390/format_process.rb | 8 ++- test/y2s390/format_process_test.rb | 110 ++++++++++++++++++++++++++++- 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/src/lib/y2s390/format_process.rb b/src/lib/y2s390/format_process.rb index 87465599..beea1df6 100644 --- a/src/lib/y2s390/format_process.rb +++ b/src/lib/y2s390/format_process.rb @@ -81,16 +81,20 @@ def running? end def read_line - return "" unless @id + return unless @id Yast::SCR.Read(Yast.path(".process.read_line"), @id) end def read + return unless @id + Yast::SCR.Read(Yast.path(".process.read"), @id) end def status + return unless @id + Yast::SCR.Read(Yast.path(".process.status"), @id) end @@ -120,7 +124,7 @@ def update_summary return unless line log.info "Updating Summary" - progress = line.split("|") + progress = line.gsub(/[[:space:]]/, "").split("|") progress.each do |d| next if d.to_s.empty? diff --git a/test/y2s390/format_process_test.rb b/test/y2s390/format_process_test.rb index 560a561a..453a47b4 100644 --- a/test/y2s390/format_process_test.rb +++ b/test/y2s390/format_process_test.rb @@ -56,6 +56,12 @@ end let(:dasds) { [dasd_0150, dasd_0160] } + let(:process_id) { 35000 } + + before do + allow(Yast::SCR).to receive(:Execute) + .with(Yast.path(".process.start_shell"), /dasdfmt -Y/).and_return(process_id) + end describe "#start" do it "starts a dasdfmt process in parallel with the disks given" do @@ -67,8 +73,8 @@ end it "returns the process id" do - expect(Yast::SCR).to receive(:Execute).with(anything, anything).and_return(3200) - expect(subject.start).to eql(3200) + expect(Yast::SCR).to receive(:Execute).with(anything, anything).and_return(process_id) + expect(subject.start).to eql(process_id) end end @@ -76,11 +82,111 @@ it "returns false if the process has not started" do expect(subject.running?).to eql(false) end + + it "returns whether the format process is still running or not" do + subject.start + expect(Yast::SCR).to receive(:Read).with(Yast.path(".process.running"), process_id) + .and_return(true, false) + expect(subject.running?).to eql(true) + expect(subject.running?).to eql(false) + end + end + + describe "#read" do + let(:process_output) { "0|1|0|\n1|0|0" } + + before do + allow(Yast::SCR).to receive(:Read) + .with(Yast.path(".process.read"), process_id).and_return(process_output) + end + + it "returns nil if no process has been started" do + expect(subject.read).to eq(nil) + end + + it "returns the output of the YaST process agent read" do + subject.start + + expect(subject.read).to eq(process_output) + end + end + + describe "#read_line" do + before do + allow(Yast::SCR).to receive(:Read) + .with(Yast.path(".process.read_line"), process_id).and_return("1500") + end + + it "returns nil if no process has been started" do + expect(subject.read_line).to eq(nil) + end + + it "returns the output of the YaST process agent read_line" do + subject.start + + expect(subject.read_line).to eql("1500") + end + end + + describe "#read_status" do + before do + allow(Yast::SCR).to receive(:Read) + .with(Yast.path(".process.status"), process_id).and_return(0) + end + + it "returns nil if no process has been started" do + expect(subject.status).to eq(nil) + end + + it "returns the output of the YaST process agent status" do + subject.start + + expect(subject.status).to eq(0) + end end describe "#initialize_summary" do + before do + allow(subject).to receive(:read_line).and_return("1500", "900") + end + + it "initializes the summary with the number of cylinders to be formatted by each DASD" do + expect(subject.summary).to eql({}) + subject.initialize_summary + expect(subject.summary.size).to eql(2) + expect(subject.summary[0].cylinders).to eql(1500) + expect(subject.summary[0].dasd.device_name).to eql("dasda") + expect(subject.summary[1].cylinders).to eql(900) + expect(subject.summary[1].dasd.device_name).to eql("dasdb") + end end describe "#update_summary" do + let(:process_output) { "0|1|0|\n1|0|0" } + + before do + allow(subject).to receive(:read).and_return(process_output) + allow(subject).to receive(:read_line).and_return(10016, 500) + end + + it "reads the output of the format process" do + expect(subject).to receive(:read) + subject.update_summary + end + + it "parses the format process output creating a summary of the updated DASDs" do + subject.initialize_summary + expect(subject.summary[0]).to receive(:update_progress!).exactly(4).times + expect(subject.summary[1]).to receive(:update_progress!).twice + + subject.update_summary + end + + context "when there is nothing read" do + it "returns nil" do + expect(subject).to receive(:read).and_return(nil) + expect(subject.update_summary).to eql(nil) + end + end end end From 1a63e752b075ba2bb52bd1ece4b689a371cdffe7 Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Fri, 21 Jan 2022 10:07:20 +0000 Subject: [PATCH 12/31] Added some missing licenses and unit tests --- src/lib/y2s390/dasd.rb | 10 ++++- src/lib/y2s390/dasd_actions/activate.rb | 19 ++++++++ src/lib/y2s390/dasd_actions/base.rb | 19 ++++++++ src/lib/y2s390/dasd_actions/deactivate.rb | 19 ++++++++ src/lib/y2s390/dasd_actions/diag.rb | 33 +++++++++++++- src/lib/y2s390/dasd_actions/format.rb | 19 ++++++++ src/lib/y2s390/dasds_reader.rb | 4 +- src/lib/y2s390/format_process.rb | 47 +++++++++++++++++--- src/modules/DASDController.rb | 53 +++++------------------ test/y2s390/format_process_test.rb | 48 +++++++++++++++++++- 10 files changed, 216 insertions(+), 55 deletions(-) diff --git a/src/lib/y2s390/dasd.rb b/src/lib/y2s390/dasd.rb index f23089ff..e688b39c 100644 --- a/src/lib/y2s390/dasd.rb +++ b/src/lib/y2s390/dasd.rb @@ -106,9 +106,9 @@ def formatted? # # @return [String] def partition_info - return "/dev/#{device_name}1" if type != "ECKD" + return "#{device_path}1" if type != "ECKD" - out = Yast::Execute.stdout.on_target!("/sbin/fdasd", "-p", "/dev/#{device_name}") + out = Yast::Execute.stdout.on_target!("/sbin/fdasd", "-p", device_path) return out if out.empty? regexp = Regexp.new("^[ \t]*([^ \t]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)" \ @@ -121,6 +121,12 @@ def partition_info end.join(", ") end + def device_path + return unless device_name + + "/dev/#{device_name}" + end + def hwinfo Y2S390::HwinfoReader.instance.for_device(id) end diff --git a/src/lib/y2s390/dasd_actions/activate.rb b/src/lib/y2s390/dasd_actions/activate.rb index bc4722e6..7c7f5d92 100644 --- a/src/lib/y2s390/dasd_actions/activate.rb +++ b/src/lib/y2s390/dasd_actions/activate.rb @@ -1,3 +1,22 @@ +# Copyright (c) [2022] 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 "y2s390/dasd_actions/base" module Y2S390 diff --git a/src/lib/y2s390/dasd_actions/base.rb b/src/lib/y2s390/dasd_actions/base.rb index cc4e93d0..74b7e89d 100644 --- a/src/lib/y2s390/dasd_actions/base.rb +++ b/src/lib/y2s390/dasd_actions/base.rb @@ -1,3 +1,22 @@ +# Copyright (c) [2022] 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 "abstract_method" diff --git a/src/lib/y2s390/dasd_actions/deactivate.rb b/src/lib/y2s390/dasd_actions/deactivate.rb index 9643214f..57dc5c22 100644 --- a/src/lib/y2s390/dasd_actions/deactivate.rb +++ b/src/lib/y2s390/dasd_actions/deactivate.rb @@ -1,3 +1,22 @@ +# Copyright (c) [2022] 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 "y2s390/dasd_actions/base" module Y2S390 diff --git a/src/lib/y2s390/dasd_actions/diag.rb b/src/lib/y2s390/dasd_actions/diag.rb index a82bfeb9..38ae0d6d 100644 --- a/src/lib/y2s390/dasd_actions/diag.rb +++ b/src/lib/y2s390/dasd_actions/diag.rb @@ -1,10 +1,31 @@ +# Copyright (c) [2022] 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 "y2s390/dasd_actions/base" module Y2S390 module DasdActions + # Base class for DIAG access actions class Diag < Base attr_accessor :use_diag + # Activate or Deactivate the use of the DIAG access over the selected DASDs def run if Yast::Mode.config selected.each { |dasd| dasd.diag_wanted = !!use_diag } @@ -21,17 +42,25 @@ def run end end + # Set selected DASDs to not use DIAG access class DiagOff < Diag + # Constructor + # + # @param selected [Array] def initialize(selected) - super(selected) @use_diag = false + super(selected) end end + # Set selected DASDs to use DIAG access class DiagOn < Diag + # Constructor + # + # @param selected [Array] def initialize(selected) - super(selected) @use_diag = true + super(selected) end end end diff --git a/src/lib/y2s390/dasd_actions/format.rb b/src/lib/y2s390/dasd_actions/format.rb index dd290ddf..277bb7fa 100644 --- a/src/lib/y2s390/dasd_actions/format.rb +++ b/src/lib/y2s390/dasd_actions/format.rb @@ -1,3 +1,22 @@ +# Copyright (c) [2022] 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 "y2s390/dasd_actions/base" module Y2S390 diff --git a/src/lib/y2s390/dasds_reader.rb b/src/lib/y2s390/dasds_reader.rb index 53f54f6c..8246aa9e 100644 --- a/src/lib/y2s390/dasds_reader.rb +++ b/src/lib/y2s390/dasds_reader.rb @@ -159,9 +159,9 @@ def use_diag?(dasd) # @param [String] disk string Disk to read info from # @return GetPartitionInfo string The info def partition_info(dasd) - return "#{dasd.device_name}1" if dasd.type != "ECKD" + return "#{dasd.device_path}1" if dasd.type != "ECKD" - out = Yast::Execute.stdout.on_target!("/sbin/fdasd", "-p", "/dev/#{dasd.device_name}") + out = Yast::Execute.stdout.on_target!("/sbin/fdasd", "-p", dasd.device_path) return out if out.empty? regexp = Regexp.new("^[ \t]*([^ \t]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)" \ diff --git a/src/lib/y2s390/format_process.rb b/src/lib/y2s390/format_process.rb index beea1df6..c1761557 100644 --- a/src/lib/y2s390/format_process.rb +++ b/src/lib/y2s390/format_process.rb @@ -51,10 +51,27 @@ def done? # This class is responsible of formatting a set of DASD volumes maintaining also the status of the # progress. + # + # Once the format process has been started it allows to check the status of the process, the + # output and also the stderr. + # + # @example + # + # process = Y2S390::FormatProcess.new(dasds_list) + # process.start + # process.initialize_summary + # while process.running? + # process.update_summary + # sleep(0.2) + # end + # report_error if process.status.to_i != 0 + # + # @see https://github.com/yast/yast-core/blob/master/agent-process/doc/ag_process_example.ycp class FormatProcess include Yast::Logger attr_accessor :id, :dasds, :summary, :updated + FORMAT_CMD = "/sbin/dasdfmt".freeze SIZE = 10 # Constructor @@ -68,7 +85,7 @@ def initialize(dasds) # Convenience method to start with the formatting process def start - @id = Yast::SCR.Execute(Yast.path(".process.start_shell"), fmt_cmd) + @id = Yast::SCR.Execute(Yast.path(".process.start_shell"), format_cmd) end # Checks whether the formatting process is still running or not @@ -80,34 +97,47 @@ def running? Yast::SCR.Read(Yast.path(".process.running"), @id) end + # Returns one line from stdout of the process or nil in case of not started. + # + # @return [String, nil] def read_line return unless @id Yast::SCR.Read(Yast.path(".process.read_line"), @id) end + # Returns the output of the process or nil in case of not started. The output could contain + # newline characters as it is not line-oriented. + # + # @return [String, nil] def read return unless @id Yast::SCR.Read(Yast.path(".process.read"), @id) end + # Returns the status of the process or nil in case of not started + # + # @returns [String, nil] def status return unless @id Yast::SCR.Read(Yast.path(".process.status"), @id) end + # Returns one line from stderr of the process + # + # @returns [String] def error - stderr = "" + stderr = [] loop do - line = Yast::SCR.Read(Yast.path(".process.read_line_stderr")) + line = Yast::SCR.Read(Yast.path(".process.read_line_stderr"), @id) break unless line stderr << line end - stderr + stderr.join(" ") end # Initializes the summary for the DASDs given in the constructor @@ -153,12 +183,15 @@ def progress private - def fmt_cmd - "/sbin/dasdfmt -Y -P #{dasds.size} -b 4096 -y -r #{SIZE} -m #{SIZE} #{disks_params}" + # Convenience method to obtain the complete format command to be used according to the DASDs + # given in the constructor + def format_cmd + "#{FORMAT_CMD} -Y -P #{dasds.size} -b 4096 -y -r #{SIZE} -m #{SIZE} #{disks_params}" end + # Convenience method to obtain parameter of the devices to be formatted def disks_params - dasds.map { |d| "-f /dev/#{d.device_name}" }.join(" ") + dasds.map { |d| "-f #{d.device_path}" }.join(" ") end end end diff --git a/src/modules/DASDController.rb b/src/modules/DASDController.rb index ca371768..5186504a 100644 --- a/src/modules/DASDController.rb +++ b/src/modules/DASDController.rb @@ -414,14 +414,6 @@ def ActivateDiag(channel, value) ActivateDisk(dasd.id, value) end - def format_dialog_for(disks_list) - if ENV["NEW_FORMAT"] - Y2S390::Dialogs::DasdFormat - else - Y2S390::Dialogs::FormatDisks - end.new(disks_list) - end - # It formats the given disks showing the progress in a separate dialog # # @param [S390::DasdsCollection] collection of dasds to be be formatted @@ -429,38 +421,6 @@ def FormatDisks(disks_list) format_dialog_for(disks_list).run end - # Get partitioninfo - # @param [String] disk string Disk to read info from - # @return GetPartitionInfo string The info - def GetPartitionInfo(disk) - outmap = Convert.to_map( - SCR.Execute( - path(".target.bash_output"), - Builtins.sformat("/sbin/fdasd -p '%1'", disk) - ) - ) - - # if not an eckd-disk it's an fba-disk. fba-disks have only one partition - return Builtins.sformat("%11", disk) if Ops.get_integer(outmap, "exit", 0) != 0 - - out = Ops.get_string(outmap, "stdout", "") - - regexp = "^[ \t]*([^ \t]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)" \ - "[ \t]+([^ \t]+)[ \t]+([^ \t]+([ \t]+[^ \t]+))*[ \t]*$" - - l = Builtins.splitstring(out, "\n") - l = Builtins.filter(l) { |s| Builtins.regexpmatch(s, regexp) } - l = Builtins.maplist(l) do |s| - tokens = Builtins.regexptokenize(s, regexp) - Builtins.sformat( - "%1 (%2)", - Ops.get_string(tokens, 0, ""), - Ops.get_string(tokens, 5, "") - ) - end - Builtins.mergestring(l, ", ") - end - publish variable: :devices, type: "map >" publish variable: :filter_min, type: "string" publish variable: :filter_max, type: "string" @@ -469,7 +429,6 @@ def GetPartitionInfo(disk) publish function: :DeactivateDisk, type: "void (string, boolean)" publish function: :ProbeDisks, type: "void ()" publish function: :FormatDisks, type: "void (list , integer)" - publish function: :GetPartitionInfo, type: "string (string)" publish function: :GetModified, type: "boolean ()" publish variable: :proposal_valid, type: "boolean" publish function: :SetModified, type: "void (boolean)" @@ -487,6 +446,18 @@ def GetPartitionInfo(disk) private + # It obtains the dialog to be used by the FormatProcess according to the NEW_FORMAT environment + # variable + # + # @param [S390::DasdsCollection] collection of dasds to be be formatted + def format_dialog_for(disks_list) + if ENV["NEW_FORMAT"] + Y2S390::Dialogs::DasdFormat + else + Y2S390::Dialogs::FormatDisks + end.new(disks_list) + end + # Convenience method to convert the device ID to integers for filtering purposes # # @param [String] the DASD id diff --git a/test/y2s390/format_process_test.rb b/test/y2s390/format_process_test.rb index 453a47b4..4dbabfaf 100644 --- a/test/y2s390/format_process_test.rb +++ b/test/y2s390/format_process_test.rb @@ -128,7 +128,7 @@ end end - describe "#read_status" do + describe "#status" do before do allow(Yast::SCR).to receive(:Read) .with(Yast.path(".process.status"), process_id).and_return(0) @@ -145,6 +145,25 @@ end end + describe "#error" do + it "returns an empty string if there is no stderr for the format process" do + expect(Yast::SCR).to receive(:Read) + .with(Yast.path(".process.read_line_stderr"), nil).and_return(nil) + + expect(subject.error).to eq("") + end + + it "returns the format process stderr" do + error = "dasdfmt: Disk /dev/dasdb is read only!" + subject.start + + expect(Yast::SCR).to receive(:Read) + .with(Yast.path(".process.read_line_stderr"), process_id).and_return(error, nil) + + expect(subject.error).to eq(error) + end + end + describe "#initialize_summary" do before do allow(subject).to receive(:read_line).and_return("1500", "900") @@ -189,4 +208,31 @@ end end end + + describe "#cylinders" do + before do + allow(subject).to receive(:read_line).and_return(10016, 500) + end + + it "returns the total number of cylinders to be formatted" do + subject.initialize_summary + expect(subject.cylinders).to eql(10516) + end + end + + describe "#progress" do + let(:process_output) { "0|1|0|\n1|0|0" } + + before do + allow(subject).to receive(:read).and_return(process_output) + allow(subject).to receive(:read_line).and_return(10016, 500) + end + + it "returns the total number of cylinders already formatted" do + subject.initialize_summary + expect(subject.progress).to eql(0) + subject.update_summary + expect(subject.progress).to eql(60) + end + end end From ec5528935c3620b4c273032e78b5cd7c3845ec33 Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Fri, 21 Jan 2022 12:49:16 +0000 Subject: [PATCH 13/31] Changes based on code review --- src/include/s390/dasd/dialogs.rb | 1 - src/lib/y2s390/dasd_actions/deactivate.rb | 8 +------- src/lib/y2s390/format_process.rb | 14 ++++++++------ test/y2s390/dasd_actions/deactivate_test.rb | 6 +++--- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/include/s390/dasd/dialogs.rb b/src/include/s390/dasd/dialogs.rb index 9fb2cbd9..85d106b7 100644 --- a/src/include/s390/dasd/dialogs.rb +++ b/src/include/s390/dasd/dialogs.rb @@ -24,7 +24,6 @@ # # $Id$ # -require "y2s390/dialogs/dasd_read" require "y2s390/dasd_actions" module Yast diff --git a/src/lib/y2s390/dasd_actions/deactivate.rb b/src/lib/y2s390/dasd_actions/deactivate.rb index 57dc5c22..36a6104a 100644 --- a/src/lib/y2s390/dasd_actions/deactivate.rb +++ b/src/lib/y2s390/dasd_actions/deactivate.rb @@ -23,17 +23,11 @@ module Y2S390 module DasdActions class Deactivate < Base def run - selected.each { |d| deactivate(d) } + selected.each { |d| controller.DeactivateDisk(d.id, d.diag_wanted) } controller.ProbeDisks true end - - private - - def deactivate(dasd) - controller.DeactivateDisk(dasd.id, dasd.diag_wanted) - end end end end diff --git a/src/lib/y2s390/format_process.rb b/src/lib/y2s390/format_process.rb index c1761557..dc2e6d72 100644 --- a/src/lib/y2s390/format_process.rb +++ b/src/lib/y2s390/format_process.rb @@ -153,16 +153,18 @@ def update_summary return unless line - log.info "Updating Summary" + log.debug "Updating Summary" progress = line.gsub(/[[:space:]]/, "").split("|") progress.each do |d| next if d.to_s.empty? - summary[d.to_i]&.update_progress! - @updated[d.to_i] = summary[d.to_i] + index = d.to_i + + summary[index]&.update_progress! + @updated[index] = summary[index] end - log.info("The summary is #{summary.inspect}") - log.info("Updated #{updated.inspect}") + log.debug "The summary is #{summary.inspect}" + log.debug "Updated #{updated.inspect}" updated end @@ -178,7 +180,7 @@ def cylinders # # @return [Integer] def progress - @summary.values.inject(0) { |sum, v| sum + v.progress } + summary.values.inject(0) { |sum, v| sum + v.progress } end private diff --git a/test/y2s390/dasd_actions/deactivate_test.rb b/test/y2s390/dasd_actions/deactivate_test.rb index 13017c89..d8717c78 100644 --- a/test/y2s390/dasd_actions/deactivate_test.rb +++ b/test/y2s390/dasd_actions/deactivate_test.rb @@ -13,12 +13,12 @@ before do allow(controller).to receive(:ProbeDisks) - allow(action).to receive(:deactivate) + allow(controller).to receive(:DeactivateDisk) end it "iterates over the the selected DASDs deactivating them" do - expect(action).to receive(:deactivate).with(dasd_0150) - expect(action).to receive(:deactivate).with(dasd_0fff) + expect(controller).to receive(:DeactivateDisk).with(dasd_0150.id, dasd_0150.diag_wanted) + expect(controller).to receive(:DeactivateDisk).with(dasd_0fff.id, dasd_0fff.diag_wanted) action.run end From d62a41cba5bee6a82f62083d2ffcff91a8c3d9fe Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Mon, 24 Jan 2022 07:58:00 +0000 Subject: [PATCH 14/31] Force an info update after activation --- src/lib/y2s390/dasd.rb | 2 +- src/lib/y2s390/dasds_reader.rb | 4 +++- src/modules/DASDController.rb | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/lib/y2s390/dasd.rb b/src/lib/y2s390/dasd.rb index e688b39c..9acb1031 100644 --- a/src/lib/y2s390/dasd.rb +++ b/src/lib/y2s390/dasd.rb @@ -89,7 +89,7 @@ def status=(value) # @return [Boolean] whether the DASD device is active or not def active? - status == :active || status == :read_only + [:active, :read_only, :no_format].include?(status) end # @return [Boolean] whether the DASD device is formatted or not diff --git a/src/lib/y2s390/dasds_reader.rb b/src/lib/y2s390/dasds_reader.rb index 8246aa9e..c4b118f6 100644 --- a/src/lib/y2s390/dasds_reader.rb +++ b/src/lib/y2s390/dasds_reader.rb @@ -81,7 +81,7 @@ def refresh_data!(dasds) end def update_info(dasd, extended: false) - data = dasd_entries(dasd: dasd).find { |e| e.start_with?(/\d/) } + data = dasd_entries(dasd: dasd.id).find { |e| e.start_with?(/\d/) } return false if data.to_s.empty? _, status, name, _, type, = data.split(" ") @@ -101,6 +101,8 @@ def update_info(dasd, extended: false) # Suggesstion: # S390_MOCKING=1 rake run"[dasd]" # + # @param offline [Boolean] whether it should obtain the offline devices too or not + # @param dasd [Y2S390::Dasd] # @return [Array] .probe.disk output def dasd_entries(offline: true, dasd: nil) if mock_filename diff --git a/src/modules/DASDController.rb b/src/modules/DASDController.rb index 5186504a..82f3204b 100644 --- a/src/modules/DASDController.rb +++ b/src/modules/DASDController.rb @@ -384,7 +384,9 @@ def activate_if_needed(dasd) return dasd.formatted? ? 0 : 8 end - ActivateDisk(dasd.id, !!dasd.diag_wanted) + ret = ActivateDisk(dasd.id, !!dasd.diag_wanted) + reader.update_info(dasd, extended: true) + ret end # Deactivate disk From 894a3e20360b7dda849ed2cd0597888b976c9e69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 25 Jan 2022 00:57:48 +0000 Subject: [PATCH 15/31] Add missing copyright headers --- src/include/s390/dasd/dialogs.rb | 15 ++++----------- src/lib/y2s390.rb | 19 +++++++++++++++++++ src/lib/y2s390/base_collection.rb | 2 +- src/lib/y2s390/dasd.rb | 2 +- src/lib/y2s390/dasd_actions.rb | 19 +++++++++++++++++++ src/lib/y2s390/dasds_reader.rb | 2 +- src/lib/y2s390/dialogs/dasd_format.rb | 19 +++++++++++++++++++ src/lib/y2s390/dialogs/format.rb | 19 +++++++++++++++++++ src/lib/y2s390/dialogs/format_dialog.rb | 19 +++++++++++++++++++ src/lib/y2s390/dialogs/format_disks.rb | 19 +++++++++++++++++++ src/lib/y2s390/hwinfo_reader.rb | 19 +++++++++++++++++++ src/lib/y2s390/presenters/summary.rb | 2 +- src/modules/DASDController.rb | 4 ++-- test/dasd_controller_test.rb | 19 +++++++++++++++++++ test/y2s390/base_collection_examples.rb | 2 +- test/y2s390/dasd_actions/activate_test.rb | 21 +++++++++++++++++++++ test/y2s390/dasd_actions/base_test.rb | 21 +++++++++++++++++++++ test/y2s390/dasd_actions/deactivate_test.rb | 21 +++++++++++++++++++++ test/y2s390/dasd_actions/diag_test.rb | 21 +++++++++++++++++++++ test/y2s390/dasd_actions/format_test.rb | 21 +++++++++++++++++++++ test/y2s390/dasd_test.rb | 2 ++ test/y2s390/dasds_collection_test.rb | 21 +++++++++++++++++++++ test/y2s390/dasds_reader_test.rb | 21 +++++++++++++++++++++ test/y2s390/dialogs/format_dialog_test.rb | 21 +++++++++++++++++++++ test/y2s390/format_process_test.rb | 2 ++ test/y2s390/presenters/summary_test.rb | 21 +++++++++++++++++++++ 26 files changed, 356 insertions(+), 18 deletions(-) diff --git a/src/include/s390/dasd/dialogs.rb b/src/include/s390/dasd/dialogs.rb index 85d106b7..34fe37d2 100644 --- a/src/include/s390/dasd/dialogs.rb +++ b/src/include/s390/dasd/dialogs.rb @@ -1,4 +1,4 @@ -# Copyright (c) 2012 Novell, Inc. +# Copyright (c) [2012-2022] SUSE LLC # # All Rights Reserved. # @@ -12,18 +12,11 @@ # more details. # # You should have received a copy of the GNU General Public License along -# with this program; if not, contact Novell, Inc. +# with this program; if not, contact SUSE LLC. # -# To contact Novell about this file by physical or electronic mail, you may -# find current contact information at www.novell.com. +# To contact SUSE LLC about this file by physical or electronic mail, you may +# find current contact information at www.suse.com. -# File: include/controller/dialogs.ycp -# Package: Configuration of controller -# Summary: Dialogs definitions -# Authors: Jiri Srain -# -# $Id$ -# require "y2s390/dasd_actions" module Yast diff --git a/src/lib/y2s390.rb b/src/lib/y2s390.rb index 51ac23fd..b46201d1 100644 --- a/src/lib/y2s390.rb +++ b/src/lib/y2s390.rb @@ -1,3 +1,22 @@ +# Copyright (c) [2022] 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 "y2s390/dasd" require "y2s390/dasds_reader" require "y2s390/dasds_collection" diff --git a/src/lib/y2s390/base_collection.rb b/src/lib/y2s390/base_collection.rb index a89b70d7..c5c46a39 100644 --- a/src/lib/y2s390/base_collection.rb +++ b/src/lib/y2s390/base_collection.rb @@ -1,4 +1,4 @@ -# Copyright (c) [2021] SUSE LLC +# Copyright (c) [2022] SUSE LLC # # All Rights Reserved. # diff --git a/src/lib/y2s390/dasd.rb b/src/lib/y2s390/dasd.rb index 9acb1031..f7813378 100644 --- a/src/lib/y2s390/dasd.rb +++ b/src/lib/y2s390/dasd.rb @@ -1,4 +1,4 @@ -# Copyright (c) [2021] SUSE LLC +# Copyright (c) [2022] SUSE LLC # # All Rights Reserved. # diff --git a/src/lib/y2s390/dasd_actions.rb b/src/lib/y2s390/dasd_actions.rb index 4631bc80..f57c54dd 100644 --- a/src/lib/y2s390/dasd_actions.rb +++ b/src/lib/y2s390/dasd_actions.rb @@ -1,3 +1,22 @@ +# Copyright (c) [2022] 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 "y2s390/dasd_actions/activate" require "y2s390/dasd_actions/deactivate" require "y2s390/dasd_actions/format" diff --git a/src/lib/y2s390/dasds_reader.rb b/src/lib/y2s390/dasds_reader.rb index c4b118f6..2b715a12 100644 --- a/src/lib/y2s390/dasds_reader.rb +++ b/src/lib/y2s390/dasds_reader.rb @@ -1,4 +1,4 @@ -# Copyright (c) [2021] SUSE LLC +# Copyright (c) [2022] SUSE LLC # # All Rights Reserved. # diff --git a/src/lib/y2s390/dialogs/dasd_format.rb b/src/lib/y2s390/dialogs/dasd_format.rb index 18d9d598..f6099876 100644 --- a/src/lib/y2s390/dialogs/dasd_format.rb +++ b/src/lib/y2s390/dialogs/dasd_format.rb @@ -1,3 +1,22 @@ +# Copyright (c) [2022] 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 "y2s390/dialogs/format_dialog" diff --git a/src/lib/y2s390/dialogs/format.rb b/src/lib/y2s390/dialogs/format.rb index 7d6fd3d2..ebbcd7d0 100644 --- a/src/lib/y2s390/dialogs/format.rb +++ b/src/lib/y2s390/dialogs/format.rb @@ -1,3 +1,22 @@ +# Copyright (c) [2022] 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 "y2s390/format_process" require "y2s390/dialogs/dasd_format" require "y2s390/dialogs/format_disks" diff --git a/src/lib/y2s390/dialogs/format_dialog.rb b/src/lib/y2s390/dialogs/format_dialog.rb index 4001abb0..853e41fe 100644 --- a/src/lib/y2s390/dialogs/format_dialog.rb +++ b/src/lib/y2s390/dialogs/format_dialog.rb @@ -1,3 +1,22 @@ +# Copyright (c) [2022] 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 "y2s390/format_process" require "ui/dialog" diff --git a/src/lib/y2s390/dialogs/format_disks.rb b/src/lib/y2s390/dialogs/format_disks.rb index 4d793813..e262f3ae 100644 --- a/src/lib/y2s390/dialogs/format_disks.rb +++ b/src/lib/y2s390/dialogs/format_disks.rb @@ -1,3 +1,22 @@ +# Copyright (c) [2022] 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 "y2s390/dialogs/format_dialog" module Y2S390 diff --git a/src/lib/y2s390/hwinfo_reader.rb b/src/lib/y2s390/hwinfo_reader.rb index 48ef31a1..b28f57e4 100644 --- a/src/lib/y2s390/hwinfo_reader.rb +++ b/src/lib/y2s390/hwinfo_reader.rb @@ -1,3 +1,22 @@ +# Copyright (c) [2022] 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 "yaml" module Y2S390 diff --git a/src/lib/y2s390/presenters/summary.rb b/src/lib/y2s390/presenters/summary.rb index c4c035e0..241f87b6 100644 --- a/src/lib/y2s390/presenters/summary.rb +++ b/src/lib/y2s390/presenters/summary.rb @@ -1,4 +1,4 @@ -# Copyright (c) [2021] SUSE LLC +# Copyright (c) [2022] SUSE LLC # # All Rights Reserved. # diff --git a/src/modules/DASDController.rb b/src/modules/DASDController.rb index 82f3204b..22c25d35 100644 --- a/src/modules/DASDController.rb +++ b/src/modules/DASDController.rb @@ -1,4 +1,4 @@ -# Copyright (c) [2021] SUSE LLC +# Copyright (c) [2012-2022] SUSE LLC # # All Rights Reserved. # @@ -16,7 +16,7 @@ # # 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 "yast2/popup" require "yast2/execute" diff --git a/test/dasd_controller_test.rb b/test/dasd_controller_test.rb index a43a337f..8fccd537 100755 --- a/test/dasd_controller_test.rb +++ b/test/dasd_controller_test.rb @@ -1,5 +1,24 @@ #!/usr/bin/env rspec +# Copyright (c) [2022] 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 "./test_helper" Yast.import "DASDController" diff --git a/test/y2s390/base_collection_examples.rb b/test/y2s390/base_collection_examples.rb index 967fba2f..dc5e27f2 100644 --- a/test/y2s390/base_collection_examples.rb +++ b/test/y2s390/base_collection_examples.rb @@ -1,4 +1,4 @@ -# Copyright (c) [2021] SUSE LLC +# Copyright (c) [2022] SUSE LLC # # All Rights Reserved. # diff --git a/test/y2s390/dasd_actions/activate_test.rb b/test/y2s390/dasd_actions/activate_test.rb index a8699c46..b21e31ac 100644 --- a/test/y2s390/dasd_actions/activate_test.rb +++ b/test/y2s390/dasd_actions/activate_test.rb @@ -1,3 +1,24 @@ +#!/usr/bin/env rspec + +# Copyright (c) [2022] 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 "../../test_helper.rb" require "y2s390/dasd_actions/activate" diff --git a/test/y2s390/dasd_actions/base_test.rb b/test/y2s390/dasd_actions/base_test.rb index 8d691bc6..75b02697 100644 --- a/test/y2s390/dasd_actions/base_test.rb +++ b/test/y2s390/dasd_actions/base_test.rb @@ -1,3 +1,24 @@ +#!/usr/bin/env rspec + +# Copyright (c) [2022] 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 "../../test_helper.rb" require "y2s390/dasd_actions/base" diff --git a/test/y2s390/dasd_actions/deactivate_test.rb b/test/y2s390/dasd_actions/deactivate_test.rb index d8717c78..73367a34 100644 --- a/test/y2s390/dasd_actions/deactivate_test.rb +++ b/test/y2s390/dasd_actions/deactivate_test.rb @@ -1,3 +1,24 @@ +#!/usr/bin/env rspec + +# Copyright (c) [2022] 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 "../../test_helper.rb" require "y2s390/dasd_actions/deactivate" diff --git a/test/y2s390/dasd_actions/diag_test.rb b/test/y2s390/dasd_actions/diag_test.rb index 90eb958b..839f8b04 100644 --- a/test/y2s390/dasd_actions/diag_test.rb +++ b/test/y2s390/dasd_actions/diag_test.rb @@ -1,3 +1,24 @@ +#!/usr/bin/env rspec + +# Copyright (c) [2022] 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 "../../test_helper.rb" require "y2s390/dasd_actions/diag" diff --git a/test/y2s390/dasd_actions/format_test.rb b/test/y2s390/dasd_actions/format_test.rb index f85d57ac..f7d0bfd8 100644 --- a/test/y2s390/dasd_actions/format_test.rb +++ b/test/y2s390/dasd_actions/format_test.rb @@ -1,3 +1,24 @@ +#!/usr/bin/env rspec + +# Copyright (c) [2022] 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 "../../test_helper.rb" require "y2s390/dasd_actions/format" diff --git a/test/y2s390/dasd_test.rb b/test/y2s390/dasd_test.rb index 63db8006..3e3fbd11 100644 --- a/test/y2s390/dasd_test.rb +++ b/test/y2s390/dasd_test.rb @@ -1,3 +1,5 @@ +#!/usr/bin/env rspec + # Copyright (c) [2022] SUSE LLC # # All Rights Reserved. diff --git a/test/y2s390/dasds_collection_test.rb b/test/y2s390/dasds_collection_test.rb index 140f417b..57d77ed4 100644 --- a/test/y2s390/dasds_collection_test.rb +++ b/test/y2s390/dasds_collection_test.rb @@ -1,3 +1,24 @@ +#!/usr/bin/env rspec + +# Copyright (c) [2022] 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 "../test_helper" require_relative "base_collection_examples" require "y2s390" diff --git a/test/y2s390/dasds_reader_test.rb b/test/y2s390/dasds_reader_test.rb index 4c34d3c1..aced9c01 100644 --- a/test/y2s390/dasds_reader_test.rb +++ b/test/y2s390/dasds_reader_test.rb @@ -1,3 +1,24 @@ +#!/usr/bin/env rspec + +# Copyright (c) [2022] 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 "../test_helper" require "y2s390/dasds_reader" diff --git a/test/y2s390/dialogs/format_dialog_test.rb b/test/y2s390/dialogs/format_dialog_test.rb index 5e53f31a..67af2265 100644 --- a/test/y2s390/dialogs/format_dialog_test.rb +++ b/test/y2s390/dialogs/format_dialog_test.rb @@ -1,3 +1,24 @@ +#!/usr/bin/env rspec + +# Copyright (c) [2022] 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 "../../test_helper.rb" require "y2s390" diff --git a/test/y2s390/format_process_test.rb b/test/y2s390/format_process_test.rb index 4dbabfaf..b80de933 100644 --- a/test/y2s390/format_process_test.rb +++ b/test/y2s390/format_process_test.rb @@ -1,3 +1,5 @@ +#!/usr/bin/env rspec + # Copyright (c) [2022] SUSE LLC # # All Rights Reserved. diff --git a/test/y2s390/presenters/summary_test.rb b/test/y2s390/presenters/summary_test.rb index c0f20bc7..a10f7d11 100644 --- a/test/y2s390/presenters/summary_test.rb +++ b/test/y2s390/presenters/summary_test.rb @@ -1,3 +1,24 @@ +#!/usr/bin/env rspec + +# Copyright (c) [2022] 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 "../../test_helper" require "cwm/rspec" From 272afd76ae364d4ca861984cf63b45dc89c6b5df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 25 Jan 2022 01:01:48 +0000 Subject: [PATCH 16/31] Add and/or update some documentation --- src/include/s390/dasd/dialogs.rb | 44 ++++++---- src/lib/y2s390/dasd.rb | 102 +++++++++++++--------- src/lib/y2s390/dasd_actions/activate.rb | 1 + src/lib/y2s390/dasd_actions/base.rb | 8 +- src/lib/y2s390/dasd_actions/deactivate.rb | 1 + src/lib/y2s390/dasd_actions/diag.rb | 9 +- src/lib/y2s390/dasd_actions/format.rb | 3 + src/lib/y2s390/dasds_collection.rb | 11 ++- src/lib/y2s390/dasds_reader.rb | 27 ++++-- 9 files changed, 138 insertions(+), 68 deletions(-) diff --git a/src/include/s390/dasd/dialogs.rb b/src/include/s390/dasd/dialogs.rb index 34fe37d2..707a3fe0 100644 --- a/src/include/s390/dasd/dialogs.rb +++ b/src/include/s390/dasd/dialogs.rb @@ -22,9 +22,9 @@ module Yast module S390DasdDialogsInclude def initialize_s390_dasd_dialogs(include_target) - Yast.import "UI" textdomain "s390" + Yast.import "UI" Yast.import "DASDController" Yast.import "Label" Yast.import "Mode" @@ -41,8 +41,9 @@ def initialize_s390_dasd_dialogs(include_target) Yast.include include_target, "s390/dasd/helps.rb" end - # List DASD devices that are currently being selected - # @return [Array] list of IDs of selected DASD devices + # Returns the ids of currently selected DASD devices + # + # @return [Array] ids of selected DASD devices def ListSelectedDASD selected = UI.QueryWidget(Id(:table), :SelectedItems) || [] log.info("selected #{selected}") @@ -65,14 +66,17 @@ def WriteDialog ret ? :next : :abort end - def yes_no(value) - String.YesNo(value) - end - + # Returns needed information for displaying given DASD in the UI + # + # @see #GetDASDDiskItems + # + # @param dasd [YS390::DASD] a Direct Access Storage Device + # @return [Array] a collection holding needed information, namely def item_elements_for(dasd) + byebug item_id = Id(dasd.id) - diag = yes_no(Mode.config ? dasd.diag_wanted : dasd.use_diag) - formatted = yes_no(dasd.formatted?) + diag = String.YesNo(Mode.config ? dasd.diag_wanted : dasd.use_diag) + formatted = String.YesNo(dasd.formatted?) return [item_id, dasd.id, d.format, diag] if Mode.config return [item_id, dasd.id, "--", "--", "--", diag, "--", "--"] unless dasd.active? @@ -83,10 +87,11 @@ def item_elements_for(dasd) ] end - # Get the list of items for the table of DASD devices - # @param min_chan integer minimal channel number - # @param max_chan integer maximal channel number - # @return a list of terms for the table + # Returns a list of items for the table of DASD devices + # + # @see DASDController.GetFilteredDevices + # + # @return [Array] def GetDASDDiskItems devices = DASDController.GetFilteredDevices @@ -121,11 +126,19 @@ def PossibleActions end end + # Returns the Y2S390::DasdAction class for given action + # + # @param action [Symbol, String] + # @return [Y2S390::DasdAction] def action_class_for(action) name = action.to_s.split("_").map(&:capitalize).join "Y2S390::DasdActions::#{name}" end + # Run given action over selected DASD devices + # + # @param action [Y2S390::DasdAction] the action to perform + # @param selected [Y2S390::DasdsCollection] the collection of DASD devices to work with def run(action, selected) Object.const_get(action_class_for(action)).run(selected) end @@ -410,8 +423,9 @@ def AddDASDDiskDialog ret end - # Run the dialog for deleting DASDs - # @return [Symbol] from DeleteDASDDiskDialog + # Run the dialog for deleting DASD devices + # + # @return [:next] def DeleteDASDDiskDialog selected = ListSelectedDASD() if selected.empty? diff --git a/src/lib/y2s390/dasd.rb b/src/lib/y2s390/dasd.rb index f7813378..2fc53c26 100644 --- a/src/lib/y2s390/dasd.rb +++ b/src/lib/y2s390/dasd.rb @@ -25,49 +25,57 @@ module Y2S390 class Dasd # Command for configuring z Systems specific devices CONFIGURE_CMD = "/sbin/dasd_configure".freeze - # # Command for displaying configuration of z Systems DASD devices + private_constant :CONFIGURE_CMD + + # Command for displaying configuration of z Systems DASD devices LIST_CMD = "/sbin/lsdasd".freeze + private_constant :LIST_CMD + + # @return [Hash] a map of known statuses + KNOWN_STATUS = { + "offline" => :offline, + "active" => :active, + "active(ro)" => :read_only, + "n/f" => :no_format + }.freeze + private_constant :KNOWN_STATUS - # @return [String] dasd type (EKCD, FBA) + # @return [String] the DASD type (EKCD, FBA) attr_accessor :type - # @return [String] dasd device type, cpu model... + # @return [String] the DASD device type, cpu model... attr_accessor :device_type # @return [String] the device id or channel attr_accessor :id - # @return [String, nil) associated device name + # @return [String, nil] the associated device name attr_accessor :device_name - # @return [Symbol] device status (:offline, :active) + # @return [Symbol] the device status (:offline, :active, :read_only, :no_format, :unknown) attr_reader :status # @return [Integer] number of cylinders attr_accessor :cylinders - # @return [Boolean] + # @return [Boolean] whether the device should be formatted attr_accessor :format_wanted - # @return [Boolean] + # @return [Boolean] whether the DIAG access method should be enabled attr_accessor :diag_wanted - # @return [Boolean] + # @return [Boolean] whether the device is formatted attr_accessor :formatted - # @return [Boolean] + # @return [Boolean] whether the DIAG access method is enabled attr_accessor :use_diag - KNOWN_STATUS = { - "offline" => :offline, "active" => :active, "active(ro)" => :read_only, "n/f" => :no_format - }.freeze - # Constructor # # @param id [String] - # @param status [String] - # @param device_name [String] - # @param type [String] + # @param status [Symbol, nil] + # @param device_name [String, nil] + # @param type [String, nil] def initialize(id, status: nil, device_name: nil, type: nil) @id = id @device_name = device_name @@ -82,17 +90,27 @@ def hex_id # Sets the device status if known or :unknown if not # # @param value [String] device current status according to lsdasd output - # @return [Symbol] device status (:active, :read_only, :offline or :unknown) + # @return [Symbol] device status (:active, :read_only, :offline, :no_format, or :unknown) def status=(value) @status = KNOWN_STATUS[value.to_s.downcase] || :unknown end - # @return [Boolean] whether the DASD device is active or not + # Whether the device is active according to its status + # + # @return [Boolean] true if it is in an active status; false otherwise def active? [:active, :read_only, :no_format].include?(status) end - # @return [Boolean] whether the DASD device is formatted or not + # Whether the device is active according to the IO {#hwinfo} + # + # @return [Boolean] true if it is active; false otherwise + def io_active? + hwinfo&.resource&.io&.first&.active + end + + + # @return [Boolean] whether the DASD device is offline or not def offline? status == :offline end @@ -102,6 +120,13 @@ def formatted? @formatted || false end + # Whether the device can be formatted or not + # + # @return [Boolean] true when the devices is an active ECKD DASD; false otherwise + def can_be_formatted? + active? && type == "ECKD" + end + # Return the partitions information # # @return [String] @@ -121,46 +146,43 @@ def partition_info end.join(", ") end + # Returns the path to the device + # + # @return [String, nil] def device_path return unless device_name "/dev/#{device_name}" end - def hwinfo - Y2S390::HwinfoReader.instance.for_device(id) - end - - # Returns whether the device can be formatted or not - # - # @return [Boolean] - def can_be_formatted? - active? && type == "ECKD" - end - - # Returns whether the device is active according to the IO hwinfo - # - # @return [Boolean] true if it is active; false otherwise - def io_active? - hwinfo&.resource&.io&.first&.active - end - - # Returns the access type ('rw', 'ro') according to the hwinfo + # Returns the access type ('rw', 'ro') according to {#hwinfo} # - # @return [Boolean] true if it is active; false otherwise + # @return [Boolean, nil] true if it is active; false otherwise def access_type hwinfo&.resource&.io&.first&.mode end - # @return [Integer] + # Returns the access type ('rw', 'ro') according to {#hwinfo} + # + # @return [Integer, nil] def sysfs_id hwinfo&.sysfs_id end + # Returns the system device name + # + # @return [String, nil] def sys_device_name cmd = ["ls", "/sys/bus/ccw/devices/#{id}/block/"] disk = Yast::Execute.stdout.on_target!(cmd).strip disk.to_s.empty? ? nil : "/dev/#{disk}" end + + # Returns the device data collected by hwinfo + # + # @return [Hash] + def hwinfo + Y2S390::HwinfoReader.instance.for_device(id) + end end end diff --git a/src/lib/y2s390/dasd_actions/activate.rb b/src/lib/y2s390/dasd_actions/activate.rb index 7c7f5d92..f27e58ad 100644 --- a/src/lib/y2s390/dasd_actions/activate.rb +++ b/src/lib/y2s390/dasd_actions/activate.rb @@ -21,6 +21,7 @@ module Y2S390 module DasdActions + # Action for activating DASD devices class Activate < Base def run textdomain "s390" diff --git a/src/lib/y2s390/dasd_actions/base.rb b/src/lib/y2s390/dasd_actions/base.rb index 74b7e89d..c4c52d46 100644 --- a/src/lib/y2s390/dasd_actions/base.rb +++ b/src/lib/y2s390/dasd_actions/base.rb @@ -32,6 +32,7 @@ class Base # @return [Boolean] abstract_method :run + # @return [Y2S390::DasdsCollection] attr_accessor :selected @@ -41,9 +42,12 @@ class Base # has to be applied def initialize(selected) textdomain "s390" + @selected = selected end + # Shortcut for `.new(selected).run` + # # @params selected [Y2S390::DasdsCollection] the collection of DASDs to which the action # has to be applied def self.run(selected) @@ -60,7 +64,9 @@ def auto_mode? Yast::Mode.autoinst end - # Convenience method + # Convenience method for shortening access to Yast::DASDController + # + # @return [Yast::DASDController] def controller Yast::DASDController end diff --git a/src/lib/y2s390/dasd_actions/deactivate.rb b/src/lib/y2s390/dasd_actions/deactivate.rb index 36a6104a..56961d18 100644 --- a/src/lib/y2s390/dasd_actions/deactivate.rb +++ b/src/lib/y2s390/dasd_actions/deactivate.rb @@ -21,6 +21,7 @@ module Y2S390 module DasdActions + # Action for deactivating DASD devices class Deactivate < Base def run selected.each { |d| controller.DeactivateDisk(d.id, d.diag_wanted) } diff --git a/src/lib/y2s390/dasd_actions/diag.rb b/src/lib/y2s390/dasd_actions/diag.rb index 38ae0d6d..f6ae2863 100644 --- a/src/lib/y2s390/dasd_actions/diag.rb +++ b/src/lib/y2s390/dasd_actions/diag.rb @@ -23,9 +23,12 @@ module Y2S390 module DasdActions # Base class for DIAG access actions class Diag < Base + # @return [Boolean] Whether the DIAG access should be active or not attr_accessor :use_diag - # Activate or Deactivate the use of the DIAG access over the selected DASDs + # Activate or deactivate the DIAG access for selected DASDs + # + # Based on the valud of {#use_diag}. See {DiagOn} and {DiagOff} def run if Yast::Mode.config selected.each { |dasd| dasd.diag_wanted = !!use_diag } @@ -42,7 +45,7 @@ def run end end - # Set selected DASDs to not use DIAG access + # Action for turning off the DIAG access of selected DASDs class DiagOff < Diag # Constructor # @@ -53,7 +56,7 @@ def initialize(selected) end end - # Set selected DASDs to use DIAG access + # Action for turning on the DIAG access of selected DASDs class DiagOn < Diag # Constructor # diff --git a/src/lib/y2s390/dasd_actions/format.rb b/src/lib/y2s390/dasd_actions/format.rb index 277bb7fa..61db742a 100644 --- a/src/lib/y2s390/dasd_actions/format.rb +++ b/src/lib/y2s390/dasd_actions/format.rb @@ -21,6 +21,7 @@ module Y2S390 module DasdActions + # Action for setting format wanted off over selected DASDs class FormatOff < Base def run selected.each { |dasd| dasd.format_wanted = false } @@ -28,6 +29,7 @@ def run end end + # Action for setting format wanted on over selected DASDs class FormatOn < Base def run selected.each { |dasd| dasd.format_wanted = true } @@ -35,6 +37,7 @@ def run end end + # Action for formatting selected DASDs class Format < Base def run textdomain "s390" diff --git a/src/lib/y2s390/dasds_collection.rb b/src/lib/y2s390/dasds_collection.rb index c42bec0f..c3acc6e8 100644 --- a/src/lib/y2s390/dasds_collection.rb +++ b/src/lib/y2s390/dasds_collection.rb @@ -1,13 +1,16 @@ require "y2s390/base_collection" module Y2S390 + # Represesnts a collection of DASD devices class DasdsCollection < BaseCollection - def filter(&block) - self.class.new(@elements.select(&block)) - end - + # Returns a new collection holing only {Yast::Y2390::Dasd#active?} devices def active filter(&:active?) end + + # Returns a new collection after selecting devices matching given blcok + def filter(&block) + self.class.new(@elements.select(&block)) + end end end diff --git a/src/lib/y2s390/dasds_reader.rb b/src/lib/y2s390/dasds_reader.rb index 2b715a12..bf006e1c 100644 --- a/src/lib/y2s390/dasds_reader.rb +++ b/src/lib/y2s390/dasds_reader.rb @@ -25,21 +25,21 @@ Yast.import "Mode" module Y2S390 - # This class is reponsible of reading the information about DASD devices + # Reads information about DASD devices in the system class DasdsReader attr_accessor :disks # Command for displaying configuration of z Systems DASD devices LIST_CMD = "/sbin/lsdasd".freeze + private_constant :LIST_CMD # Initializes a collection of DASDs based on the information read using lsdasd output and also # the hardware information (hwinfo). # # @param offline [Boolean] whether it should obtain the offline devices too or not - # @param force_probing [Boolean] in case of probing it will fetch the hwinfo if not will use the - # information cached when exist - # @return [Y2S390::DasdsCollection] a collection of Dasds read from the system using a - # comination + # @param force_probing [Boolean] in case of probing it will fetch the hwinfo; + # if not, it will use the information cached when exist + # @return [Y2S390::DasdsCollection] a collection of DASD devices read from the system def list(offline: true, force_probing: false) HwinfoReader.instance.reset if force_probing @@ -63,6 +63,10 @@ def list(offline: true, force_probing: false) Y2S390::DasdsCollection.new(a) end + # Refreshes data of given DASDs + # + # @param dasds [Y2S390::DasdsCollection] a collection of Y2S90::Dasd + # @return [true] def refresh_data!(dasds) dasd_entries(offline: true).each do |entry| next unless entry.start_with?(/\d/) @@ -80,6 +84,10 @@ def refresh_data!(dasds) true end + # Udpates information for given DASD + # + # @param dasd [Y2S390::Dasd] the DASD representation to be updated + # @param extended [Boolean] whether additional information should be updated too def update_info(dasd, extended: false) data = dasd_entries(dasd: dasd.id).find { |e| e.start_with?(/\d/) } return false if data.to_s.empty? @@ -120,6 +128,12 @@ def mock_filename ENV["S390_MOCKING"] ? "test/data/lsdasd.txt" : ENV["YAST2_S390_LSDASD"] end + # Build lsdasd command based on given params + # + # @params offline [Boolean] true for listing offline devices too; false othewise + # @params dasd [Y2S390::Dasd, nil] a Y2S390::Dasd object for specifying the device + # + # @return [Array] lsdasd command and options based on given params def cmd_for(offline: true, dasd: nil) cmd = [LIST_CMD] cmd << "-a" if offline @@ -127,6 +141,9 @@ def cmd_for(offline: true, dasd: nil) cmd end + # Update given DASD representation with extended data + # + # @param dasd [Y2S390::Dasd] def update_additional_info(dasd) dasd.cylinders = nil if dasd.offline? dasd.use_diag = use_diag?(dasd) From 2c35a2c99c3617215051a66e5c39d79c96382c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 25 Jan 2022 01:09:51 +0000 Subject: [PATCH 17/31] Fix Lint/ScriptPermission Rubocop offenses --- test/y2s390/base_collection_examples.rb | 0 test/y2s390/dasd_actions/activate_test.rb | 0 test/y2s390/dasd_actions/base_test.rb | 0 test/y2s390/dasd_actions/deactivate_test.rb | 0 test/y2s390/dasd_actions/diag_test.rb | 0 test/y2s390/dasd_actions/format_test.rb | 0 test/y2s390/dasd_test.rb | 0 test/y2s390/dasds_collection_test.rb | 0 test/y2s390/dasds_reader_test.rb | 0 test/y2s390/dialogs/format_dialog_test.rb | 0 test/y2s390/format_process_test.rb | 0 test/y2s390/presenters/summary_test.rb | 0 12 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 test/y2s390/base_collection_examples.rb mode change 100644 => 100755 test/y2s390/dasd_actions/activate_test.rb mode change 100644 => 100755 test/y2s390/dasd_actions/base_test.rb mode change 100644 => 100755 test/y2s390/dasd_actions/deactivate_test.rb mode change 100644 => 100755 test/y2s390/dasd_actions/diag_test.rb mode change 100644 => 100755 test/y2s390/dasd_actions/format_test.rb mode change 100644 => 100755 test/y2s390/dasd_test.rb mode change 100644 => 100755 test/y2s390/dasds_collection_test.rb mode change 100644 => 100755 test/y2s390/dasds_reader_test.rb mode change 100644 => 100755 test/y2s390/dialogs/format_dialog_test.rb mode change 100644 => 100755 test/y2s390/format_process_test.rb mode change 100644 => 100755 test/y2s390/presenters/summary_test.rb diff --git a/test/y2s390/base_collection_examples.rb b/test/y2s390/base_collection_examples.rb old mode 100644 new mode 100755 diff --git a/test/y2s390/dasd_actions/activate_test.rb b/test/y2s390/dasd_actions/activate_test.rb old mode 100644 new mode 100755 diff --git a/test/y2s390/dasd_actions/base_test.rb b/test/y2s390/dasd_actions/base_test.rb old mode 100644 new mode 100755 diff --git a/test/y2s390/dasd_actions/deactivate_test.rb b/test/y2s390/dasd_actions/deactivate_test.rb old mode 100644 new mode 100755 diff --git a/test/y2s390/dasd_actions/diag_test.rb b/test/y2s390/dasd_actions/diag_test.rb old mode 100644 new mode 100755 diff --git a/test/y2s390/dasd_actions/format_test.rb b/test/y2s390/dasd_actions/format_test.rb old mode 100644 new mode 100755 diff --git a/test/y2s390/dasd_test.rb b/test/y2s390/dasd_test.rb old mode 100644 new mode 100755 diff --git a/test/y2s390/dasds_collection_test.rb b/test/y2s390/dasds_collection_test.rb old mode 100644 new mode 100755 diff --git a/test/y2s390/dasds_reader_test.rb b/test/y2s390/dasds_reader_test.rb old mode 100644 new mode 100755 diff --git a/test/y2s390/dialogs/format_dialog_test.rb b/test/y2s390/dialogs/format_dialog_test.rb old mode 100644 new mode 100755 diff --git a/test/y2s390/format_process_test.rb b/test/y2s390/format_process_test.rb old mode 100644 new mode 100755 diff --git a/test/y2s390/presenters/summary_test.rb b/test/y2s390/presenters/summary_test.rb old mode 100644 new mode 100755 From d3bd616c963ffbd88bbf59be805114852cbdd012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 25 Jan 2022 01:14:24 +0000 Subject: [PATCH 18/31] Fix Style/HashEachMethods Rubocop offense --- src/lib/y2s390/dialogs/dasd_format.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/y2s390/dialogs/dasd_format.rb b/src/lib/y2s390/dialogs/dasd_format.rb index f6099876..3c6ef985 100644 --- a/src/lib/y2s390/dialogs/dasd_format.rb +++ b/src/lib/y2s390/dialogs/dasd_format.rb @@ -114,7 +114,7 @@ def update_progress progress = fmt_process.progress cylinders = fmt_process.cylinders update_progress_percent(100 * progress / cylinders) if cylinders > 0 - fmt_process.updated.values.each { |s| s.done? ? refresh_tables : update_cyl_cell(s) } + fmt_process.updated.each_value { |s| s.done? ? refresh_tables : update_cyl_cell(s) } fmt_process.running? ? :continue : :break end From bfa9b613a1e437e5ec94d8b5e0464c8cd636978f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 25 Jan 2022 01:22:30 +0000 Subject: [PATCH 19/31] Remove a leftover byebug --- src/include/s390/dasd/dialogs.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/src/include/s390/dasd/dialogs.rb b/src/include/s390/dasd/dialogs.rb index 707a3fe0..1609c054 100644 --- a/src/include/s390/dasd/dialogs.rb +++ b/src/include/s390/dasd/dialogs.rb @@ -73,7 +73,6 @@ def WriteDialog # @param dasd [YS390::DASD] a Direct Access Storage Device # @return [Array] a collection holding needed information, namely def item_elements_for(dasd) - byebug item_id = Id(dasd.id) diag = String.YesNo(Mode.config ? dasd.diag_wanted : dasd.use_diag) formatted = String.YesNo(dasd.formatted?) From f4d6ff8116eb8a2d5c610f4ab88b96476bb405f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 25 Jan 2022 01:22:52 +0000 Subject: [PATCH 20/31] Please Rubocop --- src/lib/y2s390/dasd.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/y2s390/dasd.rb b/src/lib/y2s390/dasd.rb index 2fc53c26..a2d57f63 100644 --- a/src/lib/y2s390/dasd.rb +++ b/src/lib/y2s390/dasd.rb @@ -109,7 +109,8 @@ def io_active? hwinfo&.resource&.io&.first&.active end - + # Whether the device is offline based on its status + # # @return [Boolean] whether the DASD device is offline or not def offline? status == :offline From d0a80a76024f07ac52076efa5e75191aebcd3265 Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Tue, 1 Feb 2022 15:05:32 +0000 Subject: [PATCH 21/31] Added dasds_writer class --- src/lib/y2s390/dasds_collection.rb | 51 +++++- src/lib/y2s390/dasds_reader.rb | 9 +- src/lib/y2s390/dasds_writer.rb | 154 +++++++++++++++++++ src/lib/y2s390/dialogs/mkinitrd.rb | 23 +++ src/lib/y2s390/issues/dasd_format_no_eckd.rb | 26 ++++ src/modules/DASDController.rb | 79 ++-------- test/dasd_controller_test.rb | 107 +------------ test/data/lsdasd.txt | 3 +- test/data/lsdasd_offline.txt | 12 ++ test/data/probe_disk_dasd.yml | 39 ++++- test/y2s390/dasds_collection_test.rb | 58 +++++-- test/y2s390/dasds_writer_test.rb | 130 ++++++++++++++++ 12 files changed, 498 insertions(+), 193 deletions(-) create mode 100644 src/lib/y2s390/dasds_writer.rb create mode 100644 src/lib/y2s390/dialogs/mkinitrd.rb create mode 100644 src/lib/y2s390/issues/dasd_format_no_eckd.rb create mode 100644 test/data/lsdasd_offline.txt create mode 100755 test/y2s390/dasds_writer_test.rb diff --git a/src/lib/y2s390/dasds_collection.rb b/src/lib/y2s390/dasds_collection.rb index c3acc6e8..4f047956 100644 --- a/src/lib/y2s390/dasds_collection.rb +++ b/src/lib/y2s390/dasds_collection.rb @@ -1,16 +1,63 @@ +# Copyright (c) [2022] 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 "y2s390/base_collection" +Yast.import "Mode" + module Y2S390 - # Represesnts a collection of DASD devices + # Represents a collection of DASD devices class DasdsCollection < BaseCollection - # Returns a new collection holing only {Yast::Y2390::Dasd#active?} devices + # Returns a new collection holding only {Yast::Y2390::Dasd#active?} devices + # + # @return [DasdsCollection] def active filter(&:active?) end # Returns a new collection after selecting devices matching given blcok + # + # @return [DasdsCollection] def filter(&block) self.class.new(@elements.select(&block)) end + + # Returns a new collection holding only {Yast::Y2390::Dasd#offline?} devices + # + # @return [DasdsCollection] + def offline + filter(&:offline?) + end + + # Returns a new collection holding only {Yast::Y2390::Dasd} devices which status is :no_format + # + # @return [DasdsCollection] + def unformatted + filter { |d| d.status == :no_format } + end + + # Returns a new collection holding {Yast::Y2390::Dasd} devices which wants to be formatted or + # are unformatted and should be formatted too + # + # @return [DasdsCollection] + def to_format(format_unformatted: false) + filter { |d| d.format_wanted || format_unformatted && !d.formatted? } + end end end diff --git a/src/lib/y2s390/dasds_reader.rb b/src/lib/y2s390/dasds_reader.rb index bf006e1c..eef5aa40 100644 --- a/src/lib/y2s390/dasds_reader.rb +++ b/src/lib/y2s390/dasds_reader.rb @@ -89,7 +89,7 @@ def refresh_data!(dasds) # @param dasd [Y2S390::Dasd] the DASD representation to be updated # @param extended [Boolean] whether additional information should be updated too def update_info(dasd, extended: false) - data = dasd_entries(dasd: dasd.id).find { |e| e.start_with?(/\d/) } + data = dasd_entries(dasd: dasd).find { |e| e.start_with?(/\d/) } return false if data.to_s.empty? _, status, name, _, type, = data.split(" ") @@ -113,8 +113,9 @@ def update_info(dasd, extended: false) # @param dasd [Y2S390::Dasd] # @return [Array] .probe.disk output def dasd_entries(offline: true, dasd: nil) - if mock_filename - File.read(mock_filename) + filename = mock_filename + if filename + File.read(filename) else cmd = cmd_for(offline: offline, dasd: dasd) Yast::Execute.stdout.locally!(cmd) @@ -137,7 +138,7 @@ def mock_filename def cmd_for(offline: true, dasd: nil) cmd = [LIST_CMD] cmd << "-a" if offline - cmd << dasd if dasd + cmd << dasd.id if dasd cmd end diff --git a/src/lib/y2s390/dasds_writer.rb b/src/lib/y2s390/dasds_writer.rb new file mode 100644 index 00000000..4f095978 --- /dev/null +++ b/src/lib/y2s390/dasds_writer.rb @@ -0,0 +1,154 @@ +# Copyright (c) [2022] 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 "y2s390/dasds_reader" +require "y2issues" +require "y2issues/list" +require "y2s390/issues/dasd_format_no_eckd" + +Yast.import "Popup" +Yast.import "Mode" + +module Y2S390 + # This class is responsible of activating and formatting the current selection of DASDs + class DasdsWriter + include Yast::Logger + include Yast::I18n + + # @return [Y2S390::DasdsCollection] selection of DASDs to be formatted + attr_reader :dasds + # @return [Boolean] whether unformatted DASDS should be formatted + attr_reader :format_unformatted + # @return [Y2Issues::IssuesList] + attr_reader :issues + # @return [Y2S390::DasdsCollection] + attr_accessor :to_format + # @return [Y2S390::DasdsCollection] + attr_accessor :to_reactivate + + # Constructor + # + # @param collection [Y2S390::DasdsCollection] + # @param format_unformatted [Boolean] + def initialize(collection) + textdomain "s390" + + Yast.import "DASDController" + @dasds = collection + @issues = Y2Issues::List.new + @to_reactivate = @to_format = Y2S390::DasdsCollection.new([]) + end + + # Activates and formats the current selection of DASDs + def write + pre_format_activation + obtain_dasds_to_format + sanitize_to_format + report_issues + format_dasds + reactivate_dasds + read_dasds_data + end + + private + + # It updates the DASDs info reading the information from the system activating also the devices + # which are offline + def pre_format_activation + read_dasds_data + activate_offline_dasds + read_dasds_data + end + + # Obtains the DASDs which should be formatted taking into account "format_unformatted" option + # when them are not selected explicitly and select the unformatted devices to be reactivated + # after the format is done. + def obtain_dasds_to_format + @to_format = @dasds.to_format(format_unformatted: Yast::DASDController.format_unformatted) + @dasds.unformatted.each { |d| to_format << d } if format_unformatted?(@dasds.unformatted) + @to_reactivate = to_format.unformatted + end + + # It checks and adds issues when found about the selected DASDs that should be formatted + def sanitize_to_format + to_remove_disks = [] + to_format.each do |dasd| + next if dasd.type == "ECKD" + + to_remove_disks << dasd + issues << Y2S390::Issues::DasdFormatNoECKD.new(dasd) + end + to_remove_disks.each do |dasd| + to_format.delete(dasd.id) + to_reactivate.delete(dasd.id) + end + end + + # It reports found issues if any + def report_issues + Y2Issues.report(issues, error: nil) unless issues.empty? + end + + # It formats selected DASDs + def format_dasds + Yast::DASDController.FormatDisks(to_format) unless to_format.empty? + end + + # It reactivate the DASDs selected to be reactivated + def reactivate_dasds + to_reactivate.each do |dasd| + # FIXME: general activation error handling - also in sync with above + Yast::DASDController.ActivateDisk(dasd.id, !!dasd.diag_wanted) + end + end + + def activate_offline_dasds + dasds.offline.each { |d| Yast::DASDController.activate_if_needed(d) } + end + + # Ask the user whether the unformatted DASDs should be formatted or not + # + # @param devices [Y2S390::DasdsCollection] + # return [Boolean] + def format_unformatted?(devices) + return false if Yast::Mode.autoinst || devices.empty? + + message = if devices.size == 1 + format(_("Device %s is not formatted. Format device now?"), + devices.first.device_name) + else + format(_("There are %s unformatted devices. Format them now?"), + devices.size) + end + + Yast::Popup.ContinueCancel(message) + end + + # Convenience method to obtain a new {Y2S390::DasdsReader} instance + def reader + @reader ||= Y2S390::DasdsReader.new + end + + # Convenience method to refresh the info / state of the current DASDs selection + def read_dasds_data + reader.refresh_data!(@dasds) + end + end +end diff --git a/src/lib/y2s390/dialogs/mkinitrd.rb b/src/lib/y2s390/dialogs/mkinitrd.rb new file mode 100644 index 00000000..4e835078 --- /dev/null +++ b/src/lib/y2s390/dialogs/mkinitrd.rb @@ -0,0 +1,23 @@ +require "ui/dialog" + +module Y2S390 + module Dialogs + class Mkinitrd < ::UI::Dialog + CMD = "/sbin/mkinitrd".freeze + + def dialog_content + Label(_("Running mkinitrd.")) + end + + def self.run + new.run + end + + def run + create_dialog + Yast::Execute.on_target(CMD) + close_dialog + end + end + end +end diff --git a/src/lib/y2s390/issues/dasd_format_no_eckd.rb b/src/lib/y2s390/issues/dasd_format_no_eckd.rb new file mode 100644 index 00000000..a718f47d --- /dev/null +++ b/src/lib/y2s390/issues/dasd_format_no_eckd.rb @@ -0,0 +1,26 @@ +require "yast" +require "yast/i18n" +require "y2issues" + +module Y2S390 + module Issues + class DasdFormatNoECKD < Y2Issues::Issue + include Yast::I18n + + def initialize(dasd) + textdomain "S390" + + super(build_message(dasd), severity: :error) + end + + private + + def build_message(dasd) + format( + _("Cannot format device '%s'. Only ECKD disks can be formatted."), + dasd.device_name + ) + end + end + end +end diff --git a/src/modules/DASDController.rb b/src/modules/DASDController.rb index 22c25d35..3f85b140 100644 --- a/src/modules/DASDController.rb +++ b/src/modules/DASDController.rb @@ -22,13 +22,19 @@ require "yast2/execute" require "shellwords" require "y2s390/dialogs/format" +require "y2s390/dialogs/mkinitrd" require "y2s390/dasds_reader" +require "y2s390/dasds_writer" +require "y2issues" module Yast # Dasd controller settings class DASDControllerClass < Module include Yast::Logger + # @return [Boolean] whether unformated devices should be formatted upon activation + attr_reader :format_unformatted + def main Yast.import "UI" textdomain "s390" @@ -52,7 +58,6 @@ def main # Data was modified? @modified = false - # format all unformated devices upon activation? @format_unformatted = false @proposal_valid = false @@ -100,73 +105,11 @@ def Read # Write all controller settings # @return true on success def Write - if !Mode.normal - to_format = [] - to_reactivate = [] - unformatted_devices = [] - reader.refresh_data!(@devices) - - @devices.each do |dasd| - act_ret = activate_if_needed(dasd) - format = !!dasd.format_wanted - # FIXME: general activation error handling - also in sync with below - # for AutoInstall, format unformatted disks later at once - # even disks manually selected for formatting must be reactivated - if Mode.autoinst && act_ret == 8 && (@format_unformatted || format) - format = true - to_reactivate << dasd - end - - device_name = dasd.device_name || dasd.sys_device_name - if format - if dasd.can_be_formatted? - to_format << dasd - else - Report.Error( - # TRANSLATORS %s is device name - format( - _("Cannot format device '%s'. Only ECKD disks can be formatted."), - device_name - ) - ) - end - # unformatted disk, manual (not AutoYaST) - elsif act_ret == 8 - unformatted_devices << dasd - end - end - - if !unformatted_devices.empty? - message = if unformatted_devices.size == 1 - format(_("Device %s is not formatted. Format device now?"), - unformatted_devices.first.device_name) - else - format(_("There are %s unformatted devices. Format them now?"), - unformatted_devices.size) - end - if Popup.ContinueCancel(message) - unformatted_devices.each do |dasd| - to_format << dasd - to_reactivate << dasd - end - end - end - - log.info "Disks to format: #{to_format}" - - FormatDisks(to_format) unless to_format.empty? - - to_reactivate.each do |dasd| - # FIXME: general activation error handling - also in sync with above - ActivateDisk(dasd.id, !!dasd.diag_wanted) - end - end + Y2S390::DasdsWriter.new(@devices).write if !Mode.normal - if !Mode.installation - if @disk_configured - Y2S390::Dialogs::Mkinitrd.new.run - @disk_configured = false - end + if !Mode.installation && @disk_configured + Y2S390::Dialogs::Mkinitrd.new.run + @disk_configured = false end true @@ -420,6 +363,8 @@ def ActivateDiag(channel, value) # # @param [S390::DasdsCollection] collection of dasds to be be formatted def FormatDisks(disks_list) + log.info "Disks to format: #{disks_list}" + format_dialog_for(disks_list).run end diff --git a/test/dasd_controller_test.rb b/test/dasd_controller_test.rb index 8fccd537..63d91793 100755 --- a/test/dasd_controller_test.rb +++ b/test/dasd_controller_test.rb @@ -257,122 +257,27 @@ end let(:format_unformatted) { false } let(:format) { true } - let(:channel) { "0.0.0100" } + let(:channel) { "0.0.0150" } before do - allow(Yast::SCR).to receive(:Execute).with(path(".target.bash_output"), /\/sbin\/dasdview/) - .and_return("exitstatus" => 0, "stdout" => load_file("dasdview_eckd.txt"), "stderr" => "") - allow(Yast::Mode).to receive(:normal).and_return(false) allow(Yast::Mode).to receive(:installation).and_return(true) - allow(Yast::Mode).to receive(:autoinst).and_return(true) - # speed up the test a bit - allow(subject).to receive(:ActivateDisk).and_return(0) - allow(subject).to receive(:FormatDisks) end context "during autoinstallation" do - let(:channel) { "0.0.0100" } - let(:dasd) { Yast::DASDController.devices.by_id(channel) } + let(:channel) { "0.0.0150" } + let(:dasds) { Yast::DASDController.devices } let(:can_format) { true } before do subject.Import(data) - allow(dasd).to receive(:can_be_formatted?).and_return(can_format) if dasd end - it "activates the disk" do - expect(subject).to receive(:ActivateDisk).with("0.0.0100", false) + it "calls the dasds writers with the current devices" do + expect(Y2S390::DasdsWriter).to receive(:new).with(dasds).and_call_original + expect_any_instance_of(Y2S390::DasdsWriter).to receive(:write) subject.Write end - - context "when 'format' is sets to true" do - let(:format) { true } - - context "and the disk can be formatted" do - it "formats the disk" do - expect(subject).to receive(:FormatDisks).with([dasd]) - expect(subject.Write).to eq(true) - end - end - end - - context "when 'format' is set to false" do - let(:format) { false } - - it "does not format the disk" do - expect(subject).to_not receive(:FormatDisks) - subject.Write - end - end - - context "when the activated device is not formatted" do - NOT_FORMATTED_CODE = 8 # means that the device is not formatted - - let(:format) { false } - - before do - allow(subject).to receive(:activate_if_needed).with(dasd) - .and_return(NOT_FORMATTED_CODE) - end - - context "and 'format_unformatted' is set to 'true'" do - let(:format_unformatted) { true } - - it "formats the device" do - expect(subject).to receive(:FormatDisks).with([dasd]) - subject.Write - end - - it "reactivates the disk" do - allow(subject).to receive(:FormatDisks) - expect(subject).to receive(:ActivateDisk).with(channel, false) - subject.Write - end - end - - context "and 'format_unformatted' is set to 'false'" do - let(:format_unformatted) { false } - - it "does not format the device" do - expect(subject).to_not receive(:FormatDisks) - subject.Write - end - - it "does not reactivate the disk" do - expect(subject).to_not receive(:ActivateDisk) - subject.Write - end - end - - context "and 'format' is set to 'true'" do - let(:format) { true } - let(:format_unformatted) { false } - - it "formats the device" do - expect(subject).to receive(:FormatDisks).with([dasd]) - subject.Write - end - - it "reactivates the disk" do - expect(subject).to receive(:FormatDisks) - expect(subject).to receive(:ActivateDisk).with(channel, false) - subject.Write - end - end - end - - context "when the imported disk is a FBA one" do - let(:channel) { "0.0.ffff" } - - it "does not format the disk and report an error" do - subject.Import(data) - expect(subject).to_not receive(:FormatDisks) - expect(Yast::Report).to receive(:Error) - - expect(subject.Write).to eq(true) - end - end end end diff --git a/test/data/lsdasd.txt b/test/data/lsdasd.txt index f9e30c93..2322d98a 100644 --- a/test/data/lsdasd.txt +++ b/test/data/lsdasd.txt @@ -8,4 +8,5 @@ Bus-ID Status Name Device Type BlkSz Size Blocks 0.0.0150 active dasdb 94:4 ECKD 4096 7042MB 1802880 0.0.0592 active(ro) dasdc 94:8 ECKD 4096 168MB 43200 0.0.019e active(ro) dasdd 94:12 ECKD 4096 351MB 90000 -0.0.ffff active dasdc 94:8 FBA 512 97MB 200000 +0.0.ffff active dasde 94:16 FBA 512 97MB 200000 +0.0.0300 n/f dasdf 94:20 ECKD diff --git a/test/data/lsdasd_offline.txt b/test/data/lsdasd_offline.txt new file mode 100644 index 00000000..d5ac76b9 --- /dev/null +++ b/test/data/lsdasd_offline.txt @@ -0,0 +1,12 @@ +Bus-ID Status Name Device Type BlkSz Size Blocks +================================================================================ +0.0.0160 offline +0.0.0190 offline +0.0.0191 offline +0.0.0192 offline +0.0.019d offline +0.0.0300 offline +0.0.0150 active dasdb 94:4 ECKD 4096 7042MB 1802880 +0.0.0592 active(ro) dasdc 94:8 ECKD 4096 168MB 43200 +0.0.019e active(ro) dasdd 94:12 ECKD 4096 351MB 90000 +0.0.ffff active dasde 94:16 FBA 512 97MB 200000 diff --git a/test/data/probe_disk_dasd.yml b/test/data/probe_disk_dasd.yml index 0c445c3c..8644e8e3 100644 --- a/test/data/probe_disk_dasd.yml +++ b/test/data/probe_disk_dasd.yml @@ -14,9 +14,7 @@ modules: - - dasd_eckd_mod - '' - model: |- - IBM - DASD + model: IBM DASD old_unique_key: amWp.rOENMk3aQ50 prog_if: 1 resource: @@ -47,9 +45,7 @@ modules: - - dasd_eckd_mod - '' - model: |- - IBM - DASD + model: IBM DASD prog_if: 1 resource: io: @@ -63,6 +59,37 @@ sysfs_id: "/devices/css0/0.0.0001/0.0.0150" vendor: IBM vendor_id: 286721 +- bus: CCW + bus_hwcfg: ccw + class_id: 262 + detail: + cu_model: 233 + dev_model: 12 + lcss: 0 + device: DASD + device_id: 276880 + drivers: + - active: true + modprobe: true + modules: + - - dasd_eckd_mod + - '' + model: IBM DASD + old_unique_key: amWp.rOENMk3aQ50 + prog_if: 1 + resource: + io: + active: false + length: 1 + mode: rw + start: 768 + sub_class_id: 0 + sub_device_id: 275344 + sysfs_bus_id: 0.0.0300 + sysfs_id: "/devices/css0/0.0.0013/0.0.0300" + unique_key: NY1U.ALFATSt_U8F + vendor: IBM + vendor_id: 286721 - bus: None bus_hwcfg: none class_id: 262 diff --git a/test/y2s390/dasds_collection_test.rb b/test/y2s390/dasds_collection_test.rb index 57d77ed4..5b35a0bb 100755 --- a/test/y2s390/dasds_collection_test.rb +++ b/test/y2s390/dasds_collection_test.rb @@ -26,28 +26,62 @@ describe Y2S390::DasdsCollection do include_examples "config base collection" - describe "#filter" do - let(:elements) { [element1, element2, element3] } - let(:element1) { Y2S390::Dasd.new("0.0.0150", status: "active", type: "EKCD") } - let(:element2) { Y2S390::Dasd.new("0.0.0160", status: "offline", type: "EKCD") } - let(:element3) { Y2S390::Dasd.new("0.0.0190", status: "active(ro)", type: "EKCD") } + let(:elements) { [element1, element2, element3, element4] } + let(:element1) { Y2S390::Dasd.new("0.0.0150", status: "active", type: "EKCD") } + let(:element2) { Y2S390::Dasd.new("0.0.0160", status: "offline", type: "EKCD") } + let(:element3) { Y2S390::Dasd.new("0.0.0190", status: "active(ro)", type: "EKCD") } + let(:element4) { Y2S390::Dasd.new("0.0.0300", status: "n/f", type: "EKCD") } + describe "#filter" do it "returns a new collection with the elements which the block returns true" do - expect(subject.size).to eq(3) + expect(subject.size).to eq(4) collection = subject.filter(&:offline?) expect(collection.size).to eq(1) expect(collection.by_id("0.0.0160")).to eq(element2) end end - describe "#active" do - let(:elements) { [element1, element2, element3] } - let(:element1) { Y2S390::Dasd.new("0.0.0150", status: "active", type: "EKCD") } - let(:element2) { Y2S390::Dasd.new("0.0.0160", status: "offline", type: "EKCD") } - let(:element3) { Y2S390::Dasd.new("0.0.0190", status: "active(ro)", type: "EKCD") } + describe "#offline" do + it "returns a new collection with only the offline elements" do + expect(subject.offline.ids).to eql(["0.0.0160"]) + end + end + describe "#active" do it "returns a new collection with only the active elements" do - expect(subject.active.ids).to eql(["0.0.0150", "0.0.0190"]) + expect(subject.active.ids).to eql(["0.0.0150", "0.0.0190", "0.0.0300"]) + end + end + + describe "#unformatted" do + it "returns a new collection with only the unformatted elements" do + expect(subject.unformatted.ids).to eql(["0.0.0300"]) + end + end + + describe "#to_format" do + before do + element1.format_wanted = true + element2.format_wanted = true + element3.formatted = true + element4.formatted = false + end + + context "when format_unformatted is false" do + it "returns a new collection with only the elements that wants to be formatted explicitly" do + + expect(subject.to_format.ids).to eql([element1.id, element2.id]) + end + end + + context "when format_unformatted is true" do + it "returns a new collection with elements that wants to be formatted and unformatted ones" do + element1.format_wanted = true + element2.format_wanted = true + + expect(subject.to_format(format_unformatted: true).ids) + .to eql([element1.id, element2.id, element4.id]) + end end end end diff --git a/test/y2s390/dasds_writer_test.rb b/test/y2s390/dasds_writer_test.rb new file mode 100755 index 00000000..4944260b --- /dev/null +++ b/test/y2s390/dasds_writer_test.rb @@ -0,0 +1,130 @@ +#!/usr/bin/env rspec + +# Copyright (c) [2022] 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 "../test_helper" +require "y2s390/dasds_writer" + +Yast.import "DASDController" + +describe Y2S390::DasdsWriter do + let(:dasd_150) { "0.0.0150" } + let(:dasd_160) { "0.0.0160" } + let(:dasd_300) { "0.0.0300" } + let(:unformatted) { false } + let(:s390_mocking) { true } + let(:lsdasd_file) { "test/data/lsdasd.txt" } + let(:lsdasd_file_offline) { "test/data/lsdasd_offline.txt" } + + before do + allow(ENV).to receive(:[]).with("S390_MOCKING").and_return(false) + allow(ENV).to receive(:[]).with("YAST2_S390_PROBE_DISK") + .and_return("test/data/probe_disk_dasd.yml") + allow(ENV).to receive(:[]).with("YAST2_S390_LSDASD") + .and_return(lsdasd_file_offline, lsdasd_file) + end + + let(:profile) do + { "devices" => [ + { "channel" => dasd_150, "diag" => false, "format" => true }, + { "channel" => dasd_160, "diag" => false, "format" => false }, + { "channel" => dasd_300, "diag" => false, "format" => true } + ], "format_unformatted" => unformatted } + end + + describe "write" do + subject { described_class.new(Yast::DASDController.devices) } + + before do + Yast::DASDController.Import(profile) + allow(subject).to receive(:format_dasds) + allow(subject).to receive(:report_issues) + allow(Yast::DASDController).to receive(:ActivateDisk) + end + + it "activates the current devices if needed" do + expect(subject).to receive(:pre_format_activation).and_call_original + d300 = subject.dasds.by_id(dasd_300) + d160 = subject.dasds.by_id(dasd_160) + expect(Yast::DASDController).to receive(:activate_if_needed).with(d300) + expect(Yast::DASDController).to receive(:activate_if_needed).with(d160) + subject.write + end + + it "obtains the DASDs to be formatted" do + expect(subject).to receive(:obtain_dasds_to_format).and_call_original + expect { subject.write }.to change { subject.to_format.size }.from(0).to(2) + end + + context "in autoinstallation" do + before do + allow(Yast::Mode).to receive(:autoinst).and_return(true) + end + + context "when format_unformated variable is set to true" do + let(:unformatted) { true } + + it "also obtains not formatted DASDs" do + expect(subject).to receive(:obtain_dasds_to_format).and_call_original + expect { subject.write }.to change { subject.to_format.size }.from(0).to(3) + end + end + end + + it "checks for issues in the candidates to be formatted disks" do + expect(subject).to receive(:sanitize_to_format) + subject.write + end + + context "when an issue is found" do + # FBA DASDs can't be formatted + let(:profile) { { "devices" => [{ "channel" => "0.0.ffff", "format" => true }] } } + + it "removes the DASD with the issue from the format and reactivation lists" do + allow(subject).to receive(:format_dasds).and_call_original + expect(Yast::DASDController).to_not receive(:FormatDisks) + subject.write + end + + it "reports the issue" do + expect(subject).to receive(:report_issues).and_call_original + expect(Y2Issues).to receive(:report) + subject.write + end + end + + it "formats the DASDs that are select and valid to be formatted" do + allow(subject).to receive(:format_dasds).and_call_original + expect(Yast::DASDController).to receive(:FormatDisks) + subject.write + expect(subject.to_format.ids).to eql([dasd_150, dasd_300]) + end + + context "when an unformatted device is formatted" do + it "reactives it after formatted all the devices" do + allow(subject).to receive(:activate_offline_dasds) + allow(subject).to receive(:format_dasds).and_call_original + expect(Yast::DASDController).to receive(:FormatDisks).ordered + expect(Yast::DASDController).to receive(:ActivateDisk).with(dasd_300, false).ordered + subject.write + end + end + end +end From 508b0b9e03f80c65a5c9cf4bcd1ca4de670ed57b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Tue, 1 Feb 2022 16:08:07 +0000 Subject: [PATCH 22/31] Apply suggestion from code review --- src/lib/y2s390/dasds_reader.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/lib/y2s390/dasds_reader.rb b/src/lib/y2s390/dasds_reader.rb index eef5aa40..e1c41dd3 100644 --- a/src/lib/y2s390/dasds_reader.rb +++ b/src/lib/y2s390/dasds_reader.rb @@ -195,10 +195,13 @@ def partition_info(dasd) end def device_type_for(dasd) - device_type = (dasd&.hwinfo&.device_id.to_i & 65535).to_s(16) - cu_model = dasd&.hwinfo&.detail&.cu_model.to_i.to_s(16).rjust(2, "0") - sub_device_id = (dasd&.hwinfo&.sub_device_id.to_i & 65535).to_s(16) - dev_model = dasd&.hwinfo&.detail&.dev_model.to_i.to_s(16).rjust(2, "0") + hwinfo = dasd&.hwinfo + hwinfo_detail = hwinfo&.detail + + device_type = (hwinfo&.device_id.to_i & 65535).to_s(16) + sub_device_id = (hwinfo&.sub_device_id.to_i & 65535).to_s(16) + cu_model = hwinfo_detail&.cu_model.to_i.to_s(16).rjust(2, "0") + dev_model = hwinfo_detail&.dev_model.to_i.to_s(16).rjust(2, "0") "#{device_type}/#{cu_model} #{sub_device_id}/#{dev_model}".upcase end From 4787dfc4e499dbb59c2675cb7dc6f53b49cc5d9d Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Tue, 1 Feb 2022 16:12:18 +0000 Subject: [PATCH 23/31] Added missing textdomain --- src/lib/y2s390/dialogs/mkinitrd.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/y2s390/dialogs/mkinitrd.rb b/src/lib/y2s390/dialogs/mkinitrd.rb index 4e835078..390593c5 100644 --- a/src/lib/y2s390/dialogs/mkinitrd.rb +++ b/src/lib/y2s390/dialogs/mkinitrd.rb @@ -6,6 +6,7 @@ class Mkinitrd < ::UI::Dialog CMD = "/sbin/mkinitrd".freeze def dialog_content + textdomain "s390" Label(_("Running mkinitrd.")) end From 698da932884825f64c69f58575e013eb613d8881 Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Tue, 1 Feb 2022 17:37:02 +0000 Subject: [PATCH 24/31] Some minor improvements to the format Dialog --- src/include/s390/dasd/dialogs.rb | 2 +- src/lib/y2s390/dialogs/dasd_format.rb | 4 +--- src/lib/y2s390/dialogs/format_dialog.rb | 8 ++++++-- src/modules/DASDController.rb | 14 ++++---------- test/dasd_controller_test.rb | 2 +- 5 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/include/s390/dasd/dialogs.rb b/src/include/s390/dasd/dialogs.rb index 1609c054..f4881bbc 100644 --- a/src/include/s390/dasd/dialogs.rb +++ b/src/include/s390/dasd/dialogs.rb @@ -81,7 +81,7 @@ def item_elements_for(dasd) return [item_id, dasd.id, "--", "--", "--", diag, "--", "--"] unless dasd.active? [ - item_id, dasd.id, dasd.device_name, dasd.device_type, + item_id, dasd.id, dasd.device_path, dasd.device_type, dasd.access_type.to_s.upcase, diag, formatted, dasd.partition_info ] end diff --git a/src/lib/y2s390/dialogs/dasd_format.rb b/src/lib/y2s390/dialogs/dasd_format.rb index 3c6ef985..4ece22dc 100644 --- a/src/lib/y2s390/dialogs/dasd_format.rb +++ b/src/lib/y2s390/dialogs/dasd_format.rb @@ -68,7 +68,7 @@ def in_progress_table Header( Right(_("Channel ID")), "Device", - Right(_("Cyl.") + " " * 6) # reserve some space for more digits + Right(_("Cyl.").ljust(12, " ")) # reserve some space for more digits ), in_progress_items ) @@ -109,8 +109,6 @@ def done_items end def update_progress - fmt_process.update_summary - sleep(0.2) progress = fmt_process.progress cylinders = fmt_process.cylinders update_progress_percent(100 * progress / cylinders) if cylinders > 0 diff --git a/src/lib/y2s390/dialogs/format_dialog.rb b/src/lib/y2s390/dialogs/format_dialog.rb index 853e41fe..3fca2061 100644 --- a/src/lib/y2s390/dialogs/format_dialog.rb +++ b/src/lib/y2s390/dialogs/format_dialog.rb @@ -50,7 +50,7 @@ def initialize(dasds) def run fmt_process.start - wait_for_update + wait_for_start return report_format_failed(fmt_process) unless fmt_process.running? fmt_process.initialize_summary @@ -72,10 +72,14 @@ def user_input private - def wait_for_update + def wait_for_start sleep(0.2) end + def wait_for_update + sleep(0.1) + end + def report_format_failed(process) Yast::Report.Error(format(_("Disks formatting failed. Exit code: %s.\nError output:%s"), process.status, process.error)) diff --git a/src/modules/DASDController.rb b/src/modules/DASDController.rb index 3f85b140..4ae215df 100644 --- a/src/modules/DASDController.rb +++ b/src/modules/DASDController.rb @@ -365,7 +365,7 @@ def ActivateDiag(channel, value) def FormatDisks(disks_list) log.info "Disks to format: #{disks_list}" - format_dialog_for(disks_list).run + format_dialog.new(disks_list).run end publish variable: :devices, type: "map >" @@ -393,16 +393,10 @@ def FormatDisks(disks_list) private - # It obtains the dialog to be used by the FormatProcess according to the NEW_FORMAT environment + # It obtains the dialog to be used by the FormatProcess according to the OLD_FORMAT environment # variable - # - # @param [S390::DasdsCollection] collection of dasds to be be formatted - def format_dialog_for(disks_list) - if ENV["NEW_FORMAT"] - Y2S390::Dialogs::DasdFormat - else - Y2S390::Dialogs::FormatDisks - end.new(disks_list) + def format_dialog + ENV["OLD_FORMAT"] ? Y2S390::Dialogs::FormatDisks : Y2S390::Dialogs::DasdFormat end # Convenience method to convert the device ID to integers for filtering purposes diff --git a/test/dasd_controller_test.rb b/test/dasd_controller_test.rb index 63d91793..65df57e9 100755 --- a/test/dasd_controller_test.rb +++ b/test/dasd_controller_test.rb @@ -241,7 +241,7 @@ describe "#FormatDisks" do let(:disks) { Yast::DASDController.devices.by_ids(["0.0.0150"]) } - let(:dialog) { Y2S390::Dialogs::FormatDisks } + let(:dialog) { Y2S390::Dialogs::DasdFormat } it "runs a Format Disk dialog for the given disks" do expect_any_instance_of(dialog).to receive(:run) From 266c23285c028fcef805f5bd9236411249d49d39 Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Tue, 1 Feb 2022 19:32:14 +0000 Subject: [PATCH 25/31] Bump version & changelog --- package/yast2-s390.changes | 8 ++++++++ package/yast2-s390.spec | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/package/yast2-s390.changes b/package/yast2-s390.changes index 721407d0..d14e22a6 100644 --- a/package/yast2-s390.changes +++ b/package/yast2-s390.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Tue Feb 1 19:15:35 UTC 2022 - Knut Anderssen + +- Related to jsc#SLE-20225 + - Do not limit the number of disks formatted in parallel + - New format dialog introduced +- 4.4.3 + ------------------------------------------------------------------- Fri Oct 22 10:57:05 UTC 2021 - Martin Vidner diff --git a/package/yast2-s390.spec b/package/yast2-s390.spec index add45c87..ccc1631a 100644 --- a/package/yast2-s390.spec +++ b/package/yast2-s390.spec @@ -17,7 +17,7 @@ Name: yast2-s390 -Version: 4.4.2 +Version: 4.4.3 Release: 0 Group: System/YaST License: GPL-2.0-only From 4ecc8fe9aff863a996769234f9187e9f964e3e8d Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Tue, 1 Feb 2022 19:59:04 +0000 Subject: [PATCH 26/31] Use the format dialog table space better --- src/lib/y2s390/dialogs/dasd_format.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/lib/y2s390/dialogs/dasd_format.rb b/src/lib/y2s390/dialogs/dasd_format.rb index 4ece22dc..affe001f 100644 --- a/src/lib/y2s390/dialogs/dasd_format.rb +++ b/src/lib/y2s390/dialogs/dasd_format.rb @@ -32,8 +32,7 @@ def dialog_content 0.45, # top and bottom margin; NCurses rounds this down to 0 VBox( Heading(_("Formatting DASDs")), - MinHeight(7, tables), - VSpacing(1), + MinHeight(min_height, tables), ProgressBar(Id(:progress_bar), _("Total Progress"), 100, 0), VSpacing(1) ) @@ -122,6 +121,14 @@ def refresh_tables Yast::UI.ChangeWidget(Id(:done_table), :Items, done_items) end + def min_height + (elements > 5) ? 14 : 9 + end + + def elements + @fmt_process.summary.values.size + end + def update_progress_percent(percent) @progress = percent Yast::UI.ChangeWidget(Id(:progress_bar), :Value, @progress) From 4c3ceebfc705a7124e3f790b8f1faf07ca4f47ab Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Tue, 1 Feb 2022 22:14:48 +0000 Subject: [PATCH 27/31] Added partition_info unit test --- test/data/fdasd_partition.txt | 21 +++++++++++++ test/y2s390/dasd_actions/format_test.rb | 30 +++++++++--------- test/y2s390/dasd_test.rb | 42 ++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 16 deletions(-) create mode 100644 test/data/fdasd_partition.txt diff --git a/test/data/fdasd_partition.txt b/test/data/fdasd_partition.txt new file mode 100644 index 00000000..90baf6e1 --- /dev/null +++ b/test/data/fdasd_partition.txt @@ -0,0 +1,21 @@ +reading volume label ..: VOL1 +reading vtoc ..........: ok + + +Disk /dev/dasda: + cylinders ............: 30048 + tracks per cylinder ..: 15 + blocks per track .....: 12 + bytes per block ......: 4096 + volume label .........: VOL1 + volume serial ........: 0X0160 + max partitions .......: 3 + + ------------------------------- tracks ------------------------------- + Device start end length Id System + 2 63 62 unused + /dev/dasda1 64 6463 6400 1 Linux native + /dev/dasda2 6464 414271 407808 2 Linux native + /dev/dasda3 414272 450687 36416 3 Linux native + 450688 450719 32 unused +exiting... diff --git a/test/y2s390/dasd_actions/format_test.rb b/test/y2s390/dasd_actions/format_test.rb index f7d0bfd8..eac6e41f 100755 --- a/test/y2s390/dasd_actions/format_test.rb +++ b/test/y2s390/dasd_actions/format_test.rb @@ -24,9 +24,9 @@ describe Y2S390::DasdActions::Format do let(:action) { described_class.new(selected) } - let(:selected) { Y2S390::DasdsCollection.new([dasd_0150, dasd_0fff]) } + let(:selected) { Y2S390::DasdsCollection.new([dasd_0150, dasd_ffff]) } let(:dasd_0150) { Y2S390::Dasd.new("0.0.0150", status: "active", type: "ECKD") } - let(:dasd_0fff) { Y2S390::Dasd.new("0.0.0fff", status: "active(ro)", type: "FBA") } + let(:dasd_ffff) { Y2S390::Dasd.new("0.0.ffff", status: "active(ro)", type: "FBA") } let(:controller) { Yast::DASDController } describe "#run" do @@ -39,14 +39,14 @@ allow(controller).to receive(:FormatDisks) allow(Yast::Mode).to receive(:config).and_return(config_mode) allow(dasd_0150).to receive(:io_active?).and_return(io_active) - allow(dasd_0fff).to receive(:io_active?).and_return(io_active) + allow(dasd_ffff).to receive(:io_active?).and_return(io_active) allow(dasd_0150).to receive(:access_type).and_return("rw") - allow(dasd_0fff).to receive(:access_type).and_return("ro") + allow(dasd_ffff).to receive(:access_type).and_return("ro") end context "when at least one of the DASD devices is not active" do it "reports the problem" do - expect(Yast::Popup).to receive(:Message).with(/Disk 0.0.0fff is not active/) + expect(Yast::Popup).to receive(:Message).with(/Disk 0.0.ffff is not active/) action.run end @@ -65,7 +65,7 @@ let(:io_active) { true } it "reports the problem" do - expect(Yast::Popup).to receive(:Message).with(/Disk 0.0.0fff is not accessible for writing/) + expect(Yast::Popup).to receive(:Message).with(/Disk 0.0.ffff is not accessible for writing/) action.run end @@ -83,12 +83,12 @@ context "when at least one of the DASD devices is not a ECKD one" do let(:io_active) { true } before do - dasd_0fff.status = "active" - allow(dasd_0fff).to receive(:access_type).and_return("rw") + dasd_ffff.status = "active" + allow(dasd_ffff).to receive(:access_type).and_return("rw") end it "reports the problem" do - expect(Yast::Popup).to receive(:Message).with(/Disk 0.0.0fff cannot be formatted/) + expect(Yast::Popup).to receive(:Message).with(/Disk 0.0.ffff cannot be formatted/) action.run end @@ -144,30 +144,30 @@ describe Y2S390::DasdActions::FormatOn do let(:action) { described_class.new(selected) } - let(:selected) { Y2S390::DasdsCollection.new([dasd_0150, dasd_0fff]) } + let(:selected) { Y2S390::DasdsCollection.new([dasd_0150, dasd_ffff]) } let(:dasd_0150) { Y2S390::Dasd.new("0.0.0150", status: "offline") } - let(:dasd_0fff) { Y2S390::Dasd.new("0.0.0fff", status: "offline") } + let(:dasd_ffff) { Y2S390::Dasd.new("0.0.ffff", status: "offline") } let(:controller) { Yast::DASDController } describe "#run" do it "iterates over the the selected DASDs setting the format wanted to true" do expect { action.run }.to change { dasd_0150.format_wanted }.from(nil).to(true) - .and change { dasd_0fff.format_wanted }.from(nil).to(true) + .and change { dasd_ffff.format_wanted }.from(nil).to(true) end end end describe Y2S390::DasdActions::FormatOff do let(:action) { described_class.new(selected) } - let(:selected) { Y2S390::DasdsCollection.new([dasd_0150, dasd_0fff]) } + let(:selected) { Y2S390::DasdsCollection.new([dasd_0150, dasd_ffff]) } let(:dasd_0150) { Y2S390::Dasd.new("0.0.0150", status: "offline") } - let(:dasd_0fff) { Y2S390::Dasd.new("0.0.0fff", status: "offline") } + let(:dasd_ffff) { Y2S390::Dasd.new("0.0.ffff", status: "offline") } let(:controller) { Yast::DASDController } describe "#run" do it "iterates over the the selected DASDs setting the format wanted to true" do expect { action.run }.to change { dasd_0150.format_wanted }.from(nil).to(false) - .and change { dasd_0fff.format_wanted }.from(nil).to(false) + .and change { dasd_ffff.format_wanted }.from(nil).to(false) end end end diff --git a/test/y2s390/dasd_test.rb b/test/y2s390/dasd_test.rb index 3e3fbd11..ba092019 100755 --- a/test/y2s390/dasd_test.rb +++ b/test/y2s390/dasd_test.rb @@ -24,7 +24,9 @@ describe Y2S390::Dasd do subject { described_class.new("0.0.0150") } - let(:dasda) { described_class.new("0.0.0150", status: "active", device_name: "dasda") } + let(:dasda) do + described_class.new("0.0.0150", status: "active", device_name: "dasda", type: "ECKD") + end describe "#hex_id" do it "returns an integer representation of the channel ID" do @@ -90,4 +92,42 @@ expect(subject.formatted?).to eql(false) end end + + describe "#partition_info" do + let(:execute) { instance_double("Yast::Execute", on_target: true) } + let(:fdasd) { "" } + + before do + allow(Yast::Execute).to receive(:stdout).and_return(execute) + allow(execute).to receive(:on_target!).with("/sbin/fdasd", "-p", dasda.device_path) + .and_return(fdasd) + end + + context "when the DASD type is not ECKD" do + let(:dasd_ffff) do + described_class.new("0.0.ffff", status: "active(ro)", device_name: "dasda", type: "FBA") + end + + it "assumes only one partition returning the device path with a 1 at the end" do + expect(dasd_ffff.partition_info).to eql("/dev/dasda1") + end + end + + context "when the fdasd -p '/dev/device' output does not contain any partition or is empty" do + it "returns an empty string" do + expect(dasda.partition_info).to eql("") + end + end + + context "when the fdasd -p '/dev/device' output contains some partition" do + let(:fdasd) { load_file("fdasd_partition.txt") } + let(:partition_info) do + "/dev/dasda1 (Linux native), /dev/dasda2 (Linux native), /dev/dasda3 (Linux native)" + end + + it "returns each partition info like '/dev/dasda1 (Linux native), /dev/dasda2 (Linux...'" do + expect(dasda.partition_info).to eql(partition_info) + end + end + end end From 5be90926388acb5291f71fcbfb6367667f757745 Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Wed, 2 Feb 2022 07:28:27 +0000 Subject: [PATCH 28/31] Added dasd missing unit tests. --- test/y2s390/dasd_test.rb | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/test/y2s390/dasd_test.rb b/test/y2s390/dasd_test.rb index ba092019..061fad63 100755 --- a/test/y2s390/dasd_test.rb +++ b/test/y2s390/dasd_test.rb @@ -28,6 +28,15 @@ described_class.new("0.0.0150", status: "active", device_name: "dasda", type: "ECKD") end + let(:mock_disks) { true } + let(:execute) { instance_double("Yast::Execute") } + + before do + allow(ENV).to receive(:[]).and_call_original + allow(ENV).to receive(:[]).with("S390_MOCKING").and_return(mock_disks) + allow(Yast::Execute).to receive(:stdout).and_return(execute) + end + describe "#hex_id" do it "returns an integer representation of the channel ID" do expect(subject.hex_id).to be_a(Integer) @@ -94,11 +103,9 @@ end describe "#partition_info" do - let(:execute) { instance_double("Yast::Execute", on_target: true) } let(:fdasd) { "" } before do - allow(Yast::Execute).to receive(:stdout).and_return(execute) allow(execute).to receive(:on_target!).with("/sbin/fdasd", "-p", dasda.device_path) .and_return(fdasd) end @@ -130,4 +137,18 @@ end end end + + describe "#acces_type" do + it "returns the access type ('rw', 'ro')according to the hwinfo" do + expect(dasda.access_type).to eql("rw") + end + end + + describe "#sys_device_name" do + it "returns the associated device name read from the sysfs" do + allow(execute).to receive(:on_target!).with(["ls", "/sys/bus/ccw/devices/0.0.0150/block/"]) + .and_return("#{dasda.device_name}\n") + expect(dasda.sys_device_name).to eq("/dev/dasda") + end + end end From ad1e403caa4a9f5f35fa45b85fd84bf8b6ce939f Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Wed, 2 Feb 2022 08:42:00 +0000 Subject: [PATCH 29/31] Include Yast::Logger --- src/include/s390/dasd/dialogs.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/include/s390/dasd/dialogs.rb b/src/include/s390/dasd/dialogs.rb index f4881bbc..1ba5d98a 100644 --- a/src/include/s390/dasd/dialogs.rb +++ b/src/include/s390/dasd/dialogs.rb @@ -17,10 +17,13 @@ # 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 "y2s390/dasd_actions" module Yast module S390DasdDialogsInclude + include Yast::Logger + def initialize_s390_dasd_dialogs(include_target) textdomain "s390" From 96dcf92f526171a7c579eb6eb0b6e6e5a9449595 Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Wed, 2 Feb 2022 09:47:34 +0000 Subject: [PATCH 30/31] Do not abbreviate Cylinders --- src/lib/y2s390/dialogs/dasd_format.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/y2s390/dialogs/dasd_format.rb b/src/lib/y2s390/dialogs/dasd_format.rb index affe001f..c149690f 100644 --- a/src/lib/y2s390/dialogs/dasd_format.rb +++ b/src/lib/y2s390/dialogs/dasd_format.rb @@ -67,7 +67,7 @@ def in_progress_table Header( Right(_("Channel ID")), "Device", - Right(_("Cyl.").ljust(12, " ")) # reserve some space for more digits + Right(_("Cylinders").ljust(12, " ")) # reserve some space for more digits ), in_progress_items ) From 4ce30afe34ff0990f107b175e2eccdd80cdf8fb1 Mon Sep 17 00:00:00 2001 From: Knut Anderssen Date: Wed, 2 Feb 2022 10:11:25 +0000 Subject: [PATCH 31/31] Fix format_process done? in corner case --- src/lib/y2s390/format_process.rb | 4 +++- test/y2s390/format_process_test.rb | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/lib/y2s390/format_process.rb b/src/lib/y2s390/format_process.rb index dc2e6d72..17230d45 100644 --- a/src/lib/y2s390/format_process.rb +++ b/src/lib/y2s390/format_process.rb @@ -45,7 +45,9 @@ def update_progress! # # @return [Boolean] whether the format progress has been completed or not def done? - @cylinders <= @progress + # We need to add a partial step to cover the case when the number of cylinders is not + # multiple of the format size. e.g: cylinders: 10016, format_size: 10 + @progress + (@size - 1) >= @cylinders end end diff --git a/test/y2s390/format_process_test.rb b/test/y2s390/format_process_test.rb index b80de933..fe72637b 100755 --- a/test/y2s390/format_process_test.rb +++ b/test/y2s390/format_process_test.rb @@ -26,7 +26,7 @@ describe Y2S390::FormatStatus do let(:dasd) { Y2S390::Dasd.new("0.0.0150", status: "active", type: "ECKD") } - subject { described_class.new(dasd, 1500) } + subject { described_class.new(dasd, 1016) } describe "#update_progress!" do it "increases the progress by the format size" do @@ -38,7 +38,11 @@ describe "#done?" do it "returns true when all the cylinders have been formatted" do expect(subject.done?).to eql(false) - 150.times { subject.update_progress! } + 100.times { subject.update_progress! } + expect(subject.done?).to eql(false) + expect(subject.progress).to eql(1000) + subject.update_progress! + expect(subject.progress).to eql(1010) expect(subject.done?).to eql(true) end