def get(self, bento): """ Get a BentoService info Args: bento: a BentoService identifier in the format of NAME:VERSION Returns: bentoml.yatai.proto.repository_pb2.Bento Example: >>> yatai_client = get_yatai_client() >>> bento_info = yatai_client.repository.get('my_service:version') """ track('py-api-get') if ':' not in bento: raise BentoMLException( 'BentoService name or version is missing. Please provide in the ' 'format of name:version') name, version = bento.split(':') result = self.yatai_service.GetBento( GetBentoRequest(bento_name=name, bento_version=version)) if result.status.status_code != yatai_proto.status_pb2.Status.OK: error_code, error_message = status_pb_to_error_code_and_message( result.status) raise BentoMLException( f'BentoService {name}:{version} not found - ' f'{error_code}:{error_message}') return result.bento
def __init__( self, name: str = None, channels: List[str] = None, dependencies: List[str] = None, default_env_yaml_file: str = None, override_channels: bool = False, ): self._yaml = YAML() self._yaml.default_flow_style = False if default_env_yaml_file: env_yml_file = Path(default_env_yaml_file) if not env_yml_file.is_file(): raise BentoMLException( f"Can not find conda environment config yaml file at: " f"`{default_env_yaml_file}`") self._conda_env = self._yaml.load(env_yml_file) else: self._conda_env = self._yaml.load(DEFAULT_CONDA_ENV_BASE_YAML) if name: self.set_name(name) if override_channels and channels is None: raise BentoMLException( "No `conda_channels` provided while override_channels=True") if channels: self.set_channels(channels, override_channels) if dependencies: self.add_conda_dependencies(dependencies)
def _get_onnx_inference_session(self): if self.backend == "onnxruntime" or self.backend == "onnxruntime-gpu": try: import onnxruntime except ImportError: raise MissingDependencyException( f'"{self.backend}" package is required for inference with ' f'"{self.backend}" as backend"') if self._model_proto: logger.info( "Initializing onnxruntime InferenceSession with onnx.ModelProto " "instance") return onnxruntime.InferenceSession( self._model_proto.SerializeToString()) elif self._onnx_model_path: logger.info( "Initializing onnxruntime InferenceSession from onnx file:" f"'{self._onnx_model_path}'") return onnxruntime.InferenceSession(self._onnx_model_path) else: raise BentoMLException("OnnxModelArtifact in bad state") else: raise BentoMLException( f'"{self.backend}" runtime is currently not supported for ' f"OnnxModelArtifact")
def containerize(self, bento, tag=None, build_args=None, push=False): """ Create a container image from a BentoService. Args: bento: string tag: string build_args: dict push: boolean Returns: Image tag: String """ track('py-api-containerize') if ':' not in bento: raise BentoMLException( 'BentoService name or version is missing. Please provide in the ' 'format of name:version') name, version = bento.split(':') containerize_request = ContainerizeBentoRequest( bento_name=name, bento_version=version, tag=tag, build_args=build_args, push=push, ) result = self.yatai_service.ContainerizeBento(containerize_request) if result.status.status_code != yatai_proto.status_pb2.Status.OK: error_code, error_message = status_pb_to_error_code_and_message( result.status) raise BentoMLException( f'Failed to containerize {bento} - {error_code}:{error_message}' ) return result.tag
def _upload_file_to_remote_path(remote_path, file_path, file_name): """Upload file to remote path """ parsed_url = urlparse(remote_path) bucket_name = parsed_url.netloc object_prefix_path = parsed_url.path.lstrip('/') object_path = f'{object_prefix_path}/{file_name}' if is_s3_url(remote_path): try: import boto3 except ImportError: raise BentoMLException( '"boto3" package is required for saving bento to AWS S3 bucket' ) s3_client = boto3.client('s3') with open(file_path, 'rb') as f: s3_client.upload_fileobj(f, bucket_name, object_path) elif is_gcs_url(remote_path): try: from google.cloud import storage except ImportError: raise BentoMLException( '"google.cloud" package is required for saving bento to Google ' 'Cloud Storage') gcs_client = storage.Client() bucket = gcs_client.bucket(bucket_name) blob = bucket.blob(object_path) blob.upload_from_filename(file_path) else: http_response = requests.put(remote_path) if http_response.status_code != 200: raise BentoMLException( f'Error uploading BentoService to {remote_path} ' f'{http_response.status_code}')
def resolve_bundle_path(bento, pip_installed_bundle_path): if pip_installed_bundle_path: assert ( bento is None ), "pip installed BentoService commands should not have Bento argument" return pip_installed_bundle_path if os.path.isdir(bento) or is_s3_url(bento): # bundler already support loading local and s3 path return bento elif ":" in bento: # assuming passing in BentoService in the form of Name:Version tag yatai_client = YataiClient() name, version = bento.split(':') get_bento_result = yatai_client.repository.get(name, version) if get_bento_result.status.status_code != status_pb2.Status.OK: error_code, error_message = status_pb_to_error_code_and_message( get_bento_result.status) raise BentoMLException( f'BentoService {name}:{version} not found - ' f'{error_code}:{error_message}') return get_bento_result.bento.uri.uri else: raise BentoMLException( f'BentoService "{bento}" not found - either specify the file path of ' f'the BentoService saved bundle, or the BentoService id in the form of ' f'"name:version"')
def get(self, bento: str) -> "Bento": """ Args: bento (`str`): A BentoService identifier in the format of ``NAME:VERSION`` Returns: :class:`~bentoml.BentoService` metadata from Yatai RPC server. Raises: BentoMLException: ``bento`` is missing or have invalid format. Example:: from bentoml.yatai.client import get_yatai_client yatai_client = get_yatai_client() bento_info = yatai_client.repository.get('my_service:version') """ if ':' not in bento: raise BentoMLException( 'BentoService name or version is missing. Please provide in the ' 'format of name:version') name, version = bento.split(':') result = self.yatai_service.GetBento( GetBentoRequest(bento_name=name, bento_version=version)) if result.status.status_code != yatai_proto.status_pb2.Status.OK: error_code, error_message = status_pb_to_error_code_and_message( result.status) raise BentoMLException( f'BentoService {name}:{version} not found - ' f'{error_code}:{error_message}') return result.bento
def __init__( self, tag: t.Union[str, Tag], backend: str, gpu_device_id: int, disable_copy_in_default_stream: bool, providers: t.Optional["_ProviderType"], session_options: t.Optional["ort.SessionOptions"], # type: ignore name: t.Optional[str] = None, ): super().__init__(tag, name=name) self._backend = backend if backend not in SUPPORTED_ONNX_BACKEND: raise BentoMLException( f"'{backend}' runtime is currently not supported for ONNXModel" ) if providers is not None: if not all(i in ort.get_all_providers() for i in flatten_list(providers)): raise BentoMLException( f"'{providers}' cannot be parsed by `onnxruntime`" ) else: providers = self._get_default_providers( gpu_device_id, disable_copy_in_default_stream, ) self._providers = providers self._session_options = session_options
def delete(self, bento): """ Delete bento Args: bento: a BentoService identifier in the format of NAME:VERSION Example: >>> >>> yatai_client = get_yatai_client() >>> yatai_client.repository.delete('my_service:version') """ track('py-api-delete') if ':' not in bento: raise BentoMLException( 'BentoService name or version is missing. Please provide in the ' 'format of name:version' ) name, version = bento.split(':') result = self.yatai_service.DangerouslyDeleteBento( DangerouslyDeleteBentoRequest(bento_name=name, bento_version=version) ) if result.status.status_code != yatai_proto.status_pb2.Status.OK: error_code, error_message = status_pb_to_error_code_and_message( result.status ) raise BentoMLException( f'Failed to delete Bento {bento} {error_code}:{error_message}' )
def load_from_dir(cls, path): from bentoml.archive import load_bentoml_config if cls._bento_archive_path is not None and cls._bento_archive_path != path: logger.warning( "Loaded BentoArchive from '%s' can't be loaded again from a different" "path %s", cls._bento_archive_path, path, ) artifacts_path = path # For pip installed BentoService, artifacts directory is located at # 'package_path/artifacts/', but for loading from BentoArchive, it is # in 'path/{service_name}/artifacts/' if not os.path.isdir(os.path.join(path, "artifacts")): artifacts_path = os.path.join(path, cls.name()) bentoml_config = load_bentoml_config(path) if bentoml_config["metadata"]["service_name"] != cls.name(): raise BentoMLException( "BentoService name does not match with BentoArchive in path: {}" .format(path)) if bentoml_config["kind"] != "BentoService": raise BentoMLException( "BentoArchive type '{}' can not be loaded as a BentoService". format(bentoml_config["kind"])) artifacts = ArtifactCollection.load(artifacts_path, cls._artifacts_spec) svc = cls(artifacts) return svc
def async_start_yatai_service_web_ui(yatai_server_address, ui_port, base_log_path, debug_mode, web_prefix_path): if ui_port is not None: ui_port = ui_port if isinstance(ui_port, str) else str(ui_port) web_ui_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), 'web')) web_prefix_path = web_prefix_path.strip("/") if debug_mode: # Only when src/index.ts exists, we will run dev (nodemon) if os.path.exists( os.path.join(web_ui_dir, 'src/index.ts') ) and _is_web_server_debug_tools_available(web_ui_dir): web_ui_command = [ 'npm', 'run', 'dev', '--', yatai_server_address, ui_port, base_log_path, web_prefix_path, ] else: web_ui_command = [ 'node', 'dist/bundle.js', yatai_server_address, ui_port, base_log_path, web_prefix_path, ] else: if not os.path.exists(os.path.join(web_ui_dir, 'dist', 'bundle.js')): raise BentoMLException( 'Yatai web client built is missing. ' 'Please run `npm run build` in the bentoml/yatai/web directory ' 'and then try again') web_ui_command = [ 'node', 'dist/bundle.js', yatai_server_address, ui_port, base_log_path, web_prefix_path, ] web_proc = subprocess.Popen(web_ui_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=web_ui_dir) is_web_proc_running = web_proc.poll() is None if not is_web_proc_running: web_proc_output = web_proc.stdout.read().decode('utf-8') logger.error(f'return code: {web_proc.returncode} {web_proc_output}') raise BentoMLException('Yatai web ui did not start properly') atexit.register(web_proc.terminate)
def load( tag: t.Union[str, Tag], backend: t.Optional[str] = "onnxruntime", providers: t.Optional[t.Union["_ProviderType", "_GPUProviderType"]] = None, session_options: t.Optional["ort.SessionOptions"] = None, # type: ignore model_store: "ModelStore" = Provide[BentoMLContainer.model_store], ) -> "ort.InferenceSession": """ Load a model from BentoML local modelstore with given name. Args: tag (:code:`Union[str, Tag]`): Tag of a saved model in BentoML local modelstore. backend (:code:`str`, `optional`, default to :code:`onnxruntime`): Different backend runtime supported by ONNX. Currently only accepted :obj:`onnxruntime` and :obj:`onnxruntime-gpu`. providers (`List[Union[str, Tuple[str, Dict[str, Any]]`, `optional`, default to :code:`None`): Different providers provided by users. By default BentoML will use :func:`onnxruntime.get_available_providers` when loading a model. session_options (`onnxruntime.SessionOptions`, `optional`, default to :code:`None`): SessionOptions per use case. If not specified, then default to :code:`None`. model_store (:mod:`~bentoml._internal.models.store.ModelStore`, default to :mod:`BentoMLContainer.model_store`): BentoML modelstore, provided by DI Container. Returns: :obj:`onnxruntime.InferenceSession`: an instance of ONNX model from BentoML modelstore. Examples: .. code-block:: python import bentoml model = bentoml.onnx.load(tag) """ # noqa model = model_store.get(tag) if model.info.module not in (MODULE_NAME, __name__): raise BentoMLException( f"Model {tag} was saved with module {model.info.module}, failed loading with {MODULE_NAME}." ) model_file = model.path_of(f"{SAVE_NAMESPACE}{ONNX_EXT}") if backend not in SUPPORTED_ONNX_BACKEND: raise BentoMLException( f"'{backend}' runtime is currently not supported for ONNXModel" ) if providers: if not all(i in ort.get_all_providers() for i in flatten_list(providers)): raise BentoMLException(f"'{providers}' cannot be parsed by `onnxruntime`") else: providers = ort.get_available_providers() return ort.InferenceSession( model_file, sess_options=session_options, providers=providers, )
def containerize( self, bento: str, tag: str, build_args: Dict[str, str] = None, push: bool = False, ) -> str: """ Create a container image from a :class:`~bentoml.BentoService` Args: bento (`str`): A BentoService identifier with ``NAME:VERSION`` format. tag (`str`): BentoService tag. build_args (`Dict[str, str]`, `optional`): Build args to parse to ``docker build`` push (`bool`, `optional`): Whether to push built container to remote YataiService. Returns: :obj:`str` representing the image tag of the containerized :class:`~bentoml.BentoService` Raises: BentoMLException: ``bento`` is missing or incorrect format. Example:: svc = MyModelService() svc.save() from bentoml.yatai.client import get_yatai_client yatai_client = get_yatai_client() tag = yatai_client.repository.containerize(f'{svc.name}:{svc.version}') """ # noqa: E501 if ':' not in bento: raise BentoMLException( 'BentoService name or version is missing. Please provide in the ' 'format of name:version') name, version = bento.split(':') containerize_request = ContainerizeBentoRequest( bento_name=name, bento_version=version, tag=tag, build_args=build_args, push=push, ) result = self.yatai_service.ContainerizeBento(containerize_request) if result.status.status_code != yatai_proto.status_pb2.Status.OK: error_code, error_message = status_pb_to_error_code_and_message( result.status) raise BentoMLException( f'Failed to containerize {bento} - {error_code}:{error_message}' ) return result.tag
def value_string_to_list(value_string): if not value_string.startswith('(') or not value_string.endswith(')'): raise BentoMLException( f"Query values {value_string} need to be inside (). " f"e.g. (value1, value2, ..)" ) if len(value_string) == 2: raise BentoMLException("Query values can't be empty") return [value.strip() for value in value_string[1:-1].split(',')]
def parse_bento_tag(tag): items = tag.split(':') if len(items) > 2: raise BentoMLException("More than one ':' appeared in tag '%s'" % tag) elif len(items) == 1: return tag, 'latest' else: if not items[0]: raise BentoMLException("':' can't be the leading character") if not items[1]: raise BentoMLException("Please include value for the key %s" % items[0]) return items[0], items[1]
def delete(self, bento): track('py-api-delete') if ':' not in bento: raise BentoMLException( 'BentoService name or version is missing. Please provide in the ' 'format of name:version') name, version = bento.split(':') result = self.yatai_service.DangerouslyDeleteBento( DangerouslyDeleteBentoRequest(bento_name=name, bento_version=version)) if result.status.status_code != yatai_proto.status_pb2.Status.OK: error_code, error_message = status_pb_to_error_code_and_message( result.status) raise BentoMLException( f'Failed to delete Bento {bento} {error_code}:{error_message}')
def add(self, deployment_pb): try: deployment_spec = deployment_pb.spec sagemaker_config = deployment_spec.sagemaker_operator_config sagemaker_config.region = (sagemaker_config.region or get_default_aws_region()) if sagemaker_config is None: raise YataiDeploymentException( "Sagemaker configuration is missing.") bento_pb = self.yatai_service.GetBento( GetBentoRequest( bento_name=deployment_spec.bento_name, bento_version=deployment_spec.bento_version, )) if bento_pb.bento.uri.type not in (BentoUri.LOCAL, BentoUri.S3): raise BentoMLException( "BentoML currently not support {} repository".format( BentoUri.StorageType.Name(bento_pb.bento.uri.type))) return self._add(deployment_pb, bento_pb, bento_pb.bento.uri.uri) except BentoMLException as error: deployment_pb.state.state = DeploymentState.ERROR deployment_pb.state.error_message = ( f"Error creating SageMaker deployment: {str(error)}") return ApplyDeploymentResponse(status=error.status_proto, deployment=deployment_pb)
def ensure_is_ready_to_deploy_to_cloud_formation(stack_name, region): try: cf_client = boto3.client('cloudformation', region) logger.debug('Checking stack description') describe_formation_result = cf_client.describe_stacks( StackName=stack_name) result_stacks = describe_formation_result.get('Stacks') if len(result_stacks): logger.debug('Stack "%s" exists', stack_name) stack_result = result_stacks[0] if stack_result['StackStatus'] in [ 'ROLLBACK_COMPLETE', 'ROLLBACK_FAILED', 'ROLLBACK_IN_PROGRESS', ]: logger.debug( 'Stack "%s" is in a "bad" status(%s), deleting the stack ' 'before deployment', stack_name, stack_result['StackStatus'], ) cf_client.delete_stack(StackName=stack_name) except ClientError as e: # We are brutally parse and handle stack doesn't exist, since # "AmazonCloudFormationException" currently is not implemented in boto3. Once # the current error is implemented, we need to switch error_response = e.response.get('Error', {}) error_code = error_response.get('Code') error_message = error_response.get('Message', 'Unknown') if error_code == 'ValidationError' and 'does not exist' in error_message: pass else: raise BentoMLException(str(e))
def lambda_deploy(project_dir, aws_region, stack_name): # if the stack name exists and the state is in rollback_complete or # other 'bad' state, we will delete the stack first, and then deploy # it logger.debug('Ensure stack "%s" is ready to deploy', stack_name) ensure_is_ready_to_deploy_to_cloud_formation(stack_name, aws_region) logger.debug('Stack "%s"is ready to deploy', stack_name) template_file = os.path.join(project_dir, '.aws-sam', 'build', 'packaged.yaml') return_code, stdout, stderr = call_sam_command( [ 'deploy', '--stack-name', stack_name, '--capabilities', 'CAPABILITY_IAM', '--template-file', template_file, '--region', aws_region, ], project_dir=project_dir, region=aws_region, ) if return_code != 0: error_message = stderr if not error_message: error_message = stdout raise BentoMLException( 'Failed to deploy lambda function. {}'.format(error_message)) else: return stdout
def update_sagemaker_deployment( self, deployment_name, namespace=None, api_name=None, instance_type=None, instance_count=None, num_of_gunicorn_workers_per_instance=None, bento_name=None, bento_version=None, wait=None, ): """ Update current sagemaker deployment Args: namespace: deployment_name: api_name: instance_type: instance_count: num_of_gunicorn_workers_per_instance: bento_name: bento_version: wait: Returns: Protobuf message Raises: BentoMLException """ get_deployment_result = self.get(namespace, deployment_name) if get_deployment_result.status.status_code != status_pb2.Status.OK: get_deployment_status = get_deployment_result.status raise BentoMLException( f'Failed to retrieve current deployment {deployment_name} in ' f'{namespace}. ' f'{status_pb2.Status.Code.Name(get_deployment_status.status_code)}' f':{get_deployment_status.error_message}') deployment_pb = get_deployment_result.deployment if api_name: deployment_pb.spec.sagemaker_operator_config.api_name = api_name if instance_type: deployment_pb.spec.sagemaker_operator_config.instance_type = instance_type if instance_count: deployment_pb.spec.sagemaker_operator_config.instance_count = instance_count if num_of_gunicorn_workers_per_instance: deployment_pb.spec.sagemaker_operator_config.num_of_gunicorn_workers_per_instance = ( # noqa E501 num_of_gunicorn_workers_per_instance) if bento_name: deployment_pb.spec.bento_name = bento_name if bento_version: deployment_pb.spec.bento_version = bento_version logger.debug('Updated configuration for sagemaker deployment %s', deployment_pb.name) return self.apply(deployment_pb, wait)
def update_lambda_deployment( self, deployment_name, namespace=None, bento_name=None, bento_version=None, memory_size=None, timeout=None, wait=None, ): get_deployment_result = self.get(namespace=namespace, name=deployment_name) if get_deployment_result.status.status_code != status_pb2.Status.OK: error_code = status_pb2.Status.Code.Name( get_deployment_result.status.status_code) error_message = status_pb2.status.error_message raise BentoMLException( f'Failed to retrieve current deployment {deployment_name} ' f'in {namespace}. {error_code}:{error_message}') deployment_pb = get_deployment_result.deployment if bento_name: deployment_pb.spec.bento_name = bento_name if bento_version: deployment_pb.spec.bento_version = bento_version if memory_size: deployment_pb.spec.aws_lambda_operator_config.memory_size = memory_size if timeout: deployment_pb.spec.aws_lambda_operator_config.timeout = timeout logger.debug('Updated configuration for Lambda deployment %s', deployment_name) return self.apply(deployment_pb, wait)
def update(self, deployment_pb, previous_deployment): try: ensure_sam_available_or_raise() ensure_docker_available_or_raise() deployment_spec = deployment_pb.spec bento_pb = self.yatai_service.GetBento( GetBentoRequest( bento_name=deployment_spec.bento_name, bento_version=deployment_spec.bento_version, ) ) if bento_pb.bento.uri.type not in (BentoUri.LOCAL, BentoUri.S3): raise BentoMLException( 'BentoML currently not support {} repository'.format( BentoUri.StorageType.Name(bento_pb.bento.uri.type) ) ) return self._update( deployment_pb, previous_deployment, bento_pb, bento_pb.bento.uri.uri ) except BentoMLException as error: deployment_pb.state.state = DeploymentState.ERROR deployment_pb.state.error_message = f'Error: {str(error)}' return ApplyDeploymentResponse( status=error.status_code, deployment_pb=deployment_pb )
def requirements_txt_content(self): requirements_txt_file = Path(self._requirements_txt_file) if not requirements_txt_file.is_file(): raise BentoMLException( f"requirement txt file not found at '{requirements_txt_file}'" ) return requirements_txt_file
def update_azure_functions_deployment( self, deployment_name, bento_name=None, bento_version=None, max_burst=None, min_instances=None, premium_plan_sku=None, namespace=None, wait=None, ): get_deployment_result = self.get(namespace=namespace, name=deployment_name) if get_deployment_result.status.status_code != status_pb2.Status.OK: error_code = status_pb2.Status.Code.Name( get_deployment_result.status.status_code) error_message = status_pb2.status.error_message raise BentoMLException( f'Failed to retrieve current deployment {deployment_name} in ' f'{namespace}. {error_code}:{error_message}') deployment_pb = get_deployment_result.deployment if bento_name: deployment_pb.spec.bento_name = bento_name if bento_version: deployment_pb.spec.bento_version = bento_version if max_burst: deployment_pb.spec.azure_functions_operator_config.max_burst = max_burst if min_instances: deployment_pb.spec.azure_functions_operator_config.min_instances = ( min_instances) if premium_plan_sku: deployment_pb.spec.azure_functions_operator_config.premium_plan_sku = ( premium_plan_sku) return self.apply(deployment_pb, wait)
def get(self, bento): track('py-api-get') if ':' not in bento: raise BentoMLException( 'BentoService name or version is missing. Please provide in the ' 'format of name:version') name, version = bento.split(':') result = self.yatai_service.GetBento( GetBentoRequest(bento_name=name, bento_version=version)) if result.status.status_code != yatai_proto.status_pb2.Status.OK: error_code, error_message = status_pb_to_error_code_and_message( result.status) raise BentoMLException( f'BentoService {name}:{version} not found - ' f'{error_code}:{error_message}') return result.bento
def _update(self, deployment_pb, current_deployment, bento_pb, bento_path): if loader._is_remote_path(bento_path): with loader._resolve_remote_bundle_path(bento_path) as local_path: return self._update(deployment_pb, current_deployment, bento_pb, local_path) updated_deployment_spec = deployment_pb.spec updated_lambda_deployment_config = ( updated_deployment_spec.aws_lambda_operator_config) updated_bento_service_metadata = bento_pb.bento.bento_service_metadata describe_result = self.describe(deployment_pb) if describe_result.status.status_code != status_pb2.Status.OK: error_code, error_message = status_pb_to_error_code_and_message( describe_result.status) raise YataiDeploymentException( f'Failed fetching Lambda deployment current status - ' f'{error_code}:{error_message}') latest_deployment_state = json.loads(describe_result.state.info_json) if 's3_bucket' in latest_deployment_state: lambda_s3_bucket = latest_deployment_state['s3_bucket'] else: raise BentoMLException( 'S3 Bucket is missing in the AWS Lambda deployment, please make sure ' 'it exists and try again') _deploy_lambda_function( deployment_pb=deployment_pb, bento_service_metadata=updated_bento_service_metadata, deployment_spec=updated_deployment_spec, lambda_s3_bucket=lambda_s3_bucket, lambda_deployment_config=updated_lambda_deployment_config, bento_path=bento_path, ) return ApplyDeploymentResponse(deployment=deployment_pb, status=Status.OK())
def add(self, deployment_pb): try: deployment_spec = deployment_pb.spec deployment_spec.aws_lambda_operator_config.region = ( deployment_spec.aws_lambda_operator_config.region or get_default_aws_region()) if not deployment_spec.aws_lambda_operator_config.region: raise InvalidArgument('AWS region is missing') bento_pb = self.yatai_service.GetBento( GetBentoRequest( bento_name=deployment_spec.bento_name, bento_version=deployment_spec.bento_version, )) if bento_pb.bento.uri.type not in (BentoUri.LOCAL, BentoUri.S3): raise BentoMLException( 'BentoML currently not support {} repository'.format( BentoUri.StorageType.Name(bento_pb.bento.uri.type))) return self._add(deployment_pb, bento_pb, bento_pb.bento.uri.uri) except BentoMLException as error: deployment_pb.state.state = DeploymentState.ERROR deployment_pb.state.error_message = f'Error: {str(error)}' return ApplyDeploymentResponse(status=error.status_proto, deployment=deployment_pb)
def _init_azure_functions_project(azure_functions_project_dir, bento_path, azure_functions_config): try: local_bentoml_path = os.path.dirname(__file__) shutil.copytree(bento_path, azure_functions_project_dir) shutil.copy( os.path.join(local_bentoml_path, 'host.json'), os.path.join(azure_functions_project_dir, 'host.json'), ) shutil.copy( os.path.join(local_bentoml_path, 'local.settings.json'), os.path.join(azure_functions_project_dir, 'local.settings.json'), ) shutil.copy( os.path.join(local_bentoml_path, 'Dockerfile'), os.path.join(azure_functions_project_dir, 'Dockerfile-azure'), ) app_path = os.path.join(azure_functions_project_dir, 'app') os.mkdir(app_path) shutil.copy( os.path.join(local_bentoml_path, 'app_init.py'), os.path.join(app_path, '__init__.py'), ) with open(os.path.join(app_path, 'function.json'), 'w') as f: f.write( AZURE_API_FUNCTION_JSON.format( function_auth_level=azure_functions_config. function_auth_level or DEFAULT_FUNCTION_AUTH_LEVEL)) except Exception as e: raise BentoMLException( f'Failed to initialize azure function project. {str(e)}')
def handle_aws_lambda_event(self, event, func): try: from imageio import imread except ImportError: raise ImportError( "imageio package is required to use ImageHandler") if event["headers"].get("Content-Type", None) in ACCEPTED_CONTENT_TYPES: # decodebytes introduced at python3.1 try: image = imread(base64.decodebytes(event["body"]), pilmode=self.pilmode) except AttributeError: image = imread( base64.decodestring(event["body"]), # pylint: disable=W1505 pilmode=self.pilmode, ) else: raise BentoMLException( "BentoML currently doesn't support Content-Type: {content_type} for " "AWS Lambda".format( content_type=event["headers"]["Content-Type"])) result = func(image) result = get_output_str(result, event["headers"].get("output", "json")) return {"statusCode": 200, "body": result}
def push(self, bento, labels=None): """ Push a local BentoService to a remote yatai server. Args: bento: a BentoService identifier in the format of NAME:VERSION labels: optional. List of labels for the BentoService. Returns: BentoService saved path """ track('py-api-push') if isinstance(self.yatai_service, YataiService): raise BentoMLException('need set yatai_service_url') from bentoml.yatai.client import get_yatai_client local_yc = get_yatai_client() local_bento_pb = local_yc.repository.get(bento) if local_bento_pb.uri.s3_presigned_url: bento_bundle_path = local_bento_pb.uri.s3_presigned_url elif local_bento_pb.uri.gcs_presigned_url: bento_bundle_path = local_bento_pb.uri.gcs_presigned_url else: bento_bundle_path = local_bento_pb.uri.uri return self.upload_from_dir(bento_bundle_path, labels=labels)