Пример #1
0
    def create_lv_snapshot(self, name, source_lv_name, lv_type='default'):
        """Creates a snapshot of a logical volume.

        :param name: Name to assign to new snapshot
        :param source_lv_name: Name of Logical Volume to snapshot
        :param lv_type: Type of LV (default or thin)

        """
        source_lvref = self.get_volume(source_lv_name)
        if source_lvref is None:
            LOG.error(
                _LE("Trying to create snapshot by non-existent LV: %s") %
                source_lv_name)
            raise exception.VolumeDeviceNotFound(device=source_lv_name)
        cmd = [
            'lvcreate', '--name', name, '--snapshot',
            '%s/%s' % (self.vg_name, source_lv_name)
        ]
        if lv_type != 'thin':
            size = source_lvref['size']
            cmd.extend(['-L', '%sg' % (size)])

        try:
            self._execute(*cmd,
                          root_helper=self._root_helper,
                          run_as_root=True)
        except putils.ProcessExecutionError as err:
            LOG.exception(_LE('Error creating snapshot'))
            LOG.error(_LE('Cmd     :%s') % err.cmd)
            LOG.error(_LE('StdOut  :%s') % err.stdout)
            LOG.error(_LE('StdErr  :%s') % err.stderr)
            raise
Пример #2
0
 def wait_for_path(self, volume_path):
     """Wait for a path to show up."""
     LOG.debug("Checking to see if %s exists yet.", volume_path)
     if not os.path.exists(volume_path):
         LOG.debug("%(path)s doesn't exists yet.", {'path': volume_path})
         raise exception.VolumeDeviceNotFound(device=volume_path)
     else:
         LOG.debug("%s has shown up.", volume_path)
Пример #3
0
        def _wait_for_discovery(aoe_path):
            if os.path.exists(aoe_path):
                raise loopingcall.LoopingCallDone

            if waiting_status['tries'] >= self.device_scan_attempts:
                raise exception.VolumeDeviceNotFound(device=aoe_path)

            LOG.warn(_("AoE volume not yet found at: %(path)s. "
                       "Try number: %(tries)s"),
                     {'path': aoe_device,
                      'tries': waiting_status['tries']})

            self._aoe_discover()
            waiting_status['tries'] += 1
Пример #4
0
    def disconnect_volume(self, connection_properties, device_info):
        """Detach the volume from instance_name.

        connection_properties for iSCSI must include:
        target_portal(s) - IP and optional port
        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
            host_devices = self._get_device_path(connection_properties)
            # Choose an accessible host device
            for dev in host_devices:
                if os.path.exists(dev):
                    host_device = dev
                    multipath_device = self._get_multipath_device_name(dev)
                    if multipath_device:
                        break
            if not host_device:
                LOG.error(_LE("No accessible volume device: %(host_devices)s"),
                          {'host_devices': host_devices})
                raise exception.VolumeDeviceNotFound(device=host_devices)

            if multipath_device:
                device_realpath = os.path.realpath(host_device)
                self._linuxscsi.remove_multipath_device(device_realpath)
                return self._disconnect_volume_multipath_iscsi(
                    connection_properties, multipath_device)

        # When multiple portals/iqns/luns are specified, we need to remove
        # unused devices created by logging into other LUNs' session.
        ips_iqns_luns = self._multipath_targets(connection_properties)
        if not ips_iqns_luns:
            ips_iqns_luns = [[
                connection_properties['target_portal'],
                connection_properties['target_iqn'],
                connection_properties.get('target_lun', 0)
            ]]
        for props in self._iterate_multiple_targets(connection_properties,
                                                    ips_iqns_luns):
            self._disconnect_volume_iscsi(props)
Пример #5
0
    def connect_volume(self, connection_properties):
        """Attach the volume to instance_name.

        connection_properties for iSCSI must include:
        target_portal - ip and optional port
        target_iqn - iSCSI Qualified Name
        target_lun - LUN id of the volume
        """

        device_info = {'type': 'block'}

        if self.use_multipath:
            #multipath installed, discovering other targets if available
            target_portal = connection_properties['target_portal']
            out = self._run_iscsiadm_bare(['-m',
                                           'discovery',
                                           '-t',
                                           'sendtargets',
                                           '-p',
                                           target_portal],
                                          check_exit_code=[0, 255])[0] \
                or ""

            for ip, iqn in self._get_target_portals_from_iscsiadm_output(out):
                props = connection_properties.copy()
                props['target_portal'] = ip
                props['target_iqn'] = iqn
                self._connect_to_iscsi_portal(props)

            self._rescan_iscsi()
        else:
            self._connect_to_iscsi_portal(connection_properties)

        host_device = self._get_device_path(connection_properties)

        # The /dev/disk/by-path/... node is not always present immediately
        # TODO(justinsb): This retry-with-delay is a pattern, move to utils?
        tries = 0
        while not os.path.exists(host_device):
            if tries >= self.device_scan_attempts:
                raise exception.VolumeDeviceNotFound(device=host_device)

            LOG.warn(
                _LW("ISCSI volume not yet found at: %(host_device)s. "
                    "Will rescan & retry.  Try number: %(tries)s"), {
                        'host_device': host_device,
                        'tries': tries
                    })

            # The rescan isn't documented as being necessary(?), but it helps
            self._run_iscsiadm(connection_properties, ("--rescan", ))

            tries = tries + 1
            if not os.path.exists(host_device):
                time.sleep(tries**2)

        if tries != 0:
            LOG.debug(
                "Found iSCSI node %(host_device)s "
                "(after %(tries)s rescans)", {
                    'host_device': host_device,
                    'tries': tries
                })

        if self.use_multipath:
            #we use the multipath device instead of the single path device
            self._rescan_multipath()
            multipath_device = self._get_multipath_device_name(host_device)
            if multipath_device is not None:
                host_device = multipath_device

        device_info['path'] = host_device
        return device_info
Пример #6
0
    def connect_volume(self, connection_properties):
        """Attach the volume to instance_name.

        connection_properties for iSCSI must include:
        target_portal(s) - ip and optional port
        target_iqn(s) - iSCSI Qualified Name
        target_lun(s) - LUN id of the volume
        Note that plural keys may be used when use_multipath=True
        """

        device_info = {'type': 'block'}

        if self.use_multipath:
            # multipath installed, discovering other targets if available
            for ip, iqn in self._discover_iscsi_portals(connection_properties):
                props = copy.deepcopy(connection_properties)
                props['target_portal'] = ip
                props['target_iqn'] = iqn
                self._connect_to_iscsi_portal(props)

            self._rescan_iscsi()
            host_devices = self._get_device_path(connection_properties)
        else:
            self._connect_to_iscsi_portal(connection_properties)
            host_devices = self._get_device_path(connection_properties)

        # The /dev/disk/by-path/... node is not always present immediately
        # TODO(justinsb): This retry-with-delay is a pattern, move to utils?
        tries = 0
        # Loop until at least 1 path becomes available
        while all(map(lambda x: not os.path.exists(x), host_devices)):
            if tries >= self.device_scan_attempts:
                raise exception.VolumeDeviceNotFound(device=host_devices)

            LOG.warn(
                _LW("ISCSI volume not yet found at: %(host_devices)s. "
                    "Will rescan & retry.  Try number: %(tries)s"), {
                        'host_devices': host_devices,
                        'tries': tries
                    })

            # The rescan isn't documented as being necessary(?), but it helps
            if self.use_multipath:
                self._rescan_iscsi()
            else:
                self._run_iscsiadm(connection_properties, ("--rescan", ))

            tries = tries + 1
            if all(map(lambda x: not os.path.exists(x), host_devices)):
                time.sleep(tries**2)
            else:
                break

        if tries != 0:
            LOG.debug(
                "Found iSCSI node %(host_devices)s "
                "(after %(tries)s rescans)", {
                    'host_devices': host_devices,
                    'tries': tries
                })

        # Choose an accessible host device
        host_device = next(dev for dev in host_devices if os.path.exists(dev))

        if self.use_multipath:
            # we use the multipath device instead of the single path device
            self._rescan_multipath()
            multipath_device = self._get_multipath_device_name(host_device)
            if multipath_device is not None:
                host_device = multipath_device

        device_info['path'] = host_device
        return device_info