def get_volume(self, name, volume_context=None, volume_prefix=""): logger.debug("Getting volume {} under context {}".format( name, volume_context)) if not volume_context: logger.error( "volume_context is not specified, can not get volumes from storage." ) raise array_errors.VolumeNotFoundError(name) volume_candidates = [] if config.CONTEXT_POOL in volume_context: try: volume_candidates = self.client.get_volumes_by_pool( volume_context[config.CONTEXT_POOL]) except exceptions.NotFound as ex: if ERROR_CODE_RESOURCE_NOT_EXISTS in str(ex.message).upper(): raise array_errors.PoolDoesNotExist( volume_context[config.CONTEXT_POOL], self.identifier) else: raise ex for vol in volume_candidates: if vol.name == shorten_volume_name(name, volume_prefix): logger.debug("Found volume: {}".format(vol)) return self._generate_volume_response(vol) raise array_errors.VolumeNotFoundError(name)
def unmap_volume(self, volume_id, host_name): logger.debug("un-mapping volume : {0} from host : " "{1}".format(volume_id, host_name)) vol_name = self._get_vol_by_wwn(volume_id) cli_kwargs = { 'host': host_name, 'vdisk_id': vol_name } try: self.client.svctask.rmvdiskhostmap(**cli_kwargs) except (svc_errors.CommandExecutionError, CLIFailureError) as ex: if not is_warning_message(ex.my_message): logger.error(msg="Map volume {0} to host {1} failed. Reason " "is: {2}".format(vol_name, host_name, ex)) if NAME_NOT_MEET in ex.my_message: raise controller_errors.HostNotFoundError(host_name) if OBJ_NOT_FOUND in ex.my_message: raise controller_errors.VolumeNotFoundError(vol_name) if VOL_ALREADY_UNMAPPED in ex.my_message: raise controller_errors.VolumeAlreadyUnmappedError( vol_name) raise controller_errors.UnMappingError(vol_name, host_name, ex) except Exception as ex: logger.exception(ex) raise ex
def map_volume(self, volume_id, host_name): logger.debug("mapping volume : {0} to host : {1}".format( volume_id, host_name)) vol_name = self._get_vol_by_wwn(volume_id) lun = self._get_next_available_lun(host_name) try: self.client.cmd.map_vol(host=host_name, vol=vol_name, lun=lun) except xcli_errors.OperationForbiddenForUserCategoryError as ex: logger.exception(ex) raise controller_errors.PermissionDeniedError( "map volume : {0} to host : {1}".format(volume_id, host_name)) except xcli_errors.VolumeBadNameError as ex: logger.exception(ex) raise controller_errors.VolumeNotFoundError(vol_name) except xcli_errors.HostBadNameError as ex: logger.exception(ex) raise controller_errors.HostNotFoundError(host_name) except xcli_errors.CommandFailedRuntimeError as ex: logger.exception(ex) if "LUN is already in use" in ex.status: raise controller_errors.LunAlreadyInUseError(lun, host_name) else: raise controller_errors.MappingError(vol_name, host_name, ex) return str(lun)
def test_publish_volume_map_volume_excpetions(self, enter): context = utils.FakeContext() self.mediator.map_volume.side_effect = [ array_errors.PermissionDeniedError("msg") ] enter.return_value = self.mediator self.servicer.ControllerPublishVolume(self.request, context) self.assertEqual(context.code, grpc.StatusCode.PERMISSION_DENIED) self.mediator.map_volume.side_effect = [ array_errors.VolumeNotFoundError("vol") ] enter.return_value = self.mediator self.servicer.ControllerPublishVolume(self.request, context) self.assertEqual(context.code, grpc.StatusCode.NOT_FOUND) self.mediator.map_volume.side_effect = [ array_errors.HostNotFoundError("host") ] enter.return_value = self.mediator self.servicer.ControllerPublishVolume(self.request, context) self.assertEqual(context.code, grpc.StatusCode.NOT_FOUND) self.mediator.map_volume.side_effect = [ array_errors.MappingError("", "", "") ] enter.return_value = self.mediator self.servicer.ControllerPublishVolume(self.request, context) self.assertEqual(context.code, grpc.StatusCode.INTERNAL)
def copy_to_existing_volume_from_snapshot(self, name, src_snap_name, src_snap_capacity_in_bytes, min_vol_size_in_bytes, pool=None): logger.debug( "Copy snapshot {0} data to volume {1}. Snapshot capacity {2}. Minimal requested volume capacity {3}".format( name, src_snap_name, src_snap_capacity_in_bytes, min_vol_size_in_bytes)) try: logger.debug("Formatting volume {0}".format(name)) self.client.cmd.vol_format(vol=name) logger.debug("Copying Snapshot {0} data to volume {1}.".format(name, src_snap_name)) self.client.cmd.vol_copy(vol_src=src_snap_name, vol_trg=name) if min_vol_size_in_bytes > src_snap_capacity_in_bytes: min_vol_size_in_blocks = self._convert_size_bytes_to_blocks(min_vol_size_in_bytes) logger.debug( "Increasing volume {0} size to {1} blocks.".format(name, min_vol_size_in_blocks)) self.client.cmd.vol_resize(vol=name, size_blocks=min_vol_size_in_blocks) except xcli_errors.IllegalNameForObjectError as ex: logger.exception(ex) raise controller_errors.IllegalObjectName(ex.status) except xcli_errors.SourceVolumeBadNameError as ex: logger.exception(ex) raise controller_errors.SnapshotNotFoundError(src_snap_name) except (xcli_errors.VolumeBadNameError, xcli_errors.TargetVolumeBadNameError) as ex: logger.exception(ex) raise controller_errors.VolumeNotFoundError(name) except xcli_errors.OperationForbiddenForUserCategoryError as ex: logger.exception(ex) raise controller_errors.PermissionDeniedError("create vol : {0}".format(name))
def get_volume(self, name, volume_context=None, volume_prefix=""): logger.debug("Getting volume {} under context {}".format( name, volume_context)) if not volume_context: logger.error( "volume_context is not specified, can not get volumes from storage." ) raise array_errors.VolumeNotFoundError(name) api_volume = self._get_api_volume_by_name( volume_name=name, pool_id=volume_context[config.CONTEXT_POOL]) if api_volume: return self._generate_volume_response(api_volume) raise array_errors.VolumeNotFoundError(name)
def _create_flashcopy(self, source_volume_id, target_volume_id, options=None): logger.info( "creating FlashCopy relationship from '{0}' to '{1}'".format( source_volume_id, target_volume_id)) source_volume_id = get_volume_id_from_scsi_identifier(source_volume_id) target_volume_id = get_volume_id_from_scsi_identifier(target_volume_id) if not options: options = [] options.append(FLASHCOPY_PERMIT_SPACE_EFFICIENT_TARGET) try: api_flashcopy = self.client.create_flashcopy( source_volume_id=source_volume_id, target_volume_id=target_volume_id, options=options) except (exceptions.ClientError, exceptions.ClientException) as ex: if ERROR_CODE_ALREADY_FLASHCOPY in str(ex.message).upper(): raise array_errors.SnapshotAlreadyExists( target_volume_id, self.service_address) elif ERROR_CODE_VOLUME_NOT_FOUND_OR_ALREADY_PART_OF_CS_RELATIONSHIP in str( ex.message).upper(): raise array_errors.VolumeNotFoundError('{} or {}'.format( source_volume_id, target_volume_id)) else: raise ex if not self.validate_flashcopy(api_flashcopy.id): self._delete_flashcopy(api_flashcopy.id) logger.info("Flashcopy is not in a valid state") raise ValueError return self._get_api_volume_by_id(target_volume_id)
def unmap_volume(self, volume_id, host_name): logger.debug("un-mapping volume : {0} from host : {1}".format( volume_id, host_name)) vol_name = self._get_vol_by_wwn(volume_id) try: self.client.cmd.unmap_vol(host=host_name, vol=vol_name) except xcli_errors.VolumeBadNameError as ex: logger.exception(ex) raise controller_errors.VolumeNotFoundError(vol_name) except xcli_errors.HostBadNameError as ex: logger.exception(ex) raise controller_errors.HostNotFoundError(host_name) except xcli_errors.OperationForbiddenForUserCategoryError as ex: logger.exception(ex) raise controller_errors.PermissionDeniedError( "unmap volume : {0} from host : {1}".format( volume_id, host_name)) except xcli_errors.CommandFailedRuntimeError as ex: logger.exception(ex) if "The requested mapping is not defined" in ex.status: raise controller_errors.VolumeAlreadyUnmappedError(vol_name) else: raise controller_errors.UnMappingError(vol_name, host_name, ex)
def map_volume(self, volume_id, host_name): logger.debug("mapping volume : {0} to host : " "{1}".format(volume_id, host_name)) vol_name = self._get_vol_by_wwn(volume_id) cli_kwargs = {'host': host_name, 'object_id': vol_name, 'force': True} try: lun = self.get_first_free_lun(host_name) cli_kwargs.update({'scsi': lun}) self.client.svctask.mkvdiskhostmap(**cli_kwargs) except (svc_errors.CommandExecutionError, CLIFailureError) as ex: if not is_warning_message(ex.my_message): logger.error(msg="Map volume {0} to host {1} failed. Reason " "is: {2}".format(vol_name, host_name, ex)) if NAME_NOT_MEET in ex.my_message: raise controller_errors.HostNotFoundError(host_name) if SPECIFIED_OBJ_NOT_EXIST in ex.my_message: raise controller_errors.VolumeNotFoundError(vol_name) if VOL_ALREADY_MAPPED in ex.my_message: raise controller_errors.LunAlreadyInUseError( lun, host_name) raise controller_errors.MappingError(vol_name, host_name, ex) except Exception as ex: logger.exception(ex) raise ex return str(lun)
def setUp(self, connect): self.fqdn = "fqdn" self.mediator = XIVArrayMediator("user", "password", self.fqdn) self.mediator.client = Mock() self.mediator.get_volume = Mock() self.mediator.get_volume.side_effect = [ array_errors.VolumeNotFoundError("vol") ] self.servicer = ControllerServicer(self.fqdn) self.request = Mock() caps = Mock() caps.mount = Mock() caps.mount.fs_type = "ext4" access_types = csi_pb2.VolumeCapability.AccessMode caps.access_mode.mode = access_types.SINGLE_NODE_WRITER self.request.volume_capabilities = [caps] self.pool = 'pool1' self.request.secrets = { "username": "******", "password": "******", "management_address": "mg" } self.request.parameters = {"pool": self.pool} self.capacity_bytes = 10 self.request.capacity_range.required_bytes = self.capacity_bytes self.request.name = vol_name
def _get_api_volume_by_id(self, volume_id, not_exist_err=True): try: volume = self.client.get_volume(volume_id) volume.flashcopy = self.get_flashcopies_by_volume(volume.id) return volume except exceptions.NotFound: if not_exist_err: raise array_errors.VolumeNotFoundError(volume_id)
def _get_vol_by_wwn(self, volume_id): vol_by_wwn = self.client.cmd.vol_list(wwn=volume_id).as_single_element if not vol_by_wwn: raise controller_errors.VolumeNotFoundError(volume_id) vol_name = vol_by_wwn.name logger.debug("found volume name : {0}".format(vol_name)) return vol_name
def _get_cli_volume(self, volume_name_or_id, not_exist_err=True): try: cli_volume = self.client.svcinfo.lsvdisk( bytes=True, object_id=volume_name_or_id).as_single_element if not cli_volume and not_exist_err: raise controller_errors.VolumeNotFoundError(volume_name_or_id) return cli_volume except (svc_errors.CommandExecutionError, CLIFailureError) as ex: if not is_warning_message(ex.my_message): if (OBJ_NOT_FOUND in ex.my_message or NAME_NOT_MEET in ex.my_message): logger.info("volume not found") if not_exist_err: raise controller_errors.VolumeNotFoundError( volume_name_or_id) except Exception as ex: logger.exception(ex) raise ex
def _delete_flashcopy(self, flascopy_id): try: self.client.delete_flashcopy(flascopy_id) except exceptions.NotFound: raise array_errors.VolumeNotFoundError(flascopy_id) except exceptions.ClientException as ex: logger.error( "Failed to delete flascopy {} on array {}, reason is: {}". format(flascopy_id, self.identifier, ex.details)) raise ex
def _get_vol_by_wwn(self, volume_id): filter_value = 'vdisk_UID=' + volume_id vol_by_wwn = self.client.svcinfo.lsvdisk( filtervalue=filter_value).as_single_element if not vol_by_wwn: raise controller_errors.VolumeNotFoundError(volume_id) vol_name = vol_by_wwn.name logger.debug("found volume name : {0}".format(vol_name)) return vol_name
def get_volume(self, volume_name, volume_context=None, volume_prefix=""): logger.debug("Get volume : {}".format(volume_name)) cli_volume = None try: cli_volume = self.client.svcinfo.lsvdisk( bytes=True, object_id=volume_name).as_single_element except (svc_errors.CommandExecutionError, CLIFailureError) as ex: if not is_warning_message(ex.my_message): if (OBJ_NOT_FOUND in ex.my_message or NAME_NOT_MEET in ex.my_message): logger.error("Volume not found") raise controller_errors.VolumeNotFoundError(volume_name) except Exception as ex: logger.exception(ex) raise ex if not cli_volume: raise controller_errors.VolumeNotFoundError(volume_name) logger.debug("cli volume returned : {}".format(cli_volume)) return self._generate_volume_response(cli_volume)
def get_volume_name(self, volume_id): logger.debug("Searching for volume with id: {0}".format(volume_id)) volume_id = get_volume_id_from_scsi_identifier(volume_id) try: api_volume = self.client.get_volume(volume_id) except exceptions.NotFound: raise array_errors.VolumeNotFoundError(volume_id) vol_name = api_volume.name logger.debug("found volume name : {0}".format(vol_name)) return vol_name
def delete_volume(self, volume_id): logger.info("Deleting volume {}".format(volume_id)) try: self.client.delete_volume( volume_id=get_volume_id_from_scsi_identifier(volume_id)) logger.info("Finished deleting volume {}".format(volume_id)) except exceptions.NotFound: raise array_errors.VolumeNotFoundError(volume_id) except exceptions.ClientException as ex: logger.error( "Failed to delete volume {} on array {}, reason is: {}".format( volume_id, self.identifier, ex.details)) raise array_errors.VolumeDeletionError(volume_id)
def delete_volume(self, volume_id): logger.info("Deleting volume with id : {0}".format(volume_id)) vol_name = self._get_vol_by_wwn(volume_id) try: self.client.cmd.vol_delete(vol=vol_name) except xcli_errors.VolumeBadNameError as ex: logger.exception(ex) raise controller_errors.VolumeNotFoundError(vol_name) except xcli_errors.OperationForbiddenForUserCategoryError as ex: logger.exception(ex) raise controller_errors.PermissionDeniedError("delete vol : {0}".format(vol_name)) logger.info("Finished volume deletion. id : {0}".format(volume_id))
def get_volume(self, vol_name): logger.debug("Get volume : {}".format(vol_name)) try: cli_volume = self.client.cmd.vol_list( vol=vol_name).as_single_element except xcli_errors.IllegalNameForObjectError as ex: logger.exception(ex) raise controller_errors.IllegalObjectName(ex.status) logger.debug("cli volume returned : {}".format(cli_volume)) if not cli_volume: raise controller_errors.VolumeNotFoundError(vol_name) array_vol = self._generate_volume_response(cli_volume) return array_vol
def get_volume_mappings(self, volume_id): logger.debug("Getting volume mappings for volume id : " "{0}".format(volume_id)) vol_name = self._get_vol_by_wwn(volume_id) logger.debug("vol name : {0}".format(vol_name)) try: mapping_list = self.client.svcinfo.lsvdiskhostmap(vdisk_name=vol_name) res = {} for mapping in mapping_list: logger.debug("mapping for vol is :{0}".format(mapping)) res[mapping.get('host_name', '')] = mapping.get('SCSI_id', '') except(svc_errors.CommandExecutionError, CLIFailureError) as ex: logger.error(ex) raise controller_errors.VolumeNotFoundError(volume_id) return res
def _create_similar_volume(self, target_volume_name, source_volume_name, pool_id): logger.info( "creating target api volume '{0}' from source volume '{1}'".format( target_volume_name, source_volume_name)) source_api_volume = self._get_api_volume_by_name(source_volume_name, pool_id=pool_id) if not source_api_volume: raise array_errors.VolumeNotFoundError(source_volume_name) capabilities = { config.CAPABILITIES_SPACEEFFICIENCY: source_api_volume.tp } size_in_bytes = int(source_api_volume.cap) pool = source_api_volume.pool return self.create_volume(target_volume_name, size_in_bytes, capabilities, pool)
def _delete_volume_by_name(self, volume_name, not_exist_err=True): logger.info("deleting volume with name : {0}".format(volume_name)) try: self.client.svctask.rmvolume(vdisk_id=volume_name) except (svc_errors.CommandExecutionError, CLIFailureError) as ex: if not is_warning_message(ex.my_message): logger.warning( "Failed to delete volume {}".format(volume_name)) if (OBJ_NOT_FOUND in ex.my_message or VOL_NOT_FOUND in ex.my_message) and not_exist_err: raise controller_errors.VolumeNotFoundError(volume_name) else: raise ex except Exception as ex: logger.exception(ex) raise ex
def get_volume(self, volume_name, volume_context=None, volume_prefix=""): logger.debug("Get volume : {}".format(volume_name)) try: cli_volume = self.client.cmd.vol_list(vol=volume_name).as_single_element except xcli_errors.IllegalNameForObjectError as ex: logger.exception(ex) raise controller_errors.IllegalObjectName(ex.status) logger.debug("cli volume returned : {}".format(cli_volume)) if not cli_volume: raise controller_errors.VolumeNotFoundError(volume_name) if cli_volume.master_name: raise controller_errors.VolumeNameBelongsToSnapshotError(volume_name, self.endpoint) array_vol = self._generate_volume_response(cli_volume) return array_vol
def delete_volume(self, volume_id): logger.info("Deleting volume with id : {0}".format(volume_id)) vol_name = self._get_vol_by_wwn(volume_id) try: self.client.svctask.rmvolume(vdisk_id=vol_name) except (svc_errors.CommandExecutionError, CLIFailureError) as ex: if not is_warning_message(ex.my_message): logger.warning("Failed to delete volume {}".format(vol_name)) if (OBJ_NOT_FOUND in ex.my_message or VOL_NOT_FOUND in ex.my_message): raise controller_errors.VolumeNotFoundError(vol_name) else: raise ex except Exception as ex: logger.exception(ex) raise ex logger.info("Finished volume deletion. id : {0}".format(volume_id))
def create_snapshot(self, name, volume_name, volume_context=None): logger.info("creating snapshot {0} from volume {1}".format(name, volume_name)) try: cli_snapshot = self.client.cmd.snapshot_create(name=name, vol=volume_name).as_single_element logger.info("finished creating cli snapshot {0} from volume {1}".format(name, volume_name)) return self._generate_snapshot_response(cli_snapshot) except xcli_errors.IllegalNameForObjectError as ex: logger.exception(ex) raise controller_errors.IllegalObjectName(ex.status) except xcli_errors.VolumeExistsError as ex: logger.exception(ex) raise controller_errors.SnapshotAlreadyExists(name, self.endpoint) except xcli_errors.VolumeBadNameError as ex: logger.exception(ex) raise controller_errors.VolumeNotFoundError(volume_name) except xcli_errors.OperationForbiddenForUserCategoryError as ex: logger.exception(ex) raise controller_errors.PermissionDeniedError( "create snapshot {0} from volume {1}".format(name, volume_name))
def map_volume(self, volume_id, host_name): logger.debug("Mapping volume {} to host {}".format( volume_id, host_name)) array_volume_id = get_volume_id_from_scsi_identifier(volume_id) try: mapping = self.client.map_volume_to_host(host_name, array_volume_id) lun = scsilun_to_int(mapping.lunid) logger.debug( "Successfully mapped volume to host with lun {}".format(lun)) return lun except exceptions.NotFound: raise array_errors.HostNotFoundError(host_name) except exceptions.ClientException as ex: # [BE586015] addLunMappings Volume group operation failure: volume does not exist. if ERROR_CODE_VOLUME_NOT_FOUND_FOR_MAPPING in str( ex.message).upper(): raise array_errors.VolumeNotFoundError(volume_id) else: raise array_errors.MappingError(volume_id, host_name, ex.details)
def unmap_volume(self, volume_id, host_name): logger.debug("Unmapping volume {} from host {}".format( volume_id, host_name)) array_volume_id = get_volume_id_from_scsi_identifier(volume_id) try: mappings = self.client.get_host_mappings(host_name) lunid = None for mapping in mappings: if mapping.volume == array_volume_id: lunid = mapping.id break if lunid is not None: self.client.unmap_volume_from_host(host_name=host_name, lunid=lunid) logger.debug( "Successfully unmapped volume from host with lun {}.". format(lunid)) else: raise array_errors.VolumeNotFoundError(volume_id) except exceptions.NotFound: raise array_errors.HostNotFoundError(host_name) except exceptions.ClientException as ex: raise array_errors.UnMappingError(volume_id, host_name, ex.details)
def get_snapshot(self, snapshot_name, volume_context=None): logger.debug("Get snapshot : {} with context: {}".format( snapshot_name, volume_context)) if not volume_context: logger.error( "volume_context is not specified, can not get volumes from storage." ) raise array_errors.VolumeNotFoundError(snapshot_name) target_api_volume = self._get_api_volume_by_name( volume_name=snapshot_name, pool_id=volume_context[config.CONTEXT_POOL]) if not target_api_volume: return None if not target_api_volume.flashcopy: logger.error( "FlashCopy relationship not found for target volume: {}". format(snapshot_name)) raise array_errors.SnapshotNameBelongsToVolumeError( target_api_volume.name, self.service_address) flashcopy_rel = self._get_flashcopy(target_api_volume.flashcopy[0].id) source_volume_name = self.get_volume_name( flashcopy_rel.source_volume['id']) return self._generate_snapshot_response(target_api_volume, source_volume_name)
def test_delete_volume_with_volume_not_found_error(self, ): self.delete_volume_returns_error( error=array_errors.VolumeNotFoundError("vol"), return_code=grpc.StatusCode.OK)