コード例 #1
0
        def ContainerizeBento(self, request, context=None):
            try:
                ensure_docker_available_or_raise()
                tag = request.tag
                if tag is None or len(tag) == 0:
                    name = to_valid_docker_image_name(request.bento_name)
                    version = to_valid_docker_image_version(request.bento_version)
                    tag = f"{name}:{version}"
                if ":" not in tag:
                    version = to_valid_docker_image_version(request.bento_version)
                    tag = f"{tag}:{version}"
                import docker

                docker_client = docker.from_env()
                bento_pb = self.bento_metadata_store.get(
                    request.bento_name, request.bento_version
                )
                if not bento_pb:
                    raise YataiRepositoryException(
                        f'BentoService {request.bento_name}:{request.bento_version} '
                        f'does not exist'
                    )

                with TempDirectory() as temp_dir:
                    temp_bundle_path = f'{temp_dir}/{bento_pb.name}'
                    bento_service_bundle_path = bento_pb.uri.uri
                    if bento_pb.uri.type == BentoUri.S3:
                        bento_service_bundle_path = self.repo.get(
                            bento_pb.name, bento_pb.version
                        )
                    elif bento_pb.uri.type == BentoUri.GCS:
                        bento_service_bundle_path = self.repo.get(
                            bento_pb.name, bento_pb.version
                        )
                    safe_retrieve(bento_service_bundle_path, temp_bundle_path)
                    try:
                        docker_client.images.build(
                            path=temp_bundle_path,
                            tag=tag,
                            buildargs=dict(request.build_args),
                        )
                    except (docker.errors.APIError, docker.errors.BuildError) as error:
                        logger.error(f'Encounter container building issue: {error}')
                        raise YataiRepositoryException(error)
                    if request.push is True:
                        try:
                            docker_client.images.push(
                                repository=request.repository, tag=tag
                            )
                        except docker.errors.APIError as error:
                            raise YataiRepositoryException(error)

                    return ContainerizeBentoResponse(status=Status.OK(), tag=tag)
            except BentoMLException as e:
                logger.error(f"RPC ERROR ContainerizeBento: {e}")
                return ContainerizeBentoResponse(status=e.status_proto)
            except Exception as e:  # pylint: disable=broad-except
                logger.error(f"RPC ERROR ContainerizeBento: {e}")
                return ContainerizeBentoResponse(status=Status.INTERNAL(e))
コード例 #2
0
 def dangerously_delete(self, bento_name, bento_version):
     with create_session(self.sess_maker) as sess:
         try:
             bento_obj = (sess.query(Bento).filter_by(
                 name=bento_name, version=bento_version).one())
             if bento_obj.deleted:
                 raise YataiRepositoryException(
                     "Bento {}:{} has already been deleted".format(
                         bento_name, bento_version))
             bento_obj.deleted = True
         except NoResultFound:
             raise YataiRepositoryException(
                 "Bento %s:%s is not found in repository" % bento_name,
                 bento_version)
コード例 #3
0
 def get(self, bento_name, bento_version):
     saved_path = os.path.join(self.base_path, bento_name, bento_version)
     if not os.path.exists(saved_path):
         raise YataiRepositoryException(
             "Bento {}:{} not found in target repository".format(
                 bento_name, bento_version))
     return saved_path
コード例 #4
0
 def update_bento_service_metadata(
     self, bento_name, bento_version, bento_service_metadata_pb
 ):
     with create_session(self.sess_maker) as sess:
         try:
             bento_obj = (
                 sess.query(Bento)
                 .filter_by(name=bento_name, version=bento_version, deleted=False)
                 .one()
             )
             service_metadata = ProtoMessageToDict(bento_service_metadata_pb)
             bento_obj.bento_service_metadata = service_metadata
             if service_metadata.get('labels', None) is not None:
                 bento = (
                     sess.query(Bento)
                     .filter_by(name=bento_name, version=bento_version)
                     .one()
                 )
                 add_or_update_labels(
                     sess, RESOURCE_TYPE.bento, bento.id, service_metadata['labels']
                 )
         except NoResultFound:
             raise YataiRepositoryException(
                 "Bento %s:%s is not found in repository" % bento_name, bento_version
             )
コード例 #5
0
    def add(self, bento_name, bento_version):
        # Full path containing saved BentoService bundle, it the base path with service
        # name and service version as prefix. e.g.:
        # with base_path = '/tmp/my_bento_repo/', the saved bento will resolve in
        # the directory: '/tmp/my_bento_repo/service_name/version/'
        target_dir = os.path.join(self.base_path, bento_name, bento_version)

        # Ensure parent directory exist
        Path(os.path.join(self.base_path), bento_name).mkdir(
            parents=True, exist_ok=True
        )

        # Raise if target bento version already exist in storage
        if os.path.exists(target_dir):
            raise YataiRepositoryException(
                "Existing BentoService bundle {name}:{version} found in repository: "
                "{target_dir}".format(
                    name=bento_name, version=bento_version, target_dir=target_dir
                )
            )

        # Create target directory for upload
        os.mkdir(target_dir)

        return BentoUri(type=self.uri_type, uri=target_dir)
コード例 #6
0
    def add(self, bento_name, bento_version):
        # Generate pre-signed s3 path for upload

        object_name = self._get_object_name(bento_name, bento_version)

        try:
            response = self.s3_client.generate_presigned_post(
                self.bucket,
                object_name,
                Fields=None,
                Conditions=None,
                ExpiresIn=self._expiration,
            )
        except Exception as e:
            raise YataiRepositoryException(
                "Not able to get pre-signed URL on S3. Error: {}".format(e)
            )

        additional_fields = response['fields']
        additional_fields['url'] = response['url']
        return BentoUri(
            type=self.uri_type,
            uri='s3://{}/{}'.format(self.bucket, object_name),
            additional_fields=json.dumps(additional_fields),
        )
コード例 #7
0
    def dangerously_delete(self, bento_name, bento_version):
        # Remove gcs path containing related Bento files

        object_name = self._get_object_name(bento_name, bento_version)

        try:
            bucket = self.gcs_client.bucket(self.bucket)
            blob = bucket.blob(object_name)
            blob.delete()
        except Exception as e:
            raise YataiRepositoryException(
                "Not able to delete object on GCS. Error: {}".format(e))
コード例 #8
0
 def update_bento_service_metadata(self, bento_name, bento_version,
                                   bento_service_metadata_pb):
     with create_session(self.sess_maker) as sess:
         try:
             bento_obj = (sess.query(Bento).filter_by(name=bento_name,
                                                      version=bento_version,
                                                      deleted=False).one())
             bento_obj.bento_service_metadata = ProtoMessageToDict(
                 bento_service_metadata_pb)
         except NoResultFound:
             raise YataiRepositoryException(
                 "Bento %s:%s is not found in repository" % bento_name,
                 bento_version)
コード例 #9
0
ファイル: metadata.py プロジェクト: soeque1/BentoML
 def update_upload_status(sess, bento_name, bento_version,
                          upload_status_pb):
     try:
         bento_obj = (sess.query(Bento).filter_by(name=bento_name,
                                                  version=bento_version,
                                                  deleted=False).one())
         # TODO:
         # if bento_obj.upload_status and bento_obj.upload_status.updated_at >
         # upload_status_pb.updated_at, update should be ignored
         bento_obj.upload_status = ProtoMessageToDict(upload_status_pb)
     except NoResultFound:
         raise YataiRepositoryException(
             "Bento %s:%s is not found in repository" % bento_name,
             bento_version)
コード例 #10
0
    def dangerously_delete(self, bento_name, bento_version):
        # Remove s3 path containing related Bento files

        object_name = self._get_object_name(bento_name, bento_version)

        try:
            response = self.s3_client.delete_object(Bucket=self.bucket,
                                                    Key=object_name)

            DELETE_MARKER = 'DeleteMarker'  # whether object is successfully deleted.
        except Exception as e:
            raise YataiRepositoryException(
                "Not able to delete object on S3. Error: {}".format(e))

        return response[DELETE_MARKER]
コード例 #11
0
    def __init__(self, base_url):
        try:
            from google.cloud import storage
        except ImportError:
            raise YataiRepositoryException(
                '"google-cloud-storage" package is required for Google Cloud '
                'Storage Repository. You can install it with pip: '
                '"pip install google-cloud-storage"'
            )
        self.uri_type = BentoUri.GCS

        parse_result = urlparse(base_url)
        self.bucket = parse_result.netloc
        self.base_path = parse_result.path.lstrip('/')
        self.gcs_client = storage.Client()
コード例 #12
0
    def get(self, bento_name, bento_version):
        # Return s3 path containing uploaded Bento files

        object_name = self._get_object_name(bento_name, bento_version)

        try:
            response = self.s3_client.generate_presigned_url(
                'get_object',
                Params={'Bucket': self.bucket, 'Key': object_name},
                ExpiresIn=self._expiration,
            )
        except Exception as e:
            raise YataiRepositoryException(
                "Not able to get pre-signed URL on S3. Error: {}".format(e)
            )
        return response
コード例 #13
0
    def add(self, bento_name, bento_version):
        object_name = self._get_object_name(bento_name, bento_version)
        try:
            bucket = self.gcs_client.bucket(self.bucket)
            blob = bucket.blob(object_name)

            response = blob.generate_signed_url(
                version="v4", expiration=self._expiration, method="PUT",
            )
        except Exception as e:
            raise YataiRepositoryException(
                "Not able to get pre-signed URL on GCS. Error: {}".format(e)
            )

        return BentoUri(
            type=self.uri_type,
            uri='gs://{}/{}'.format(self.bucket, object_name),
            gcs_presigned_url=response,
        )
コード例 #14
0
    def add(self, bento_name, bento_version):
        # Generate pre-signed s3 path for upload

        object_name = self._get_object_name(bento_name, bento_version)
        try:
            response = self.s3_client.generate_presigned_url(
                'put_object',
                Params={'Bucket': self.bucket, 'Key': object_name},
                ExpiresIn=self.expiration,
            )
        except Exception as e:
            raise YataiRepositoryException(
                "Not able to get pre-signed URL on S3. Error: {}".format(e)
            )

        return BentoUri(
            type=self.uri_type,
            uri='s3://{}/{}'.format(self.bucket, object_name),
            s3_presigned_url=response,
        )
コード例 #15
0
    def dangerously_delete(self, bento_name, bento_version):
        # Remove s3 path containing related Bento files

        from botocore.exceptions import ClientError

        object_name = self._get_object_name(bento_name, bento_version)

        try:
            response = self.s3_client.delete_object(Bucket=self.bucket, Key=object_name)
            DELETE_MARKER = 'DeleteMarker'  # whether object is successfully deleted.

            # Note: as of boto3 v1.13.13. delete_object returns an incorrect format as
            # expected from documentation.
            # Expected format:
            # {
            #   'DeleteMarker': True|False,
            #   'VersionId': 'string',
            #   'RequestCharged': 'requester'
            # }
            # Current return:
            # {
            #   'ResponseMetadata': {
            #     'RequestId': '****************',
            #     'HostId': '*****/******',
            #     'HTTPStatusCode': 204,
            #     'HTTPHeaders': {
            #       'x-amz-id-2': '*****/xxxxx',
            #       'x-amz-request-id': '332EE9F7AB555D2B',
            #        'date': 'Tue, 19 May 2020 19:46:57 GMT',
            #        'server': 'AmazonS3'
            #     },
            #     'RetryAttempts': 0
            #   }
            # }
            # An open issue on github: https://github.com/boto/boto3/issues/759
            if DELETE_MARKER in response:
                if response[DELETE_MARKER]:
                    return
                else:
                    logger.warning(
                        f"BentoML has deleted service '{bento_name}:{bento_version}' "
                        f"from YataiService records, but it failed to delete the saved "
                        f"bundle files stored in s3://{self.bucket}/{object_name}, "
                        f"the files may have already been deleted by the user."
                    )
                    return
            elif 'ResponseMetadata' in response:
                # Note: Use head_object to 'check' is the object deleted or not.
                # head_object only try to retrieve the metadata without returning
                # the object itself.
                try:
                    self.s3_client.head_object(Bucket=self.bucket, Key=object_name)
                    logger.warning(
                        f"BentoML has deleted service '{bento_name}:{bento_version}' "
                        f"from YataiService records, but it failed to delete the saved "
                        f"bundle files stored in s3://{self.bucket}/{object_name}, "
                        f"the files may have already been deleted by the user."
                    )
                except ClientError as e:
                    # expected ClientError with Code 404, as target object should be
                    # deleted and 'head_object' should raise
                    error_response = e.response.get('Error', {})
                    error_code = error_response.get('Code', None)
                    if error_code == '404':
                        # Error code 404 means target file object does not exist, as
                        # expected after delete_object call
                        return
                    else:
                        # unexpected boto3 ClientError
                        raise e
            else:
                raise YataiRepositoryException(
                    'Unrecognized response format from s3 delete_object'
                )
        except Exception as e:
            raise YataiRepositoryException(
                "Not able to delete object on S3. Error: {}".format(e)
            )