我正在将整个CloudFormation堆栈迁移到Troposphere,包括Lambda和依赖Lambda的CFN自定义资源。
我的目标之一是完全避免创建模板文件,使Python代码成为唯一的“真理来源”(即,没有创建因此可以进行编辑的模板文件,从而导致配置漂移)。
这需要具备以下能力:
将类似文件的对象传递给SAM构建器(而不是文件名)
从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 package
和sam deploy
仅仅是aws cloudformation package
和aws cloudformation deploy
的别名,这意味着可以在boto3中使用!
有人可能已经解决了这个问题吗?我已经在这里搜索和搜索过,但没有找到任何内容。
我使用PyCharm和AWS Toolkit,如果它们非常适合开发和调试,并且从那里 可以运行SAM构建,但是在PyCharm插件中“隐藏”了-用科特林写的!
我目前的解决方法是将CFN模板创建为临时文件,并将其传递给从Python调用的CLI命令,这是我一直不喜欢的方法。
我可能会向aws-sam-cli团队提出功能请求,然后看看他们怎么说,除非其中一个人读懂了。
答案 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
另请参见同一仓库中的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)