Skip to content

Commit

Permalink
Added new classes for DASDs management
Browse files Browse the repository at this point in the history
  • Loading branch information
teclator committed Nov 16, 2021
1 parent 6349054 commit b7e5997
Show file tree
Hide file tree
Showing 25 changed files with 1,654 additions and 2 deletions.
4 changes: 4 additions & 0 deletions src/lib/y2s390.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
require "y2s390/dasd"
require "y2s390/dasds_reader"
require "y2s390/dasds_collection"
require "y2s390/hwinfo_reader"
88 changes: 88 additions & 0 deletions src/lib/y2s390/base_collection.rb
Original file line number Diff line number Diff line change
@@ -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<Objects>]
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<Object>]
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<String>]
def ids
map(&:id)
end
end
end
170 changes: 170 additions & 0 deletions src/lib/y2s390/dasd.rb
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions src/lib/y2s390/dasd_actions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
require "y2s390/dasd_actions/activate"
require "y2s390/dasd_actions/deactivate"
require "y2s390/dasd_actions/format"
require "y2s390/dasd_actions/diag"
61 changes: 61 additions & 0 deletions src/lib/y2s390/dasd_actions/activate.rb
Original file line number Diff line number Diff line change
@@ -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

return true
end

private

# Convenience method for checking if the activated DASD without format need to be formatted
# now or not.
#
# @param unformatted_disks [Array<Dasd>]
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[0])
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
39 changes: 39 additions & 0 deletions src/lib/y2s390/dasd_actions/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require "yast"
require "abstract_method"

Yast.import "DASDController"
Yast.import "Mode"
Yast.import "Popup"

module Y2S390
module DasdActions
class Base
include Yast::I18n

# @return [Boolean]
abstract_method :run
attr_accessor :selected

def initialize(selected)
textdomain "s390"
@selected = selected
end

def self.run(selected)
new(selected).run
end

def controller
Yast::DASDController
end

def config_mode?
Yast::Mode.config
end

def auto_mode?
Yast::Mode.autoinst
end
end
end
end
20 changes: 20 additions & 0 deletions src/lib/y2s390/dasd_actions/deactivate.rb
Original file line number Diff line number Diff line change
@@ -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

return true
end

private

def deactivate(dasd)
controller.DeactivateDisk(dasd.id, dasd.diag_wanted)
end
end
end
end
Loading

0 comments on commit b7e5997

Please sign in to comment.