-
Notifications
You must be signed in to change notification settings - Fork 4.5k
aws-codepipeline-actions: EcrSourceAction should trigger for all tags when imageTag is empty string #20594
Description
Describe the bug
Per aws-cdk documentation, https://github.com/aws/aws-cdk/blob/main/packages/%40aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts#L39 I should be able to provide an empty string to the EcrSourceAction to have it trigger on any push to any tag.
new aws_codepipeline_actions.EcrSourceAction({
actionName: 'Image',
imageTag: '', // this doesn't work as documented. Instead it is just omitted.
repository,
output: imageInput,
}),
However, when I write that, CDK omits the ImageTag from the rendered CloudFormation. When I force the issue with
const pCfn = p.node.defaultChild as aws_codepipeline.CfnPipeline;
// However, when we set this to an empty string, Cfn refuses to deploy because the value can't be an empty string.
pCfn.addPropertyOverride('Stages.0.Actions.0.Configuration.ImageTag', '');
CloudFormation refuses to actually deploy with
1 validation error detected: Value at 'pipeline.stages.1.member.actions.1.member.configuration' failed to satisfy constraint:
Map value must satisfy constraint: [Member must have length less than or equal to 50000, Member must have length greater than or equal to 1]
(Service: AWSCodePipeline; Status Code: 400; Error Code: ValidationException; Request ID: 2ac8177d-d157-4d78-8632-48960d278613; Proxy: null)
When I went into the console and attempted to produce the desired behaviour (CodePipeline triggers on ECR pushes to any docker tag), it instead defaulted to latest. It does not appear to be possible to configure it to trigger for pushed to any docker tag.
ECR has immutable tags as a feature. We'd like to leverage that to ensure that the tags we are deploying can be deterministically mapped back to the code the were built with.
Expected Behavior
It should do what it says.
Current Behavior
Silently defaults to latest.
Reproduction Steps
I've already wasted 2 days on this false trail. Here's what I was using.
export class CouplerPipelineStack extends core.Stack {
constructor(scope: Construct, id: Namer, props: CouplerPipelineStackProps) {
super(scope, id.addSuffix(['coupler']), props);
const imageInput = new aws_codepipeline.Artifact('Image');
const updateInput = new aws_codepipeline.Artifact('ImageDefinitions');
const repositoryName = id.addSuffix(['repository']).pascal;
const repository = aws_ecr.Repository.fromRepositoryAttributes(this, 'Repository', {
repositoryArn: core.Param.get(this, 'repositoryArn', {
rootId: name.pascal,
stackId: repositoryName,
constructId: name.pascal,
}),
repositoryName: id.kebab,
});
const cluster = aws_ecs.Cluster.fromClusterAttributes(this, 'Cluster', {
clusterName: id.kebab,
securityGroups: [],
vpc: this.vpc,
});
const service = aws_ecs.FargateService.fromFargateServiceAttributes(this, 'Service', {
cluster,
serviceName: id.pascal,
});
const p = new aws_codepipeline.Pipeline(this, id.pascal, {
pipelineName: id.pascal,
stages: [
{
stageName: 'Received',
actions: [
new aws_codepipeline_actions.EcrSourceAction({
actionName: 'Image',
imageTag: '', // this doesn't work as documented. Instead it is just omitted.
repository,
output: imageInput,
}),
],
},
{
stageName: 'GenerateImageDefinitions',
actions: [
new aws_codepipeline_actions.CodeBuildAction({
environmentVariables: {
ECR_REPO_URI: { value: `${this.account}.dkr.ecr.${this.region}.amazonaws.com/${id.pascal}` },
},
input: imageInput,
outputs: [updateInput],
actionName: 'GenerateImageDefinitions',
project: new aws_codebuild.Project(this, 'GenerateImageDefinitions', {
buildSpec: aws_codebuild.BuildSpec.fromObject({
version: '0.2',
phases: {
build: {
commands: [
'printenv',
//https://stackoverflow.com/a/57015190
`TAG=$(cat imageDetail.json | python -c "import sys, json; print(json.load(sys.stdin)['ImageTags'][0])")`,
'echo "${ECR_REPO_URI}:${TAG}"',
`printf '[{\"name\":\"${id.kebab}\",\"imageUri\":\"%s\"}]' $ECR_REPO_URI:$TAG > imagedefinitions.json`,
'pwd; ls -al; cat imagedefinitions.json',
],
},
},
artifacts: { files: ['imagedefinitions.json'] },
}),
}),
}),
],
},
{
stageName: 'UpdateFargate',
actions: [
new aws_codepipeline_actions.EcsDeployAction({
actionName: 'Deploy',
input: updateInput,
service,
}),
],
},
],
});
const pCfn = p.node.defaultChild as aws_codepipeline.CfnPipeline;
// However, when we set this to an empty string, Cfn refuses to deploy because the value can't be an empty string.
pCfn.addPropertyOverride('Stages.0.Actions.0.Configuration.ImageTag', '');
}
}
Possible Solution
Initially, you should probably just update the comment to reflect the unfortunate reality of CodePipeline sucking.
Additional Information/Context
No response
CDK CLI Version
2.26.0 (build a409d63)
Framework Version
No response
Node.js Version
v16.13.1
OS
Mac
Language
Typescript
Language Version
4.7.2
Other information
No response