Example #1
0
    def list_volumes(self):
        LOG.debug('Entering EMCUnityBlockAPI.list_volumes')

        volumes = []
        cluster_luns = [lun for lun in self.client.get_lun()
                        if self._is_cluster_volume(lun.name)]

        hosts = self.client.get_host()

        for index, lun in enumerate(cluster_luns):
            blockdevice_id = self._get_blockdevice_id_from_lun_name(lun.name)

            for host in hosts:
                if host.has_alu(lun):
                    attached_to = unicode(host.name)
                    break
            else:
                attached_to = None

            vol = loopback._blockdevicevolume_from_blockdevice_id(
                blockdevice_id=blockdevice_id,
                size=lun.size_total,
                attached_to=attached_to)
            LOG.info('[Volume %s]: '
                     'volume_name=%s, volume_size=%s, attach_to=%s',
                     index,
                     lun.name,
                     lun.size_total,
                     attached_to)
            volumes.append(vol)

        LOG.debug('Exiting EMCUnityBlockAPI.list_volumes')

        return volumes
Example #2
0
    def list_volumes(self):
        volumes = []
        cluster_luns = self._cluster_luns()
        lun_storage_group_map = self._lun_storagegroup_map(
            cluster_lun_ids=[l['lun_id'] for l in cluster_luns]
        )
        for each in cluster_luns:
            lun_id = each['lun_id']
            blockdevice_id = self._get_blockdevice_id_from_lun_name(
                each['lun_name'].decode('ascii')
            )

            attached_to = None
            try:
                group_name, group = lun_storage_group_map[lun_id]
            except KeyError:
                # LUN is not attached anywhere.
                pass
            else:
                if group_name == self._group:
                    # LUN attached here.
                    attached_to = unicode(self._hostname)
                else:
                    # Lun attached elsewhere.
                    # A node can see that a LUN has been added to another
                    # storage group but that's all.  It can't know whether the
                    # host in that foreign storage group has created a device
                    # for the LUN.  As far as it knows, it's non-manifest.  But
                    # problems occur because our BlockDeviceDeployer reports it
                    # as a non-manifest volume in the NodeState.  The control
                    # service ends up seeing and reporting a DeployementState
                    # where a dataset is both manifest on the other node and
                    # non-manifest.
                    # The workarounds for now is to list the volume as attached
                    # to a non-existent compute_id. This only works because the
                    # local deployer only reports the state of locally attached
                    # and non-manifest datasets.
                    attached_to = UNKNOWN_COMPUTE_ID

            size = int(1024*1024*1024*each['total_capacity_gb'])
            vol = _blockdevicevolume_from_blockdevice_id(
                blockdevice_id=blockdevice_id,
                size=size,
                attached_to=attached_to)
            Message.new(operation=u'list_volumes_output',
                        blockdevice_id=blockdevice_id,
                        size=size,
                        attached_to=attached_to).write()
            volumes.append(vol)
        return volumes
    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
Example #4
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
    def list_volumes(self):
        LOG.debug('Entering EMCVNXBlockAPI.list_volumes')

        volumes = []
        cluster_luns = [lun for lun in self.client.get_lun()
                        if self._is_cluster_volume(lun.name) and
                        not self.client.is_lun_destroyed(lun)]

        storage_groups = self.client.get_storage_group()

        for index, lun in enumerate(cluster_luns):
            blockdevice_id = self._get_blockdevice_id_from_lun_name(lun.name)

            for storage_group in storage_groups:
                if storage_group.has_alu(lun):
                    attached_to = unicode(storage_group.name)
                    break
            else:
                attached_to = None

            volume_size = self._gib_to_bytes(lun.total_capacity_gb)

            vol = loopback._blockdevicevolume_from_blockdevice_id(
                blockdevice_id=blockdevice_id,
                size=volume_size,
                attached_to=attached_to)
            LOG.info('[Volume %s]: '
                     'volume_name=%s, volume_size=%s, attach_to=%s',
                     index,
                     lun.name,
                     volume_size,
                     attached_to)
            volumes.append(vol)

        LOG.debug('Exiting EMCVNXBlockAPI.list_volumes')

        return volumes
Example #6
0
    def attach_volume(self, blockdevice_id, attach_to):
        Message.new(operation=u'attach_volume',
                    blockdevice_id=blockdevice_id,
                    attach_to=attach_to).write()
        lun_name = self._get_lun_name_from_blockdevice_id(blockdevice_id)
        lun = self._client.get_lun_by_name(lun_name)

        if lun == {}:
            raise UnknownVolume(blockdevice_id)
        alu = lun['lun_id']

        rc, out = self._client.get_storage_group(self._group)
        if rc != 0:
            raise Exception(rc, out)

        lunmap = self._client.parse_sg_content(out)['lunmap']
        try:
            # The LUN has already been added to this storage group....perhaps
            # by a previous attempt to attach in which the OS device did not
            # appear.
            hlu = lunmap[alu]
        except KeyError:
            # Add LUN to storage group
            hlu = self._choose_hlu(lunmap)
            rc, out = self._client.add_volume_to_sg(str(hlu),
                                                    str(alu),
                                                    self._group)
            if rc != 0:
                if rc == 66:
                    raise AlreadyAttachedVolume(blockdevice_id)
                else:
                    raise Exception(rc, out)

        volume = _blockdevicevolume_from_blockdevice_id(
            blockdevice_id=blockdevice_id,
            size=int(lun['total_capacity_gb']*1024*1024*1024),
            attached_to=unicode(attach_to)
        )

        # Rescan and wait for the expected bus 3 times and wait successively
        # longer for the device to appear.
        # Sometimes the bus doesn't appear until you rescan repeatedly.
        # XXX Often it never appears....which is a problem
        counter = 1
        start_time = time.time()
        # XXX This will only operate on the first available HLU bus
        hlu_bus_path = _hlu_bus_paths(hlu)[0]
        # /sys/class/scsi_disks/<fc_port>:0:0:<hlu>/device/block/ contains
        # symlinks whose names are the device names that have been allocated eg
        # sdvb.
        block_device_pointers = hlu_bus_path.descendant(['device', 'block'])

        # Do an early check to see if the device is already present.
        if _directory_listable(block_device_pointers):
            new_device = _device_paths_for_hlu_bus_path(hlu_bus_path)[0]
            if _device_path_is_usable(new_device):
                raise AlreadyAttachedVolume(blockdevice_id)

        while True:
            with open(os.devnull, 'w') as discard:
                check_output(
                    ["rescan-scsi-bus", "--luns={}".format(hlu)],
                    stderr=discard
                )
            try:
                wait_for(
                    predicate=lambda: _directory_listable(
                        block_device_pointers
                    ),
                    timeout=5 * counter
                )
                break
            except Timeout:
                if counter > 5:
                    elapsed_time = time.time() - start_time
                    raise Timeout(
                        "HLU bus did not appear. "
                        "Expected {}. "
                        "Waited {}s and performed {} scsi bus rescans.".format(
                            hlu_bus_path,
                            elapsed_time,
                            counter,
                        ),
                        hlu_bus_path, elapsed_time, counter
                    )
                else:
                    counter += 1

        # Once the bus is available we can discover the device path and check
        # that the device path is usable It may not be usable. For example the
        # device is sometimes initially 0 size until you force a rescan:

        # (echo 1 > /sys/class/scsi_disk/1:0:0:219/device/rescan)
        # Nov 07 04:55:40 00009bb1a4558a12 kernel: sd 1:0:0:219: [sdup] 16777216 512-byte logical blocks: (8.58 GB/8.00 GiB)
        # Nov 07 04:55:40 00009bb1a4558a12 kernel: sdup: detected capacity change from 0 to 8589934592
        # 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.
        new_device = _device_paths_for_hlu_bus_path(hlu_bus_path)[0]
        rescan_device = hlu_bus_path.descendant(['device', 'rescan'])
        counter = 1
        while True:
            try:
                wait_for(
                    predicate=lambda: _device_path_is_usable(new_device),
                    timeout=5 * counter
                )
                break
            except Timeout:
                if counter > 5:
                    elapsed_time = time.time() - start_time
                    raise Timeout(
                        "Device did not appear. "
                        "Expected {}. "
                        "Waited {}s and performed {} scsi bus rescans.".format(
                            new_device,
                            elapsed_time,
                            counter,
                        ),
                        new_device, elapsed_time, counter
                    )
                else:
                    with rescan_device.open('w') as f:
                        f.write('1\n')
                    counter += 1

        Message.new(
            operation=u'attach_volume_output',
            blockdevice_id=blockdevice_id,
            attach_to=attach_to,
            lun_name=lun_name,
            alu=alu,
            hlu=hlu,
            device_path=repr(new_device)
        ).write()
        return volume