Пример #1
0
    def _add(self, deployment_pb, bento_pb, bento_path):
        if loader._is_remote_path(bento_path):
            with loader._resolve_remote_bundle_path(bento_path) as local_path:
                return self._add(deployment_pb, bento_pb, local_path)

        deployment_spec = deployment_pb.spec
        lambda_deployment_config = deployment_spec.aws_lambda_operator_config
        bento_service_metadata = bento_pb.bento.bento_service_metadata
        lambda_s3_bucket = generate_aws_compatible_string(
            'btml-{namespace}-{name}-{random_string}'.format(
                namespace=deployment_pb.namespace,
                name=deployment_pb.name,
                random_string=uuid.uuid4().hex[:6].lower(),
            ))
        try:
            create_s3_bucket_if_not_exists(lambda_s3_bucket,
                                           lambda_deployment_config.region)
            _deploy_lambda_function(
                deployment_pb=deployment_pb,
                bento_service_metadata=bento_service_metadata,
                deployment_spec=deployment_spec,
                lambda_s3_bucket=lambda_s3_bucket,
                lambda_deployment_config=lambda_deployment_config,
                bento_path=bento_path,
            )
            return ApplyDeploymentResponse(status=Status.OK(),
                                           deployment=deployment_pb)
        except BentoMLException as error:
            if lambda_s3_bucket and lambda_deployment_config:
                cleanup_s3_bucket_if_exist(lambda_s3_bucket,
                                           lambda_deployment_config.region)
            raise error
Пример #2
0
    def _add(self, deployment_pb, bento_pb, bento_path):
        try:
            if loader._is_remote_path(bento_path):
                with loader._resolve_remote_bundle_path(
                        bento_path) as local_path:
                    return self._add(deployment_pb, bento_pb, local_path)

            deployment_spec = deployment_pb.spec
            aws_ec2_deployment_config = deployment_spec.aws_ec2_operator_config

            user_id = get_aws_user_id()
            artifact_s3_bucket_name = generate_aws_compatible_string(
                "btml-{user_id}-{namespace}".format(
                    user_id=user_id,
                    namespace=deployment_pb.namespace,
                ))
            create_s3_bucket_if_not_exists(artifact_s3_bucket_name,
                                           aws_ec2_deployment_config.region)
            self.deploy_service(
                deployment_pb,
                deployment_spec,
                bento_path,
                aws_ec2_deployment_config,
                artifact_s3_bucket_name,
                aws_ec2_deployment_config.region,
            )
        except BentoMLException as error:
            if artifact_s3_bucket_name and aws_ec2_deployment_config.region:
                cleanup_s3_bucket_if_exist(artifact_s3_bucket_name,
                                           aws_ec2_deployment_config.region)
            raise error
        return ApplyDeploymentResponse(status=Status.OK(),
                                       deployment=deployment_pb)
Пример #3
0
    def _add(self, deployment_pb, bento_pb, bento_path):
        if loader._is_remote_path(bento_path):
            with loader._resolve_remote_bundle_path(bento_path) as local_path:
                return self._add(deployment_pb, bento_pb, local_path)

        deployment_spec = deployment_pb.spec
        lambda_deployment_config = deployment_spec.aws_lambda_operator_config
        bento_service_metadata = bento_pb.bento.bento_service_metadata
        lambda_s3_bucket = generate_aws_compatible_string(
            'btml-{namespace}-{name}-{random_string}'.format(
                namespace=deployment_pb.namespace,
                name=deployment_pb.name,
                random_string=uuid.uuid4().hex[:6].lower(),
            ))

        try:
            py_major, py_minor, _ = bento_service_metadata.env.python_version.split(
                '.')
            if py_major != '3':
                raise BentoMLException(
                    'Python 2 is not supported for Lambda Deployment')
            python_runtime = 'python{}.{}'.format(py_major, py_minor)

            artifact_types = [
                item.artifact_type for item in bento_service_metadata.artifacts
            ]
            if any(i in ['TensorflowSavedModelArtifact', 'KerasModelArtifact']
                   for i in artifact_types) and (py_major, py_minor) != ('3',
                                                                         '6'):
                raise BentoMLException(
                    'For Tensorflow and Keras model, only python3.6 is '
                    'supported for AWS Lambda deployment')

            api_names = ([lambda_deployment_config.api_name]
                         if lambda_deployment_config.api_name else
                         [api.name for api in bento_service_metadata.apis])

            raise_if_api_names_not_found_in_bento_service_metadata(
                bento_service_metadata, api_names)

            create_s3_bucket_if_not_exists(lambda_s3_bucket,
                                           lambda_deployment_config.region)
            deployment_path_prefix = os.path.join(deployment_pb.namespace,
                                                  deployment_pb.name)
            with TempDirectory() as lambda_project_dir:
                logger.debug(
                    'Generating cloudformation template.yaml for lambda project at %s',
                    lambda_project_dir,
                )
                template_file_path = _create_aws_lambda_cloudformation_template_file(
                    project_dir=lambda_project_dir,
                    namespace=deployment_pb.namespace,
                    deployment_name=deployment_pb.name,
                    deployment_path_prefix=deployment_path_prefix,
                    api_names=api_names,
                    bento_service_name=deployment_spec.bento_name,
                    s3_bucket_name=lambda_s3_bucket,
                    py_runtime=python_runtime,
                    memory_size=lambda_deployment_config.memory_size,
                    timeout=lambda_deployment_config.timeout,
                )
                logger.debug('Validating generated template.yaml')
                validate_lambda_template(
                    template_file_path,
                    lambda_deployment_config.region,
                    lambda_project_dir,
                )
                logger.debug(
                    'Initializing lambda project in directory: %s ...',
                    lambda_project_dir,
                )
                init_sam_project(
                    lambda_project_dir,
                    bento_path,
                    deployment_pb.name,
                    deployment_spec.bento_name,
                    api_names,
                    aws_region=lambda_deployment_config.region,
                )
                for api_name in api_names:
                    build_directory = os.path.join(lambda_project_dir,
                                                   '.aws-sam', 'build',
                                                   api_name)
                    logger.debug(
                        'Checking is function "%s" bundle under lambda size '
                        'limit',
                        api_name,
                    )
                    # Since we only use s3 get object in lambda function, and
                    # lambda function pack their own boto3/botocore modules,
                    # we will just delete those modules from function bundle
                    # directory
                    delete_list = ['boto3', 'botocore']
                    for name in delete_list:
                        logger.debug('Remove module "%s" from build directory',
                                     name)
                        shutil.rmtree(os.path.join(build_directory, name))
                    total_build_dir_size = total_file_or_directory_size(
                        build_directory)
                    if total_build_dir_size > LAMBDA_FUNCTION_MAX_LIMIT:
                        raise BentoMLException(
                            'Build function size is over 700MB, max size '
                            'capable for AWS Lambda function')
                    if total_build_dir_size >= LAMBDA_FUNCTION_LIMIT:
                        logger.debug(
                            'Function %s is over lambda size limit, attempting '
                            'reduce it',
                            api_name,
                        )
                        reduce_bundle_size_and_upload_extra_resources_to_s3(
                            build_directory=build_directory,
                            region=lambda_deployment_config.region,
                            s3_bucket=lambda_s3_bucket,
                            deployment_prefix=deployment_path_prefix,
                            function_name=api_name,
                            lambda_project_dir=lambda_project_dir,
                        )
                    else:
                        logger.debug(
                            'Function bundle is within Lambda limit, removing '
                            'download_extra_resources.py file from function bundle'
                        )
                        os.remove(
                            os.path.join(build_directory,
                                         'download_extra_resources.py'))
                logger.info('Packaging AWS Lambda project at %s ...',
                            lambda_project_dir)
                lambda_package(
                    lambda_project_dir,
                    lambda_deployment_config.region,
                    lambda_s3_bucket,
                    deployment_path_prefix,
                )
                logger.info('Deploying lambda project')
                stack_name = generate_aws_compatible_string(
                    deployment_pb.namespace + '-' + deployment_pb.name)
                lambda_deploy(
                    lambda_project_dir,
                    lambda_deployment_config.region,
                    stack_name=stack_name,
                )

            deployment_pb.state.state = DeploymentState.PENDING
            return ApplyDeploymentResponse(status=Status.OK(),
                                           deployment=deployment_pb)
        except BentoMLException as error:
            if lambda_s3_bucket and lambda_deployment_config:
                _cleanup_s3_bucket_if_exist(lambda_s3_bucket,
                                            lambda_deployment_config.region)
            raise error
Пример #4
0
def temporary_s3_bucket():
    random_hash = uuid.uuid4().hex[:6]
    bucket_name = f'e2e-yatai-server-{random_hash}'
    create_s3_bucket_if_not_exists(bucket_name, 'us-west-2')
    yield f's3://{bucket_name}/repo'
    _cleanup_s3_bucket_if_exist(bucket_name, 'us-west-2')