Skip to content

Commit

Permalink
fix(codepipeline-actions): ecr source action doesn't trigger the pipe…
Browse files Browse the repository at this point in the history
…line (#21580)

When the ECR source action was initially released, ECR did not yet
integrate with EventBridge so it was necessary to use CloudTrail.
Since then ECR was updated to integrate with EventBridge so relying on
CloudTrail is no longer necessary.

This PR changes the event rule that triggers the pipeline to use the
`ECR Image Action` instead of the CloudTrail event.

This change does lead to the `AWS::Events::Rule` resource being deleted
and recreated, but that should not cause any issues since there is no
state involved. I tested this by using the integ test and manually
validated that pushing an image to the ecr repo triggers the pipeline.
The steps are outlined in the `integ.pipeline-ecr-source.ts` file.

fix #10901


----

### All Submissions:

* [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md)

### Adding new Unconventional Dependencies:

* [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies)

### New Features

* [x] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)?
	* [x] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)?

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
corymhall authored Aug 12, 2022
1 parent 1187f8c commit f135b80
Show file tree
Hide file tree
Showing 10 changed files with 431 additions and 176 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as codepipeline from '@aws-cdk/aws-codepipeline';
import * as ecr from '@aws-cdk/aws-ecr';
import { Rule } from '@aws-cdk/aws-events';
import * as targets from '@aws-cdk/aws-events-targets';
import * as iam from '@aws-cdk/aws-iam';
import { Names } from '@aws-cdk/core';
Expand Down Expand Up @@ -85,16 +86,27 @@ export class EcrSourceAction extends Action {
};
}

protected bound(_scope: Construct, stage: codepipeline.IStage, options: codepipeline.ActionBindOptions):
protected bound(scope: Construct, stage: codepipeline.IStage, options: codepipeline.ActionBindOptions):
codepipeline.ActionConfig {
options.role.addToPolicy(new iam.PolicyStatement({
actions: ['ecr:DescribeImages'],
resources: [this.props.repository.repositoryArn],
}));

this.props.repository.onCloudTrailImagePushed(Names.nodeUniqueId(stage.pipeline.node) + 'SourceEventRule', {
target: new targets.CodePipeline(stage.pipeline),
imageTag: this.props.imageTag === '' ? undefined : (this.props.imageTag ?? 'latest'),
new Rule(scope, Names.nodeUniqueId(stage.pipeline.node) + 'SourceEventRule', {
targets: [
new targets.CodePipeline(stage.pipeline),
],
eventPattern: {
detailType: ['ECR Image Action'],
source: ['aws.ecr'],
detail: {
'result': ['SUCCESS'],
'repository-name': [this.props.repository.repositoryName],
'image-tag': [this.props.imageTag === '' ? undefined : (this.props.imageTag ?? 'latest')],
'action-type': ['PUSH'],
},
},
});

// the Action Role also needs to write to the Pipeline's bucket
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,10 @@ describe('ecr source action', () => {
Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', {
'EventPattern': {
'detail': {
'requestParameters': {
'imageTag': ['latest'],
},
'result': ['SUCCESS'],
'repository-name': ['repo'],
'image-tag': ['latest'],
'action-type': ['PUSH'],
},
},
});
Expand Down Expand Up @@ -110,9 +111,10 @@ describe('ecr source action', () => {
'aws.ecr',
],
'detail': {
'requestParameters': {
'imageTag': Match.absent(),
},
'result': ['SUCCESS'],
'repository-name': ['repo'],
'image-tag': [],
'action-type': ['PUSH'],
},
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,28 @@ import * as codepipeline from '@aws-cdk/aws-codepipeline';
import * as ecr from '@aws-cdk/aws-ecr';
import * as s3 from '@aws-cdk/aws-s3';
import * as cdk from '@aws-cdk/core';
import { IntegTest } from '@aws-cdk/integ-tests';
import * as cpactions from '../lib';

/**
* Manual validation steps
*
* Run test with `-vv` so that the outputs are printed and
* `--no-clean` flag so that the stack is not deleted after the deployment is complete
*
* You should see output like:
*
* Outputs:
* aws-cdk-codepipeline-ecr-source.PipelineConsoleLink = https://us-east-1.console.aws.amazon.com/codesuite/codepipeline/pipelines/aws-cdk-codepipeline-ecr-source-MyPipelineAED38ECF-1P0OYRLWF8FHY/view?region=us-east-1
* aws-cdk-codepipeline-ecr-source.LoginCommand = aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 11111111111.dkr.ecr.us-east-1.amazonaws.com
* aws-cdk-codepipeline-ecr-source.PushCommand = docker tag public.ecr.aws/lambda/provided 11111111111.dkr.ecr.us-east-1.amazonaws.com/aws-cdk-codepipeline-ecr-source-myecrrepo767466d0-gsrntpvfwc5w:latest \
* && docker push 11111111111.dkr.ecr.us-east-1.amazonaws.com/aws-cdk-codepipeline-ecr-source-myecrrepo767466d0-gsrntpvfwc5w:latest
*
* Run the LoginCommand & PushCommand to tag and push an image to the ECR repository.
* Then use the PipelineConsoleLink to navigate to the pipeline console page to validate that the pipeline
* was triggered successfully.
*/

const app = new cdk.App();

const stack = new cdk.Stack(app, 'aws-cdk-codepipeline-ecr-source');
Expand All @@ -28,4 +48,18 @@ sourceStage.addAction(new cpactions.EcrSourceAction({
const approveStage = pipeline.addStage({ stageName: 'Approve' });
approveStage.addAction(new cpactions.ManualApprovalAction({ actionName: 'ManualApproval' }));

app.synth();
new cdk.CfnOutput(stack, 'LoginCommand', {
value: `aws ecr get-login-password --region ${stack.region} | docker login --username AWS --password-stdin ${stack.account}.dkr.ecr.${stack.region}.amazonaws.com`,
});

new cdk.CfnOutput(stack, 'PushCommand', {
value: `docker tag public.ecr.aws/lambda/provided ${repository.repositoryUriForTag('latest')} && docker push ${repository.repositoryUriForTag('latest')}`,
});

new cdk.CfnOutput(stack, 'PipelineConsoleLink', {
value: `https://${stack.region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${pipeline.pipelineName}/view?region=${stack.region}`,
});

new IntegTest(app, 'ecr-source-action', {
testCases: [stack],
});

This file was deleted.

Loading

0 comments on commit f135b80

Please sign in to comment.