i want to run a CloudFormation template with CodePipeline. This template is expecting an input parameter which needs to contain the current Date/Time. Unfortunately CloudFormation isn't able to generate the current DateTime by itself out-of-the-box.
My approach was first to run a simple Lambda function to create the current timestamp and save it as OutputArtifacts
. The subsequently CloudFormation task imports this artifact as InputArtifacts
and gets the value from the DateTime attribut and passes it to CloudFormation via ParameterOverrides
instruction.
Unfortunately CodePipeline keeps saying the DateTimeInput
parameter is invalid (obviously GetArtifactAtt lookup failed).
I assume the lambda output (python: print) doesn't get saved as artifact properly?
Do you know how to pass the lambda output correctly or do you have an idea how to achieve this on a better way?
All pipeline components are defined with CloudFormation as YAML. Here are the relevant parts:
Lambda Function:
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
here are the pipeline tasks:
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" ] }
}
Update: I was to naive and thought there would be a simple way. Now I know it is a more advanced and manual task just to deliver a simple output artifact with lambda.
Inside the python code one must evaluate the passed event
dictionary (CodePipeline.job
) to lookup:
- the predefined OutputArtifacts (S3 Bucket/Key) and
- temporary S3 session credentials provided by CodePipeline.
Then a S3 client must be initialized by these credentials. S3 put_object
needs to run afterwards.
https://docs.aws.amazon.com/codepipeline/latest/userguide/actions-invoke-lambda-function.html https://forums.aws.amazon.com/thread.jspa?threadID=232174
So my question is again: Do you guys have an idea how to achieve this on a better or more simple way?
I merely want to put the current date and time as input parameter for CloudFormation and don't want to break automation.