由于@fedonev 已经回答了这个问题,我将专注于使用 CodePipeline(特别是 Python 中的 CDK 管道)的潜在实现,因为我已经在研究它了。我限制自己不使用任何实验性或预览版。
示例代码:https://github.com/KMK-Git/aws-cdk-sam-testing-demo
流程
阶段
来源
source = pipelines.CodePipelineSource.connection(
"KMK-Git/aws-cdk-sam-testing-demo",
"main",
connection_arn=ssm.StringParameter.value_for_string_parameter(
self,
"codestar_connection_arn",
),
)
源代码存储库是使用 CodeStar 连接配置的。连接是事先手动完成的,我从 SSM 参数存储中获取 ARN。
构建、SelfMutate 和 UploadAssets
cdk_codepipeline = pipelines.CodePipeline(
self,
"Pipeline",
synth=pipelines.ShellStep(
"Synth",
input=source,
install_commands=[
"pip install -r requirements.txt",
"npm install -g aws-cdk",
],
commands=[
"cdk synth",
],
),
)
- Synth 阶段用于将 CDK 代码合成到 CloudFormation 模板中。
- SelfMutate 阶段是一项 CDK 功能,用于更新管道本身内部的管道。即使在初始部署之后,您也可以对管道进行更改。
- Assets 阶段使用 cdk-assets 命令将所有 cdk 资产上传到其目的地。由于我已将堆栈分为两个单独的阶段,因此每个阶段都有自己的资产上传步骤。
如果您不使用 CDK 管道,这里是所有阶段的构建规范:
合成器:
{
"version": "0.2",
"phases": {
"install": {
"commands": [
"pip install -r requirements.txt",
"npm install -g aws-cdk"
]
},
"build": {
"commands": [
"cdk synth"
]
}
},
"artifacts": {
"base-directory": "cdk.out",
"files": "**/*"
}
}
对于自我变异:
{
"version": "0.2",
"phases": {
"install": {
"commands": [
"npm install -g aws-cdk"
]
},
"build": {
"commands": [
"cdk -a . deploy PipelineStack --require-approval=never --verbose"
]
}
}
}
对于资产:
{
"version": "0.2",
"phases": {
"install": {
"commands": [
"npm install -g cdk-assets"
]
},
"build": {
"commands": [
"cdk-assets --path \"assembly-LambdaStage/LambdaStageLambdasStackABCD123.assets.json\" --verbose publish \"longrandomstring:current_account-current_region\""
]
}
}
}
单元测试
testing = pipelines.CodeBuildStep(
"UnitTesting",
input=source,
install_commands=[
"pip install -r requirements.txt -r requirements-dev.txt",
],
commands=[
"pytest --cov",
],
env={
"QUEUE_URL": "SampleQueue",
"TABLE_NAME": "SampleTest",
},
build_environment=codebuild.BuildEnvironment(
build_image=codebuild.LinuxBuildImage.STANDARD_5_0,
privileged=True,
compute_type=codebuild.ComputeType.SMALL,
),
)
这是一个简单的步骤,它会在您的代码中运行任何单元测试。
如果您不使用 CDK 管道,这里是构建规范:
{
"version": "0.2",
"phases": {
"install": {
"commands": [
"pip install -r requirements.txt -r requirements-dev.txt"
]
},
"build": {
"commands": [
"pytest --cov"
]
}
}
}
部署支持资源
cdk_codepipeline.add_stage(
supporting_resources_stage,
pre=[
testing,
pipelines.ConfirmPermissionsBroadening(
"CheckSupporting", stage=supporting_resources_stage
),
],
)
这将部署支持资源,这是您的sam local 测试正常运行所必需的。如果 IAM 权限有任何扩展,权限扩展步骤会停止管道并强制手动批准。您也可以在单独的阶段添加单元测试。
如果您不使用 CDK 管道,这里是构建规范:
{
"version": 0.2,
"phases": {
"build": {
"commands": [
"npm install -g aws-cdk",
"export PIPELINE_NAME=\"$(node -pe '`${process.env.CODEBUILD_INITIATOR}`.split(\"/\")[1]')\"",
"payload=\"$(node -pe 'JSON.stringify({ \"PipelineName\": process.env.PIPELINE_NAME, \"StageName\": process.env.STAGE_NAME, \"ActionName\": process.env.ACTION_NAME })' )\"",
"ARN=$CODEBUILD_BUILD_ARN",
"REGION=\"$(node -pe '`${process.env.ARN}`.split(\":\")[3]')\"",
"ACCOUNT_ID=\"$(node -pe '`${process.env.ARN}`.split(\":\")[4]')\"",
"PROJECT_NAME=\"$(node -pe '`${process.env.ARN}`.split(\":\")[5].split(\"/\")[1]')\"",
"PROJECT_ID=\"$(node -pe '`${process.env.ARN}`.split(\":\")[6]')\"",
"export LINK=\"https://$REGION.console.aws.amazon.com/codesuite/codebuild/$ACCOUNT_ID/projects/$PROJECT_NAME/build/$PROJECT_NAME:$PROJECT_ID/?region=$REGION\"",
"export PIPELINE_LINK=\"https://$REGION.console.aws.amazon.com/codesuite/codepipeline/pipelines/$PIPELINE_NAME/view?region=$REGION\"",
"if cdk diff -a . --security-only --fail $STAGE_PATH/\\*; then aws lambda invoke --function-name PipelineStack-PipelinePipelinesSecurityCheckCDKalpha-numeric --invocation-type Event --payload \"$payload\" lambda.out; export MESSAGE=\"No security-impacting changes detected.\"; else [ -z \"${NOTIFICATION_ARN}\" ] || aws sns publish --topic-arn $NOTIFICATION_ARN --subject \"$NOTIFICATION_SUBJECT\" --message \"An upcoming change would broaden security changes in $PIPELINE_NAME.\nReview and approve the changes in CodePipeline to proceed with the deployment.\n\nReview the changes in CodeBuild:\n\n$LINK\n\nApprove the changes in CodePipeline (stage $STAGE_NAME, action $ACTION_NAME):\n\n$PIPELINE_LINK\"; export MESSAGE=\"Deployment would make security-impacting changes. Click the link below to inspect them, then click Approve if all changes are expected.\"; fi"
]
}
},
"env": {
"exported-variables": [
"LINK",
"MESSAGE"
]
}
}
sam 本地测试
sam_cli_test_step = pipelines.CodeBuildStep(
"SAMTesting",
input=source,
env_from_cfn_outputs={
"QUEUE_URL": supporting_resources_stage.stack.queue_url,
"TABLE_NAME": supporting_resources_stage.stack.table_name,
},
install_commands=[
"pip install -r requirements.txt",
"npm install -g aws-cdk",
"mkdir testoutput",
],
commands=[
'cdk synth -a "python synth_lambdas_stack.py" -o sam.out',
'echo "{\\""SqsLambdaFunction\\"": {\\""QUEUE_URL\\"": \\""$QUEUE_URL\\""},'
+ '\\""DynamodbLambdaFunction\\"": {\\""TABLE_NAME\\"": \\""$TABLE_NAME\\"" }}"'
+ " > locals.json",
'sam local invoke -t "sam.out/LambdasStack.template.json" --env-vars locals.json'
+ ' --no-event "DynamodbLambdaFunction"',
'sam local invoke -t "sam.out/LambdasStack.template.json" --env-vars locals.json'
+ ' --no-event "SqsLambdaFunction"',
"nohup sam local start-api -t sam.out/LambdasStack.template.json"
+ " --env-vars locals.json > testoutput/testing.log & ",
"",
"sleep 30",
"curl --fail http://127.0.0.1:3000/sqs",
"curl --fail http://127.0.0.1:3000/dynamodb",
],
build_environment=codebuild.BuildEnvironment(
build_image=codebuild.LinuxBuildImage.STANDARD_5_0,
privileged=True,
compute_type=codebuild.ComputeType.SMALL,
),
primary_output_directory="testoutput/",
role_policy_statements=[
iam.PolicyStatement(
actions=[
"sqs:SendMessage",
"sqs:GetQueueAttributes",
"sqs:GetQueueUrl",
],
resources=["*"],
),
iam.PolicyStatement(
actions=[
"dynamodb:BatchWriteItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:DeleteItem",
],
resources=["*"],
),
],
)
- 在您的支持资源堆栈中,您需要定义 Lambda 代码作为堆栈输出所需的任何参数,例如资源名称和 ARN。我已使用环境变量将这些值提供给我的 Lambda 函数。
- 在我的堆栈代码中,我指定了 CloudFormation Lambda 函数资源的逻辑 ID,而不是依赖于 CDK 自动生成的值。
sqs_lambda_base: _lambda.CfnFunction = sqs_lambda.node.default_child
sqs_lambda_base.override_logical_id("SqsLambdaFunction")
- 我创建了一个单独的应用程序文件,它只合成我的 Lambda 堆栈,而不是完整的管道堆栈。从理论上讲,您应该能够使用完整堆栈的合成器输出,但这更易于配置。
- 我添加了我的 Lambda 所需的权限,以便与我的支持资源堆栈创建的资源进行交互。
-
sam-beta-cdk 可用于简化此工作流程,但我没有在这里使用它,因为它仍处于预览阶段。
如果您不使用 CDK 管道,这里是构建规范:
{
"version": "0.2",
"phases": {
"install": {
"commands": [
"pip install -r requirements.txt",
"npm install -g aws-cdk",
"curl --version",
"mkdir testoutput"
]
},
"build": {
"commands": [
"cdk synth -a \"python synth_lambdas_stack.py\" -o sam.out",
"echo \"{\\\"\"SqsLambdaFunction\\\"\": {\\\"\"QUEUE_URL\\\"\": \\\"\"$QUEUE_URL\\\"\"},\\\"\"DynamodbLambdaFunction\\\"\": {\\\"\"TABLE_NAME\\\"\": \\\"\"$TABLE_NAME\\\"\" }}\" > locals.json",
"sam local invoke -t \"sam.out/LambdasStack.template.json\" --env-vars locals.json --no-event \"DynamodbLambdaFunction\"",
"sam local invoke -t \"sam.out/LambdasStack.template.json\" --env-vars locals.json --no-event \"SqsLambdaFunction\"",
"nohup sam local start-api -t sam.out/LambdasStack.template.json --env-vars locals.json > testoutput/testing.log & ",
"",
"sleep 30",
"curl --fail http://127.0.0.1:3000/sqs",
"curl --fail http://127.0.0.1:3000/dynamodb"
]
}
},
"artifacts": {
"base-directory": "testoutput/",
"files": "**/*"
}
}
部署 Lambda 函数
cdk_codepipeline.add_stage(
lambdas_stage,
pre=[
sam_cli_test_step,
pipelines.ConfirmPermissionsBroadening(
"CheckLambda", stage=lambdas_stage
),
],
)
这类似于部署支持资源阶段。您也可以在其自己的单独阶段添加 sam 本地测试。
注意事项:
- 如果您不想先部署,DynamoDB 特别支持local testing。
- 虽然我的管道仅部署一组资源,但您可以创建不同的阶段以部署到不同的环境/帐户。
- 此处定义的 sam 本地测试步骤非常简单。您可以使用 API 测试工具等功能来运行一整套测试用例。 Here 是一个官方的 AWS 示例,它使用 selenium 来测试 Web 服务器,API 在 sam local 上运行。
限制
- API 网关授权方是 not supported 用于
sam local 测试,因此如果您打算使用 Cognito 授权方,您将无法测试它们。