Exemple #1
0
    def attach_volume(self, blockdevice_id, attach_to):
        """
        Attach ``blockdevice_id`` to ``host``.

        :param unicode blockdevice_id: The unique identifier for the block
            device being attached.
        :param unicode 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.
        :raises AlreadyAttachedVolume: If the supplied ``blockdevice_id`` is
            already attached.
        :returns: A ``BlockDeviceVolume`` with a ``host`` attribute set to
            ``host``.
        """
        # Raises UnknownVolume
        volume = self._get(blockdevice_id)
        # raises AlreadyAttachedVolume
        if volume.attached_to is not None:
            Message.new(Error="Could Not Destroy Volume "
                        + str(blockdevice_id)
                        + "is already attached").write(_logger)
            raise AlreadyAttachedVolume(blockdevice_id)

        # Get the SDC Object by the GUID of the host.
        sdc = self._client.get_sdc_by_guid(
            self._instance_id.upper())

        # Try mapping volumes

        # TODO errors are currently hard to get from sclaeio-py
        # https://github.com/swevm/scaleio-py/issues/6
        # ultimately we should be able to get more specific
        # errors about why the failure happened such as
        # ``{"message":"Only a single SDC may be mapped to this
        # volume at a time","httpStatusCode":500,"errorCode":306}``
        try:
            self._client.map_volume_to_sdc(
                self._client.get_volume_by_id(
                    str(blockdevice_id)), sdcObj=sdc,
                allowMultipleMappings=False)
        except Exception as e:
            # TODO real errors need to be returned by scaleio-py
            Message.new(Error=str(blockdevice_id) + " "
                        + str(e)).write(_logger)
            raise AlreadyAttachedVolume(blockdevice_id)

        attached_volume = volume.set(
            attached_to=self._instance_id)
        return attached_volume
Exemple #2
0
    def attach_volume(self, blockdevice_id, attach_to):
        """
        Attach ``blockdevice_id`` to the node indicated by ``attach_to``.

        :param unicode blockdevice_id: The unique identifier for the block
            device being attached.
        :param unicode 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.
        :raises AlreadyAttachedVolume: If the supplied ``blockdevice_id`` is
            already attached.
        :returns: A ``BlockDeviceVolume`` with a ``attached_to`` attribute set
            to ``attach_to``.
        """
        # This also checks if it exists
        if self._is_already_mapped(blockdevice_id):
            raise AlreadyAttachedVolume(blockdevice_id)

        if attach_to != self.compute_instance_id():
            # TODO log this.
            return

        self._check_output([b"rbd", b"-p", self._pool, b"map",
            blockdevice_id])

        rbd_image = rbd.Image(self._ioctx, _rbd_blockdevice_id(blockdevice_id))
        size = int(rbd_image.stat()["size"])
        return BlockDeviceVolume(blockdevice_id=blockdevice_id, size=size,
                attached_to=self.compute_instance_id(),
                dataset_id=_dataset_id(blockdevice_id))
Exemple #3
0
    def attach_volume(self, blockdevice_id, attach_to):
        """
        See ``IBlockDeviceAPI.attach_volume``.
        :returns:
        """
        volume = self._get_volume(blockdevice_id)

        if volume['attach_to'] is not None:
            LOG.error("attach_volume: AlreadyAttachedVolume, " +
                      unicode(blockdevice_id))
            raise AlreadyAttachedVolume(blockdevice_id)

        connector = self._find_vmax_host(attach_to)
        if connector is None:
            LOG.error("attach_volume: VolumeException, " +
                      unicode(blockdevice_id))
            raise VolumeException(blockdevice_id)

        LOG.info("attach_volume " + unicode(volume) + " to " +
                 unicode(connector))

        volume['attach_to'] = unicode(attach_to)
        self.dbconn.update_volume_by_id(blockdevice_id, volume)
        self.vmax_common.initialize_connection(volume, connector)
        return _blockdevicevolume_from_vmax_volume(blockdevice_id, volume)
Exemple #4
0
    def attach_volume(self, blockdevice_id, attach_to):
        """
        Attach ``blockdevice_id`` to the node indicated by ``attach_to``.

        :param unicode blockdevice_id: The unique identifier for the block
            device being attached.
        :param unicode 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.
        :raises AlreadyAttachedVolume: If the supplied ``blockdevice_id`` is
            already attached.

        :returns: A ``BlockDeviceVolume`` with a ``attached_to`` attribute set
            to ``attach_to``.
        """
        current_vol = self.eqlx_con.volume_info(blockdevice_id)
        if current_vol.attached_to != None:
            raise AlreadyAttachedVolume('attached to %s' %
                                        current_vol.attached_to)
        self.eqlx_con.allow_volume(blockdevice_id, attach_to)
        self.eqlx_con.iscsi_login(blockdevice_id)
        return current_vol.set(attached_to=attach_to)
Exemple #5
0
    def attach_volume(self, blockdevice_id, attach_to):
        """
        Attach ``blockdevice_id`` to the node indicated by ``attach_to``.

        :param unicode blockdevice_id: The unique identifier for the block
            device being attached.
        :param unicode 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.
        :raises AlreadyAttachedVolume: If the supplied ``blockdevice_id`` is
            already attached.
        :returns: A ``BlockDeviceVolume`` with a ``attached_to`` attribute set
            to ``attach_to``.
        """
        ascii_blockdevice_id = blockdevice_id.encode()
        self._check_exists(ascii_blockdevice_id)

        if self._is_already_mapped(blockdevice_id):
            raise AlreadyAttachedVolume(blockdevice_id)

        if attach_to != self.compute_instance_id():
            return

        Blktap.Tapdisk.create(blockdevice_id)
        object_id = self.client.get_object_id(str("/%s.raw" % blockdevice_id))
        size = self.client.info_volume(object_id).volume_size
        return BlockDeviceVolume(blockdevice_id=blockdevice_id,
                                 size=size,
                                 attached_to=self.compute_instance_id(),
                                 dataset_id=_dataset_id(blockdevice_id))
Exemple #6
0
    def resize_volume(self, blockdevice_id, size):
        """
        Resize an unattached ``blockdevice_id``.

        This changes the amount of storage available.  It does not change the
        data on the volume (including the filesystem).

        :param unicode blockdevice_id: The unique identifier for the block
            device being detached.
        :param int size: The required size, in bytes, of the volume.

        :raises UnknownVolume: If the supplied ``blockdevice_id`` does not
            exist.

        :returns: ``None``
        """
        # raises UnknownVolume
        volume = self._get(blockdevice_id)

        # raises AlreadyAttachedVolume, do we want this?
        # is says only an unattached volume, if it is attached
        # do we detach and then resize thenr reattach? Or should we
        # just assume that all things that call this function know
        # that the volume is detached already?
        if volume.attached_to is not None:
            Message.new(Error="Cannot Resize Volume "
                        + str(blockdevice_id)
                        + "is attached").write(_logger)
            raise AlreadyAttachedVolume(blockdevice_id)

        sio_volume = self._client.get_volume_by_id(str(blockdevice_id))

        size_in_gb = int(Byte(size).to_GiB().value)
        self._client.resize_volume(sio_volume, size_in_gb)
Exemple #7
0
    def attach_volume(self, blockdevice_id, attach_to):
        """
        Attach an CIO volume to given compute instance.

        :param unicode blockdevice_id: CIO UUID for volume to be attached.
        :param unicode attach_to: Instance id of CIO Compute instance to
            attached the blockdevice to.

        :raises UnknownVolume: If there does not exist a BlockDeviceVolume
            corresponding to the input blockdevice_id.
        :raises AlreadyAttachedVolume: If the input volume is already attached
            to a device.
        :raises AttachedUnexpectedDevice: If the attach operation fails to
            associate the volume with the expected OS device file.  This
            indicates use on an unsupported OS, a misunderstanding of the CIO
            device assignment rules, or some other bug in this implementation.
        """
        command = [
            b"/usr/bin/cio", b"vdinfo", b"-u",
            unicode(blockdevice_id), b"-v"
        ]
        output = check_output(command).split(b'\n')[0]
        cio_volume = output.split()[0]
        if cio_volume == "Fail:":
            raise UnknownVolume(blockdevice_id)
        command = [
            b"/usr/bin/cio", b"vdinfo", b"-v",
            bytes(cio_volume), b"--attachstatus"
        ]
        current_attachment = check_output(command).split(b'\n')[0]
        if current_attachment != "None":
            #if current_attachment == attach_to:
            raise AlreadyAttachedVolume(blockdevice_id)
        #else :
        #   compute_instance_id = self.compute_instance_id()
        #   if attach_to != compute_instance_id :
        #      move_volume_command = [b"/usr/bin/cio", b"vdmv", b"-v", bytes(cio_volume), b"-N", attach_to]
        #      command_output = check_output(move_volume_command).split(b'\n')
        else:
            if attach_to != None:
                add_attach_metadata_command = [
                    b"/usr/bin/cio", b"vdmod", b"-v",
                    bytes(cio_volume), b"--attachstatus", attach_to
                ]
                command_output = check_output(
                    add_attach_metadata_command).split(b'\n')
        command = [
            b"/usr/bin/cio", b"vdinfo", b"-v",
            bytes(cio_volume), b"--datasetid"
        ]
        output = check_output(command).split(b'\n')[0]
        dataset_id = output.split()[0].decode("ascii")
        return _blockdevicevolume_from_cio_volume(bytes(cio_volume),
                                                  datasetid=UUID(dataset_id),
                                                  computeinstanceid=attach_to)
    def attach_volume(self, blockdevice_id, attach_to):
        """ Attach ``blockdevice_id`` to ``host``.

        :param unicode blockdevice_id: The unique identifier for the block
            device being attached.
        :param unicode 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.
        :raises AlreadyAttachedVolume: If the supplied ``blockdevice_id`` is
            already attached.
        :returns: A ``BlockDeviceVolume`` with a ``host`` attribute set to
            ``host``.
        """

        vol = self._get_solidfire_volume(blockdevice_id)
        if not vol:
            raise UnknownVolume(blockdevice_id)

        tgt_iqn = vol['iqn']
        if utils.path_exists('/dev/disk/by-path/ip-%s-iscsi-%s-lun-0' %
                             (self.svip, tgt_iqn), 1):
            raise AlreadyAttachedVolume(blockdevice_id)

        # It's not attached here, make sure it's not attached somewhere else
        # In the future we can add multi-attach support maybe, but for now
        # avoid the trouble of file-systems etc
        current_sessions = self._current_iscsi_sessions(blockdevice_id)
        if current_sessions:
            raise AlreadyAttachedVolume(blockdevice_id)

        targets = utils.iscsi_discovery(self.svip)
        if len(targets) < 1 and tgt_iqn not in targets:
            raise Exception("No targes found during discovery.")
        if utils.iscsi_login(self.svip, tgt_iqn):
            return BlockDeviceVolume(
                blockdevice_id=unicode(blockdevice_id),
                size=vol['totalSize'],
                attached_to=attach_to,
                dataset_id=uuid.UUID(str(vol['name'])))
        raise Exception("Failed iSCSI login to device: %s" % blockdevice_id)
    def attach_volume(self, blockdevice_id, attach_to):
        """
        Attach ``blockdevice_id`` to ``host``.
        :param unicode blockdevice_id: The unique identifier for the block
            device being attached.
        :param unicode 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.
        :raises AlreadyAttachedVolume: If the supplied ``blockdevice_id`` is
            already attached.
        :returns: A ``BlockDeviceVolume`` with a ``host`` attribute set to
            ``host``.
        """

        log_info('Attempting to attach ' + str(blockdevice_id)
                 + ' to ' + str(attach_to))

        _vmstate_lock.acquire()
        try:
            # Make sure disk is present.  Also, need the disk size is needed.
            disks = self._manager.list_disks()
            target_disk = None
            for disk in disks:
                if disk.name == blockdevice_id:
                    target_disk = disk
                    break
            if target_disk is None:
                raise UnknownVolume(blockdevice_id)

            (disk, vmname, lun) = self._get_disk_vmname_lun(blockdevice_id)
            if vmname is not None:
                if unicode(vmname) != self.compute_instance_id():
                    raise AlreadyAttachedVolume(blockdevice_id)
                else:
                    return self._blockdevicevolume_from_azure_volume(
                        blockdevice_id,
                        target_disk.properties.content_length,
                        attach_to)

            self._manager.attach_disk(
                str(attach_to),
                target_disk.name,
                int(GiB(bytes=target_disk.properties.content_length)))
        finally:
            _vmstate_lock.release()

        log_info('disk attached')

        return self._blockdevicevolume_from_azure_volume(
            blockdevice_id,
            target_disk.properties.content_length,
            attach_to)
    def attach_volume(self, blockdevice_id, attach_to):
        """
        Attach ``blockdevice_id`` to the node indicated by ``attach_to``.
        :param unicode blockdevice_id: The unique identifier for the block
            device being attached.
        :param unicode 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.
        :raises AlreadyAttachedVolume: If the supplied ``blockdevice_id`` is
            already attached.
        :raises UnknownVm: If the supplied ``attach_to`` vm does not
            exist.
        :raises VolumeAttachFailure: If the attach volume failed with some error.
            exist.
        :returns: A ``BlockDeviceVolume`` with a ``attached_to`` attribute set
            to ``attach_to``.
        """
        logging.debug("Attaching {} to {}".format(blockdevice_id, attach_to))
        vm = self._si.content.searchIndex.FindByUuid(datacenter=None,
                                                     uuid=attach_to,
                                                     vmSearch=True,
                                                     instanceUuid=True)
        try:
            if vm is None:
                raise UnknownVm("VM not found {}".format(attach_to))

            vsphere_volume = self._get_vsphere_blockdevice_volume(
                blockdevice_id)
            if vsphere_volume.blockDeviceVolume.attached_to is not None:
                logging.error("Volume is attached to a vm so cannot attach.")
                raise AlreadyAttachedVolume(blockdevice_id)

            try:
                attached_volume = self._attach_vmdk(vm, vsphere_volume)
            except Exception as e:
                logging.error("Cannot attach volume {} to {} ({}) "
                              "because of exception: {}".format(
                                  blockdevice_id, attach_to, vm.name, e))
                raise VolumeAttachFailure(e)

            logging.debug("Volume attached to {}".format(
                attached_volume.attached_to))
            logging.debug("Block Device {} will be attached to {} {}".format(
                blockdevice_id, attach_to, attached_volume))
            logging.debug("Rescanning scsi bus for attached disk")
            self._rescan_scsi()
            return attached_volume
        except Exception, ex:
            logging.error(
                'An error occurred attaching volume {} to {}: {}'.format(
                    blockdevice_id, attach_to, ex))
            raise VolumeAttachFailure(ex)
Exemple #11
0
    def attach_volume(self, blockdevice_id, attach_to):
        """
        Attach ``blockdevice_id`` to ``host``.

        :param unicode blockdevice_id: The unique identifier for the block
            device being attached.
        :param unicode 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.
        :raises AlreadyAttachedVolume: If the supplied ``blockdevice_id`` is
            already attached.
        :returns: A ``BlockDeviceVolume`` with a ``host`` attribute set to
            ``host``.
        """
        volName = str(blockdevice_id)
        vdiskInfo = findVDisk(volName)
        if (vdiskInfo == None):
            raise UnknownVolume(blockdevice_id)

        computeHost = socket.getfqdn(attach_to)
        try:
            tgtHost = hedvigLookupTgt('wood', self.logger_)
            lunnum = hedvigGetLun(tgtHost, volName, self.logger_)
        except:
            raise Exception("Failed to get Lun number")
        if lunnum == -1:
            self.logger_.error("failed to add vDiskName:%s:tgtHost:%s",
                               volName, tgtHost)
            raise Exception("Failed to add Lun")
        if (self._is_attached(tgtHost, lunnum) != None):
            raise AlreadyAttachedVolume(blockdevice_id)
        try:
            hedvigAddAccess(tgtHost, lunnum,
                            socket.gethostbyname(socket.getfqdn(computeHost)),
                            self.logger_)
            hedvigAddAccess(tgtHost, lunnum,
                            socket.gethostbyname(socket.getfqdn()),
                            self.logger_)
            targetName, portal = hedvigDoIscsiDiscovery(
                tgtHost, lunnum, self.logger_)
        except Exception as e:
            self.logger_.exception(
                "volume assignment to connector failed :volume:%s:connector:%s",
                volName, attach_to)
            return None
        return BlockDeviceVolume(blockdevice_id=unicode(blockdevice_id),
                                 size=vdiskInfo.size,
                                 attached_to=attach_to,
                                 dataset_id=UUID(blockdevice_id))
 def attach_volume(self, blockdevice_id, attach_to):
     with start_action(action_type=six.text_type(
             "flocker:node:agents:do:attach_volume"),
                       blockdevice_id=blockdevice_id,
                       droplet_id=attach_to):
         try:
             vol = self._get_volume(blockdevice_id)
             if vol.droplet_ids:
                 raise AlreadyAttachedVolume(blockdevice_id)
             r = vol.attach(attach_to, vol.region["slug"])
             if self._await_action_id(r['action']['id']):
                 vol.droplet_ids = [attach_to]
             return self._to_block_device_volume(vol)
         except NotFoundError as _:
             raise UnknownVolume(blockdevice_id)
    def attach_volume(self, blockdevice_id, attach_to):
        """
        Attach volume associates a volume with to a initiator group. The resultant of this is a
        LUN - Logical Unit Number. This association can be made to any number of initiator groups. Post of this
        attachment, the device shall appear in /dev/sd<1>.
        See ``IBlockDeviceAPI.attach_volume`` for parameter and return type
        documentation.
        """

        volume = self._get_vol_details(blockdevice_id)

        if volume.attached_to is None:
            self.data.create_lun_map(str(blockdevice_id), str(attach_to))
        else:
            raise AlreadyAttachedVolume(blockdevice_id)

        attached_volume = volume.set(attached_to=unicode(attach_to))
        self.volume_list[str(blockdevice_id)] = attached_volume
        Message.new(attached_to=attached_volume.attached_to).write(_logger)
        self.data.rescan_scsi()
        return attached_volume
Exemple #14
0
    def attachOsnexusVolume(self, blockdevice_id, attach_to):
        vol = self.validateVolume(blockdevice_id)
        volUuid = self.getDataSetId(vol._name)
        if volUuid is None:
            raise UnknownVolume(blockdevice_id)

        if self.isVolumeAttached(blockdevice_id) is True:
            raise AlreadyAttachedVolume(blockdevice_id)

        self.createHost()
        self._qsclient.volume_attach(blockdevice_id, self._osnexusHostId)

        try:
            self.doIscsiLogin(vol._name)
        except Exception as e:
            self._logger.error("failed to login")
            raise UnattachedVolume(blockdevice_id)

        return BlockDeviceVolume(blockdevice_id=blockdevice_id,
                                 size=int(vol._size),
                                 attached_to=attach_to,
                                 dataset_id=volUuid)
    def attach_volume(self, blockdevice_id, attach_to):
        """
        Attach ``blockdevice_id`` to ``host``.

        :param unicode blockdevice_id: The unique identifier for the block
            device being attached.
        :param unicode 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.
        :raises AlreadyAttachedVolume: If the supplied ``blockdevice_id`` is
            already attached.
        :returns: A ``BlockDeviceVolume`` with a ``host`` attribute set to
            ``host``.
        """
        # Raises UnknownVolume
        volume = self._get_volume(blockdevice_id)

        # raises AlreadyAttachedVolume
        if volume.attached_to is not None:
            LOG.error("Could Not attach Volume {} is already attached".
                      format(str(blockdevice_id)))
            raise AlreadyAttachedVolume(blockdevice_id)

        # Try to map the volume
        self._client.map_volume(wwn=blockdevice_id, host=attach_to)

        attached_volume = volume.set(attached_to=attach_to)
        LOG.info(messages.DRIVER_OPERATION_VOL_ATTACH.format(
            blockdevice_id=blockdevice_id, attach_to=attach_to))

        # Rescan the OS to discover the attached volume
        LOG.info(messages.DRIVER_OPERATION_VOL_RESCAN_START_ATTACH.format(
            blockdevice_id=blockdevice_id))
        self._host_ops.rescan_scsi()

        return attached_volume
Exemple #16
0
    def attach_volume(self, blockdevice_id, attach_to):
        """
        1)  Add initiator to storage instance
        2)  Login
        """

        if self._is_attached(blockdevice_id):
            raise AlreadyAttachedVolume(blockdevice_id)

        if not self._known(blockdevice_id):
            raise UnknownVolume(blockdevice_id)

        ai_name = self._vols[blockdevice_id]['ai_name']
        si = get_datera_storageinst(self._api, ai_name)

        ii = self._initiator_exists(attach_to)
        if not ii:
            ii = self._initiator_create(attach_to)
            if not ii:
                raise DeviceExceptionAPIError(attach_to)
        Message.new(
            Info=' adding initiator : ',
            attached_to=attach_to).write(_logger)
        ensure_acl_exists(si, ii)
        login_to_target(si)
        # Need to let multipath do its thing before moving on
        time.sleep (ISCSI_LOGIN_TIME_DELAY)
        self._vols[blockdevice_id]['attached_to'] = attach_to
        volume = BlockDeviceVolume(
            size=self._vols[blockdevice_id]['size'],
            attached_to=attach_to,
            dataset_id=self._vols[blockdevice_id]['dataset_id'],
            blockdevice_id=blockdevice_id)
        self._vols[blockdevice_id]['volume'] = volume
        Message.new(
            Info=' attach_volume', vol=blockdevice_id,
            attached_to=attach_to).write(_logger)
        return volume
Exemple #17
0
    def attach_volume(self, blockdevice_id, attach_to):
        """
        Attach ``blockdevice_id`` to ``host``.
        :param unicode blockdevice_id: The unique identifier for the block
            device being attached.
        :param unicode 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.
        :raises AlreadyAttachedVolume: If the supplied ``blockdevice_id`` is
            already attached.
        :returns: A ``BlockDeviceVolume`` with a ``host`` attribute set to
            ``host``.
        """

        (target_disk, role_name, lun) = \
            self._get_disk_vmname_lun(blockdevice_id)

        if target_disk is None:
            raise UnknownVolume(blockdevice_id)

        if lun is not None:
            raise AlreadyAttachedVolume(blockdevice_id)

        log_info('Attempting to attach ' + str(blockdevice_id) + ' to ' +
                 str(attach_to))

        disk_size = self._attach_disk(blockdevice_id, target_disk, attach_to)

        self._wait_for_attach(blockdevice_id)

        log_info('disk attached')

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

        If host is not created, it will create the host
        :param blockdevice_id: WWID of the reduxio Volume
        :param attach_to: is the value generated by the compute_instance_id ... here IQN of the current node
        :return: BlockDeviceVolume with attachd_to
        """

        logger.info("Attaching Volume with blockdevice id {} with iscsi target {}".format(blockdevice_id, attach_to))
        try:
            new_host_created = False
            volume_info = self.find_volume_by_blockdevice_id(blockdevice_id)
            dataset_id = uuid.UUID(volume_info[u'description'])
            volume_name = volume_info[u'name']
            logger.debug('Found the Volume, Volume name is {}, dataset id is {} .'.format(volume_name, dataset_id))
        except Exception as e:
            logger.error(
                'An error occured finding the volume with blockdevice id {} .'.format(blockdevice_id))
            logger.error('Exception: ' + str(e))
            raise UnknownVolume(e)

        try:
            logger.info("Checking if the volume {} is attached to any node/s".format(volume_name))
            assignmentlist = self._rdxapi.list_assignments(vol=volume_name)
            if len(assignmentlist) > 0:
                logger.error("Volume {} is already attached to a node.".format(volume_name))
                raise AlreadyAttachedVolume(blockdevice_id)

            hostname = None
            logger.debug('Listing all the hosts.')
            host_list = self._rdxapi.list_hosts()
            logger.debug("Checking if the host with iscsi name {} already exist.".format(attach_to))
            for host in host_list:
                if attach_to == host[u'iscsi_name']:
                    hostname = host[u'name']
                    logger.debug('Host with iscsi name {} exists, Host name is {}'.format(attach_to, hostname))
                    break

            if hostname is None:
                logger.debug('Host not found, must be created.')
                hostname = self._rdxhelper._host_name()
                logger.debug(
                    "Trying to create host {} with iscsi name {} since it does not exist.".format(hostname, attach_to))
                self._rdxapi.create_host(name=hostname,
                                         iscsi_name=attach_to,
                                         user_chap=self._chap_user,
                                         pwd_chap=self._chap_password)
                new_host_created = True
                logger.debug("Created host {} with iscsi name {} successfuly".format(hostname, attach_to))

            logger.debug("Trying to assign host {} to volume {} .".format(hostname, volume_name))
            self._rdxapi.assign(vol_name=volume_name, host_name=hostname)
            volume_size = volume_info[u'size']

            attached_volume = self.build_block_device(blockdevice_id=blockdevice_id, dataset_id=dataset_id,
                                                      volume_size=volume_size, attach_to=attach_to)
            logger.info('Assigning host {} to volume {} is successful.'.format(hostname, volume_name))
            # Fetching the DataIPs and add to iscsi session
        except Exception as ex:
            logger.error('An error occurred attaching volume {} to {}'.format(blockdevice_id, attach_to))
            logger.error('Exception: ' + str(ex))
            raise VolumeAttachFailure(ex)
        try:
            logger.debug("Getting all data IPs.")
            data_ips = []
            settings_info = self._rdxapi.get_settings()
            data_ips.append(settings_info[u'iscsi_network1'][u'controller_1_port_1'])
            data_ips.append(settings_info[u'iscsi_network1'][u'controller_2_port_1'])
            data_ips.append(settings_info[u'iscsi_network2'][u'controller_1_port_2'])
            data_ips.append(settings_info[u'iscsi_network2'][u'controller_2_port_2'])

            logger.debug("Listing all data IPs:")
            logger.debug(data_ips[0])
            logger.debug(data_ips[1])
            logger.debug(data_ips[2])
            logger.debug(data_ips[3])

            scsi_tcp_port = settings_info[u'network_configuration'][u'iscsi_target_tcp_port']
            logger.debug("Scsi TCP port is {} .".format(scsi_tcp_port))
            iter_count = 0
            for data_ip in data_ips:
                try:
                    iter_count += 1
                    _manage_session(ip_addr=data_ip,
                                    port=scsi_tcp_port,
                                    chap_user=self._chap_user,
                                    chap_password=self._chap_password)
                    break
                except Exception:
                    logger.debug(
                        'Failed to discover targets with data ip {}, will continue with next data ip.'.format(data_ip))
                    if iter_count == data_ips.__len__():
                        logger.error('No more data ips, Target discovery failed.')
                        raise Exception()
                    continue
            rescan_iscsi_session()
        except Exception as exc:
            logger.error('An error occurred while discovering the attached volume.')
            logger.error("Exception: {}".format(str(exc)))
            try:
                logger.debug("Error occurred while discovering attached volume."
                             "unassigning the volume {} from host {}.".format(volume_name, hostname))
                self._rdxapi.unassign(vol_name=volume_name, host_name=hostname)
                logger.debug('unassigned the volume {} from host {} successfully.'.format(volume_name, hostname))
            except Exception as ex:
                logger.error('Error occurred while unassigning the volume {} from host {},'
                             ' Exception: {}'.format(volume_name, hostname, str(ex)))
            try:
                if new_host_created:
                    logger.debug("Error occured while discovering attached volume.")
                    self._rdxapi.delete_host(name=hostname)
                    logger.debug("Deleted host {} successfully.".format(hostname))
            except Exception as ex:
                logger.error("Error occurred while deleting host {},"
                             " Exception: {}".format(hostname, str(ex)))
        return attached_volume
    def attach_volume(self, blockdevice_id, attach_to):
        """
        Attach ``blockdevice_id`` to the node indicated by ``attach_to``.

        :param unicode blockdevice_id: The unique identifier for the block
            device being attached.
        :param unicode attach_to: An identifier like the one returned by the
            ``compute_instance_id`` method indicating the node to which to
            attach the volume.
        :returns: A ``BlockDeviceVolume`` with a ``attached_to`` attribute set
            to ``attach_to``.
        """
        LOG.debug("Call attach_volume blockdevice_id=%s, attach_to=%s"
                 % (blockdevice_id, attach_to))

        if not self.rest.is_lun(self.Pool, blockdevice_id):
            raise UnknownVolume(blockdevice_id)

        vol_info = self.rest.get_lun(self.Pool, blockdevice_id)

        target_name = '{}{}.{}'.format(self.jovian_target_prefix,
                                        blockdevice_id, attach_to)

        targets = [targ['name'] for targ in self.rest.get_targets(self.Pool)]
        for target in targets:
            if blockdevice_id in target and target_name != target and \
                    self.rest.is_target_lun(self.Pool, target, blockdevice_id):
                raise AlreadyAttachedVolume(blockdevice_id)
            elif target_name == target and jcom.check_target_by_path(
                                                                target_name):
                raise AlreadyAttachedVolume(blockdevice_id)

        if not self.rest.is_target(self.Pool, target_name):
            self.rest.create_target(self.Pool, target_name)

        if not self.rest.is_target_lun(self.Pool, target_name, blockdevice_id):
            try:
                self.rest.attach_target_vol(self.Pool, target_name,
                                            blockdevice_id)
                if not self.rest.is_target_lun(self.Pool, target_name,
                                               blockdevice_id):
                    self.rest.delete_target(self.Pool, target_name)
                    raise VolumeException(blockdevice_id)
            except jexc.JDSSRESTException as error_message:
                LOG.debug(error_message)
                raise VolumeException(error_message)

        if not jcom.check_target_by_path(target_name):
            jcom.iscsiadm_discovery_target(target_name, self.host)
            jcom.iscsiadm_login_target(target_name, self.host, self.target_port)
        else:
            raise AlreadyAttachedVolume(blockdevice_id)

        jcom.check_local_disck_by_path()

        attached_volume = BlockDeviceVolume(
            size=int(vol_info['volsize']),
            attached_to=attach_to,
            dataset_id=UUID('{}'.format(blockdevice_id.split('.')[-1])),
            blockdevice_id=blockdevice_id)
        return attached_volume