Skip to content

Commit

Permalink
feat(events): dead-letter queue support for CodeBuild (#13448)
Browse files Browse the repository at this point in the history
Resolves #13447

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
DaWyz authored Mar 9, 2021
1 parent e08213f commit abfc0ea
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 2 deletions.
33 changes: 33 additions & 0 deletions packages/@aws-cdk/aws-events-targets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,39 @@ const rule = new events.Rule(this, 'rule', {
rule.addTarget(new targets.CloudWatchLogGroup(logGroup));
```

## Trigger a CodeBuild project

Use the `CodeBuildProject` target to trigger a CodeBuild project.

The code snippet below creates a CodeCommit repository that triggers a CodeBuild project
on commit to the master branch. You can optionally attach a
[dead letter queue](https://docs.aws.amazon.com/eventbridge/latest/userguide/rule-dlq.html).

```ts
import * as codebuild from '@aws-sdk/aws-codebuild';
import * as codecommit from '@aws-sdk/aws-codecommit';
import * as sqs from '@aws-sdk/aws-sqs';
import * as targets from "@aws-cdk/aws-events-targets";

const repo = new codecommit.Repository(this, 'MyRepo', {
repositoryName: 'aws-cdk-codebuild-events',
});

const project = new codebuild.Project(this, 'MyProject', {
source: codebuild.Source.codeCommit({ repository: repo }),
});

const deadLetterQueue = new sqs.Queue(this, 'DeadLetterQueue');

// trigger a build when a commit is pushed to the repo
const onCommitRule = repo.onCommit('OnCommit', {
target: new targets.CodeBuildProject(project, {
deadLetterQueue: deadLetterQueue,
}),
branches: ['master'],
});
```

## Trigger a State Machine

Use the `SfnStateMachine` target to trigger a State Machine.
Expand Down
21 changes: 20 additions & 1 deletion packages/@aws-cdk/aws-events-targets/lib/codebuild.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as codebuild from '@aws-cdk/aws-codebuild';
import * as events from '@aws-cdk/aws-events';
import * as iam from '@aws-cdk/aws-iam';
import { singletonEventRole } from './util';
import * as sqs from '@aws-cdk/aws-sqs';
import { addToDeadLetterQueueResourcePolicy, singletonEventRole } from './util';

/**
* Customize the CodeBuild Event Target
Expand All @@ -24,6 +25,18 @@ export interface CodeBuildProjectProps {
* @default - the entire EventBridge event
*/
readonly event?: events.RuleTargetInput;

/**
* The SQS queue to be used as deadLetterQueue.
* Check out the [considerations for using a dead-letter queue](https://docs.aws.amazon.com/eventbridge/latest/userguide/rule-dlq.html#dlq-considerations).
*
* The events not successfully delivered are automatically retried for a specified period of time,
* depending on the retry policy of the target.
* If an event is not delivered before all retry attempts are exhausted, it will be sent to the dead letter queue.
*
* @default - no dead-letter queue
*/
readonly deadLetterQueue?: sqs.IQueue;
}

/**
Expand All @@ -39,9 +52,15 @@ export class CodeBuildProject implements events.IRuleTarget {
* Allows using build projects as event rule targets.
*/
public bind(_rule: events.IRule, _id?: string): events.RuleTargetConfig {

if (this.props.deadLetterQueue) {
addToDeadLetterQueueResourcePolicy(_rule, this.props.deadLetterQueue);
}

return {
id: '',
arn: this.project.projectArn,
deadLetterConfig: this.props.deadLetterQueue ? { arn: this.props.deadLetterQueue?.queueArn } : undefined,
role: this.props.eventRole || singletonEventRole(this.project, [
new iam.PolicyStatement({
actions: ['codebuild:StartBuild'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { expect, haveResource } from '@aws-cdk/assert';
import * as codebuild from '@aws-cdk/aws-codebuild';
import * as events from '@aws-cdk/aws-events';
import * as iam from '@aws-cdk/aws-iam';
import * as sqs from '@aws-cdk/aws-sqs';
import { CfnElement, Stack } from '@aws-cdk/core';
import * as targets from '../../lib';

Expand Down Expand Up @@ -120,4 +121,84 @@ describe('CodeBuild event target', () => {
],
}));
});

test('use a Dead Letter Queue for the rule target', () => {
// GIVEN
const rule = new events.Rule(stack, 'Rule', {
schedule: events.Schedule.expression('rate(1 hour)'),
});

const queue = new sqs.Queue(stack, 'Queue');

// WHEN
const eventInput = {
buildspecOverride: 'buildspecs/hourly.yml',
};

rule.addTarget(
new targets.CodeBuildProject(project, {
event: events.RuleTargetInput.fromObject(eventInput),
deadLetterQueue: queue,
}),
);

// THEN
expect(stack).to(haveResource('AWS::Events::Rule', {
Targets: [
{
Arn: projectArn,
Id: 'Target0',
DeadLetterConfig: {
Arn: {
'Fn::GetAtt': [
'Queue4A7E3555',
'Arn',
],
},
},
Input: JSON.stringify(eventInput),
RoleArn: {
'Fn::GetAtt': ['MyProjectEventsRole5B7D93F5', 'Arn'],
},
},
],
}));

expect(stack).to(haveResource('AWS::SQS::QueuePolicy', {
PolicyDocument: {
Statement: [
{
Action: 'sqs:SendMessage',
Condition: {
ArnEquals: {
'aws:SourceArn': {
'Fn::GetAtt': [
'Rule4C995B7F',
'Arn',
],
},
},
},
Effect: 'Allow',
Principal: {
Service: 'events.amazonaws.com',
},
Resource: {
'Fn::GetAtt': [
'Queue4A7E3555',
'Arn',
],
},
Sid: 'AllowEventRuleRule',
},
],
Version: '2012-10-17',
},
Queues: [
{
Ref: 'Queue4A7E3555',
},
],
}));
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@
"Arn"
]
},
"DeadLetterConfig": {
"Arn": {
"Fn::GetAtt": [
"DeadLetterQueue9F481546",
"Arn"
]
}
},
"Id": "Target0",
"RoleArn": {
"Fn::GetAtt": [
Expand Down Expand Up @@ -394,6 +402,50 @@
}
}
},
"DeadLetterQueue9F481546": {
"Type": "AWS::SQS::Queue",
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete"
},
"DeadLetterQueuePolicyB1FB890C": {
"Type": "AWS::SQS::QueuePolicy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": "sqs:SendMessage",
"Condition": {
"ArnEquals": {
"aws:SourceArn": {
"Fn::GetAtt": [
"MyRepoOnCommit0E80B304",
"Arn"
]
}
}
},
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Resource": {
"Fn::GetAtt": [
"DeadLetterQueue9F481546",
"Arn"
]
},
"Sid": "AllowEventRuleawscdkcodebuildeventsMyRepoOnCommit0ED1137A"
}
],
"Version": "2012-10-17"
},
"Queues": [
{
"Ref": "DeadLetterQueue9F481546"
}
]
}
},
"MyTopic86869434": {
"Type": "AWS::SNS::Topic"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const project = new codebuild.Project(stack, 'MyProject', {
});

const queue = new sqs.Queue(stack, 'MyQueue');
const deadLetterQueue = new sqs.Queue(stack, 'DeadLetterQueue');

const topic = new sns.Topic(stack, 'MyTopic');
topic.addSubscription(new subs.SqsSubscription(queue));
Expand All @@ -39,7 +40,9 @@ project.onPhaseChange('PhaseChange', {

// trigger a build when a commit is pushed to the repo
const onCommitRule = repo.onCommit('OnCommit', {
target: new targets.CodeBuildProject(project),
target: new targets.CodeBuildProject(project, {
deadLetterQueue: deadLetterQueue,
}),
branches: ['master'],
});

Expand Down

0 comments on commit abfc0ea

Please sign in to comment.