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)
 def destroy_volume(self, blockdevice_id):
     """
     Destroy an existing volume.
     :param unicode blockdevice_id: The unique identifier for the volume to
         destroy.
     :raises UnknownVolume: If the supplied ``blockdevice_id`` does not
         exist.
     :return: ``None``
     """
     try:
         eliot.Message.new(Info="Destroying Volume" +
                           str(blockdevice_id)).write(_logger)
         try:
             self._disconnect_volume(blockdevice_id)
         except blockdevice.UnattachedVolume:
             # Don't worry if it is not connected, normally it won't be
             pass
         self._array.destroy_volume(blockdevice_id)
     except purestorage.PureHTTPError as err:
         if (err.code == 400
                 and (ERR_MSG_NOT_EXIST in err.text
                      or ERR_MSG_PENDING_ERADICATION in err.text)):
             raise blockdevice.UnknownVolume(blockdevice_id)
         else:
             eliot.Message.new(
                 Error="Failed to delete volume for dataset " +
                 str(blockdevice_id),
                 Exception=err).write(_logger)
             raise
Exemple #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)
Exemple #6
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
Exemple #7
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 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
 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 destroy_volume(self, blockdevice_id):
        LOG.debug('Entering EMCVNXBlockAPI.destroy_volume: blockdevice_id=%s',
                  blockdevice_id)

        volume_name = self._build_volume_name_from_blockdevice_id(
            blockdevice_id)

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

        lun.delete()

        LOG.debug('Exiting EMCVNXBlockAPI.destroy_volume: volume_name=%s',
                  volume_name)
    def _connect_volume(self, vol_name):
        """Connect the volume object to our Purity host.

        We need to return a dictionary with target information that will be
        consumed by os-brick.
        """
        try:
            connection = self._array.connect_host(self._purity_hostname,
                                                  vol_name)
        except purestorage.PureHTTPError as err:
            if err.code == 400 and ERR_MSG_ALREADY_EXISTS in err.text:
                raise blockdevice.AlreadyAttachedVolume(vol_name)
            elif err.code == 400 and ERR_MSG_NOT_EXIST in err.text:
                raise blockdevice.UnknownVolume(vol_name)
            else:
                raise
        return self._format_connection_info(connection)
    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 resize_volume(self, blockdevice_id, size):
        """Resize an existing volume.

        :param blockdevice_id: The unique identifier for the device.
        :param size: The new requested size.
        :raises UnknownVolume: If the supplied ``blockdevice_id`` does
            not exist.
        :returns: ``None``
        """
        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)

            volume_size = self._bytes_to_gig(size)
            if not api.expand_volume(scvolume, volume_size):
                raise blockdevice.VolumeException(blockdevice_id)
    def attach_volume(self, blockdevice_id, attach_to):
        LOG.debug('Entering EMCVNXBlockAPI.attach_volume: '
                  'blockdevice_id=%s, attach_to=%s',
                  blockdevice_id, attach_to)

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

        if self._lun_already_in_sg(lun):
            raise blockdevice.AlreadyAttachedVolume(blockdevice_id)

        host_info = self._build_host_info(self.host_ip, attach_to)
        storage_group = self._assure_storage_group(host_info)

        try:
            hlu = self._assure_host_access(storage_group, lun)
        except exception.VNXAluAlreadyAttachedError:
            raise blockdevice.AlreadyAttachedVolume(blockdevice_id)

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

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

        volume_size = self._gib_to_bytes(lun.total_capacity_gb)
        volume = loopback._blockdevicevolume_from_blockdevice_id(
            blockdevice_id=blockdevice_id,
            size=volume_size,
            attached_to=unicode(attach_to))

        LOG.debug('Exiting EMCVNXBlockAPI.attach_volume: '
                  'storage_group=%s, volume_name=%s, volume_size=%s, hlu=%s, '
                  'target_prop=%s',
                  attach_to,
                  volume_name,
                  volume_size,
                  hlu,
                  connection_properties)

        return volume
Exemple #15
0
    def attach_volume(self, blockdevice_id, attach_to):
        LOG.debug('Entering EMCUnityBlockAPI.attach_volume: '
                  'blockdevice_id=%s, attach_to=%s',
                  blockdevice_id, attach_to)

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

        if self._lun_already_in_host(lun):
            raise blockdevice.AlreadyAttachedVolume(blockdevice_id)

        host_info = self._build_host_info(attach_to)
        host = self._assure_host(host_info)

        try:
            hlu = self._assure_host_access(host, lun)
        except exception.UnityAluAlreadyAttachedError:
            raise blockdevice.AlreadyAttachedVolume(blockdevice_id)

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

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

        volume = loopback._blockdevicevolume_from_blockdevice_id(
            blockdevice_id=blockdevice_id,
            size=lun.size_total,
            attached_to=unicode(attach_to))

        LOG.debug('Exiting EMCUnityBlockAPI.attach_volume: '
                  'host=%s, volume_name=%s, volume_size=%s, hlu=%s, '
                  'target_prop=%s',
                  attach_to,
                  volume_name,
                  lun.size_total,
                  hlu,
                  connection_properties)

        return volume
Exemple #16
0
    def destroy_volume(self, blockdevice_id):
        """Destroy an existing volume from an initiator (host).

        :param blockdevice_id: The volume unique ID.
        """
        LOG.info('Destroying volume %s', blockdevice_id)
        try:
            volume = self.krest.search("volumes", scsi_sn=blockdevice_id)
            if volume.total == 0:
                raise blockdevice.UnknownVolume(blockdevice_id)
            volume = volume.hits[0]
            volume_group = self.api_client.rgetattr(volume, "volume_group",
                                                    None)
            volume.delete()
            volume_group.delete()
        except Exception:
            raise StorageDriverAPIException(
                'Error destroying volume blockdevice_id:{}'.format(
                    blockdevice_id))
        return None
    def destroy_volume(self, blockdevice_id):
        """Destroy an existing volume.

        :param blockdevice_id: The volume unique ID.
        """
        deleted = False
        LOG.info('Destroying volume %s', blockdevice_id)
        with self._client.open_connection() as api:
            try:
                volume = api.find_volume(blockdevice_id)
                if not volume:
                    raise blockdevice.UnknownVolume(blockdevice_id)
                deleted = api.delete_volume(blockdevice_id)
            except Exception:
                # TODO(smcginnis) Catch more specific exception
                LOG.exception('Error destroying volume.')
                raise
        if not deleted:
            # Something happened
            raise BlockDriverAPIException('Unable to delete volume.')
Exemple #18
0
    def attach_volume(self, blockdevice_id, attach_to):
        """Attach an existing volume to an initiator (host).

        :param blockdevice_id: The unique identifier(scsi_sn of k2)
            for the volume.
        :param attach_to: It is a hostname of node which is returned
            by "compute_instance_id" method.
        :raises UnknownVolume: If the supplied "blockdevice_id" does not
            exist.
        :returns: A  "BlockDeviceVolume" with a "attached_to" attribute set
            to "attach_to".
        """
        LOG.info('attaching to blockdevice_id %s and host is %s',
                 blockdevice_id, attach_to)
        # Searching for volume by scsi_sn via krest
        volume = self.krest.search("volumes", scsi_sn=blockdevice_id)
        if volume.total == 0:
            raise blockdevice.UnknownVolume(blockdevice_id)

        # Check for host which is associate with iqn(iSCSI Qualified Name)
        iqn = self.api_client.get_initiator_name()
        host_iqns = self.krest.search("host_iqns", iqn=iqn)
        host = self.api_client.rgetattr(host_iqns.hits[0], "host", None) \
            if host_iqns.total > 0 else None

        # if iqn is not associate with any host
        if not host:
            # searching instance or node host which is return
            # by compute_instance_id method.
            host = self.krest.search("hosts", name=attach_to)
            if host.total > 0:
                raise InvalidDataException(
                    'Present host is not mapped with iqn')
            else:
                host = self._create_new_host(attach_to)
                self._map_host_with_iqn(host_iqns.hits[0], host)

        # Make sure the server is logged in to the array
        ips = self.krest.search("system/net_ips")
        for ip in ips.hits:
            self.api_client.iscsi_login(
                self.api_client.rgetattr(ip, 'ip_address', None), 3260)

        # Make sure we were able to find host
        if not host:
            raise InvalidDataException('Host does not exits')

        volume = volume.hits[0]
        # First check if we are already mapped
        mapped = self.krest.search('mappings', volume=volume)

        if mapped.total > 0:
            # Get the mapped host
            mapped_host = self.api_client.rgetattr(mapped.hits[0], "host",
                                                   None)
            if mapped_host != host:
                LOG.info("Mapped server %s", mapped_host)
                # raise exception for attached volume
                raise blockdevice.AlreadyAttachedVolume(blockdevice_id)

        # Make sure host should not be associate with host group
        # Note: Currently host groups not supported.
        try:
            mapping = self.krest.new("mappings", volume=volume, host=host)
            mapping.save()
            LOG.info("Mapping is done- %s", mapping)
        except Exception:
            raise StorageDriverAPIException('Unable to map volume to server.')

        # start iscsi rescan
        self._iscsi_rescan('attach')

        return self._return_to_block_device_volume(volume, attach_to)
    def attach_volume(self, blockdevice_id, attach_to):
        """Attach an existing volume to an initiator.

        :param blockdevice_id: The unique identifier for the volume.
        :param attach_to: An identifier like the one returned by the
            ``compute_instance_id`` method indicating the node to which to
            attach the volume.

        :raises UnknownVolume: If the supplied ``blockdevice_id`` does not
            exist.
        :returns: A ``BlockDeviceVolume`` with a ``attached_to`` attribute set
            to ``attach_to``.
        """
        LOG.info('Attaching %s to %s', blockdevice_id, attach_to)

        # Functional tests expect a failure if it's already
        # attached, even if we're being asked to attach to
        # the same host.
        # not_local = attach_to != self.compute_instance_id()
        not_local = True

        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)

            # 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(attach_to, iqn)
                LOG.info("Created server %s", host)
            # Make sure the server is logged in to the array
            ports = api.get_iscsi_ports()
            for port in ports:
                iscsi_utils.iscsi_login(port[0], port[1])

            # Make sure we were able to find something
            if not host:
                raise BlockDriverAPIException()

            # First check if we are already mapped
            mappings = api.find_mapping_profiles(scvolume)
            if mappings:
                # See if it is to this server
                if not_local:
                    raise blockdevice.AlreadyAttachedVolume(blockdevice_id)
                for mapping in mappings:
                    if (mapping['server']['instanceName'] !=
                            host['instanceName']):
                        raise blockdevice.AlreadyAttachedVolume(blockdevice_id)

            mapping = api.map_volume(scvolume, host)
            if not mapping:
                raise BlockDriverAPIException(
                    'Unable to map volume to server.')

            self._do_rescan('attach')

            return self._to_blockdevicevolume(scvolume, attach_to)