从Python脚本中运行AWS SAM构建

时间:2019-04-18 07:07:18

标签: aws-sam-cli

我正在将整个CloudFormation堆栈迁移到Troposphere,包括Lambda和依赖Lambda的CFN自定义资源。

我的目标之一是完全避免创建模板文件,使Python代码成为唯一的“真理来源”(即,没有创建因此可以进行编辑的模板文件,从而导致配置漂移)。

这需要具备以下能力:

  1. 将类似文件的对象传递给SAM构建器(而不是文件名)

  2. 从Python而不是CLI调用AWS SAM构建器

我的第一个天真想法是,我将能够从aws-sam-cli导入一些模块,并在其周围放置io.StringIO的包装器(将模板保存为类似文件的对象)并保存!然后,我查看了sam build的源代码,所有人都希望我离开:

  • 我可能无法使用Docker /容器进行构建,因为它会映射包括模板文件在内的构建环境。

  • AWS SAM CLI并非设计为具有一组纯粹可调用的库函数,类似于boto3。关闭,但不太完全。

这是Python源代码的核心

with BuildContext(template,
                  base_dir,
                  build_dir,
                  clean=clean,
                  manifest_path=manifest_path,
                  use_container=use_container,
                  parameter_overrides=parameter_overrides,
                  docker_network=docker_network,
                  skip_pull_image=skip_pull_image,
                  mode=mode) as ctx:

    builder = ApplicationBuilder(ctx.function_provider,
                                 ctx.build_dir,
                                 ctx.base_dir,
                                 manifest_path_override=ctx.manifest_path_override,
                                 container_manager=ctx.container_manager,
                                 mode=ctx.mode
                                 )
    try:
        artifacts = builder.build()
        modified_template = builder.update_template(ctx.template_dict,
                                                    ctx.original_template_path,
                                                    artifacts)

        move_template(ctx.original_template_path,
                      ctx.output_template_path,
                      modified_template)

        click.secho("\nBuild Succeeded", fg="green")

        msg = gen_success_msg(os.path.relpath(ctx.build_dir),
                              os.path.relpath(ctx.output_template_path),
                              os.path.abspath(ctx.build_dir) == os.path.abspath(DEFAULT_BUILD_DIR))

        click.secho(msg, fg="yellow")

这依赖于aws-sam-cli内部库的大量导入,其中以构建为重点的导入

from samcli.commands.build.build_context import BuildContext
from samcli.lib.build.app_builder import ApplicationBuilder, BuildError, UnsupportedBuilderLibraryVersionError, ContainerBuildNotSupported
from samcli.lib.build.workflow_config import UnsupportedRuntimeException

很明显,这意味着它不像创建一个boto3客户端之类的东西那么简单!看起来我更像是不得不把整个东西分叉,并把构建命令,上下文和环境中剩下的几乎所有东西都扔掉了。

有趣的是,根据文档,sam packagesam deploy仅仅是aws cloudformation packageaws cloudformation deploy的别名,这意味着可以在boto3中使用!

有人可能已经解决了这个问题吗?我已经在这里搜索和搜索过,但没有找到任何内容。

我使用PyCharmAWS Toolkit,如果它们非常适合开发和调试,并且从那里 可以运行SAM构建,但是在PyCharm插件中“隐藏”了-用科特林写的!

我目前的解决方法是将CFN模板创建为临时文件,并将其传递给从Python调用的CLI命令,这是我一直不喜欢的方法。

我可能会向aws-sam-cli团队提出功能请求,然后看看他们怎么说,除非其中一个人读懂了。

2 个答案:

答案 0 :(得分:1)

我已经设法从python3脚本启动sam local start-api

首先,pip3 install aws-sam-cli

然后可以导入并运行单个命令。

import sys
from samcli.commands.local.start_api.cli import cli
sys.exit(cli())

...,前提是当前目录中有一个template.yaml。

我还没有做的是影响cli()会收到的命令行参数,因此我可以告诉它使用哪个-t template

编辑

看看aws-sam-cli集成测试的工作方式,看来它们实际上启动了运行CLI的过程。因此,它们实际上根本不会将参数传递给cli()调用:-(

例如:

class TestSamPython36HelloWorldIntegration(InvokeIntegBase):
    template = Path("template.yml")

    def test_invoke_returncode_is_zero(self):
        command_list = self.get_command_list(
            "HelloWorldServerlessFunction", template_path=self.template_path, event_path=self.event_path
        )

        process = Popen(command_list, stdout=PIPE)
        return_code = process.wait()

        self.assertEquals(return_code, 0)

   .... etc

来自https://github.com/awslabs/aws-sam-cli/blob/a83aa9e620ff679ca740496a3f1ff4872b88894a/tests/integration/local/invoke/test_integrations_cli.py

另请参见同一仓库中的start_api_integ_base.py

我认为总体上这是可以预期的,因为整个事情都是根据click命令行应用程序框架实现的。不幸。

请参见http://click.palletsprojects.com/en/7.x/testing/,其中说:“ CliRunner.invoke()方法独立运行命令行脚本 ...” –我的重点。

答案 1 :(得分:0)

我正在使用以下python脚本运行sam cli命令。这也应该为您工作。

import json
import sys
import os

try:
    LAMBDA_S3_BUCKET="s3-bucket-name-in-same-region"
    AWS_REGION="us-east-1"      
    API_NAME = "YourAPIName"
    BASE_PATH="/path/to/your/project/code/dir"
    STACK_NAME="YourCloudFormationStackName"
    BUILD_DIR="%s/%s" % (BASE_PATH, "build_artifact")

    if not os.path.exists(BUILD_DIR):
        os.mkdir(BUILD_DIR)

    os.system("cd %s && sam build --template template.yaml --build-dir %s" % (BASE_PATH, BUILD_DIR))
    os.system("cd %s && sam package --template-file %s/template.yaml --output-template-file packaged.yaml --s3-bucket %s" %(BASE_PATH, BUILD_DIR,  LAMBDA_S3_BUCKET))
    os.system("cd %s && sam deploy  --template-file packaged.yaml --stack-name %s --capabilities CAPABILITY_IAM --region %s" %(BASE_PATH, STACK_NAME, AWS_REGION))  

except Exception as e:
    print(e.message)
    exit(1)