Skip to content

Commit 7ae6aea

Browse files
authored
Merge branch 'master' into add-ingress-protocol
2 parents eb560ca + abfc0ea commit 7ae6aea

20 files changed

+548
-158
lines changed

packages/@aws-cdk/aws-cloudfront/lib/cache-policy.ts

+3
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,9 @@ export class CacheHeaderBehavior {
231231
if (headers.length === 0) {
232232
throw new Error('At least one header to allow must be provided');
233233
}
234+
if (headers.length > 10) {
235+
throw new Error(`Maximum allowed headers in Cache Policy is 10; got ${headers.length}.`);
236+
}
234237
return new CacheHeaderBehavior('whitelist', headers);
235238
}
236239

packages/@aws-cdk/aws-cloudfront/test/cache-policy.test.ts

+11
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,17 @@ describe('CachePolicy', () => {
9696
expect(() => new CachePolicy(stack, 'CachePolicy6', { cachePolicyName: 'My_Policy' })).not.toThrow();
9797
});
9898

99+
test('throws if more than 10 CacheHeaderBehavior headers are being passed', () => {
100+
const errorMessage = /Maximum allowed headers in Cache Policy is 10; got (.*?)/;
101+
expect(() => new CachePolicy(stack, 'CachePolicy1', {
102+
headerBehavior: CacheHeaderBehavior.allowList('Lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipiscing', 'elit', 'sed', 'do', 'eiusmod'),
103+
})).toThrow(errorMessage);
104+
105+
expect(() => new CachePolicy(stack, 'CachePolicy2', {
106+
headerBehavior: CacheHeaderBehavior.allowList('Lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipiscing', 'elit', 'sed', 'do'),
107+
})).not.toThrow();
108+
});
109+
99110
test('does not throw if cachePolicyName is a token', () => {
100111
expect(() => new CachePolicy(stack, 'CachePolicy', {
101112
cachePolicyName: Aws.STACK_NAME,

packages/@aws-cdk/aws-codebuild/README.md

+28
Original file line numberDiff line numberDiff line change
@@ -617,3 +617,31 @@ if (project.enableBatchBuilds()) {
617617
console.log('Batch builds were enabled');
618618
}
619619
```
620+
621+
## Timeouts
622+
623+
There are two types of timeouts that can be set when creating your Project.
624+
The `timeout` property can be used to set an upper limit on how long your Project is able to run without being marked as completed.
625+
The default is 60 minutes.
626+
An example of overriding the default follows.
627+
628+
```ts
629+
import * as codebuild from '@aws-cdk/aws-codebuild';
630+
631+
new codebuild.Project(stack, 'MyProject', {
632+
timeout: Duration.minutes(90)
633+
});
634+
```
635+
636+
The `queuedTimeout` property can be used to set an upper limit on how your Project remains queued to run.
637+
There is no default value for this property.
638+
As an example, to allow your Project to queue for up to thirty (30) minutes before the build fails,
639+
use the following code.
640+
641+
```ts
642+
import * as codebuild from '@aws-cdk/aws-codebuild';
643+
644+
new codebuild.Project(stack, 'MyProject', {
645+
queuedTimeout: Duration.minutes(30)
646+
});
647+
```

packages/@aws-cdk/aws-codebuild/lib/project.ts

+10
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,15 @@ export interface CommonProjectProps {
575575
* @default - no log configuration is set
576576
*/
577577
readonly logging?: LoggingOptions;
578+
579+
/**
580+
* The number of minutes after which AWS CodeBuild stops the build if it's
581+
* still in queue. For valid values, see the timeoutInMinutes field in the AWS
582+
* CodeBuild User Guide.
583+
*
584+
* @default - no queue timeout is set
585+
*/
586+
readonly queuedTimeout?: Duration
578587
}
579588

580589
export interface ProjectProps extends CommonProjectProps {
@@ -869,6 +878,7 @@ export class Project extends ProjectBase {
869878
cache: cache._toCloudFormation(),
870879
name: this.physicalName,
871880
timeoutInMinutes: props.timeout && props.timeout.toMinutes(),
881+
queuedTimeoutInMinutes: props.queuedTimeout && props.queuedTimeout.toMinutes(),
872882
secondarySources: Lazy.any({ produce: () => this.renderSecondarySources() }),
873883
secondarySourceVersions: Lazy.any({ produce: () => this.renderSecondarySourceVersions() }),
874884
secondaryArtifacts: Lazy.any({ produce: () => this.renderSecondaryArtifacts() }),

packages/@aws-cdk/aws-codebuild/test/test.project.ts

+43
Original file line numberDiff line numberDiff line change
@@ -960,4 +960,47 @@ export = {
960960
test.done();
961961
},
962962
},
963+
964+
'Timeouts': {
965+
'can add queued timeout'(test: Test) {
966+
// GIVEN
967+
const stack = new cdk.Stack();
968+
969+
// WHEN
970+
new codebuild.Project(stack, 'Project', {
971+
source: codebuild.Source.s3({
972+
bucket: new s3.Bucket(stack, 'Bucket'),
973+
path: 'path',
974+
}),
975+
queuedTimeout: cdk.Duration.minutes(30),
976+
});
977+
978+
// THEN
979+
expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', {
980+
QueuedTimeoutInMinutes: 30,
981+
}));
982+
983+
test.done();
984+
},
985+
'can override build timeout'(test: Test) {
986+
// GIVEN
987+
const stack = new cdk.Stack();
988+
989+
// WHEN
990+
new codebuild.Project(stack, 'Project', {
991+
source: codebuild.Source.s3({
992+
bucket: new s3.Bucket(stack, 'Bucket'),
993+
path: 'path',
994+
}),
995+
timeout: cdk.Duration.minutes(30),
996+
});
997+
998+
// THEN
999+
expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', {
1000+
TimeoutInMinutes: 30,
1001+
}));
1002+
1003+
test.done();
1004+
},
1005+
},
9631006
};

packages/@aws-cdk/aws-ecr/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const user = new iam.User(this, 'User', { ... });
5757
ecr.AuthorizationToken.grantRead(user);
5858
```
5959

60-
If you access images in the [Public ECR Gallery](https://gallery.ecr.aws/) as well, it is recommended you authenticate to the regsitry to benefit from
60+
If you access images in the [Public ECR Gallery](https://gallery.ecr.aws/) as well, it is recommended you authenticate to the registry to benefit from
6161
higher rate and bandwidth limits.
6262

6363
> See `Pricing` in https://aws.amazon.com/blogs/aws/amazon-ecr-public-a-new-public-container-registry/ and [Service quotas](https://docs.aws.amazon.com/AmazonECR/latest/public/public-service-quotas.html).

packages/@aws-cdk/aws-ecs/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,8 @@ obtained from either DockerHub or from ECR repositories, or built directly from
299299
image directly from a `Dockerfile` in your source directory.
300300
- `ecs.ContainerImage.fromDockerImageAsset(asset)`: uses an existing
301301
`@aws-cdk/aws-ecr-assets.DockerImageAsset` as a container image.
302+
- `new ecs.TagParameterContainerImage(repository)`: use the given ECR repository as the image
303+
but a CloudFormation parameter as the tag.
302304

303305
### Environment variables
304306

packages/@aws-cdk/aws-ecs/lib/images/tag-parameter-container-image.ts

+16
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,20 @@ export class TagParameterContainerImage extends ContainerImage {
4949
},
5050
});
5151
}
52+
53+
/**
54+
* Returns the value of the CloudFormation Parameter that represents the tag of the image
55+
* in the ECR repository.
56+
*/
57+
public get tagParameterValue(): string {
58+
return cdk.Lazy.string({
59+
produce: () => {
60+
if (this.imageTagParameter) {
61+
return this.imageTagParameter.valueAsString;
62+
} else {
63+
throw new Error('TagParameterContainerImage must be used in a container definition when using tagParameterValue');
64+
}
65+
},
66+
});
67+
}
5268
}

packages/@aws-cdk/aws-ecs/test/images/tag-parameter-container-image.test.ts

+16
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,21 @@ nodeunitShim({
2121

2222
test.done();
2323
},
24+
25+
'throws an error when tagParameterValue() is used without binding the image'(test: Test) {
26+
// GIVEN
27+
const stack = new cdk.Stack();
28+
const repository = new ecr.Repository(stack, 'Repository');
29+
const tagParameterContainerImage = new ecs.TagParameterContainerImage(repository);
30+
new cdk.CfnOutput(stack, 'Output', {
31+
value: tagParameterContainerImage.tagParameterValue,
32+
});
33+
34+
test.throws(() => {
35+
SynthUtils.synthesize(stack);
36+
}, /TagParameterContainerImage must be used in a container definition when using tagParameterValue/);
37+
38+
test.done();
39+
},
2440
},
2541
});

packages/@aws-cdk/aws-events-targets/README.md

+33
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,39 @@ const rule = new events.Rule(this, 'rule', {
9090
rule.addTarget(new targets.CloudWatchLogGroup(logGroup));
9191
```
9292

93+
## Trigger a CodeBuild project
94+
95+
Use the `CodeBuildProject` target to trigger a CodeBuild project.
96+
97+
The code snippet below creates a CodeCommit repository that triggers a CodeBuild project
98+
on commit to the master branch. You can optionally attach a
99+
[dead letter queue](https://docs.aws.amazon.com/eventbridge/latest/userguide/rule-dlq.html).
100+
101+
```ts
102+
import * as codebuild from '@aws-sdk/aws-codebuild';
103+
import * as codecommit from '@aws-sdk/aws-codecommit';
104+
import * as sqs from '@aws-sdk/aws-sqs';
105+
import * as targets from "@aws-cdk/aws-events-targets";
106+
107+
const repo = new codecommit.Repository(this, 'MyRepo', {
108+
repositoryName: 'aws-cdk-codebuild-events',
109+
});
110+
111+
const project = new codebuild.Project(this, 'MyProject', {
112+
source: codebuild.Source.codeCommit({ repository: repo }),
113+
});
114+
115+
const deadLetterQueue = new sqs.Queue(this, 'DeadLetterQueue');
116+
117+
// trigger a build when a commit is pushed to the repo
118+
const onCommitRule = repo.onCommit('OnCommit', {
119+
target: new targets.CodeBuildProject(project, {
120+
deadLetterQueue: deadLetterQueue,
121+
}),
122+
branches: ['master'],
123+
});
124+
```
125+
93126
## Trigger a State Machine
94127

95128
Use the `SfnStateMachine` target to trigger a State Machine.

packages/@aws-cdk/aws-events-targets/lib/codebuild.ts

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import * as codebuild from '@aws-cdk/aws-codebuild';
22
import * as events from '@aws-cdk/aws-events';
33
import * as iam from '@aws-cdk/aws-iam';
4-
import { singletonEventRole } from './util';
4+
import * as sqs from '@aws-cdk/aws-sqs';
5+
import { addToDeadLetterQueueResourcePolicy, singletonEventRole } from './util';
56

67
/**
78
* Customize the CodeBuild Event Target
@@ -24,6 +25,18 @@ export interface CodeBuildProjectProps {
2425
* @default - the entire EventBridge event
2526
*/
2627
readonly event?: events.RuleTargetInput;
28+
29+
/**
30+
* The SQS queue to be used as deadLetterQueue.
31+
* Check out the [considerations for using a dead-letter queue](https://docs.aws.amazon.com/eventbridge/latest/userguide/rule-dlq.html#dlq-considerations).
32+
*
33+
* The events not successfully delivered are automatically retried for a specified period of time,
34+
* depending on the retry policy of the target.
35+
* If an event is not delivered before all retry attempts are exhausted, it will be sent to the dead letter queue.
36+
*
37+
* @default - no dead-letter queue
38+
*/
39+
readonly deadLetterQueue?: sqs.IQueue;
2740
}
2841

2942
/**
@@ -39,9 +52,15 @@ export class CodeBuildProject implements events.IRuleTarget {
3952
* Allows using build projects as event rule targets.
4053
*/
4154
public bind(_rule: events.IRule, _id?: string): events.RuleTargetConfig {
55+
56+
if (this.props.deadLetterQueue) {
57+
addToDeadLetterQueueResourcePolicy(_rule, this.props.deadLetterQueue);
58+
}
59+
4260
return {
4361
id: '',
4462
arn: this.project.projectArn,
63+
deadLetterConfig: this.props.deadLetterQueue ? { arn: this.props.deadLetterQueue?.queueArn } : undefined,
4564
role: this.props.eventRole || singletonEventRole(this.project, [
4665
new iam.PolicyStatement({
4766
actions: ['codebuild:StartBuild'],

packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts

+81
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { expect, haveResource } from '@aws-cdk/assert';
22
import * as codebuild from '@aws-cdk/aws-codebuild';
33
import * as events from '@aws-cdk/aws-events';
44
import * as iam from '@aws-cdk/aws-iam';
5+
import * as sqs from '@aws-cdk/aws-sqs';
56
import { CfnElement, Stack } from '@aws-cdk/core';
67
import * as targets from '../../lib';
78

@@ -120,4 +121,84 @@ describe('CodeBuild event target', () => {
120121
],
121122
}));
122123
});
124+
125+
test('use a Dead Letter Queue for the rule target', () => {
126+
// GIVEN
127+
const rule = new events.Rule(stack, 'Rule', {
128+
schedule: events.Schedule.expression('rate(1 hour)'),
129+
});
130+
131+
const queue = new sqs.Queue(stack, 'Queue');
132+
133+
// WHEN
134+
const eventInput = {
135+
buildspecOverride: 'buildspecs/hourly.yml',
136+
};
137+
138+
rule.addTarget(
139+
new targets.CodeBuildProject(project, {
140+
event: events.RuleTargetInput.fromObject(eventInput),
141+
deadLetterQueue: queue,
142+
}),
143+
);
144+
145+
// THEN
146+
expect(stack).to(haveResource('AWS::Events::Rule', {
147+
Targets: [
148+
{
149+
Arn: projectArn,
150+
Id: 'Target0',
151+
DeadLetterConfig: {
152+
Arn: {
153+
'Fn::GetAtt': [
154+
'Queue4A7E3555',
155+
'Arn',
156+
],
157+
},
158+
},
159+
Input: JSON.stringify(eventInput),
160+
RoleArn: {
161+
'Fn::GetAtt': ['MyProjectEventsRole5B7D93F5', 'Arn'],
162+
},
163+
},
164+
],
165+
}));
166+
167+
expect(stack).to(haveResource('AWS::SQS::QueuePolicy', {
168+
PolicyDocument: {
169+
Statement: [
170+
{
171+
Action: 'sqs:SendMessage',
172+
Condition: {
173+
ArnEquals: {
174+
'aws:SourceArn': {
175+
'Fn::GetAtt': [
176+
'Rule4C995B7F',
177+
'Arn',
178+
],
179+
},
180+
},
181+
},
182+
Effect: 'Allow',
183+
Principal: {
184+
Service: 'events.amazonaws.com',
185+
},
186+
Resource: {
187+
'Fn::GetAtt': [
188+
'Queue4A7E3555',
189+
'Arn',
190+
],
191+
},
192+
Sid: 'AllowEventRuleRule',
193+
},
194+
],
195+
Version: '2012-10-17',
196+
},
197+
Queues: [
198+
{
199+
Ref: 'Queue4A7E3555',
200+
},
201+
],
202+
}));
203+
});
123204
});

0 commit comments

Comments
 (0)