'Attach an EBS volume to given compute instance.
:param unicode blockdevice_id: EBS UUID for volume to be attached.
:param unicode attach_to: Instance id of AWS 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 AttachFailed: If the volume could not be attached.
: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 EBS
device assignment rules, or some other bug in this implementation.
:raises NoAvailableDevice: If there are no available device names.'

def attach_volume(self, blockdevice_id, attach_to):

    ebs_volume = self._get_ebs_volume(blockdevice_id)
    volume = _blockdevicevolume_from_ebs_volume(ebs_volume)
    if ((volume.attached_to is not None) or (ebs_volume.state != VolumeStates.AVAILABLE.value)):
        raise AlreadyAttachedVolume(blockdevice_id)
    local_instance_id = self.compute_instance_id()
    if (attach_to != local_instance_id):
        raise AttachUnexpectedInstance(blockdevice_id, attach_to, local_instance_id)
    attached = False
    for _ in range(3):
        with self.lock:
            device = _next_device()
            blockdevices = _get_blockdevices()
            attached = _attach_volume_and_wait_for_device(volume, attach_to, self._attach_ebs_volume, self._detach_ebs_volume, device, blockdevices)
            if attached:
                _wait_for_volume_state_change(VolumeOperations.ATTACH, ebs_volume)
                attached_volume = volume.set('attached_to', attach_to)
                return attached_volume
    raise AttachFailed(volume.blockdevice_id, attach_to, device)
