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
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
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
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