Ejemplo n.º 1
0
    def get_device_path(self, blockdevice_id):
        """Return the device path.

        Returns the local device path that has been allocated to the block
        device on the host to which it is currently attached.
        :param unicode blockdevice_id: The unique identifier for the block
            device.
        :raises UnknownVolume: If the supplied ``blockdevice_id`` does not
            exist.
        :raises UnattachedVolume: If the supplied ``blockdevice_id`` is
            not attached to a host.
        :returns: A ``FilePath`` for the device.
        """
        # Check for volume
        volume = self.krest.search("volumes", scsi_sn=blockdevice_id)
        if volume.total == 0:
            raise blockdevice.UnknownVolume(blockdevice_id)

        volume = volume.hits[0]
        # Check for volume is mapped or not
        # NOTE: The assumption right now is if we are mapped,
        # we are mapped to the instance host.
        mapped = self.krest.search("mappings", volume=volume)
        if mapped.total == 0:
            # if not mapped raise exception
            raise blockdevice.UnattachedVolume(blockdevice_id)

        # Get devices path
        paths = self.api_client.find_paths(blockdevice_id)
        if paths:
            # return the first path
            LOG.info('%s path', paths[0])
            return filepath.FilePath(paths[0])
        return None
    def get_device_path(self, blockdevice_id):
        LOG.debug('Entering EMCVNXBlockAPI.get_device_path blockdevice_id=%s',
                  blockdevice_id)

        lun_name = self._build_volume_name_from_blockdevice_id(blockdevice_id)
        lun = self.client.get_lun(lun_name)
        if self.client.is_lun_destroyed(lun):
            raise blockdevice.UnknownVolume(blockdevice_id)

        storage_groups = self.client.get_storage_group()
        for storage_group in storage_groups:
            if storage_group.has_alu(lun):
                hlu = storage_group.get_hlu(lun)
                break
        else:
            raise blockdevice.UnattachedVolume(blockdevice_id)

        # XXX This will only operate on one of the resulting device paths.
        # /sys/class/scsi_disk/x:x:x:HLU/device/block/sdvb for example.
        connection_properties = self.connector.build_connection_properties(
            hlu, storage_group=storage_group)

        device_info = self.connector.get_device_info(
            connection_properties['data'])

        LOG.info('Exiting EMCVNXBlockAPI.get_device_path device_info=%s',
                 device_info)

        return filepath.FilePath(device_info['path'])
    def _get_target_info(self, vol_name):
        """Build a dictionary of information about the target.

        :param vol_name:
        :return: dictionary containing the following info:

        iSCSI:
            target_portal(s) - ip and optional port
            target_iqn(s) - iSCSI Qualified Name
            target_lun(s) - LUN id of the volume
        FC:
            target_wwn - World Wide Name
            target_lun - LUN id of the volume

        ALL:
            volume - A dictionary representation of the Purity volume object
        """
        conn_info = {}
        try:
            connected_hosts = self._array.list_volume_private_connections(
                vol_name)
        except purestorage.PureHTTPError as err:
            if err.code == 400 and ERR_MSG_NOT_EXIST in err.text:
                raise blockdevice.UnknownVolume(vol_name)
            else:
                raise
        for host_info in connected_hosts:
            if host_info["host"] == self._purity_hostname:
                conn_info = host_info
                break

        if not conn_info:
            raise blockdevice.UnattachedVolume(vol_name)

        return self._format_connection_info(conn_info)
    def detach_volume(self, blockdevice_id):
        LOG.debug('Entering EMCVNXBlockAPI.detach_volume: blockdevice_id=%s',
                  blockdevice_id)

        volume_name = self._build_volume_name_from_blockdevice_id(
            blockdevice_id)
        lun = self.client.get_lun(volume_name)
        if self.client.is_lun_destroyed(lun):
            raise blockdevice.UnknownVolume(blockdevice_id)

        storage_groups = self.client.get_storage_group()

        for storage_group in storage_groups:
            if storage_group.has_alu(lun):
                hlu = storage_group.get_hlu(lun)
                break
        else:
            raise blockdevice.UnattachedVolume(blockdevice_id)

        connection_properties = self.connector.build_connection_properties(
            hlu, storage_group=storage_group)

        self.connector.disconnect_volume(connection_properties['data'])

        storage_group.detach_alu(lun)

        LOG.debug('Exiting EMCVNXBlockAPI.detach_volume: '
                  'storage_group=%s, volume_name=%s, volume_id=%s, hlu=%s, '
                  'target_prop=%s',
                  storage_group.name,
                  volume_name,
                  lun.lun_id,
                  hlu,
                  connection_properties)
Ejemplo n.º 5
0
    def detach_volume(self, blockdevice_id):
        LOG.debug('Entering EMCUnityBlockAPI.detach_volume: blockdevice_id=%s',
                  blockdevice_id)

        volume_name = self._build_volume_name_from_blockdevice_id(
            blockdevice_id)
        lun = self.client.get_lun(volume_name)
        if self.client.is_lun_destroyed(lun):
            raise blockdevice.UnknownVolume(blockdevice_id)

        hosts = self.client.get_host()
        for host in hosts:
            if host.has_alu(lun):
                hlu = host.get_hlu(lun)
                break
        else:
            raise blockdevice.UnattachedVolume(blockdevice_id)

        connection_properties = self.connector.build_connection_properties(
            hlu, host=host)

        self.connector.disconnect_volume(connection_properties['data'])

        host.detach_alu(lun)

        LOG.debug('Exiting EMCUnityBlockAPI.detach_volume: '
                  'host=%s, volume_name=%s, volume_id=%s, hlu=%s, '
                  'target_prop=%s',
                  host.name,
                  volume_name,
                  lun.id,
                  hlu,
                  connection_properties)
Ejemplo n.º 6
0
    def detach_volume(self, blockdevice_id):
        """Detach ``blockdevice_id`` from whatever host it is attached to.

        :param unicode blockdevice_id: The unique identifier for the block
            device being detached.
        :raises UnknownVolume: If the supplied ``blockdevice_id`` does not
            exist.
        :raises UnattachedVolume: If the supplied ``blockdevice_id`` is
            not attached to anything.
        :returns: ``None``
        """
        LOG.info('Detaching %s', blockdevice_id)
        # Check for volume by block device id(scsi_sn)
        volume = self.krest.search("volumes", scsi_sn=blockdevice_id)
        if volume.total == 0:
            raise blockdevice.UnknownVolume(blockdevice_id)

        # First check if we are mapped.
        mapped = self.krest.search("mappings", volume=volume)
        if mapped.total == 0:
            raise blockdevice.UnattachedVolume(blockdevice_id)

        #  executing sync cmd for synchronize data on disk with memory
        self.api_client.sync_device()

        paths = self.api_client.find_paths(blockdevice_id)
        for path in paths:
            if "/dev/mapper/" in path:
                self.api_client.remove_multipath(path)
                break

        # Make sure iqn is mapped with host.
        iqn = self.api_client.get_initiator_name()
        host_iqns = self.krest.search("host_iqns", iqn=iqn)

        if host_iqns.total > 0:
            # find host which is associate with iqn.
            host_iqns = self.api_client.rgetattr(host_iqns.hits[0], "host",
                                                 None)

        # Get the mapped host
        host = self.api_client.rgetattr(mapped.hits[0], "host", None)
        # Make sure host should be exists for volume
        if not host:
            raise StorageDriverAPIException('Unable to locate server.')

        # Make sure both host have same name which is to be unmapped
        if host.name == host_iqns.name:
            mapped.hits[0].delete()
            LOG.info("Removed mapped host %s", host.name)
        if self.destroy_host:
            try:
                host.delete()
            except Exception as e:
                LOG.exception("Unable to delete host due to %s", e.message)
                pass
        # start iscsi rescan
        self._iscsi_rescan('detach')
        return None
 def _disconnect_volume(self, vol_name):
     try:
         self._array.disconnect_host(self._purity_hostname, vol_name)
     except purestorage.PureHTTPError as err:
         if err.code == 400 and ERR_MSG_NOT_CONNECTED in err.text:
             raise blockdevice.UnattachedVolume(vol_name)
         elif err.code == 400 and ERR_MSG_NOT_EXIST in err.text:
             raise blockdevice.UnknownVolume(vol_name)
         else:
             raise
    def get_device_path(self, blockdevice_id):
        """
        Return the device path that has been allocated to the block device on
        the host to which it is currently attached.
        Returning the wrong value here can lead to data loss or corruption
        if a container is started with an unexpected volume. Make very
        sure you are returning the correct result.
        :param unicode blockdevice_id: The unique identifier for the block
            device.
        :raises UnknownVolume: If the supplied ``blockdevice_id`` does not
            exist.
        :raises UnattachedVolume: If the supplied ``blockdevice_id`` is
            not attached to a host.
        :returns: A ``FilePath`` for the device.
        """
        eliot.Message.new(Info="Looking for a volume path for {0}".format(
            blockdevice_id)).write(_logger)

        if blockdevice_id in self._volume_path_cache:
            path = self._volume_path_cache[blockdevice_id]
            eliot.Message.new(
                Info="Found volume path for {0} in cache at {1}".format(
                    blockdevice_id, path)).write(_logger)
            return filepath.FilePath(path)

        target_info = self._get_target_info(blockdevice_id)

        host_devices = self._connector.get_volume_paths(target_info)
        eliot.Message.new(Info="Found volume paths for {0} at {1}".format(
            blockdevice_id, host_devices)).write(_logger)

        valid_device = None
        if host_devices:
            valid_device = next(dev for dev in host_devices
                                if os.path.exists(dev))

        if not valid_device:
            raise blockdevice.UnattachedVolume(blockdevice_id)

        # Slow way, check the output of multipath -l, and scan through the devices
        # TODO: check if friendly names are off and just use /dev/mapper/<WWN>
        valid_device = os.path.realpath(valid_device)
        mpath_info = self._connector._linuxscsi.find_multipath_device(
            valid_device)
        path = mpath_info['device']

        eliot.Message.new(Info="Using volume path for {0} at {1}".format(
            blockdevice_id, path)).write(_logger)

        self._volume_path_cache[blockdevice_id] = path
        return filepath.FilePath(path)
    def detach_volume(self, blockdevice_id):
        """Detach ``blockdevice_id`` from whatever host it is attached to.

        :param unicode blockdevice_id: The unique identifier for the block
            device being detached.
        :raises UnknownVolume: If the supplied ``blockdevice_id`` does not
            exist.
        :raises UnattachedVolume: If the supplied ``blockdevice_id`` is
            not attached to anything.
        :returns: ``None``
        """
        LOG.info('Detaching %s', blockdevice_id)

        with self._client.open_connection() as api:
            # Check that we have that volume
            scvolume = api.find_volume(blockdevice_id)
            if not scvolume:
                raise blockdevice.UnknownVolume(blockdevice_id)

            # First check if we are mapped
            mappings = api.find_mapping_profiles(scvolume)
            if not mappings:
                raise blockdevice.UnattachedVolume(blockdevice_id)

            device_id = scvolume['deviceId']
            paths = iscsi_utils.find_paths(device_id)
            paths.reverse()
            for path in paths:
                iscsi_utils.remove_device(path)

            # Make sure we have a server defined for this host
            iqn = iscsi_utils.get_initiator_name()
            host = api.find_server(iqn)
            LOG.info("Search for server returned: %s", host)
            if not host:
                # Try to create a new host
                host = api.create_server(self.compute_instance_id(), iqn)
            LOG.info("Created server %s", host)

            # Make sure we were able to find something
            if not host:
                raise BlockDriverAPIException('Unable to locate server.')

            api.unmap_volume(scvolume, host)
        self._do_rescan('detach')
    def get_device_path(self, blockdevice_id):
        """Return the device path.

        Returns the local device path that has been allocated to the block
        device on the host to which it is currently attached.
        :param unicode blockdevice_id: The unique identifier for the block
            device.
        :raises UnknownVolume: If the supplied ``blockdevice_id`` does not
            exist.
        :raises UnattachedVolume: If the supplied ``blockdevice_id`` is
            not attached to a host.
        :returns: A ``FilePath`` for the device.
        """
        device_id = None
        with self._client.open_connection() as api:
            # Check that we have that volume
            volume = api.find_volume(blockdevice_id)
            if not volume:
                raise blockdevice.UnknownVolume(blockdevice_id)

            scvolume = api.find_volume(blockdevice_id)
            device_id = scvolume['deviceId']

            # First check if we are mapped
            # NOTE: The assumption right now is if we are mapped,
            # we are mapped to the local compute host.
            mappings = api.find_mapping_profiles(scvolume)
            if not mappings:
                raise blockdevice.UnattachedVolume(blockdevice_id)

        if not device_id:
            raise blockdevice.UnknownVolume(blockdevice_id)

        # Look for any new devices
        retries = 0
        while retries < 4:
            paths = iscsi_utils.find_paths(device_id)
            if paths:
                # Just return the first path
                return filepath.FilePath(paths[0]).realpath()
            retries += 1
            LOG.info('%s not found, attempt %d', device_id, retries)
            time.sleep(5)
        return None