Created
January 19, 2016 19:42
-
-
Save patrick-east/aae38b179fb1ae2bbc40 to your computer and use it in GitHub Desktop.
MOS 7 patches
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/cinder/brick/initiator/connector.py b/cinder/brick/initiator/connector.py | |
| index 7514c6f..605e77d 100644 | |
| --- a/cinder/brick/initiator/connector.py | |
| +++ b/cinder/brick/initiator/connector.py | |
| @@ -43,6 +43,8 @@ LOG = logging.getLogger(__name__) | |
| synchronized = lockutils.synchronized_with_prefix('brick-') | |
| DEVICE_SCAN_ATTEMPTS_DEFAULT = 3 | |
| MULTIPATH_ERROR_REGEX = re.compile("\w{3} \d+ \d\d:\d\d:\d\d \|.*$") | |
| +MULTIPATH_DEV_CHECK_REGEX = re.compile("\s+dm-\d+\s+") | |
| +MULTIPATH_PATH_CHECK_REGEX = re.compile("\s+\d+:\d+:\d+:\d+\s+") | |
| def _check_multipathd_running(root_helper, enforce_multipath): | |
| @@ -136,21 +138,21 @@ class InitiatorConnector(executor.Executor): | |
| *args, **kwargs) | |
| elif protocol == "FIBRE_CHANNEL": | |
| if arch in (S390, S390X): | |
| - return FibreChannelConnectorS390X(root_helper=root_helper, | |
| - driver=driver, | |
| - execute=execute, | |
| - use_multipath=use_multipath, | |
| - device_scan_attempts= | |
| - device_scan_attempts, | |
| - *args, **kwargs) | |
| + return FibreChannelConnectorS390X( | |
| + root_helper=root_helper, | |
| + driver=driver, | |
| + execute=execute, | |
| + use_multipath=use_multipath, | |
| + device_scan_attempts=device_scan_attempts, | |
| + *args, **kwargs) | |
| else: | |
| - return FibreChannelConnector(root_helper=root_helper, | |
| - driver=driver, | |
| - execute=execute, | |
| - use_multipath=use_multipath, | |
| - device_scan_attempts= | |
| - device_scan_attempts, | |
| - *args, **kwargs) | |
| + return FibreChannelConnector( | |
| + root_helper=root_helper, | |
| + driver=driver, | |
| + execute=execute, | |
| + use_multipath=use_multipath, | |
| + device_scan_attempts=device_scan_attempts, | |
| + *args, **kwargs) | |
| elif protocol == "AOE": | |
| return AoEConnector(root_helper=root_helper, | |
| driver=driver, | |
| @@ -171,12 +173,12 @@ class InitiatorConnector(executor.Executor): | |
| device_scan_attempts=device_scan_attempts, | |
| *args, **kwargs) | |
| elif protocol == "HUAWEISDSHYPERVISOR": | |
| - return HuaweiStorHyperConnector(root_helper=root_helper, | |
| - driver=driver, | |
| - execute=execute, | |
| - device_scan_attempts= | |
| - device_scan_attempts, | |
| - *args, **kwargs) | |
| + return HuaweiStorHyperConnector( | |
| + root_helper=root_helper, | |
| + driver=driver, | |
| + execute=execute, | |
| + device_scan_attempts=device_scan_attempts, | |
| + *args, **kwargs) | |
| else: | |
| msg = (_("Invalid InitiatorConnector protocol " | |
| "specified %(protocol)s") % | |
| @@ -226,11 +228,11 @@ class ISCSIConnector(InitiatorConnector): | |
| device_scan_attempts=DEVICE_SCAN_ATTEMPTS_DEFAULT, | |
| *args, **kwargs): | |
| self._linuxscsi = linuxscsi.LinuxSCSI(root_helper, execute) | |
| - super(ISCSIConnector, self).__init__(root_helper, driver=driver, | |
| - execute=execute, | |
| - device_scan_attempts= | |
| - device_scan_attempts, | |
| - *args, **kwargs) | |
| + super(ISCSIConnector, self).__init__( | |
| + root_helper, driver=driver, | |
| + execute=execute, | |
| + device_scan_attempts=device_scan_attempts, | |
| + *args, **kwargs) | |
| self.use_multipath = use_multipath | |
| def set_execute(self, execute): | |
| @@ -365,12 +367,6 @@ class ISCSIConnector(InitiatorConnector): | |
| target_iqn(s) - iSCSI Qualified Name | |
| target_lun(s) - LUN id of the volume | |
| """ | |
| - # Moved _rescan_iscsi and _rescan_multipath | |
| - # from _disconnect_volume_multipath_iscsi to here. | |
| - # Otherwise, if we do rescan after _linuxscsi.remove_multipath_device | |
| - # but before logging out, the removed devices under /dev/disk/by-path | |
| - # will reappear after rescan. | |
| - self._rescan_iscsi() | |
| if self.use_multipath: | |
| self._rescan_multipath() | |
| host_device = multipath_device = None | |
| @@ -447,13 +443,17 @@ class ISCSIConnector(InitiatorConnector): | |
| def _run_iscsiadm(self, connection_properties, iscsi_command, **kwargs): | |
| check_exit_code = kwargs.pop('check_exit_code', 0) | |
| + attempts = kwargs.pop('attempts', 1) | |
| + delay_on_retry = kwargs.pop('delay_on_retry', True) | |
| (out, err) = self._execute('iscsiadm', '-m', 'node', '-T', | |
| connection_properties['target_iqn'], | |
| '-p', | |
| connection_properties['target_portal'], | |
| *iscsi_command, run_as_root=True, | |
| root_helper=self._root_helper, | |
| - check_exit_code=check_exit_code) | |
| + check_exit_code=check_exit_code, | |
| + attempts=attempts, | |
| + delay_on_retry=delay_on_retry) | |
| LOG.debug("iscsiadm %s: stdout=%s stderr=%s" % | |
| (iscsi_command, out, err)) | |
| return (out, err) | |
| @@ -467,12 +467,21 @@ class ISCSIConnector(InitiatorConnector): | |
| def _get_target_portals_from_iscsiadm_output(self, output): | |
| # return both portals and iqns | |
| - return [line.split() for line in output.splitlines()] | |
| + # | |
| + # as we are parsing a command line utility, allow for the | |
| + # possibility that additional debug data is spewed in the | |
| + # stream, and only grab actual ip / iqn lines. | |
| + targets = [] | |
| + for data in [line.split() for line in output.splitlines()]: | |
| + if len(data) == 2 and data[1].startswith('iqn.'): | |
| + targets.append(data) | |
| + return targets | |
| def _disconnect_volume_multipath_iscsi(self, connection_properties, | |
| multipath_name): | |
| """This removes a multipath device and it's LUNs.""" | |
| LOG.debug("Disconnect multipath device %s" % multipath_name) | |
| + mpath_map = self._get_multipath_device_map() | |
| block_devices = self.driver.get_all_block_devices() | |
| devices = [] | |
| for dev in block_devices: | |
| @@ -480,14 +489,24 @@ class ISCSIConnector(InitiatorConnector): | |
| if "/mapper/" in dev: | |
| devices.append(dev) | |
| else: | |
| - mpdev = self._get_multipath_device_name(dev) | |
| + mpdev = mpath_map.get(dev) | |
| if mpdev: | |
| devices.append(mpdev) | |
| # Do a discovery to find all targets. | |
| # Targets for multiple paths for the same multipath device | |
| # may not be the same. | |
| - ips_iqns = self._discover_iscsi_portals(connection_properties) | |
| + all_ips_iqns = self._discover_iscsi_portals(connection_properties) | |
| + | |
| + # As discovery result may contain other targets' iqns, extract targets | |
| + # to be disconnected whose block devices are already deleted here. | |
| + ips_iqns = [] | |
| + entries = map(lambda x: x.lstrip('ip-').split('-lun-')[0], | |
| + self._get_iscsi_devices()) | |
| + for ip, iqn in all_ips_iqns: | |
| + ip_iqn = "%s-iscsi-%s" % (ip.split(",")[0], iqn) | |
| + if ip_iqn not in entries: | |
| + ips_iqns.append([ip, iqn]) | |
| if not devices: | |
| # disconnect if no other multipath devices | |
| @@ -495,8 +514,7 @@ class ISCSIConnector(InitiatorConnector): | |
| return | |
| # Get a target for all other multipath devices | |
| - other_iqns = [self._get_multipath_iqn(device) | |
| - for device in devices] | |
| + other_iqns = self._get_multipath_iqns(devices, mpath_map) | |
| # Get all the targets for the current multipath device | |
| current_iqns = [iqn for ip, iqn in ips_iqns] | |
| @@ -587,7 +605,9 @@ class ISCSIConnector(InitiatorConnector): | |
| self._run_iscsiadm(connection_properties, ("--logout",), | |
| check_exit_code=[0, 21, 255]) | |
| self._run_iscsiadm(connection_properties, ('--op', 'delete'), | |
| - check_exit_code=[0, 21, 255]) | |
| + check_exit_code=[0, 21, 255], | |
| + attempts=5, | |
| + delay_on_retry=True) | |
| def _get_multipath_device_name(self, single_path_device): | |
| device = os.path.realpath(single_path_device) | |
| @@ -617,14 +637,34 @@ class ISCSIConnector(InitiatorConnector): | |
| self._rescan_multipath() | |
| - def _get_multipath_iqn(self, multipath_device): | |
| + def _get_multipath_iqns(self, multipath_devices, mpath_map): | |
| entries = self._get_iscsi_devices() | |
| + iqns = [] | |
| for entry in entries: | |
| entry_real_path = os.path.realpath("/dev/disk/by-path/%s" % entry) | |
| - entry_multipath = self._get_multipath_device_name(entry_real_path) | |
| - if entry_multipath == multipath_device: | |
| - return entry.split("iscsi-")[1].split("-lun")[0] | |
| - return None | |
| + entry_multipath = mpath_map.get(entry_real_path) | |
| + if entry_multipath and entry_multipath in multipath_devices: | |
| + iqns.append(entry.split("iscsi-")[1].split("-lun")[0]) | |
| + return iqns | |
| + | |
| + def _get_multipath_device_map(self): | |
| + out = self._run_multipath(['-ll'], check_exit_code=[0, 1])[0] | |
| + mpath_line = [line for line in out.splitlines() | |
| + if not re.match(MULTIPATH_ERROR_REGEX, line)] | |
| + mpath_dev = None | |
| + mpath_map = {} | |
| + for line in out.splitlines(): | |
| + m = MULTIPATH_DEV_CHECK_REGEX.split(line) | |
| + if len(m) >= 2: | |
| + mpath_dev = '/dev/mapper/' + m[0].split(" ")[0] | |
| + continue | |
| + m = MULTIPATH_PATH_CHECK_REGEX.split(line) | |
| + if len(m) >= 2: | |
| + mpath_map['/dev/' + m[1].split(" ")[0]] = mpath_dev | |
| + | |
| + if mpath_line and not mpath_map: | |
| + LOG.warn(_LW("Failed to parse the output of multipath -ll.")) | |
| + return mpath_map | |
| def _run_iscsiadm_bare(self, iscsi_command, **kwargs): | |
| check_exit_code = kwargs.pop('check_exit_code', 0) | |
| @@ -676,11 +716,11 @@ class FibreChannelConnector(InitiatorConnector): | |
| *args, **kwargs): | |
| self._linuxscsi = linuxscsi.LinuxSCSI(root_helper, execute) | |
| self._linuxfc = linuxfc.LinuxFibreChannel(root_helper, execute) | |
| - super(FibreChannelConnector, self).__init__(root_helper, driver=driver, | |
| - execute=execute, | |
| - device_scan_attempts= | |
| - device_scan_attempts, | |
| - *args, **kwargs) | |
| + super(FibreChannelConnector, self).__init__( | |
| + root_helper, driver=driver, | |
| + execute=execute, | |
| + device_scan_attempts=device_scan_attempts, | |
| + *args, **kwargs) | |
| self.use_multipath = use_multipath | |
| def set_execute(self, execute): | |
| @@ -880,12 +920,12 @@ class FibreChannelConnectorS390X(FibreChannelConnector): | |
| execute=putils.execute, use_multipath=False, | |
| device_scan_attempts=DEVICE_SCAN_ATTEMPTS_DEFAULT, | |
| *args, **kwargs): | |
| - super(FibreChannelConnectorS390X, self).__init__(root_helper, | |
| - driver=driver, | |
| - execute=execute, | |
| - device_scan_attempts= | |
| - device_scan_attempts, | |
| - *args, **kwargs) | |
| + super(FibreChannelConnectorS390X, self).__init__( | |
| + root_helper, | |
| + driver=driver, | |
| + execute=execute, | |
| + device_scan_attempts=device_scan_attempts, | |
| + *args, **kwargs) | |
| LOG.debug("Initializing Fibre Channel connector for S390") | |
| self._linuxscsi = linuxscsi.LinuxSCSI(root_helper, execute) | |
| self._linuxfc = linuxfc.LinuxFibreChannelS390X(root_helper, execute) | |
| @@ -942,11 +982,12 @@ class AoEConnector(InitiatorConnector): | |
| execute=putils.execute, | |
| device_scan_attempts=DEVICE_SCAN_ATTEMPTS_DEFAULT, | |
| *args, **kwargs): | |
| - super(AoEConnector, self).__init__(root_helper, driver=driver, | |
| - execute=execute, | |
| - device_scan_attempts= | |
| - device_scan_attempts, | |
| - *args, **kwargs) | |
| + super(AoEConnector, self).__init__( | |
| + root_helper, | |
| + driver=driver, | |
| + execute=execute, | |
| + device_scan_attempts=device_scan_attempts, | |
| + *args, **kwargs) | |
| def _get_aoe_info(self, connection_properties): | |
| shelf = connection_properties['target_shelf'] | |
| @@ -1074,11 +1115,12 @@ class RemoteFsConnector(InitiatorConnector): | |
| self._remotefsclient = remotefs.RemoteFsClient(mount_type, root_helper, | |
| execute=execute, | |
| *args, **kwargs) | |
| - super(RemoteFsConnector, self).__init__(root_helper, driver=driver, | |
| - execute=execute, | |
| - device_scan_attempts= | |
| - device_scan_attempts, | |
| - *args, **kwargs) | |
| + super(RemoteFsConnector, self).__init__( | |
| + root_helper, | |
| + driver=driver, | |
| + execute=execute, | |
| + device_scan_attempts=device_scan_attempts, | |
| + *args, **kwargs) | |
| def set_execute(self, execute): | |
| super(RemoteFsConnector, self).set_execute(execute) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/cinder/volume/drivers/pure.py b/cinder/volume/drivers/pure.py | |
| index c35b7df..dfa0ab7 100644 | |
| --- a/cinder/volume/drivers/pure.py | |
| +++ b/cinder/volume/drivers/pure.py | |
| @@ -58,6 +58,8 @@ CHAP_SECRET_KEY = "PURE_TARGET_CHAP_SECRET" | |
| ERR_MSG_NOT_EXIST = "does not exist" | |
| ERR_MSG_PENDING_ERADICATION = "has been destroyed" | |
| +CONNECT_LOCK_NAME = 'PureVolumeDriver_connect' | |
| + | |
| def _get_vol_name(volume): | |
| """Return the name of the volume Purity will use.""" | |
| @@ -329,7 +331,7 @@ class PureISCSIDriver(san.SanISCSIDriver): | |
| } | |
| return username, password, initiator_updates | |
| - @utils.synchronized('PureISCSIDriver._connect', external=True) | |
| + @utils.synchronized(CONNECT_LOCK_NAME, external=True) | |
| def _connect(self, volume, connector, initiator_data): | |
| """Connect the host and volume; return dict describing connection.""" | |
| connection = None | |
| @@ -414,6 +416,7 @@ class PureISCSIDriver(san.SanISCSIDriver): | |
| return host | |
| return None | |
| + @utils.synchronized(CONNECT_LOCK_NAME, external=True) | |
| def terminate_connection(self, volume, connector, **kwargs): | |
| """Terminate connection.""" | |
| LOG.debug("Enter PureISCSIDriver.terminate_connection.") | |
| @@ -438,12 +441,21 @@ class PureISCSIDriver(san.SanISCSIDriver): | |
| ctxt.reraise = False | |
| LOG.error(_LE("Disconnection failed with message: " | |
| "%(msg)s."), {"msg": err.text}) | |
| - if (GENERATED_NAME.match(host_name) and | |
| - not self._array.list_host_connections(host_name, | |
| - private=True)): | |
| - LOG.info(_LI("Deleting unneeded host %(host_name)r."), | |
| - {"host_name": host_name}) | |
| - self._array.delete_host(host_name) | |
| + try: | |
| + if (GENERATED_NAME.match(host_name) and | |
| + not self._array.list_host_connections(host_name, | |
| + private=True)): | |
| + LOG.info(_LI("Deleting unneeded host %(host_name)r."), | |
| + {"host_name": host_name}) | |
| + self._array.delete_host(host_name) | |
| + except purestorage.PureHTTPError as err: | |
| + with excutils.save_and_reraise_exception() as ctxt: | |
| + if err.code == 400 and ERR_MSG_NOT_EXIST in err.text: | |
| + # Happens if the host is already deleted. | |
| + # This is fine though, just treat it as a warning. | |
| + ctxt.reraise = False | |
| + LOG.warning(_LW("Purity host deletion failed: " | |
| + "%(msg)s."), {"msg": err.text}) | |
| LOG.debug("Leave PureISCSIDriver._disconnect_host.") | |
| def get_volume_stats(self, refresh=False): |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/nova/storage/linuxscsi.py b/nova/storage/linuxscsi.py | |
| index 285dda9..53308a0 100644 | |
| --- a/nova/storage/linuxscsi.py | |
| +++ b/nova/storage/linuxscsi.py | |
| @@ -27,6 +27,7 @@ import re | |
| LOG = logging.getLogger(__name__) | |
| MULTIPATH_WWID_REGEX = re.compile("\((?P<wwid>.+)\)") | |
| +MULTIPATH_ERROR_REGEX = re.compile("\w{3} \d+ \d\d:\d\d:\d\d \|.*$") | |
| def echo_scsi_command(path, content): | |
| @@ -95,7 +96,15 @@ def remove_device(device): | |
| def find_multipath_device(device): | |
| - """Try and discover the multipath device for a volume.""" | |
| + """Discover multipath devices for a mpath device. | |
| + | |
| + This uses the slow multipath -l command to find a | |
| + multipath device description, then screen scrapes | |
| + the output to discover the multipath device name | |
| + and it's devices. | |
| + | |
| + """ | |
| + | |
| mdev = None | |
| devices = [] | |
| out = None | |
| @@ -110,39 +119,32 @@ def find_multipath_device(device): | |
| if out: | |
| lines = out.strip() | |
| lines = lines.split("\n") | |
| + lines = [line for line in lines | |
| + if not re.match(MULTIPATH_ERROR_REGEX, line)] | |
| if lines: | |
| - # Use the device name, be it the WWID, mpathN or custom alias of | |
| - # a device to build the device path. This should be the first item | |
| - # on the first line of output from `multipath -l /dev/${path}`. | |
| mdev_name = lines[0].split(" ")[0] | |
| mdev = '/dev/mapper/%s' % mdev_name | |
| - # Find the WWID for the LUN if we are using mpathN or aliases. | |
| + # Confirm that the device is present. | |
| + try: | |
| + os.stat(mdev) | |
| + except OSError: | |
| + LOG.warn(_LW("Couldn't find multipath device %s"), mdev) | |
| + return | |
| + | |
| wwid_search = MULTIPATH_WWID_REGEX.search(lines[0]) | |
| if wwid_search is not None: | |
| mdev_id = wwid_search.group('wwid') | |
| else: | |
| mdev_id = mdev_name | |
| - # Confirm that the device is present. | |
| - try: | |
| - os.stat(mdev) | |
| - except OSError: | |
| - LOG.warning(_LW("Couldn't find multipath device %s"), mdev) | |
| - return None | |
| - | |
| LOG.debug("Found multipath device = %s", mdev) | |
| device_lines = lines[3:] | |
| for dev_line in device_lines: | |
| if dev_line.find("policy") != -1: | |
| continue | |
| - if '#' in dev_line: | |
| - LOG.warning(_LW('Skip faulty line "%(dev_line)s" of' | |
| - ' multipath device %(mdev)s'), | |
| - {'mdev': mdev, 'dev_line': dev_line}) | |
| - continue | |
| dev_line = dev_line.lstrip(' |-`') | |
| dev_info = dev_line.split() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/nova/virt/libvirt/volume.py b/nova/virt/libvirt/volume.py | |
| index 59e3835..9445fc0 100644 | |
| --- a/nova/virt/libvirt/volume.py | |
| +++ b/nova/virt/libvirt/volume.py | |
| @@ -118,6 +118,10 @@ volume_opts = [ | |
| CONF = cfg.CONF | |
| CONF.register_opts(volume_opts, 'libvirt') | |
| +MULTIPATH_ERROR_REGEX = re.compile("\w{3} \d+ \d\d:\d\d:\d\d \|.*$") | |
| +MULTIPATH_DEV_CHECK_REGEX = re.compile("\s+dm-\d+\s+") | |
| +MULTIPATH_PATH_CHECK_REGEX = re.compile("\s+\d+:\d+:\d+:\d+\s+") | |
| + | |
| class LibvirtBaseVolumeDriver(object): | |
| """Base class for volume drivers.""" | |
| @@ -546,6 +550,7 @@ class LibvirtISCSIVolumeDriver(LibvirtBaseVolumeDriver): | |
| host_device = self._get_host_device(iscsi_properties) | |
| multipath_device = None | |
| if self.use_multipath: | |
| + self._rescan_multipath() | |
| if 'multipath_id' in iscsi_properties: | |
| multipath_device = ('/dev/mapper/%s' % | |
| iscsi_properties['multipath_id']) | |
| @@ -556,6 +561,8 @@ class LibvirtISCSIVolumeDriver(LibvirtBaseVolumeDriver): | |
| self).disconnect_volume(connection_info, disk_dev) | |
| if self.use_multipath and multipath_device: | |
| + device_realpath = os.path.realpath(host_device) | |
| + self._remove_multipath_device(device_realpath) | |
| return self._disconnect_volume_multipath_iscsi(iscsi_properties, | |
| multipath_device) | |
| @@ -579,6 +586,9 @@ class LibvirtISCSIVolumeDriver(LibvirtBaseVolumeDriver): | |
| device_name = os.path.basename(os.path.realpath(device_path)) | |
| delete_control = '/sys/block/' + device_name + '/device/delete' | |
| if os.path.exists(delete_control): | |
| + # flush any outstanding IO first | |
| + self._flush_device_io(device_path) | |
| + | |
| # Copy '1' from stdin to the device delete control file | |
| utils.execute('cp', '/dev/stdin', delete_control, | |
| process_input='1', run_as_root=True) | |
| @@ -599,46 +609,59 @@ class LibvirtISCSIVolumeDriver(LibvirtBaseVolumeDriver): | |
| % {'dev_mapper': disk_descriptor, | |
| 'msg': exc.message}) | |
| + def _remove_multipath_device(self, multipath_name): | |
| + """This removes LUNs associated with a multipath device | |
| + and the multipath device itself. | |
| + """ | |
| + | |
| + LOG.debug("remove multipath device %s", multipath_name) | |
| + mpath_dev = linuxscsi.find_multipath_device(multipath_name) | |
| + if mpath_dev: | |
| + devices = mpath_dev['devices'] | |
| + LOG.debug("multipath LUNs to remove %s", devices) | |
| + for device in devices: | |
| + self._delete_device(device['device']) | |
| + self._remove_multipath_device_descriptor(mpath_dev['id']) | |
| + | |
| + def _flush_device_io(self, device): | |
| + """This is used to flush any remaining IO in the buffers.""" | |
| + try: | |
| + LOG.debug("Flushing IO for device %s" % device) | |
| + utils.execute('blockdev', '--flushbufs', device, run_as_root=True) | |
| + except processutils.ProcessExecutionError as exc: | |
| + LOG.warn(_LW("Failed to flush IO buffers prior to removing" | |
| + " device: (%(code)s)"), {'code': exc.exit_code}) | |
| + | |
| def _disconnect_volume_multipath_iscsi(self, iscsi_properties, | |
| multipath_device): | |
| - self._rescan_iscsi() | |
| - self._rescan_multipath() | |
| + LOG.debug("Disconnect multipath device %s", multipath_device) | |
| block_devices = self.connection._get_all_block_devices() | |
| + mpath_map = self._get_multipath_device_map() | |
| devices = [] | |
| for dev in block_devices: | |
| - if "/mapper/" in dev: | |
| - devices.append(dev) | |
| - else: | |
| - mpdev = self._get_multipath_device_name(dev) | |
| - if mpdev: | |
| - devices.append(mpdev) | |
| + if os.path.exists(dev): | |
| + if "/mapper/" in dev: | |
| + devices.append(dev) | |
| + else: | |
| + mpdev = mpath_map.get(dev) | |
| + if mpdev: | |
| + devices.append(mpdev) | |
| # Do a discovery to find all targets. | |
| # Targets for multiple paths for the same multipath device | |
| # may not be the same. | |
| out = self._run_iscsiadm_discover(iscsi_properties) | |
| + all_ips_iqns = self._get_target_portals_from_iscsiadm_output(out) | |
| - # Extract targets for the current multipath device. | |
| + # As discovery result may contain other targets' iqns, extract targets | |
| + # to be disconnected whose block devices are already deleted here. | |
| ips_iqns = [] | |
| - entries = self._get_iscsi_devices() | |
| - for ip, iqn in self._get_target_portals_from_iscsiadm_output(out): | |
| + entries = [device.lstrip('ip-').split('-lun-')[0] | |
| + for device in self._get_iscsi_devices()] | |
| + for ip, iqn in all_ips_iqns: | |
| ip_iqn = "%s-iscsi-%s" % (ip.split(",")[0], iqn) | |
| - for entry in entries: | |
| - entry_ip_iqn = entry.split("-lun-")[0] | |
| - if entry_ip_iqn[:3] == "ip-": | |
| - entry_ip_iqn = entry_ip_iqn[3:] | |
| - elif entry_ip_iqn[:4] == "pci-": | |
| - # Look at an offset of len('pci-0000:00:00.0') | |
| - offset = entry_ip_iqn.find("ip-", 16, 21) | |
| - entry_ip_iqn = entry_ip_iqn[(offset + 3):] | |
| - if (ip_iqn != entry_ip_iqn): | |
| - continue | |
| - entry_real_path = os.path.realpath("/dev/disk/by-path/%s" % | |
| - entry) | |
| - entry_mpdev = self._get_multipath_device_name(entry_real_path) | |
| - if entry_mpdev == multipath_device: | |
| - ips_iqns.append([ip, iqn]) | |
| - break | |
| + if ip_iqn not in entries: | |
| + ips_iqns.append([ip, iqn]) | |
| if not devices: | |
| # disconnect if no other multipath devices | |
| @@ -662,15 +685,7 @@ class LibvirtISCSIVolumeDriver(LibvirtBaseVolumeDriver): | |
| if not in_use: | |
| # disconnect if no other multipath devices with same iqn | |
| self._disconnect_mpath(iscsi_properties, ips_iqns) | |
| - return | |
| - elif multipath_device not in devices: | |
| - # delete the devices associated w/ the unused multipath | |
| - self._delete_mpath(iscsi_properties, multipath_device, ips_iqns) | |
| - | |
| - # else do not disconnect iscsi portals, | |
| - # as they are used for other luns, | |
| - # just remove multipath mapping device descriptor | |
| - self._remove_multipath_device_descriptor(multipath_device) | |
| + | |
| return | |
| def _connect_to_iscsi_portal(self, iscsi_properties): | |
| @@ -740,7 +755,9 @@ class LibvirtISCSIVolumeDriver(LibvirtBaseVolumeDriver): | |
| self._run_iscsiadm(iscsi_properties, ("--logout",), | |
| check_exit_code=[0, 21, 255]) | |
| self._run_iscsiadm(iscsi_properties, ('--op', 'delete'), | |
| - check_exit_code=[0, 21, 255]) | |
| + check_exit_code=[0, 21, 255], | |
| + attempts=5, | |
| + delay_on_retry=True) | |
| def _get_multipath_device_name(self, single_path_device): | |
| device = os.path.realpath(single_path_device) | |
| @@ -768,21 +785,6 @@ class LibvirtISCSIVolumeDriver(LibvirtBaseVolumeDriver): | |
| return iscsi_devs | |
| - def _delete_mpath(self, iscsi_properties, multipath_device, ips_iqns): | |
| - entries = self._get_iscsi_devices() | |
| - # Loop through ips_iqns to construct all paths | |
| - iqn_luns = [] | |
| - for ip, iqn in ips_iqns: | |
| - iqn_lun = '%s-lun-%s' % (iqn, | |
| - iscsi_properties.get('target_lun', 0)) | |
| - iqn_luns.append(iqn_lun) | |
| - for dev in ['/dev/disk/by-path/%s' % dev for dev in entries]: | |
| - for iqn_lun in iqn_luns: | |
| - if iqn_lun in dev: | |
| - self._delete_device(dev) | |
| - | |
| - self._rescan_multipath() | |
| - | |
| def _disconnect_mpath(self, iscsi_properties, ips_iqns): | |
| for ip, iqn in ips_iqns: | |
| props = iscsi_properties.copy() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment