def ControllerUnpublishVolume(self, request, context): set_current_thread_name(request.volume_id) logger.info("ControllerUnpublishVolume") try: try: utils.validate_unpublish_volume_request(request) except ValidationException as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.INVALID_ARGUMENT) return csi_pb2.ControllerUnpublishVolumeResponse() volume_id_info = utils.get_volume_id_info(request.volume_id) system_id = volume_id_info.system_id array_type = volume_id_info.array_type volume_id = volume_id_info.object_id node_id_info = NodeIdInfo(request.node_id) node_name = node_id_info.node_name initiators = node_id_info.initiators logger.debug( "node name for this unpublish operation is : {0}".format( node_name)) array_connection_info = utils.get_array_connection_info_from_secrets( request.secrets, system_id=system_id) with get_agent(array_connection_info, array_type).get_mediator() as array_mediator: array_mediator.unmap_volume_by_initiators( volume_id, initiators) logger.info("finished ControllerUnpublishVolume") return csi_pb2.ControllerUnpublishVolumeResponse() except array_errors.VolumeAlreadyUnmappedError: logger.debug("Idempotent case. volume is already unmapped.") return csi_pb2.ControllerUnpublishVolumeResponse() except array_errors.ObjectNotFoundError as ex: logger.debug("Idempotent case. volume is already deleted.") return csi_pb2.ControllerUnpublishVolumeResponse() except array_errors.PermissionDeniedError as ex: context.set_code(grpc.StatusCode.PERMISSION_DENIED) context.set_details(ex.message) return csi_pb2.ControllerUnpublishVolumeResponse() except array_errors.HostNotFoundError as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.NOT_FOUND) return csi_pb2.ControllerUnpublishVolumeResponse() 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.ControllerUnpublishVolumeResponse()
def ControllerExpandVolume(self, request, context): set_current_thread_name(request.volume_id) logger.info("ControllerExpandVolume") secrets = request.secrets utils.validate_expand_volume_request(request) try: volume_id_info = utils.get_volume_id_info(request.volume_id) except ObjectIdError as ex: return handle_exception(ex, context, grpc.StatusCode.INVALID_ARGUMENT, csi_pb2.ControllerExpandVolumeResponse) try: system_id = volume_id_info.system_id array_type = volume_id_info.array_type volume_id = volume_id_info.object_id array_connection_info = utils.get_array_connection_info_from_secrets( secrets, system_id=system_id) with get_agent(array_connection_info, array_type).get_mediator() as array_mediator: logger.debug(array_mediator) required_bytes = request.capacity_range.required_bytes max_size = array_mediator.maximal_volume_size_in_bytes volume_before_expand = array_mediator.get_object_by_id( volume_id, config.VOLUME_TYPE_NAME) if not volume_before_expand: raise array_errors.ObjectNotFoundError(volume_id) if volume_before_expand.capacity_bytes >= required_bytes: context.set_code(grpc.StatusCode.OK) return utils.generate_csi_expand_volume_response( volume_before_expand.capacity_bytes, node_expansion_required=False) 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.ControllerExpandVolumeResponse) logger.debug("expanding volume {0}".format(volume_id)) array_mediator.expand_volume(volume_id=volume_id, required_bytes=required_bytes) volume_after_expand = array_mediator.get_object_by_id( volume_id, config.VOLUME_TYPE_NAME) if not volume_after_expand: raise array_errors.ObjectNotFoundError(volume_id) res = utils.generate_csi_expand_volume_response( volume_after_expand.capacity_bytes) logger.info("finished expanding volume") return res except array_errors.NotEnoughSpaceInPool as ex: return handle_exception(ex, context, grpc.StatusCode.RESOURCE_EXHAUSTED, csi_pb2.ControllerExpandVolumeResponse)
def DeleteVolume(self, request, context): set_current_thread_name(request.volume_id) logger.info("DeleteVolume") secrets = request.secrets try: utils.validate_delete_volume_request(request) user, password, array_addresses = utils.get_array_connection_info_from_secret( secrets) try: array_type, vol_id = utils.get_volume_id_info( request.volume_id) except ObjectIdError as ex: logger.warning("volume id is invalid. error : {}".format(ex)) return csi_pb2.DeleteVolumeResponse() with get_agent(user, password, array_addresses, array_type).get_mediator() as array_mediator: logger.debug(array_mediator) try: logger.debug("Deleting volume {0}".format(vol_id)) array_mediator.delete_volume(vol_id) except controller_errors.ObjectNotFoundError as ex: logger.debug( "volume was not found during deletion: {0}".format(ex)) except controller_errors.PermissionDeniedError as ex: context.set_code(grpc.StatusCode.PERMISSION_DENIED) context.set_details(ex) return csi_pb2.DeleteVolumeResponse() except controller_errors.ObjectIsStillInUseError as ex: logger.info("could not delete volume while in use: {0}".format(ex)) context.set_code(grpc.StatusCode.FAILED_PRECONDITION) context.set_details(ex.message) return csi_pb2.DeleteVolumeResponse() except ValidationException as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.INVALID_ARGUMENT) return csi_pb2.DeleteVolumeResponse() 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.DeleteVolumeResponse() logger.debug("generating delete volume response") res = csi_pb2.DeleteVolumeResponse() logger.info("finished DeleteVolume") return res
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) try: snapshot_id_info = utils.get_snapshot_id_info( request.snapshot_id) except ObjectIdError as ex: logger.warning("Snapshot id is invalid. error : {}".format(ex)) return csi_pb2.DeleteSnapshotResponse() system_id = snapshot_id_info.system_id array_type = snapshot_id_info.array_type snapshot_id = snapshot_id_info.object_id array_connection_info = utils.get_array_connection_info_from_secrets( secrets, system_id=system_id) with get_agent(array_connection_info, array_type).get_mediator() as array_mediator: logger.debug(array_mediator) try: array_mediator.delete_snapshot(snapshot_id) except array_errors.ObjectNotFoundError as ex: logger.debug( "Snapshot was not found during deletion: {0}".format( ex)) except array_errors.ObjectNotFoundError as ex: logger.debug("snapshot was not found during deletion: {0}".format( ex.message)) context.set_code(grpc.StatusCode.OK) return csi_pb2.DeleteSnapshotResponse() except array_errors.ObjectIsStillInUseError as ex: logger.info("could not delete snapshot while in use: {0}".format( ex.message)) context.set_code(grpc.StatusCode.FAILED_PRECONDITION) context.set_details(ex.message) return csi_pb2.DeleteSnapshotResponse() except array_errors.PermissionDeniedError as ex: context.set_code(grpc.StatusCode.PERMISSION_DENIED) context.set_details(ex.message) return csi_pb2.DeleteSnapshotResponse() except (ValidationException, array_errors.IllegalObjectID) 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 ResyncVolume(self, request, context): set_current_thread_name(request.volume_id) logger.info("ResyncVolume") utils.validate_addons_request(request) volume_id_info = utils.get_volume_id_info(request.volume_id) volume_internal_id = volume_id_info.internal_id other_volume_id_info = utils.get_volume_id_info(request.replication_id) other_volume_internal_id = other_volume_id_info.internal_id other_system_id = request.parameters.get(config.PARAMETERS_SYSTEM_ID) connection_info = utils.get_array_connection_info_from_secrets(request.secrets) with get_agent(connection_info, volume_id_info.array_type).get_mediator() as mediator: replication = mediator.get_replication(volume_internal_id, other_volume_internal_id, other_system_id) if not replication: message = "could not find replication for volume internal id: {} " \ "with volume internal id: {} of system: {}".format(volume_internal_id, other_volume_internal_id, other_system_id) return build_error_response(message, context, grpc.StatusCode.FAILED_PRECONDITION, pb2.ResyncVolumeResponse) logger.info("is replication {} ready: {}".format(replication.name, replication.is_ready)) return pb2.ResyncVolumeResponse(ready=replication.is_ready)
def _ensure_volume_role(self, request, context, is_to_promote, response_type): set_current_thread_name(request.volume_id) method_name = "PromoteVolume" if is_to_promote else "DemoteVolume" logger.info(method_name) utils.validate_addons_request(request) volume_id_info = utils.get_volume_id_info(request.volume_id) volume_internal_id = volume_id_info.internal_id other_volume_id_info = utils.get_volume_id_info(request.replication_id) other_volume_internal_id = other_volume_id_info.internal_id other_system_id = request.parameters.get(config.PARAMETERS_SYSTEM_ID) connection_info = utils.get_array_connection_info_from_secrets(request.secrets) with get_agent(connection_info, volume_id_info.array_type).get_mediator() as mediator: replication = mediator.get_replication(volume_internal_id, other_volume_internal_id, other_system_id) if not replication: message = "could not find replication for volume internal id: {} " \ "with volume internal id: {} of system: {}".format(volume_internal_id, other_volume_internal_id, other_system_id) return build_error_response(message, context, grpc.StatusCode.FAILED_PRECONDITION, response_type) logger.info("found replication {} on system {}".format(replication.name, mediator.identifier)) self._ensure_volume_role_for_replication(mediator, replication, is_to_promote) logger.info("finished {}".format(method_name)) return response_type()
def ControllerPublishVolume(self, request, context): set_current_thread_name(request.volume_id) logger.info("ControllerPublishVolume") try: utils.validate_publish_volume_request(request) array_type, vol_id = utils.get_volume_id_info(request.volume_id) node_id_info = NodeIdInfo(request.node_id) node_name = node_id_info.node_name initiators = node_id_info.initiators logger.debug("node name for this publish operation is : {0}".format(node_name)) user, password, array_addresses = utils.get_array_connection_info_from_secret(request.secrets) lun, connectivity_type, array_initiators = map_volume(user, password, array_addresses, array_type, vol_id, initiators) logger.info("finished ControllerPublishVolume") res = utils.generate_csi_publish_volume_response(lun, connectivity_type, self.cfg, array_initiators) return res except controller_errors.VolumeMappedToMultipleHostsError as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.FAILED_PRECONDITION) return csi_pb2.ControllerPublishVolumeResponse() except controller_errors.PermissionDeniedError as ex: context.set_code(grpc.StatusCode.PERMISSION_DENIED) context.set_details(ex) return csi_pb2.ControllerPublishVolumeResponse() except (controller_errors.LunAlreadyInUseError, controller_errors.NoAvailableLunError) as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.RESOURCE_EXHAUSTED) return csi_pb2.ControllerPublishVolumeResponse() except (controller_errors.HostNotFoundError, controller_errors.VolumeNotFoundError, controller_errors.BadNodeIdError) as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.NOT_FOUND) return csi_pb2.ControllerPublishVolumeResponse() except ValidationException as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.INVALID_ARGUMENT) return csi_pb2.ControllerPublishVolumeResponse() 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.ControllerPublishVolumeResponse()
def ControllerUnpublishVolume(self, request, context): set_current_thread_name(request.volume_id) logger.info("ControllerUnpublishVolume") try: try: utils.validate_unpublish_volume_request(request) except ValidationException as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.INVALID_ARGUMENT) return csi_pb2.ControllerUnpublishVolumeResponse() array_type, vol_id = utils.get_volume_id_info(request.volume_id) node_id_info = NodeIdInfo(request.node_id) node_name = node_id_info.node_name initiators = node_id_info.initiators logger.debug("node name for this unpublish operation is : {0}".format(node_name)) user, password, array_addresses = utils.get_array_connection_info_from_secret(request.secrets) unmap_volume(user, password, array_addresses, array_type, vol_id, initiators) logger.info("finished ControllerUnpublishVolume") return csi_pb2.ControllerUnpublishVolumeResponse() except controller_errors.VolumeAlreadyUnmappedError as ex: logger.debug("Idempotent case. volume is already unmapped.") return csi_pb2.ControllerUnpublishVolumeResponse() except controller_errors.PermissionDeniedError as ex: context.set_code(grpc.StatusCode.PERMISSION_DENIED) context.set_details(ex) return csi_pb2.ControllerPublishVolumeResponse() except (controller_errors.HostNotFoundError, controller_errors.VolumeNotFoundError) as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.NOT_FOUND) return csi_pb2.ControllerUnpublishVolumeResponse() 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.ControllerUnpublishVolumeResponse()
def ControllerPublishVolume(self, request, context): set_current_thread_name(request.volume_id) logger.info("ControllerPublishVolume") utils.validate_publish_volume_request(request) try: volume_id_info = utils.get_volume_id_info(request.volume_id) system_id = volume_id_info.system_id array_type = volume_id_info.array_type volume_id = volume_id_info.object_id node_id_info = NodeIdInfo(request.node_id) node_name = node_id_info.node_name initiators = node_id_info.initiators logger.debug( "node name for this publish operation is : {0}".format( node_name)) array_connection_info = utils.get_array_connection_info_from_secrets( request.secrets, system_id=system_id) with get_agent(array_connection_info, array_type).get_mediator() as array_mediator: lun, connectivity_type, array_initiators = array_mediator.map_volume_by_initiators( volume_id, initiators) logger.info("finished ControllerPublishVolume") res = utils.generate_csi_publish_volume_response( lun, connectivity_type, self.cfg, array_initiators) return res except array_errors.VolumeMappedToMultipleHostsError as ex: return handle_exception(ex, context, grpc.StatusCode.FAILED_PRECONDITION, csi_pb2.ControllerPublishVolumeResponse) except (array_errors.LunAlreadyInUseError, array_errors.NoAvailableLunError) as ex: return handle_exception(ex, context, grpc.StatusCode.RESOURCE_EXHAUSTED, csi_pb2.ControllerPublishVolumeResponse) except (array_errors.NoIscsiTargetsFoundError, ObjectIdError) as ex: return handle_exception(ex, context, grpc.StatusCode.NOT_FOUND, csi_pb2.ControllerPublishVolumeResponse) except array_errors.UnsupportedConnectivityTypeError as ex: return handle_exception(ex, context, grpc.StatusCode.INVALID_ARGUMENT, csi_pb2.ControllerPublishVolumeResponse)
def DeleteVolume(self, request, context): set_current_thread_name(request.volume_id) logger.info("DeleteVolume") secrets = request.secrets utils.validate_delete_volume_request(request) try: volume_id_info = utils.get_volume_id_info(request.volume_id) except ObjectIdError as ex: logger.warning("volume id is invalid. error : {}".format(ex)) return csi_pb2.DeleteVolumeResponse() system_id = volume_id_info.system_id array_type = volume_id_info.array_type volume_id = volume_id_info.object_id array_connection_info = utils.get_array_connection_info_from_secrets( secrets, system_id=system_id) with get_agent(array_connection_info, array_type).get_mediator() as array_mediator: logger.debug(array_mediator) try: logger.debug("Deleting volume {0}".format(volume_id)) array_mediator.delete_volume(volume_id) except array_errors.ObjectNotFoundError as ex: logger.debug( "volume was not found during deletion: {0}".format(ex)) except array_errors.PermissionDeniedError as ex: return handle_exception(ex, context, grpc.StatusCode.PERMISSION_DENIED, csi_pb2.DeleteVolumeResponse) logger.debug("generating delete volume response") res = csi_pb2.DeleteVolumeResponse() logger.info("finished DeleteVolume") return res
def DeleteSnapshot(self, request, context): set_current_thread_name(request.snapshot_id) logger.info("Delete snapshot") secrets = request.secrets utils.validate_delete_snapshot_request(request) try: try: snapshot_id_info = utils.get_snapshot_id_info( request.snapshot_id) except ObjectIdError as ex: logger.warning("Snapshot id is invalid. error : {}".format(ex)) return csi_pb2.DeleteSnapshotResponse() system_id = snapshot_id_info.system_id array_type = snapshot_id_info.array_type snapshot_id = snapshot_id_info.object_id array_connection_info = utils.get_array_connection_info_from_secrets( secrets, system_id=system_id) with get_agent(array_connection_info, array_type).get_mediator() as array_mediator: logger.debug(array_mediator) try: array_mediator.delete_snapshot(snapshot_id) except array_errors.ObjectNotFoundError as ex: logger.debug( "Snapshot was not found during deletion: {0}".format( ex)) except array_errors.ObjectNotFoundError as ex: logger.debug("snapshot was not found during deletion: {0}".format( ex.message)) context.set_code(grpc.StatusCode.OK) return csi_pb2.DeleteSnapshotResponse() logger.debug("generating delete snapshot response") res = csi_pb2.DeleteSnapshotResponse() logger.info("finished DeleteSnapshot") return res
def EnableVolumeReplication(self, request, context): set_current_thread_name(request.volume_id) logger.info("EnableVolumeReplication") utils.validate_addons_request(request) volume_id_info = utils.get_volume_id_info(request.volume_id) volume_id = volume_id_info.object_id volume_internal_id = volume_id_info.internal_id other_volume_id_info = utils.get_volume_id_info(request.replication_id) other_volume_internal_id = other_volume_id_info.internal_id other_system_id = request.parameters.get(config.PARAMETERS_SYSTEM_ID) copy_type = request.parameters.get(config.PARAMETERS_COPY_TYPE, REPLICATION_DEFAULT_COPY_TYPE) connection_info = utils.get_array_connection_info_from_secrets(request.secrets) with get_agent(connection_info, volume_id_info.array_type).get_mediator() as mediator: volume = mediator.get_object_by_id(volume_id, config.VOLUME_TYPE_NAME) if not volume: raise array_errors.ObjectNotFoundError(volume_id) replication = mediator.get_replication(volume_internal_id, other_volume_internal_id, other_system_id) if replication: if replication.copy_type != copy_type: message = "replication already exists " \ "but has copy type of {} and not {}".format(replication.copy_type, copy_type) return build_error_response(message, context, grpc.StatusCode.ALREADY_EXISTS, pb2.EnableVolumeReplicationResponse) logger.info("idempotent case. replication already exists " "for volume {} with system: {}".format(volume.name, other_system_id)) return pb2.EnableVolumeReplicationResponse() logger.info("creating replication for volume {} with system: {}".format(volume.name, other_system_id)) mediator.create_replication(volume_internal_id, other_volume_internal_id, other_system_id, copy_type) return pb2.EnableVolumeReplicationResponse()
def ControllerUnpublishVolume(self, request, context): set_current_thread_name(request.volume_id) logger.info("ControllerUnpublishVolume") utils.validate_unpublish_volume_request(request) try: volume_id_info = utils.get_volume_id_info(request.volume_id) system_id = volume_id_info.system_id array_type = volume_id_info.array_type volume_id = volume_id_info.object_id node_id_info = NodeIdInfo(request.node_id) node_name = node_id_info.node_name initiators = node_id_info.initiators logger.debug( "node name for this unpublish operation is : {0}".format( node_name)) array_connection_info = utils.get_array_connection_info_from_secrets( request.secrets, system_id=system_id) with get_agent(array_connection_info, array_type).get_mediator() as array_mediator: array_mediator.unmap_volume_by_initiators( volume_id, initiators) logger.info("finished ControllerUnpublishVolume") return csi_pb2.ControllerUnpublishVolumeResponse() except ObjectIdError as ex: return handle_exception(ex, context, grpc.StatusCode.INVALID_ARGUMENT, array_errors.VolumeAlreadyUnmappedError) except array_errors.VolumeAlreadyUnmappedError: logger.debug("Idempotent case. volume is already unmapped.") return csi_pb2.ControllerUnpublishVolumeResponse() except array_errors.ObjectNotFoundError: logger.debug("Idempotent case. volume is already deleted.") return csi_pb2.ControllerUnpublishVolumeResponse()
def DisableVolumeReplication(self, request, context): set_current_thread_name(request.volume_id) logger.info("DisableVolumeReplication") utils.validate_addons_request(request) volume_id_info = utils.get_volume_id_info(request.volume_id) volume_internal_id = volume_id_info.internal_id other_volume_id_info = utils.get_volume_id_info(request.replication_id) other_volume_internal_id = other_volume_id_info.internal_id other_system_id = request.parameters.get(config.PARAMETERS_SYSTEM_ID) connection_info = utils.get_array_connection_info_from_secrets(request.secrets) with get_agent(connection_info, volume_id_info.array_type).get_mediator() as mediator: replication = mediator.get_replication(volume_internal_id, other_volume_internal_id, other_system_id) if replication: logger.info("deleting replication {} with system {}".format(replication.name, other_system_id)) mediator.delete_replication(replication.name) else: logger.info("idempotent case. replication is already deleted with system {}".format(other_system_id)) return pb2.DisableVolumeReplicationResponse()
def CreateVolume(self, request, context): 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() volume_name = request.name logger.debug("volume name : {}".format(volume_name)) if config.PARAMETERS_PREFIX in request.parameters: volume_prefix = request.parameters[config.PARAMETERS_PREFIX] volume_full_name = volume_prefix + settings.NAME_PREFIX_SEPARATOR + volume_name else: volume_prefix = "" volume_full_name = volume_name 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 with ArrayConnectionManager(user, password, array_addresses) as array_mediator: logger.debug(array_mediator) if len(volume_prefix ) > array_mediator.max_volume_prefix_length: raise controller_errors.IllegalObjectName( "The volume name prefix {} is too long, max allowed length is {}" .format( volume_prefix, array_mediator.max_volume_prefix_length, )) if len(volume_full_name) > array_mediator.max_vol_name_length: raise controller_errors.IllegalObjectName( "The volume name {} is too long, max allowed length is {}" .format( volume_full_name, array_mediator.max_vol_name_length, )) 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 as ex: 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 (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() 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: 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 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 ControllerExpandVolume(self, request, context): set_current_thread_name(request.volume_id) logger.info("ControllerExpandVolume") secrets = request.secrets try: utils.validate_expand_volume_request(request) try: volume_id_info = utils.get_volume_id_info(request.volume_id) except ObjectIdError as ex: logger.warning("volume id is invalid. error : {}".format(ex)) context.set_code(grpc.StatusCode.INVALID_ARGUMENT) return csi_pb2.ControllerExpandVolumeResponse() system_id = volume_id_info.system_id array_type = volume_id_info.array_type volume_id = volume_id_info.object_id array_connection_info = utils.get_array_connection_info_from_secrets( secrets, system_id=system_id) with get_agent(array_connection_info, array_type).get_mediator() as array_mediator: logger.debug(array_mediator) required_bytes = request.capacity_range.required_bytes max_size = array_mediator.maximal_volume_size_in_bytes volume_before_expand = array_mediator.get_object_by_id( volume_id, config.VOLUME_TYPE_NAME) if not volume_before_expand: raise array_errors.ObjectNotFoundError(volume_id) if volume_before_expand.capacity_bytes >= required_bytes: context.set_code(grpc.StatusCode.OK) return utils.generate_csi_expand_volume_response( volume_before_expand.capacity_bytes, node_expansion_required=False) if required_bytes > max_size: message = messages.SizeOutOfRangeError_message.format( required_bytes, max_size) logger.error(message) context.set_code(grpc.StatusCode.OUT_OF_RANGE) context.set_details(message) return csi_pb2.ControllerExpandVolumeResponse() logger.debug("expanding volume {0}".format(volume_id)) array_mediator.expand_volume(volume_id=volume_id, required_bytes=required_bytes) volume_after_expand = array_mediator.get_object_by_id( volume_id, config.VOLUME_TYPE_NAME) if not volume_after_expand: raise array_errors.ObjectNotFoundError(volume_id) res = utils.generate_csi_expand_volume_response( volume_after_expand.capacity_bytes) logger.info("finished expanding volume") return res except array_errors.PermissionDeniedError as ex: context.set_code(grpc.StatusCode.PERMISSION_DENIED) context.set_details(ex.message) return csi_pb2.ControllerExpandVolumeResponse() except array_errors.ObjectNotFoundError as ex: logger.info("Volume not found: {0}".format(ex)) context.set_code(grpc.StatusCode.NOT_FOUND) context.set_details(ex.message) return csi_pb2.ControllerExpandVolumeResponse() except (ValidationException, array_errors.IllegalObjectID) as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.INVALID_ARGUMENT) return csi_pb2.ControllerExpandVolumeResponse() except array_errors.NotEnoughSpaceInPool as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.RESOURCE_EXHAUSTED) return csi_pb2.ControllerExpandVolumeResponse() 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.ControllerExpandVolumeResponse()
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 CreateSnapshot(self, request, context): set_current_thread_name(request.name) logger.info("Create snapshot") utils.validate_create_snapshot_request(request) source_volume_id = request.source_volume_id logger.info("Snapshot base name : {}. Source volume id : {}".format( request.name, source_volume_id)) secrets = request.secrets try: volume_id_info = utils.get_volume_id_info(source_volume_id) system_id = volume_id_info.system_id array_type = volume_id_info.array_type volume_id = volume_id_info.object_id array_connection_info = utils.get_array_connection_info_from_secrets( secrets, system_id=system_id) snapshot_parameters = utils.get_snapshot_parameters( parameters=request.parameters, system_id=array_connection_info.system_id) pool = snapshot_parameters.pool space_efficiency = snapshot_parameters.space_efficiency with get_agent(array_connection_info, array_type).get_mediator() as array_mediator: logger.debug(array_mediator) snapshot_final_name = self._get_snapshot_final_name( snapshot_parameters, request.name, array_mediator) logger.info("Snapshot name : {}. Volume id : {}".format( snapshot_final_name, volume_id)) snapshot = array_mediator.get_snapshot(volume_id, snapshot_final_name, pool=pool) if snapshot: if snapshot.source_volume_id != volume_id: message = messages.SnapshotWrongVolumeError_message.format( snapshot_final_name, snapshot.source_volume_id, volume_id) return build_error_response( message, context, grpc.StatusCode.ALREADY_EXISTS, csi_pb2.CreateSnapshotResponse) else: logger.debug( "Snapshot doesn't exist. Creating a new snapshot {0} from volume {1}" .format(snapshot_final_name, volume_id)) array_mediator.validate_supported_space_efficiency( space_efficiency) snapshot = array_mediator.create_snapshot( volume_id, snapshot_final_name, space_efficiency, pool) logger.debug("generating create snapshot response") res = utils.generate_csi_create_snapshot_response( snapshot, system_id, source_volume_id) logger.info("finished create snapshot") return res except (ObjectIdError, array_errors.SnapshotSourcePoolMismatch, array_errors.SpaceEfficiencyNotSupported) as ex: return handle_exception(ex, context, grpc.StatusCode.INVALID_ARGUMENT, csi_pb2.CreateSnapshotResponse) except array_errors.SnapshotAlreadyExists as ex: return handle_exception(ex, context, grpc.StatusCode.ALREADY_EXISTS, csi_pb2.CreateSnapshotResponse) except array_errors.NotEnoughSpaceInPool as ex: return handle_exception(ex, context, grpc.StatusCode.RESOURCE_EXHAUSTED, csi_pb2.CreateSnapshotResponse)
def ControllerPublishVolume(self, request, context): set_current_thread_name(request.volume_id) logger.info("ControllerPublishVolume") try: utils.validate_publish_volume_request(request) volume_id_info = utils.get_volume_id_info(request.volume_id) system_id = volume_id_info.system_id array_type = volume_id_info.array_type volume_id = volume_id_info.object_id node_id_info = NodeIdInfo(request.node_id) node_name = node_id_info.node_name initiators = node_id_info.initiators logger.debug( "node name for this publish operation is : {0}".format( node_name)) array_connection_info = utils.get_array_connection_info_from_secrets( request.secrets, system_id=system_id) with get_agent(array_connection_info, array_type).get_mediator() as array_mediator: lun, connectivity_type, array_initiators = array_mediator.map_volume_by_initiators( volume_id, initiators) logger.info("finished ControllerPublishVolume") res = utils.generate_csi_publish_volume_response( lun, connectivity_type, self.cfg, array_initiators) return res except array_errors.VolumeMappedToMultipleHostsError as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.FAILED_PRECONDITION) return csi_pb2.ControllerPublishVolumeResponse() except array_errors.PermissionDeniedError as ex: context.set_code(grpc.StatusCode.PERMISSION_DENIED) context.set_details(ex.message) return csi_pb2.ControllerPublishVolumeResponse() except (array_errors.LunAlreadyInUseError, array_errors.NoAvailableLunError) as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.RESOURCE_EXHAUSTED) return csi_pb2.ControllerPublishVolumeResponse() except (array_errors.HostNotFoundError, array_errors.ObjectNotFoundError, array_errors.NoIscsiTargetsFoundError, ObjectIdError) as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.NOT_FOUND) return csi_pb2.ControllerPublishVolumeResponse() except (ValidationException, array_errors.IllegalObjectID, array_errors.UnsupportedConnectivityTypeError) as ex: logger.exception(ex) context.set_details(ex.message) context.set_code(grpc.StatusCode.INVALID_ARGUMENT) return csi_pb2.ControllerPublishVolumeResponse() 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.ControllerPublishVolumeResponse()
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()
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 try: volume_id_info = utils.get_volume_id_info(source_volume_id) system_id = volume_id_info.system_id array_type = volume_id_info.array_type volume_id = volume_id_info.object_id array_connection_info = utils.get_array_connection_info_from_secrets( secrets, system_id=system_id) snapshot_parameters = utils.get_snapshot_parameters( parameters=request.parameters, system_id=array_connection_info.system_id) pool = snapshot_parameters.pool with get_agent(array_connection_info, array_type).get_mediator() as array_mediator: logger.debug(array_mediator) snapshot_final_name = self._get_snapshot_final_name( snapshot_parameters, request.name, array_mediator) logger.info("Snapshot name : {}. Volume id : {}".format( snapshot_final_name, volume_id)) snapshot = array_mediator.get_snapshot(volume_id, snapshot_final_name, pool=pool) if snapshot: if snapshot.source_volume_id != volume_id: context.set_details( messages.SnapshotWrongVolumeError_message.format( snapshot_final_name, snapshot.source_volume_id, volume_id)) 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_final_name, volume_id)) snapshot = array_mediator.create_snapshot( volume_id, snapshot_final_name, pool) 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 (array_errors.IllegalObjectName, array_errors.IllegalObjectID, array_errors.SnapshotSourcePoolMismatch) as ex: context.set_details(ex.message) context.set_code(grpc.StatusCode.INVALID_ARGUMENT) return csi_pb2.CreateSnapshotResponse() except array_errors.ObjectNotFoundError as ex: context.set_code(grpc.StatusCode.NOT_FOUND) context.set_details(ex.message) return csi_pb2.CreateSnapshotResponse() except array_errors.PermissionDeniedError as ex: context.set_code(grpc.StatusCode.PERMISSION_DENIED) context.set_details(ex.message) return csi_pb2.CreateSnapshotResponse() except array_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()