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]
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]
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)
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)))
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']}
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.' ]
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)))
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)
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))
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)