def test_validate_aws_lambda_schema():
    test_pb = Deployment(name='test_deployment_name', namespace='namespace')
    test_pb.spec.bento_name = 'bento_name'
    test_pb.spec.bento_version = 'bento_version'
    test_pb.spec.operator = DeploymentSpec.DeploymentOperator.Value(
        'AWS_LAMBDA')
    test_pb.spec.aws_lambda_operator_config.api_name = 'api_name'
    test_pb.spec.aws_lambda_operator_config.region = 'us-west-2'
    test_pb.spec.aws_lambda_operator_config.timeout = 100
    test_pb.spec.aws_lambda_operator_config.memory_size = 128

    result = validate_deployment_pb_schema(test_pb)
    assert result is None

    test_pb.spec.aws_lambda_operator_config.timeout = 1000
    test_pb.spec.aws_lambda_operator_config.memory_size = 129
    failed_memory_test = validate_deployment_pb_schema(test_pb)
    print(failed_memory_test)
    aws_spec_fail_msg = failed_memory_test['spec'][0][
        'aws_lambda_operator_config'][0]

    assert aws_spec_fail_msg['memory_size']
    assert 'AWS Lambda memory' in aws_spec_fail_msg['memory_size'][0]
    assert aws_spec_fail_msg['timeout']
    assert 'max value is 900' in aws_spec_fail_msg['timeout'][0]
예제 #2
0
def test_validate_aws_lambda_schema():
    deployment_pb = _get_test_lambda_deployment_pb()
    assert validate_deployment_pb_schema(deployment_pb) is None

    deployment_pb_with_bad_memory_size = _get_test_lambda_deployment_pb()
    deployment_pb_with_bad_memory_size.spec.aws_lambda_operator_config.timeout = 1000
    deployment_pb_with_bad_memory_size.spec.aws_lambda_operator_config.memory_size = 129
    errors = validate_deployment_pb_schema(deployment_pb_with_bad_memory_size)
    aws_spec_fail_msg = errors['spec'][0]['aws_lambda_operator_config'][0]

    assert 'AWS Lambda memory' in aws_spec_fail_msg['memory_size'][0]
    assert 'max value is 900' in aws_spec_fail_msg['timeout'][0]
예제 #3
0
    def apply(self, deployment_info, wait):
        if isinstance(deployment_info, dict):
            deployment_pb = deployment_dict_to_pb(deployment_info)
        elif isinstance(deployment_info, str):
            deployment_pb = deployment_yaml_string_to_pb(deployment_info)
        elif isinstance(deployment_info, Deployment):
            deployment_pb = deployment_info
        else:
            raise YataiDeploymentException(
                'Unexpected argument type, expect deployment info to be str in yaml '
                'format or a dict or a deployment protobuf obj, instead got: {}'
                .format(str(type(deployment_info))))

        validation_errors = validate_deployment_pb_schema(deployment_pb)
        if validation_errors:
            raise YataiDeploymentException(
                f'Failed to validate deployment {deployment_pb.name}: '
                f'{validation_errors}')

        apply_result = self.yatai_service.ApplyDeployment(
            ApplyDeploymentRequest(deployment=deployment_pb))
        if apply_result.status.status_code != status_pb2.Status.OK:
            error_code, error_message = status_pb_to_error_code_and_message(
                apply_result.status)
            raise YataiDeploymentException(f'{error_code}:{error_message}')
        if wait:
            self._wait_deployment_action_complete(deployment_pb.name,
                                                  deployment_pb.namespace)
        return self.get(namespace=deployment_pb.namespace,
                        name=deployment_pb.name)
예제 #4
0
def apply_deployment(deployment_info, yatai_service=None):
    if yatai_service is None:
        from bentoml.yatai import get_yatai_service

        yatai_service = get_yatai_service()

    try:
        if isinstance(deployment_info, dict):
            deployment_pb = deployment_dict_to_pb(deployment_info)
        elif isinstance(deployment_info, str):
            deployment_pb = deployment_yaml_string_to_pb(deployment_info)
        else:
            raise YataiDeploymentException(
                'Unexpected argument type, expect deployment info to be str in yaml '
                'format or a dict, instead got: {}'.format(
                    str(type(deployment_info))))

        validation_errors = validate_deployment_pb_schema(deployment_pb)
        if validation_errors:
            return ApplyDeploymentResponse(status=Status.INVALID_ARGUMENT(
                'Failed to validate deployment: {errors}'.format(
                    errors=validation_errors)))

        return yatai_service.ApplyDeployment(
            ApplyDeploymentRequest(deployment=deployment_pb))
    except BentoMLException as error:
        return ApplyDeploymentResponse(status=Status.INTERNAL(str(error)))
예제 #5
0
def test_validate_deployment_pb_schema():
    test_pb = Deployment(name='test_deployment_name', namespace='namespace')
    test_pb.spec.bento_name = 'bento_name'
    test_pb.spec.bento_version = 'bento_version'
    test_pb.spec.operator = DeploymentSpec.DeploymentOperator.Value(
        'AWS_SAGEMAKER')
    test_pb.spec.sagemaker_operator_config.api_name = 'api_name'

    result = validate_deployment_pb_schema(test_pb)

    assert result is None

    test_bad_pb = test_pb
    test_bad_pb.name = ''
    bad_result = validate_deployment_pb_schema(test_bad_pb)
    assert bad_result == {'name': ['required field']}
예제 #6
0
def test_validate_deployment_pb_schema():
    deployment_pb = _get_test_sagemaker_deployment_pb()
    assert validate_deployment_pb_schema(deployment_pb) is None

    deployment_pb_with_empty_name = _get_test_sagemaker_deployment_pb()
    deployment_pb_with_empty_name.name = ''
    errors = validate_deployment_pb_schema(deployment_pb_with_empty_name)
    assert errors == {'name': ['required field']}

    deployment_pb_with_invalid_service_version = _get_test_sagemaker_deployment_pb(
    )
    deployment_pb_with_invalid_service_version.spec.bento_version = 'latest'
    errors = validate_deployment_pb_schema(
        deployment_pb_with_invalid_service_version)
    assert errors['spec'][0]['bento_version'] == [
        'Must use specific "bento_version" in deployment, using "latest" is an '
        'anti-pattern.'
    ]
예제 #7
0
    def ApplyDeployment(self, request, context=None):
        try:
            # apply default namespace if not set
            request.deployment.namespace = (
                request.deployment.namespace or self.default_namespace
            )

            validation_errors = validate_deployment_pb_schema(request.deployment)
            if validation_errors:
                return ApplyDeploymentResponse(
                    status=Status.INVALID_ARGUMENT(
                        'Failed to validate deployment. {errors}'.format(
                            errors=validation_errors
                        )
                    )
                )

            previous_deployment = self.deployment_store.get(
                request.deployment.name, request.deployment.namespace
            )
            if previous_deployment:
                # check deployment platform
                if (
                    previous_deployment.spec.operator
                    != request.deployment.spec.operator
                ):
                    return ApplyDeploymentResponse(
                        status=Status.ABORTED(
                            'Can not change the target deploy platform of existing '
                            'active deployment. Try delete existing deployment and '
                            'deploy to new target platform again'
                        )
                    )
                request.deployment.state.state = DeploymentState.PENDING
            else:
                request.deployment.created_at.GetCurrentTime()

            request.deployment.last_updated_at.GetCurrentTime()

            self.deployment_store.insert_or_update(request.deployment)
            # find deployment operator based on deployment spec
            operator = get_deployment_operator(request.deployment)

            # deploying to target platform
            response = operator.apply(request.deployment, self, previous_deployment)

            # update deployment state
            self.deployment_store.insert_or_update(response.deployment)

            return response

        except BentoMLException as e:
            logger.error("INTERNAL ERROR: %s", e)
            return ApplyDeploymentResponse(status=Status.INTERNAL(str(e)))
예제 #8
0
    def create(self, deployment_info, wait):
        if isinstance(deployment_info, dict):
            deployment_pb = deployment_dict_to_pb(deployment_info)
        elif isinstance(deployment_info, str):
            deployment_pb = deployment_yaml_string_to_pb(deployment_info)
        elif isinstance(deployment_info, Deployment):
            deployment_pb = deployment_info
        else:
            raise YataiDeploymentException(
                'Unexpected argument type, expect deployment info to be str in yaml '
                'format or a dict or a deployment protobuf obj, instead got: {}'.format(
                    str(type(deployment_info))
                )
            )

        validation_errors = validate_deployment_pb_schema(deployment_pb)
        if validation_errors:
            raise YataiDeploymentException(
                f'Failed to validate deployment {deployment_pb.name}: '
                f'{validation_errors}'
            )

        # Make sure there is no active deployment with the same deployment name
        get_deployment_pb = self.yatai_service.GetDeployment(
            GetDeploymentRequest(
                deployment_name=deployment_pb.name, namespace=deployment_pb.namespace
            )
        )
        if get_deployment_pb.status.status_code != status_pb2.Status.NOT_FOUND:
            raise BentoMLException(
                f'Deployment "{deployment_pb.name}" already existed, use Update or '
                f'Apply for updating existing deployment, delete the deployment, '
                f'or use a different deployment name'
            )
        apply_result = self.yatai_service.ApplyDeployment(
            ApplyDeploymentRequest(deployment=deployment_pb)
        )
        if apply_result.status.status_code != status_pb2.Status.OK:
            error_code, error_message = status_pb_to_error_code_and_message(
                apply_result.status
            )
            raise YataiDeploymentException(f'{error_code}:{error_message}')
        if wait:
            self._wait_deployment_action_complete(
                deployment_pb.name, deployment_pb.namespace
            )
        return self.get(namespace=deployment_pb.namespace, name=deployment_pb.name)
예제 #9
0
    def apply_deployment(self, deployment_info):
        if isinstance(deployment_info, dict):
            deployment_pb = deployment_dict_to_pb(deployment_info)
        elif isinstance(deployment_info, str):
            deployment_pb = deployment_yaml_string_to_pb(deployment_info)
        elif isinstance(deployment_info, Deployment):
            deployment_pb = deployment_info
        else:
            raise YataiDeploymentException(
                'Unexpected argument type, expect deployment info to be str in yaml '
                'format or a dict or a deployment protobuf obj, instead got: {}'
                .format(str(type(deployment_info))))

        validation_errors = validate_deployment_pb_schema(deployment_pb)
        if validation_errors:
            return ApplyDeploymentResponse(status=Status.INVALID_ARGUMENT(
                'Failed to validate deployment: {errors}'.format(
                    errors=validation_errors)))

        return self.yatai_service.ApplyDeployment(
            ApplyDeploymentRequest(deployment=deployment_pb))
예제 #10
0
    def ApplyDeployment(self, request, context=None):
        try:
            # apply default namespace if not set
            request.deployment.namespace = (
                request.deployment.namespace or self.default_namespace
            )

            validation_errors = validate_deployment_pb_schema(request.deployment)
            if validation_errors:
                raise InvalidArgument(
                    'Failed to validate deployment. {errors}'.format(
                        errors=validation_errors
                    )
                )

            previous_deployment = self.deployment_store.get(
                request.deployment.name, request.deployment.namespace
            )
            if not previous_deployment:
                request.deployment.created_at.GetCurrentTime()
            request.deployment.last_updated_at.GetCurrentTime()

            self.deployment_store.insert_or_update(request.deployment)
            # find deployment operator based on deployment spec
            operator = get_deployment_operator(self, request.deployment)

            # deploying to target platform
            if previous_deployment:
                response = operator.update(request.deployment, previous_deployment)
            else:
                response = operator.add(request.deployment)

            if response.status.status_code == status_pb2.Status.OK:
                # update deployment state
                if response and response.deployment:
                    self.deployment_store.insert_or_update(response.deployment)
                else:
                    raise BentoMLException(
                        "DeploymentOperator Internal Error: failed to add or update "
                        "deployment metadata to database"
                    )
                logger.info(
                    "ApplyDeployment (%s, namespace %s) succeeded",
                    request.deployment.name,
                    request.deployment.namespace,
                )
            else:
                if not previous_deployment:
                    # When failed to create the deployment, delete it from active
                    # deployments records
                    self.deployment_store.delete(
                        request.deployment.name, request.deployment.namespace
                    )
                logger.debug(
                    "ApplyDeployment (%s, namespace %s) failed: %s",
                    request.deployment.name,
                    request.deployment.namespace,
                    response.status.error_message,
                )

            return response

        except BentoMLException as e:
            logger.error("RPC ERROR ApplyDeployment: %s", e)
            return ApplyDeploymentResponse(status=e.status_proto)