summaryrefslogtreecommitdiffstats
path: root/pyanaconda/storage/iscsi.py
diff options
context:
space:
mode:
Diffstat (limited to 'pyanaconda/storage/iscsi.py')
-rw-r--r--pyanaconda/storage/iscsi.py437
1 files changed, 0 insertions, 437 deletions
diff --git a/pyanaconda/storage/iscsi.py b/pyanaconda/storage/iscsi.py
deleted file mode 100644
index 8b7cbf80d..000000000
--- a/pyanaconda/storage/iscsi.py
+++ /dev/null
@@ -1,437 +0,0 @@
-#
-# iscsi.py - iscsi class
-#
-# Copyright (C) 2005, 2006 IBM, Inc. All rights reserved.
-# Copyright (C) 2006 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/>.
-#
-
-from . import ROOT_PATH
-from udev import udev_settle
-from . import util
-from .flags import flags
-import os
-import logging
-import shutil
-import time
-import hashlib
-import random
-import itertools
-log = logging.getLogger("storage")
-
-import gettext
-_ = lambda x: gettext.ldgettext("anaconda", x)
-
-has_libiscsi = True
-try:
- import libiscsi
-except ImportError:
- has_libiscsi = False
-
-# Note that stage2 copies all files under /sbin to /usr/sbin
-ISCSID=""
-INITIATOR_FILE="/etc/iscsi/initiatorname.iscsi"
-
-ISCSI_MODULES=['cxgb3i', 'bnx2i', 'be2iscsi']
-
-def has_iscsi():
- global ISCSID
-
- if not os.access("/sys/module/iscsi_tcp", os.X_OK):
- return False
-
- if not ISCSID:
- location = util.find_program_in_path("iscsid")
- if not location:
- return False
- ISCSID = location
- log.info("ISCSID is %s" % (ISCSID,))
-
- return True
-
-def randomIname():
- """Generate a random initiator name the same way as iscsi-iname"""
-
- s = "iqn.1994-05.com.domain:01."
- m = hashlib.md5()
- u = os.uname()
- for i in u:
- m.update(i)
- dig = m.hexdigest()
-
- for i in range(0, 6):
- s += dig[random.randrange(0, 32)]
- return s
-
-class iscsi(object):
- """ iSCSI utility class.
-
- This class will automatically discover and login to iBFT (or
- other firmware) configured iscsi devices when the startup() method
- gets called. It can also be used to manually configure iscsi devices
- through the addTarget() method.
-
- As this class needs to make sure certain things like starting iscsid
- and logging in to firmware discovered disks only happens once
- and as it keeps a global list of all iSCSI devices it is implemented as
- a Singleton.
- """
-
- def __init__(self):
- # Dictionary of discovered targets containing list of (node,
- # logged_in) tuples.
- self.discovered_targets = {}
- # This list contains nodes discovered through iBFT (or other firmware)
- self.ibftNodes = []
- self._initiator = ""
- self.initiatorSet = False
- self.started = False
- self.ifaces = {}
-
- if flags.ibft:
- try:
- initiatorname = libiscsi.get_firmware_initiator_name()
- self._initiator = initiatorname
- self.initiatorSet = True
- except Exception:
- pass
-
- # So that users can write iscsi() to get the singleton instance
- def __call__(self):
- return self
-
- def _getInitiator(self):
- if self._initiator != "":
- return self._initiator
-
- return randomIname()
-
- def _setInitiator(self, val):
- if self.initiatorSet and val != self._initiator:
- raise ValueError, _("Unable to change iSCSI initiator name once set")
- if len(val) == 0:
- raise ValueError, _("Must provide an iSCSI initiator name")
- self._initiator = val
-
- initiator = property(_getInitiator, _setInitiator)
-
- def active_nodes(self, target=None):
- """Nodes logged in to"""
- if target:
- return [node for (node, logged_in) in
- self.discovered_targets.get(target, [])
- if logged_in]
- else:
- return [node for (node, logged_in) in
- itertools.chain(*self.discovered_targets.values())
- if logged_in] + self.ibftNodes
-
- def _getMode(self):
- if not self.active_nodes():
- return "none"
- if self.ifaces:
- return "bind"
- else:
- return "default"
-
- mode = property(_getMode)
-
- def _mark_node_active(self, node, active=True):
- """Mark node as one logged in to
-
- Returns False if not found
- """
- for target_nodes in self.discovered_targets.values():
- for nodeinfo in target_nodes:
- if nodeinfo[0] is node:
- nodeinfo[1] = active
- return True
- return False
-
-
- def _startIBFT(self):
- if not flags.ibft:
- return
-
- try:
- found_nodes = libiscsi.discover_firmware()
- except Exception:
- log.info("iscsi: No IBFT info found.");
- # an exception here means there is no ibft firmware, just return
- return
-
- for node in found_nodes:
- try:
- node.login()
- log.info("iscsi IBFT: logged into %s at %s:%s through %s" % (
- node.name, node.address, node.port, node.iface))
- self.ibftNodes.append(node)
- except IOError as e:
- log.error("Could not log into ibft iscsi target %s: %s" %
- (node.name, str(e)))
- pass
-
- self.stabilize()
-
- def stabilize(self):
- # Wait for udev to create the devices for the just added disks
-
- # It is possible when we get here the events for the new devices
- # are not send yet, so sleep to make sure the events are fired
- time.sleep(2)
- udev_settle()
-
- def create_interfaces(self, ifaces):
- for iface in ifaces:
- iscsi_iface_name = "iface%d" % len(self.ifaces)
- #iscsiadm -m iface -I iface0 --op=new
- util.run_program(["iscsiadm", "-m", "iface",
- "-I", iscsi_iface_name, "--op=new"])
- #iscsiadm -m iface -I iface0 --op=update -n iface.net_ifacename -v eth0
- util.run_program(["iscsiadm", "-m", "iface",
- "-I", iscsi_iface_name, "--op=update",
- "-n", "iface.net_ifacename", "-v", iface])
-
- self.ifaces[iscsi_iface_name] = iface
- log.debug("created_interface %s:%s" % (iscsi_iface_name, iface))
-
- def delete_interfaces(self):
- if not self.ifaces:
- return None
- for iscsi_iface_name in self.ifaces:
- #iscsiadm -m iface -I iface0 --op=delete
- util.run_program(["iscsiadm", "-m", "iface",
- "-I", iscsi_iface_name, "--op=delete"])
- self.ifaces = {}
-
- def startup(self):
- if self.started:
- return
-
- if not has_iscsi():
- return
-
- if self._initiator == "":
- log.info("no initiator set")
- return
-
- log.debug("Setting up %s" % (INITIATOR_FILE, ))
- log.info("iSCSI initiator name %s", self.initiator)
- if os.path.exists(INITIATOR_FILE):
- os.unlink(INITIATOR_FILE)
- if not os.path.isdir("/etc/iscsi"):
- os.makedirs("/etc/iscsi", 0755)
- fd = os.open(INITIATOR_FILE, os.O_RDWR | os.O_CREAT)
- os.write(fd, "InitiatorName=%s\n" %(self.initiator))
- os.close(fd)
- self.initiatorSet = True
-
- for dir in ['ifaces','isns','nodes','send_targets','slp','static']:
- fulldir = "/var/lib/iscsi/%s" % (dir,)
- if not os.path.isdir(fulldir):
- os.makedirs(fulldir, 0755)
-
- log.info("iSCSI startup")
- util.run_program(['modprobe', '-a'] + ISCSI_MODULES)
- # iscsiuio is needed by Broadcom offload cards (bnx2i). Currently
- # not present in iscsi-initiator-utils for Fedora.
- try:
- iscsiuio = util.find_program_in_path('iscsiuio',
- raise_on_error=True)
- except RuntimeError:
- log.info("iscsi: iscsiuio not found.")
- else:
- log.debug("iscsi: iscsiuio is at %s" % iscsiuio)
- util.run_program([iscsiuio])
- # run the daemon
- util.run_program([ISCSID])
- time.sleep(1)
-
- self._startIBFT()
- self.started = True
-
- def discover(self, ipaddr, port="3260", username=None, password=None,
- r_username=None, r_password=None, intf=None):
- """
- Discover iSCSI nodes on the target available for login.
-
- If we are logged in a node discovered for specified target
- do not do the discovery again as it can corrupt credentials
- stored for the node (setAuth and getAuth are using database
- in /var/lib/iscsi/nodes which is filled by discovery). Just
- return nodes obtained and stored in the first discovery
- instead.
-
- Returns list of nodes user can log in.
- """
- authinfo = None
-
- if not has_iscsi():
- raise IOError, _("iSCSI not available")
- if self._initiator == "":
- raise ValueError, _("No initiator name set")
-
- if self.active_nodes((ipaddr, port)):
- log.debug("iSCSI: skipping discovery of %s:%s due to active nodes" %
- (ipaddr, port))
- else:
- if username or password or r_username or r_password:
- # Note may raise a ValueError
- authinfo = libiscsi.chapAuthInfo(username=username,
- password=password,
- reverse_username=r_username,
- reverse_password=r_password)
- self.startup()
-
- # Note may raise an IOError
- found_nodes = libiscsi.discover_sendtargets(address=ipaddr,
- port=int(port),
- authinfo=authinfo)
- if found_nodes is None:
- return None
- self.discovered_targets[(ipaddr, port)] = []
- for node in found_nodes:
- self.discovered_targets[(ipaddr, port)].append([node, False])
- log.debug("discovered iSCSI node: %s" % node.name)
-
- # only return the nodes we are not logged into yet
- return [node for (node, logged_in) in
- self.discovered_targets[(ipaddr, port)]
- if not logged_in]
-
- def log_into_node(self, node, username=None, password=None,
- r_username=None, r_password=None, intf=None):
- """
- Raises IOError.
- """
- rc = False # assume failure
- msg = ""
-
- if intf:
- w = intf.waitWindow(_("Logging in to iSCSI node"),
- _("Logging in to iSCSI node %s") % node.name)
- try:
- authinfo = None
- if username or password or r_username or r_password:
- # may raise a ValueError
- authinfo = libiscsi.chapAuthInfo(username=username,
- password=password,
- reverse_username=r_username,
- reverse_password=r_password)
- node.setAuth(authinfo)
- node.login()
- rc = True
- log.info("iSCSI: logged into %s at %s:%s through %s" % (
- node.name, node.address, node.port, node.iface))
- if not self._mark_node_active(node):
- log.error("iSCSI: node not found among discovered")
- except (IOError, ValueError) as e:
- msg = str(e)
- log.warning("iSCSI: could not log into %s: %s" % (node.name, msg))
- if intf:
- w.pop()
-
- return (rc, msg)
-
- # NOTE: the same credentials are used for discovery and login
- # (unlike in UI)
- def addTarget(self, ipaddr, port="3260", user=None, pw=None,
- user_in=None, pw_in=None, intf=None, target=None, iface=None):
- found = 0
- logged_in = 0
-
- found_nodes = self.discover(ipaddr, port, user, pw, user_in, pw_in,
- intf)
- if found_nodes == None:
- raise IOError, _("No iSCSI nodes discovered")
-
- for node in found_nodes:
- if target and target != node.name:
- log.debug("iscsi: skipping logging to iscsi node '%s'" %
- node.name)
- continue
- if iface:
- node_net_iface = self.ifaces.get(node.iface, node.iface)
- if iface != node_net_iface:
- log.debug("iscsi: skipping logging to iscsi node '%s' via %s" %
- (node.name, node_net_iface))
- continue
-
- found = found + 1
-
- (rc, msg) = self.log_into_node(node, user, pw, user_in, pw_in,
- intf)
- if rc:
- logged_in = logged_in +1
-
- if found == 0:
- raise IOError, _("No new iSCSI nodes discovered")
-
- if logged_in == 0:
- raise IOError, _("Could not log in to any of the discovered nodes")
-
- self.stabilize(intf)
-
- def write(self, storage):
- if not self.initiatorSet:
- return
-
- # set iscsi nodes to autostart
- root = storage.rootDevice
- for node in self.active_nodes():
- autostart = True
- disks = self.getNodeDisks(node, storage)
- for disk in disks:
- # nodes used for root get started by the initrd
- if root.dependsOn(disk):
- autostart = False
-
- if autostart:
- node.setParameter("node.startup", "automatic")
-
- if not os.path.isdir(ROOT_PATH + "/etc/iscsi"):
- os.makedirs(ROOT_PATH + "/etc/iscsi", 0755)
- fd = os.open(ROOT_PATH + INITIATOR_FILE, os.O_RDWR | os.O_CREAT)
- os.write(fd, "InitiatorName=%s\n" %(self.initiator))
- os.close(fd)
-
- # copy "db" files. *sigh*
- if os.path.isdir(ROOT_PATH + "/var/lib/iscsi"):
- shutil.rmtree(ROOT_PATH + "/var/lib/iscsi")
- if os.path.isdir("/var/lib/iscsi"):
- shutil.copytree("/var/lib/iscsi", ROOT_PATH + "/var/lib/iscsi",
- symlinks=True)
-
- def getNode(self, name, address, port, iface):
- for node in self.active_nodes():
- if node.name == name and node.address == address and \
- node.port == int(port) and node.iface == iface:
- return node
-
- return None
-
- def getNodeDisks(self, node, storage):
- nodeDisks = []
- iscsiDisks = storage.devicetree.getDevicesByType("iscsi")
- for disk in iscsiDisks:
- if disk.node == node:
- nodeDisks.append(disk)
-
- return nodeDisks
-
-# Create iscsi singleton
-iscsi = iscsi()
-
-# vim:tw=78:ts=4:et:sw=4