diff options
Diffstat (limited to 'pyanaconda/storage/zfcp.py')
-rw-r--r-- | pyanaconda/storage/zfcp.py | 428 |
1 files changed, 0 insertions, 428 deletions
diff --git a/pyanaconda/storage/zfcp.py b/pyanaconda/storage/zfcp.py deleted file mode 100644 index 23be6cd9d..000000000 --- a/pyanaconda/storage/zfcp.py +++ /dev/null @@ -1,428 +0,0 @@ -# -# zfcp.py - mainframe zfcp configuration install data -# -# Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc. All rights reserved. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# 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, see <http://www.gnu.org/licenses/>. -# -# Author(s): Karsten Hopp <karsten@redhat.com> -# - -import string -import os -from . import ROOT_PATH -from udev import udev_settle -from . import util - -import gettext -_ = lambda x: gettext.ldgettext("anaconda", x) - -import logging -log = logging.getLogger("storage") - -def loggedWriteLineToFile(fn, value): - f = open(fn, "w") - log.debug("echo %s > %s" % (value, fn)) - f.write("%s\n" % (value)) - f.close() - -zfcpsysfs = "/sys/bus/ccw/drivers/zfcp" -scsidevsysfs = "/sys/bus/scsi/devices" -zfcpconf = "/etc/zfcp.conf" - -class ZFCPDevice: - def __init__(self, devnum, wwpn, fcplun): - self.devnum = self.sanitizeDeviceInput(devnum) - self.wwpn = self.sanitizeWWPNInput(wwpn) - self.fcplun = self.sanitizeFCPLInput(fcplun) - - if not self.checkValidDevice(self.devnum): - raise ValueError, _("You have not specified a device number or the number is invalid") - if not self.checkValidWWPN(self.wwpn): - raise ValueError, _("You have not specified a worldwide port name or the name is invalid.") - if not self.checkValidFCPLun(self.fcplun): - raise ValueError, _("You have not specified a FCP LUN or the number is invalid.") - - def __str__(self): - return "%s %s %s" %(self.devnum, self.wwpn, self.fcplun) - - def sanitizeDeviceInput(self, dev): - if dev is None or dev == "": - return None - dev = dev.lower() - bus = dev[:string.rfind(dev, ".") + 1] - dev = dev[string.rfind(dev, ".") + 1:] - dev = "0" * (4 - len(dev)) + dev - if not len(bus): - return "0.0." + dev - else: - return bus + dev - - def sanitizeWWPNInput(self, id): - if id is None or id == "": - return None - id = id.lower() - if id[:2] != "0x": - return "0x" + id - return id - - # ZFCP LUNs are usually entered as 16 bit, sysfs accepts only 64 bit - # (#125632), expand with zeroes if necessary - def sanitizeFCPLInput(self, lun): - if lun is None or lun == "": - return None - lun = lun.lower() - if lun[:2] == "0x": - lun = lun[2:] - lun = "0x" + "0" * (4 - len(lun)) + lun - lun = lun + "0" * (16 - len(lun) + 2) - return lun - - def _hextest(self, hex): - try: - int(hex, 16) - return True - except TypeError: - return False - - def checkValidDevice(self, id): - if id is None or id == "": - return False - if len(id) != 8: # p.e. 0.0.0600 - return False - if id[0] not in string.digits or id[2] not in string.digits: - return False - if id[1] != "." or id[3] != ".": - return False - return self._hextest(id[4:]) - - def checkValid64BitHex(self, hex): - if hex is None or hex == "": - return False - if len(hex) != 18: - return False - return self._hextest(hex) - checkValidWWPN = checkValidFCPLun = checkValid64BitHex - - def onlineDevice(self): - online = "%s/%s/online" %(zfcpsysfs, self.devnum) - portadd = "%s/%s/port_add" %(zfcpsysfs, self.devnum) - portdir = "%s/%s/%s" %(zfcpsysfs, self.devnum, self.wwpn) - unitadd = "%s/unit_add" %(portdir) - unitdir = "%s/%s" %(portdir, self.fcplun) - failed = "%s/failed" %(unitdir) - - if not os.path.exists(online): - log.info("Freeing zFCP device %s" % (self.devnum,)) - util.run_program(["zfcp_cio_free", "-d", self.devnum]) - - if not os.path.exists(online): - raise ValueError, _( - "zFCP device %s not found, not even in device ignore list." - %(self.devnum,)) - - try: - f = open(online, "r") - devonline = f.readline().strip() - f.close() - if devonline != "1": - loggedWriteLineToFile(online, "1") - except IOError as e: - raise ValueError, _("Could not set zFCP device %(devnum)s " - "online (%(e)s).") \ - % {'devnum': self.devnum, 'e': e} - - if not os.path.exists(portdir): - if os.path.exists(portadd): - # older zfcp sysfs interface - try: - loggedWriteLineToFile(portadd, self.wwpn) - udev_settle() - except IOError as e: - raise ValueError, _("Could not add WWPN %(wwpn)s to zFCP " - "device %(devnum)s (%(e)s).") \ - % {'wwpn': self.wwpn, - 'devnum': self.devnum, - 'e': e} - else: - # newer zfcp sysfs interface with auto port scan - raise ValueError, _("WWPN %(wwpn)s not found at zFCP device " - "%(devnum)s.") % {'wwpn': self.wwpn, - 'devnum': self.devnum} - else: - if os.path.exists(portadd): - # older zfcp sysfs interface - log.info("WWPN %(wwpn)s at zFCP device %(devnum)s already " - "there." % {'wwpn': self.wwpn, - 'devnum': self.devnum}) - - if not os.path.exists(unitdir): - try: - loggedWriteLineToFile(unitadd, self.fcplun) - udev_settle() - except IOError as e: - raise ValueError, _("Could not add LUN %(fcplun)s to WWPN " - "%(wwpn)s on zFCP device %(devnum)s " - "(%(e)s).") \ - % {'fcplun': self.fcplun, 'wwpn': self.wwpn, - 'devnum': self.devnum, 'e': e} - else: - raise ValueError, _("LUN %(fcplun)s at WWPN %(wwpn)s on zFCP " - "device %(devnum)s already configured.") \ - % {'fcplun': self.fcplun, - 'wwpn': self.wwpn, - 'devnum': self.devnum} - - fail = "0" - try: - f = open(failed, "r") - fail = f.readline().strip() - f.close() - except IOError as e: - raise ValueError, _("Could not read failed attribute of LUN " - "%(fcplun)s at WWPN %(wwpn)s on zFCP device " - "%(devnum)s (%(e)s).") \ - % {'fcplun': self.fcplun, - 'wwpn': self.wwpn, - 'devnum': self.devnum, - 'e': e} - if fail != "0": - self.offlineDevice() - raise ValueError, _("Failed LUN %(fcplun)s at WWPN %(wwpn)s on " - "zFCP device %(devnum)s removed again.") \ - % {'fcplun': self.fcplun, - 'wwpn': self.wwpn, - 'devnum': self.devnum} - - return True - - def offlineSCSIDevice(self): - f = open("/proc/scsi/scsi", "r") - lines = f.readlines() - f.close() - # alternatively iterate over /sys/bus/scsi/devices/*:0:*:*/ - - for line in lines: - if not line.startswith("Host"): - continue - scsihost = string.split(line) - host = scsihost[1] - channel = "0" - id = scsihost[5] - lun = scsihost[7] - scsidev = "%s:%s:%s:%s" % (host[4:], channel, id, lun) - fcpsysfs = "%s/%s" % (scsidevsysfs, scsidev) - scsidel = "%s/%s/delete" % (scsidevsysfs, scsidev) - - f = open("%s/hba_id" %(fcpsysfs), "r") - fcphbasysfs = f.readline().strip() - f.close() - f = open("%s/wwpn" %(fcpsysfs), "r") - fcpwwpnsysfs = f.readline().strip() - f.close() - f = open("%s/fcp_lun" %(fcpsysfs), "r") - fcplunsysfs = f.readline().strip() - f.close() - - if fcphbasysfs == self.devnum \ - and fcpwwpnsysfs == self.wwpn \ - and fcplunsysfs == self.fcplun: - loggedWriteLineToFile(scsidel, "1") - udev_settle() - return - - log.warn("no scsi device found to delete for zfcp %s %s %s" - %(self.devnum, self.wwpn, self.fcplun)) - - def offlineDevice(self): - offline = "%s/%s/online" %(zfcpsysfs, self.devnum) - portadd = "%s/%s/port_add" %(zfcpsysfs, self.devnum) - portremove = "%s/%s/port_remove" %(zfcpsysfs, self.devnum) - unitremove = "%s/%s/%s/unit_remove" %(zfcpsysfs, self.devnum, self.wwpn) - portdir = "%s/%s/%s" %(zfcpsysfs, self.devnum, self.wwpn) - devdir = "%s/%s" %(zfcpsysfs, self.devnum) - - try: - self.offlineSCSIDevice() - except IOError as e: - raise ValueError, _("Could not correctly delete SCSI device of " - "zFCP %(devnum)s %(wwpn)s %(fcplun)s " - "(%(e)s).") \ - % {'devnum': self.devnum, 'wwpn': self.wwpn, - 'fcplun': self.fcplun, 'e': e} - - try: - loggedWriteLineToFile(unitremove, self.fcplun) - except IOError as e: - raise ValueError, _("Could not remove LUN %(fcplun)s at WWPN " - "%(wwpn)s on zFCP device %(devnum)s " - "(%(e)s).") \ - % {'fcplun': self.fcplun, 'wwpn': self.wwpn, - 'devnum': self.devnum, 'e': e} - - if os.path.exists(portadd): - # only try to remove ports with older zfcp sysfs interface - for lun in os.listdir(portdir): - if lun.startswith("0x") and \ - os.path.isdir(os.path.join(portdir, lun)): - log.info("Not removing WWPN %s at zFCP device %s since port still has other LUNs, e.g. %s." - %(self.wwpn, self.devnum, lun)) - return True - - try: - loggedWriteLineToFile(portremove, self.wwpn) - except IOError as e: - raise ValueError, _("Could not remove WWPN %(wwpn)s on zFCP " - "device %(devnum)s (%(e)s).") \ - % {'wwpn': self.wwpn, - 'devnum': self.devnum, 'e': e} - - if os.path.exists(portadd): - # older zfcp sysfs interface - for port in os.listdir(devdir): - if port.startswith("0x") and \ - os.path.isdir(os.path.join(devdir, port)): - log.info("Not setting zFCP device %s offline since it still has other ports, e.g. %s." - %(self.devnum, port)) - return True - else: - # newer zfcp sysfs interface with auto port scan - import glob - luns = glob.glob("%s/0x????????????????/0x????????????????" - %(devdir,)) - if len(luns) != 0: - log.info("Not setting zFCP device %s offline since it still has other LUNs, e.g. %s." - %(self.devnum, luns[0])) - return True - - try: - loggedWriteLineToFile(offline, "0") - except IOError as e: - raise ValueError, _("Could not set zFCP device %(devnum)s " - "offline (%(e)s).") \ - % {'devnum': self.devnum, 'e': e} - - return True - -class ZFCP: - """ ZFCP utility class. - - This class will automatically online to ZFCP drives configured in - /tmp/fcpconfig when the startup() method gets called. It can also be - used to manually configure ZFCP devices through the addFCP() method. - - As this class needs to make sure that /tmp/fcpconfig configured - drives are only onlined once and as it keeps a global list of all ZFCP - devices it is implemented as a Singleton. - """ - - def __init__(self): - self.intf = None - self.fcpdevs = set() - self.hasReadConfig = False - self.down = True - - # So that users can write zfcp() to get the singleton instance - def __call__(self): - return self - - def readConfig(self): - try: - f = open(zfcpconf, "r") - except IOError: - log.info("no %s; not configuring zfcp" % (zfcpconf,)) - return - - lines = map(lambda x: x.strip().lower(), f.readlines()) - f.close() - - for line in lines: - if line.startswith("#") or line == '': - continue - - fields = line.split() - - if len(fields) == 3: - devnum = fields[0] - wwpn = fields[1] - fcplun = fields[2] - elif len(fields) == 5: - # support old syntax of: - # devno scsiid wwpn scsilun fcplun - devnum = fields[0] - wwpn = fields[2] - fcplun = fields[4] - else: - log.warn("Invalid line found in %s: %s" % (zfcpconf, line,)) - continue - - try: - self.addFCP(devnum, wwpn, fcplun) - except ValueError as e: - if self.intf: - self.intf.messageWindow(_("Error"), str(e)) - else: - log.warning(str(e)) - - def addFCP(self, devnum, wwpn, fcplun): - d = ZFCPDevice(devnum, wwpn, fcplun) - if d.onlineDevice(): - self.fcpdevs.add(d) - - def shutdown(self): - if self.down: - return - self.down = True - if len(self.fcpdevs) == 0: - return - for d in self.fcpdevs: - try: - d.offlineDevice() - except ValueError as e: - log.warn(str(e)) - - def startup(self): - if not self.down: - return - self.down = False - if not self.hasReadConfig: - self.readConfig() - self.hasReadConfig = True - # readConfig calls addFCP which calls onlineDevice already - return - - if len(self.fcpdevs) == 0: - return - for d in self.fcpdevs: - try: - d.onlineDevice() - except ValueError as e: - log.warn(str(e)) - - def write(self): - if len(self.fcpdevs) == 0: - return - f = open(ROOT_PATH + zfcpconf, "w") - for d in self.fcpdevs: - f.write("%s\n" %(d,)) - f.close() - - f = open(ROOT_PATH + "/etc/modprobe.conf", "a") - f.write("alias scsi_hostadapter zfcp\n") - f.close() - -# Create ZFCP singleton -ZFCP = ZFCP() - -# vim:tw=78:ts=4:et:sw=4 |