AWS CodePipeline:将Lambda函数输出传递给CloudFormation

时间:2018-10-30 13:10:53

标签: lambda amazon-cloudformation aws-codepipeline artifact

我想使用CodePipeline运行CloudFormation模板。该模板需要一个输入参数,该参数需要包含当前的日期/时间。不幸的是,CloudFormation不能直接生成当前的DateTime。

我的方法是首先运行一个简单的Lambda函数来创建当前时间戳并将其保存为OutputArtifacts。随后的CloudFormation任务将此工件导入为InputArtifacts,并从DateTime属性获取值,并通过ParameterOverrides指令将其传递给CloudFormation。

不幸的是,CodePipeline一直说DateTimeInput参数无效(显然GetArtifactAtt查找失败)。 我认为lambda输出(python:print)没有正确保存为工件?

您知道如何正确传递lambda输出,还是有一个更好的方法来实现这一点?

所有管道组件都使用CloudFormation定义为YAML。以下是相关部分:

Lambda函数:

Resources:
  ...
  GetDateTimeFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.lambda_handler
      Runtime: python2.7
      Timeout: '10'
      Role: !GetAtt GetDateTimeFunctionExecutionRole.Arn
      Code:
        ZipFile: |
                import datetime
                import boto3
                import json

                code_pipeline = boto3.client('codepipeline')

                def lambda_handler(event, context):
                  now = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
                  responseData = {'DateTime':now}
                  print json.dumps(responseData)
                  response = code_pipeline.put_job_success_result(jobId=event['CodePipeline.job']['id'])
                  return response

以下是管道任务:

Resources:
...
  Pipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      ArtifactStore:
        Location: !Ref ArtifactStoreBucket
        Type: S3
      DisableInboundStageTransitions: []
      Name: !Ref PipelineName
      RoleArn: !GetAtt PipelineRole.Arn
      Stages:
        - Name: Deploy
          Actions:
            - Name: GetDateTime
              RunOrder: 1
              ActionTypeId:
                Category: Invoke
                Owner: AWS
                Provider: Lambda
                Version: '1'
              Configuration:
                 FunctionName: !Ref GetDateTimeFunction
              OutputArtifacts:
                - Name: GetDateTimeOutput
            - Name: CreateStack
              RunOrder: 2
              ActionTypeId:
                Category: Deploy
                Owner: AWS
                Provider: CloudFormation
                Version: '1'
              InputArtifacts:
                - Name: TemplateSource
                - Name: GetDateTimeOutput
              Configuration:
                ActionMode: REPLACE_ON_FAILURE
                Capabilities: CAPABILITY_IAM
                RoleArn: !GetAtt CloudFormationRole.Arn
                StackName: !Ref CFNStackname
                TemplatePath: !Sub TemplateSource::${CFNScriptfile}
                TemplateConfiguration: !Sub TemplateSource::${CFNConfigfile}
                ParameterOverrides: |
                  {
                    "DateTimeInput" : { "Fn::GetArtifactAtt" : [ "GetDateTimeOutput", "DateTime" ] }
                  }

更新:我很天真,认为会有一种简单的方法。 现在,我知道这是一个更高级的手动任务,只是提供带有lambda的简单输出工件。

在python代码内部,必须评估传递的event字典(CodePipeline.job)才能查找:
-预定义的OutputArtifacts(S3存储桶/密钥)和
-CodePipeline提供的临时S3会话凭据。
然后,必须使用这些凭据来初始化S3客户端。 S3 put_object之后需要运行。

https://docs.aws.amazon.com/codepipeline/latest/userguide/actions-invoke-lambda-function.html https://forums.aws.amazon.com/thread.jspa?threadID=232174

所以我的问题又是:你们是否有一个想法,如何以更好或更简单的方式实现这一目标?
我只想将当前日期和时间作为CloudFormation的输入参数,并且不想破坏自动化。

2 个答案:

答案 0 :(得分:2)

是的,我不知道需要自己亲自处理输出工件。

最后,这成功了:

import Data.List(sortBy)
import Data.Ord(comparing)

check :: (Ord n, Enum n) => [n] -> [[n]]
check = go . sortBy (comparing fromEnum)
    where go (x:na@(n:xs)) | succ x == n || x == n = (x:r) : rs
                           | otherwise = [x]: ra
              where ra@(~(r:rs)) = go na
          go [x] = [[x]]
          go [] = []

这项琐碎的任务的开销很大;-)

答案 1 :(得分:0)

您应使用“ Fn :: GetParam”而不是“ Fn :: GetArtifactAtt”。根据CloudFormation文档,“ Fn :: GetArtifactAtt”只能获取工件的属性,例如BucketName,ObjectKey和URL。 “ Fn :: GetParam”可以从工件中的json文件中获取值。因此,如果您可以将工件“ GetDateTimeOutput”生成为zip文件,其中包括具有以下内容的JSON文件(例如param.json)

{     “ DateTime”:“ 2018/10/31 13:32:00” }

然后您可以使用{“ Fn :: GetParam”:[“ GetDateTimeOutput”,“ param.json”,“ DateTime”]}来获取时间。

您可以修改Lambda函数来执行此操作,也可以使用CodeBuild操作。 CodeBuild负责创建zip,您只需指定构建命令即可在输出文件夹中创建JSON文件。您可以在以下文档中找到有关如何在CodePipeline中使用CodeBuild的更多信息。

CloudFormation文档 https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-parameter-override-functions.html#w2ab1c13c17b9

CodeBuild文档 https://docs.aws.amazon.com/codebuild/latest/userguide/how-to-create-pipeline.html