Exemple #1
0
    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)
Exemple #2
0
    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 test_get_volume_id_info(self):
        with self.assertRaises(ObjectIdError) as ex:
            utils.get_volume_id_info("badvolumeformat")
            self.assertTrue("volume" in str(ex))

        volume_id_info = utils.get_volume_id_info("xiv:volume-id")
        self.assertEqual(volume_id_info.array_type, "xiv")
        self.assertEqual(volume_id_info.object_id, "volume-id")
    def test_get_volume_id_info(self):
        with self.assertRaises(ObjectIdError) as ex:
            utils.get_volume_id_info("badvolumeformat")
            self.assertTrue("volume" in ex.message)

        arr_type, vol = utils.get_volume_id_info("xiv:vol")
        self.assertEqual(arr_type, "xiv")
        self.assertEqual(vol, "vol")
    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)
Exemple #7
0
    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 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()
Exemple #9
0
 def _test_get_volume_id_info(self,
                              object_id,
                              system_id=None,
                              internal_id=None):
     system_id_field = ':{}'.format(system_id) if system_id else ''
     ids_field = '{};{}'.format(internal_id,
                                object_id) if internal_id else object_id
     volume_id = '{}{}:{}'.format('xiv', system_id_field, ids_field)
     volume_id_info = utils.get_volume_id_info(volume_id)
     self.assertEqual(volume_id_info.array_type, "xiv")
     self.assertEqual(volume_id_info.system_id, system_id)
     self.assertEqual(volume_id_info.internal_id, internal_id)
     self.assertEqual(volume_id_info.object_id, object_id)
Exemple #10
0
    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()
Exemple #11
0
    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 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 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 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 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 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)
Exemple #18
0
 def test_get_volume_id_info_too_many_semicolons_fail(self):
     with self.assertRaises(ObjectIdError) as ex:
         utils.get_volume_id_info("xiv:0;volume;id")
     self.assertIn("Wrong volume id format", str(ex.exception))
    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()
Exemple #20
0
 def test_get_volume_id_info_no_id_fail(self):
     with self.assertRaises(ObjectIdError) as ex:
         utils.get_volume_id_info("badvolumeformat")
     self.assertIn("Wrong volume id format", str(ex.exception))
    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 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 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()