【问题标题】:Running AWS SAM build from within Python script从 Python 脚本中运行 AWS SAM 构建
【发布时间】:2019-04-18 07:07:18
【问题描述】:

我正在将整个 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 团队提出功能请求,看看他们说什么,除非其中有人读到此内容。

【问题讨论】:

    标签: aws-sam-cli


    【解决方案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 在同一个 repo 中。

    我认为总的来说这是可以预料的,因为整个事情是根据click 命令行应用程序框架实现的。很遗憾。

    参见 http://click.palletsprojects.com/en/7.x/testing/ 示例,它说“CliRunner.invoke() 方法单独运行命令行脚本 ...”——我的重点。

    【讨论】:

    • 哇!你花了多长时间才找到这条路? :D 这正是我正在寻找的。如果您设法找出如何通过模板,它会打勾。 ;) 我会看看我是否可以自己尝试一下,然后在 IDE/调试器中单步执行,也许可以找出参数的存储位置。
    • 我查看了 GitHub 上的 aws-sam-cli 源代码并解决了它......可能是单元测试解释了如何设置命令行参数,还没有看那么远。 github.com/awslabs/aws-sam-cli
    【解决方案2】:

    我正在使用以下 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)
    

    【讨论】:

    • 是的,我目前的解决方法是使用os.system() 调用,以及返回值的评估等等。这不是一个理想的情况。
    猜你喜欢
    • 2022-06-10
    • 1970-01-01
    • 2020-02-22
    • 2020-10-28
    • 1970-01-01
    • 1970-01-01
    • 2021-10-11
    • 2016-09-29
    • 2019-09-20
    相关资源
    最近更新 更多