Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aws-codepipeline-actions: EcrSourceAction should trigger for all tags when imageTag is empty string #20594

Closed
ahammond opened this issue Jun 2, 2022 · 10 comments · Fixed by #20897
Assignees
Labels
@aws-cdk/aws-codepipeline-actions bug This issue is a bug. documentation This is a problem with documentation. effort/small Small work item – less than a day of effort p1

Comments

@ahammond
Copy link
Contributor

ahammond commented Jun 2, 2022

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

@ahammond ahammond added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Jun 2, 2022
@peterwoodworth
Copy link
Contributor

Our docs might be incorrect - the CodePipeline API states that no tag will default to latest

https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference-ECR.html#action-reference-ECR-config

@peterwoodworth peterwoodworth added p1 documentation This is a problem with documentation. and removed needs-triage This issue or PR still needs to be triaged. labels Jun 3, 2022
@peterwoodworth peterwoodworth added the effort/small Small work item – less than a day of effort label Jun 3, 2022
@ahammond
Copy link
Contributor Author

ahammond commented Jun 3, 2022

I believe this is (mostly) a doc fix on the aws-cdk side. It does however demonstrate that the CodePipeline EcrSourceAction is totally unusable with the ECR ImmutableTags feature.

@peterwoodworth
Copy link
Contributor

Check out this PR #17270. It explains what the expected functionality is

@peterwoodworth
Copy link
Contributor

@sparten11740 could you help us out with this?

@TheRealAmazonKendra
Copy link
Contributor

So, I've been looking into this issue and I think that it isn't actually a documentation issue. We do intend to allow you to trigger on all tags when you provide an empty string, so if that isn't working, it is a bug. One question, though. You mentioned that when you provide the empty string, it's just absent in the template. Did you deploy the pipeline itself and find that it wasn't triggering on all tags or is this issue submitted as a result of what the template is showing?

Doing something directly in the console isn't always analogous to doing it in code. There is typically default functionality built into the console. In this case, the imageTag: 'latest' is added via console but should not be if it's not in the code.

We don't have any changes that should have stopped this from working on our end, and it was working on our end, so I'm trying to track down if/where something may have changed to make this no longer work. Can you confirm that you deployed the cdk app and that the pipeline was only triggering on latest or was this issue opened because the generated template is not what you expected?

@ahammond
Copy link
Contributor Author

@TheRealAmazonKendra I deployed the stack. The pipeline didn't work as expected. I dug into it in an AWS Support ticket. We discovered that it was filtering on latest. I tried the hacks I mentioned above to get it to work as documented. They didn't work either.

@ahammond
Copy link
Contributor Author

@TheRealAmazonKendra I... really wish I was the kind of guy who is diligent and thorough enough to read the templates, but... I never do unless I'm trying to debug something. :)

@rix0rrr
Copy link
Contributor

rix0rrr commented Jun 28, 2022

The docs for CodePipeline seem to indicate that triggering on all tags is not an option. If the tag is omitted (which we currently do) then it defaults to latest.

image

https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference-ECR.html#action-reference-ECR-config

@rix0rrr
Copy link
Contributor

rix0rrr commented Jun 28, 2022

Had a look at the ECR Source Action source code and I'm pretty sure triggering on all tags is not a feature.

Now trying to understand what the original contributor in #17270 thought he was changing, because it looks to not be exactly what was advertised.

rix0rrr added a commit that referenced this issue Jun 28, 2022
The current ECR source action docs seem to indicate you can make it
trigger on more than one tag at a time (or even all tags). This is
not true, so stop advertising that feature.

Fixes #20594.
@mergify mergify bot closed this as completed in #20897 Jun 30, 2022
mergify bot pushed a commit that referenced this issue Jun 30, 2022
The current ECR source action docs seem to indicate you can make it
trigger on more than one tag at a time (or even all tags). This is
not true, so stop advertising that feature.

Fixes #20594.

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
@github-actions
Copy link

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

daschaa pushed a commit to daschaa/aws-cdk that referenced this issue Jul 9, 2022
The current ECR source action docs seem to indicate you can make it
trigger on more than one tag at a time (or even all tags). This is
not true, so stop advertising that feature.

Fixes aws#20594.

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-codepipeline-actions bug This issue is a bug. documentation This is a problem with documentation. effort/small Small work item – less than a day of effort p1
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants