运行 AWS SAM 从 Python 脚本中构建
Running AWS SAM build from within Python script
我正在将整个 CloudFormation 堆栈迁移到 Troposphere,包括 Lambda 和依赖 Lambda 的 CFN 自定义资源。
我的目标之一是完全避免模板文件的创建,使 Python 代码成为唯一的 "source of truth"(即没有创建模板文件,因此可以编辑,导致配置漂移)。
这需要能够:
将类似文件的对象传递给 SAM 生成器(而不是文件名)
从 Python 而不是 CLI
调用 AWS SAM 构建器
我第一个幼稚的想法是,我可以从 aws-sam-cli
导入一些模块,并在其周围放置 io.StringIO
的包装器(将模板保存为类似文件的对象),然后 presto !然后我查看了 sam build
的源代码,所有的希望都离开了我:
我可能无法使用 Docker/containers 进行构建,因为我会映射构建环境,包括模板文件。
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 package
和 sam deploy
仅仅是 aws cloudformation package
和 aws cloudformation deploy
的别名,这意味着 可以 用于boto3!
有人可能已经解决了这个问题吗?我在这里用谷歌搜索,但没有找到任何东西。
我使用 PyCharm and the AWS Toolkit 如果它非常适合开发和调试,我可以从那里 运行 SAM 构建,但它是 "hidden" PyCharm 插件 - 用 Kotlin 编写!
我目前的解决方法是将 CFN 模板创建为临时文件,并将它们传递给从 Python 调用的 CLI 命令 - 我一直不喜欢的方法。
我可能会向 aws-sam-cli 团队提出功能请求,看看他们怎么说,除非他们中有人读到了这篇文章。
我正在使用以下 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)
我已成功从 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
另请参阅同一存储库中的 start_api_integ_base.py
。
我认为总的来说这是可以预料的,因为整个事情都是根据 click
命令行应用程序框架实现的。很遗憾。
例如 http://click.palletsprojects.com/en/7.x/testing/ 上面写着 "The CliRunner.invoke() method runs the command line script in isolation ..." -- 我的重点。
我正在将整个 CloudFormation 堆栈迁移到 Troposphere,包括 Lambda 和依赖 Lambda 的 CFN 自定义资源。
我的目标之一是完全避免模板文件的创建,使 Python 代码成为唯一的 "source of truth"(即没有创建模板文件,因此可以编辑,导致配置漂移)。
这需要能够:
将类似文件的对象传递给 SAM 生成器(而不是文件名)
从 Python 而不是 CLI
调用 AWS SAM 构建器
我第一个幼稚的想法是,我可以从 aws-sam-cli
导入一些模块,并在其周围放置 io.StringIO
的包装器(将模板保存为类似文件的对象),然后 presto !然后我查看了 sam build
的源代码,所有的希望都离开了我:
我可能无法使用 Docker/containers 进行构建,因为我会映射构建环境,包括模板文件。
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 package
和 sam deploy
仅仅是 aws cloudformation package
和 aws cloudformation deploy
的别名,这意味着 可以 用于boto3!
有人可能已经解决了这个问题吗?我在这里用谷歌搜索,但没有找到任何东西。
我使用 PyCharm and the AWS Toolkit 如果它非常适合开发和调试,我可以从那里 运行 SAM 构建,但它是 "hidden" PyCharm 插件 - 用 Kotlin 编写!
我目前的解决方法是将 CFN 模板创建为临时文件,并将它们传递给从 Python 调用的 CLI 命令 - 我一直不喜欢的方法。
我可能会向 aws-sam-cli 团队提出功能请求,看看他们怎么说,除非他们中有人读到了这篇文章。
我正在使用以下 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)
我已成功从 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
另请参阅同一存储库中的 start_api_integ_base.py
。
我认为总的来说这是可以预料的,因为整个事情都是根据 click
命令行应用程序框架实现的。很遗憾。
例如 http://click.palletsprojects.com/en/7.x/testing/ 上面写着 "The CliRunner.invoke() method runs the command line script in isolation ..." -- 我的重点。