def test_get_agent_return_new(self): self.assertEqual(len(get_agents()), 0) agent = get_agent("", "", [ "ds8k_host", ]) self.assertIsInstance(agent, StorageAgent) self.assertEqual(len(get_agents()), 1) get_agent("test", "test", [ "ds8k_host", ]) self.assertEqual(len(get_agents()), 2)
def test_get_agent_return_new_when_password_changed(self): name = "test_name" endpoints = [ "ds8k_host", ] self.assertEqual(len(get_agents()), 0) agent = get_agent(name, "pa", endpoints) self.assertEqual(len(get_agents()), 1) new_agent = get_agent(name, "pb", endpoints) self.assertEqual(len(get_agents()), 1) self.assertNotEqual(id(agent), id(new_agent))
def test_get_agent_return_existing(self): name = "test_name" password = "******" endpoints = [ "ds8k_host", ] self.assertEqual(len(get_agents()), 0) agent = get_agent(name, password, endpoints) self.assertEqual(len(get_agents()), 1) new_agent = get_agent(name, password, endpoints) self.assertEqual(len(get_agents()), 1) self.assertEqual(id(agent), id(new_agent))
def new_action(in_q): if is_timeout: with self.assertRaises( array_errors.NoConnectionAvailableException): with get_agent("test", "test", [ "ds8k_host", ]).get_mediator(timeout=timeout): in_q.put(True) else: with get_agent("test", "test", [ "ds8k_host", ]).get_mediator(timeout=timeout): in_q.put(True)
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 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 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 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 test_get_multiple_mediators_parallelly_in_different_threads(self): def verify_mediator(current_size): agent = get_agent("test", "test", [ "ds8k_host", ]) with agent.get_mediator() as mediator: self.assertIsInstance(mediator, DS8KArrayMediator) self.assertEqual(agent.conn_pool.current_size, current_size) # get_system is called in setUp() too. self.assertEqual(self.client_mock.get_system.call_count, current_size + 1) sleep(0.2) t1 = Thread(target=verify_mediator, args=(1, )) t2 = Thread(target=verify_mediator, args=(2, )) t3 = Thread(target=verify_mediator, args=(3, )) t1.start() t2.start() t3.start() t1.join() t2.join() t3.join() self.assertEqual( get_agent("test", "test", [ "ds8k_host", ]).conn_pool.current_size, 3)
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 test_get_agent_return_new_when_password_changed(self): name = "test_name" endpoints = [ "ds8k_host", ] self.assertEqual(len(get_agents()), 0) agent = get_agent( ArrayConnectionInfo(array_addresses=endpoints, user=name, password="******")) self.assertEqual(len(get_agents()), 1) new_agent = get_agent( ArrayConnectionInfo(array_addresses=endpoints, user=name, password="******")) self.assertEqual(len(get_agents()), 1) self.assertNotEqual(id(agent), id(new_agent))
def test_get_agent_return_new(self): self.assertEqual(len(get_agents()), 0) agent = get_agent( ArrayConnectionInfo(array_addresses=[ "ds8k_host", ], user="", password="")) self.assertIsInstance(agent, StorageAgent) self.assertEqual(len(get_agents()), 1) get_agent( ArrayConnectionInfo(array_addresses=[ "ds8k_host", ], user="******", password="******")) self.assertEqual(len(get_agents()), 2)
def blocking_action(): with get_agent( ArrayConnectionInfo(array_addresses=[ "ds8k_host", ], user="******", password="******")).get_mediator(): sleep(0.2)
def test_get_agent_return_existing(self): name = "test_name" password = "******" endpoints = [ "ds8k_host", ] self.assertEqual(len(get_agents()), 0) agent = get_agent( ArrayConnectionInfo(array_addresses=endpoints, user=name, password=password)) self.assertEqual(len(get_agents()), 1) new_agent = get_agent( ArrayConnectionInfo(array_addresses=endpoints, user=name, password=password)) self.assertEqual(len(get_agents()), 1) self.assertEqual(id(agent), id(new_agent))
def verify_mediator(current_size): agent = get_agent("test", "test", [ "ds8k_host", ]) with agent.get_mediator() as mediator: self.assertIsInstance(mediator, DS8KArrayMediator) self.assertEqual(agent.conn_pool.current_size, current_size) # get_system is called in setUp() too. self.assertEqual(self.client_mock.get_system.call_count, current_size + 1) sleep(0.2)
def new_action(in_q): if is_timeout: with self.assertRaises( array_errors.NoConnectionAvailableException): with get_agent( ArrayConnectionInfo(array_addresses=[ "ds8k_host", ], user="******", password="******")).get_mediator( timeout=timeout): in_q.put(True) else: with get_agent( ArrayConnectionInfo( array_addresses=[ "ds8k_host", ], user="******", password="******")).get_mediator(timeout=timeout): in_q.put(True)
def verify_mediator(current_size): agent = get_agent( ArrayConnectionInfo(array_addresses=[ "ds8k_host", ], user="******", password="******")) with agent.get_mediator() as mediator: self.assertIsInstance(mediator, DS8KArrayMediator) self.assertEqual(agent.conn_pool.current_size, current_size) # get_system is called in setUp() too. self.assertEqual(self.client_mock.get_system.call_count, current_size + 1) sleep(0.2)
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 ValidateVolumeCapabilities(self, request, context): logger.info("ValidateVolumeCapabilities") try: utils.validate_validate_volume_capabilities_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 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: volume = array_mediator.get_object_by_id( object_id=volume_id, object_type=config.VOLUME_TYPE_NAME) if not volume: raise array_errors.ObjectNotFoundError(volume_id) logger.debug("volume found : {}".format(volume)) if request.volume_context: utils.validate_volume_context_match_volume( request.volume_context, volume) if request.parameters: utils.validate_parameters_match_volume(request.parameters, volume) logger.info("finished ValidateVolumeCapabilities") return utils.generate_csi_validate_volume_capabilities_response( request.volume_context, request.volume_capabilities, request.parameters) except ObjectIdError as ex: return handle_exception(ex, context, grpc.StatusCode.NOT_FOUND, csi_pb2.CreateSnapshotResponse) except array_errors.SpaceEfficiencyNotSupported as ex: return handle_exception(ex, context, grpc.StatusCode.INVALID_ARGUMENT, csi_pb2.CreateSnapshotResponse)
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 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 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 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) with get_agent(user, password, array_addresses, array_type).get_mediator() as array_mediator: lun, connectivity_type, array_initiators = array_mediator.map_volume_by_initiators( 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, controller_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, controller_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") 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 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()