def DeleteSnapshot(self, request, context): set_current_thread_name(request.snapshot_id) logger.info("Delete snapshot") secrets = request.secrets try: utils.validate_delete_snapshot_request(request) user, password, array_addresses = utils.get_array_connection_info_from_secret( secrets) try: array_type, snapshot_id = utils.get_snapshot_id_info( request.snapshot_id) except ObjectIdError as ex: logger.warning("volume id is invalid. error : {}".format(ex)) return csi_pb2.DeleteVolumeResponse() array_type = detect_array_type(array_addresses) with get_agent(user, password, array_addresses, array_type).get_mediator() as array_mediator: logger.debug(array_mediator) try: array_mediator.delete_snapshot(snapshot_id) except controller_errors.SnapshotNotFoundError as ex: logger.debug( "Snapshot was not found during deletion: {0}".format( ex)) except controller_errors.SnapshotNotFoundError: logger.debug( "snapshot was not found during deletion: {0}".format(ex)) context.set_code(grpc.StatusCode.OK) return csi_pb2.DeleteSnapshotResponse() except controller_errors.SnapshotIsStillInUseError: logger.info( "could not delete snapshot while in use: {0}".format(ex)) context.set_code(grpc.StatusCode.FAILED_PRECONDITION) context.set_details(ex) return csi_pb2.DeleteSnapshotResponse() except controller_errors.PermissionDeniedError as ex: context.set_code(grpc.StatusCode.PERMISSION_DENIED) context.set_details(ex) return csi_pb2.DeleteSnapshotResponse() except ValidationException as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.INVALID_ARGUMENT) return csi_pb2.DeleteSnapshotResponse() except Exception as ex: logger.debug("an internal exception occurred") logger.exception(ex) context.set_code(grpc.StatusCode.INTERNAL) context.set_details( 'an internal exception occurred : {}'.format(ex)) return csi_pb2.DeleteSnapshotResponse() logger.debug("generating delete snapshot response") res = csi_pb2.DeleteSnapshotResponse() logger.info("finished DeleteSnapshot") return res
def test_detect_array_type(self, _): self.assertEqual(detect_array_type([ "svc_host", ]), SVCArrayMediator.array_type) self.assertEqual(detect_array_type([ "ds8k_host", ]), DS8KArrayMediator.array_type) self.assertEqual(detect_array_type([ "xiv_host", ]), XIVArrayMediator.array_type) with self.assertRaises(FailedToFindStorageSystemType): detect_array_type([ "unknown_host", ])
def CreateVolume(self, request, context): set_current_thread_name(request.name) logger.info("create volume") try: utils.validate_create_volume_request(request) except ObjectIdError as ex: return handle_exception(ex, context, grpc.StatusCode.NOT_FOUND, csi_pb2.CreateVolumeResponse) logger.debug("volume name : {}".format(request.name)) source_type, source_id = self._get_source_type_and_id(request) logger.debug("Source {0} id : {1}".format(source_type, source_id)) topologies = utils.get_volume_topologies(request) secrets = request.secrets try: array_connection_info = utils.get_array_connection_info_from_secrets( secrets=secrets, topologies=topologies) volume_parameters = utils.get_volume_parameters( parameters=request.parameters, system_id=array_connection_info.system_id) pool = volume_parameters.pool if not pool: raise ValidationException( controller_messages.pool_should_not_be_empty_message) space_efficiency = volume_parameters.space_efficiency # TODO : pass multiple array addresses array_type = detect_array_type( array_connection_info.array_addresses) with get_agent(array_connection_info, array_type).get_mediator() as array_mediator: logger.debug(array_mediator) volume_final_name = self._get_volume_final_name( volume_parameters, request.name, array_mediator) required_bytes = request.capacity_range.required_bytes max_size = array_mediator.maximal_volume_size_in_bytes min_size = array_mediator.minimal_volume_size_in_bytes if required_bytes > max_size: message = messages.SizeOutOfRangeError_message.format( required_bytes, max_size) return build_error_response(message, context, grpc.StatusCode.OUT_OF_RANGE, csi_pb2.CreateVolumeResponse) if required_bytes == 0: required_bytes = min_size logger.debug( "requested size is 0 so the default size will be used : {0} " .format(required_bytes)) try: volume = array_mediator.get_volume( volume_final_name, pool=pool, ) except array_errors.ObjectNotFoundError: logger.debug( "volume was not found. creating a new volume with parameters: {0}" .format(request.parameters)) array_mediator.validate_supported_space_efficiency( space_efficiency) volume = array_mediator.create_volume( volume_final_name, required_bytes, space_efficiency, pool) else: logger.debug("volume found : {}".format(volume)) if not source_id and volume.capacity_bytes != request.capacity_range.required_bytes: message = "Volume was already created with different size." return build_error_response( message, context, grpc.StatusCode.ALREADY_EXISTS, csi_pb2.CreateVolumeResponse) copy_source_res = self._handle_existing_volume_source( volume, source_id, source_type, array_connection_info.system_id, context) if copy_source_res: return copy_source_res if source_id: self._copy_to_existing_volume_from_source( volume, source_id, source_type, required_bytes, array_mediator) volume.copy_source_id = source_id res = utils.generate_csi_create_volume_response( volume, array_connection_info.system_id, source_type) logger.info("finished create volume") return res except array_errors.InvalidArgumentError as ex: return handle_exception(ex, context, grpc.StatusCode.INVALID_ARGUMENT, csi_pb2.CreateVolumeResponse) except array_errors.VolumeAlreadyExists as ex: return handle_exception(ex, context, grpc.StatusCode.ALREADY_EXISTS, csi_pb2.CreateVolumeResponse)
def CreateVolume(self, request, context): # pylint: disable=too-many-branches set_current_thread_name(request.name) logger.info("create volume") try: utils.validate_create_volume_request(request) except ValidationException as ex: logger.error("failed request validation") logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.INVALID_ARGUMENT) return csi_pb2.CreateVolumeResponse() except ObjectIdError as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.NOT_FOUND) return csi_pb2.CreateVolumeResponse() volume_name = request.name logger.debug("volume name : {}".format(volume_name)) src_snapshot_id = self._get_src_snapshot_id(request) logger.debug("Source snapshot id : {}".format(src_snapshot_id)) secrets = request.secrets user, password, array_addresses = utils.get_array_connection_info_from_secret( secrets) pool = request.parameters[config.PARAMETERS_POOL] capabilities = { key: value for key, value in request.parameters.items() if key in [ config.PARAMETERS_CAPABILITIES_SPACEEFFICIENCY, ] } try: # TODO : pass multiple array addresses array_type = detect_array_type(array_addresses) with get_agent(user, password, array_addresses, array_type).get_mediator() as array_mediator: logger.debug(array_mediator) # TODO: CSI-1358 - remove try/except try: volume_full_name, volume_prefix = self._get_volume_name_and_prefix( request, array_mediator) except controller_errors.IllegalObjectName as ex: context.set_details(ex.message) context.set_code(grpc.StatusCode.INVALID_ARGUMENT) return csi_pb2.CreateSnapshotResponse() size = request.capacity_range.required_bytes if size == 0: size = array_mediator.minimal_volume_size_in_bytes logger.debug( "requested size is 0 so the default size will be used : {0} " .format(size)) try: vol = array_mediator.get_volume( volume_full_name, volume_context=request.parameters, volume_prefix=volume_prefix, ) except controller_errors.VolumeNotFoundError: logger.debug( "volume was not found. creating a new volume with parameters: {0}" .format(request.parameters)) array_mediator.validate_supported_capabilities( capabilities) vol = array_mediator.create_volume(volume_full_name, size, capabilities, pool, volume_prefix) else: logger.debug("volume found : {}".format(vol)) if not src_snapshot_id and vol.capacity_bytes != request.capacity_range.required_bytes: context.set_details( "Volume was already created with different size.") context.set_code(grpc.StatusCode.ALREADY_EXISTS) return csi_pb2.CreateVolumeResponse() copy_source_res = self._handle_existing_vol_src_snap( vol, src_snapshot_id, context) if copy_source_res: return copy_source_res if src_snapshot_id: self._copy_to_existing_volume_from_snapshot( vol, src_snapshot_id, size, array_mediator, pool) vol.copy_src_object_id = src_snapshot_id logger.debug("generating create volume response") res = utils.generate_csi_create_volume_response(vol) logger.info("finished create volume") return res except (controller_errors.IllegalObjectName, controller_errors.StorageClassCapabilityNotSupported, controller_errors.PoolDoesNotExist, controller_errors.PoolDoesNotMatchCapabilities) as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.INVALID_ARGUMENT) return csi_pb2.CreateVolumeResponse() except controller_errors.PermissionDeniedError as ex: context.set_code(grpc.StatusCode.PERMISSION_DENIED) context.set_details(ex) return csi_pb2.CreateVolumeResponse() except controller_errors.VolumeAlreadyExists as ex: context.set_details(ex.message) context.set_code(grpc.StatusCode.ALREADY_EXISTS) return csi_pb2.CreateVolumeResponse() except Exception as ex: logger.error("an internal exception occurred") logger.exception(ex) context.set_code(grpc.StatusCode.INTERNAL) context.set_details( 'an internal exception occurred : {}'.format(ex)) return csi_pb2.CreateVolumeResponse()
def CreateSnapshot(self, request, context): set_current_thread_name(request.name) logger.info("Create snapshot") try: utils.validate_create_snapshot_request(request) except ValidationException as ex: logger.error("failed request validation") logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.INVALID_ARGUMENT) return csi_pb2.CreateSnapshotResponse() source_volume_id = request.source_volume_id logger.info("Snapshot base name : {}. Source volume id : {}".format( request.name, source_volume_id)) secrets = request.secrets user, password, array_addresses = utils.get_array_connection_info_from_secret( secrets) try: _, vol_id = utils.get_volume_id_info(source_volume_id) array_type = detect_array_type(array_addresses) with get_agent(user, password, array_addresses, array_type).get_mediator() as array_mediator: logger.debug(array_mediator) # TODO: CSI-1358 - remove try/except try: snapshot_name = self._get_snapshot_name( request, array_mediator) except controller_errors.IllegalObjectName as ex: context.set_details(ex.message) context.set_code(grpc.StatusCode.INVALID_ARGUMENT) return csi_pb2.CreateSnapshotResponse() volume_name = array_mediator.get_volume_name(vol_id) logger.info("Snapshot name : {}. Volume name : {}".format( snapshot_name, volume_name)) snapshot = array_mediator.get_snapshot( snapshot_name, volume_context=request.parameters) if snapshot: if snapshot.volume_name != volume_name: context.set_details( messages.SnapshotWrongVolumeError_message.format( snapshot_name, snapshot.volume_name, volume_name)) context.set_code(grpc.StatusCode.ALREADY_EXISTS) return csi_pb2.CreateSnapshotResponse() else: logger.debug( "Snapshot doesn't exist. Creating a new snapshot {0} from volume {1}" .format(snapshot_name, volume_name)) snapshot = array_mediator.create_snapshot( snapshot_name, volume_name, request.parameters) logger.debug("generating create snapshot response") res = utils.generate_csi_create_snapshot_response( snapshot, source_volume_id) logger.info("finished create snapshot") return res except (controller_errors.IllegalObjectName, controller_errors.VolumeNotFoundError) as ex: context.set_details(ex.message) context.set_code(grpc.StatusCode.INVALID_ARGUMENT) return csi_pb2.CreateSnapshotResponse() except controller_errors.PermissionDeniedError as ex: context.set_code(grpc.StatusCode.PERMISSION_DENIED) context.set_details(ex) return csi_pb2.CreateSnapshotResponse() except controller_errors.SnapshotAlreadyExists as ex: context.set_details(ex.message) context.set_code(grpc.StatusCode.ALREADY_EXISTS) return csi_pb2.CreateSnapshotResponse() except Exception as ex: logger.error("an internal exception occurred") logger.exception(ex) context.set_code(grpc.StatusCode.INTERNAL) context.set_details( 'an internal exception occurred : {}'.format(ex)) return csi_pb2.CreateSnapshotResponse()