Skip to content

Commit 3177d2e

Browse files
committed
Support update hook for DummyTaskDefinition
1 parent a4736e5 commit 3177d2e

3 files changed

Lines changed: 243 additions & 35 deletions

File tree

packages/cdk-blue-green-container-deployment/src/__tests__/__snapshots__/dummy-task-definition.test.ts.snap

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ Object {
6060
Object {
6161
"Action": Array [
6262
"ecs:RegisterTaskDefinition",
63+
"ecs:DescribeTaskDefinition",
6364
"ecs:DeregisterTaskDefinition",
6465
],
6566
"Effect": "Allow",
@@ -116,6 +117,178 @@ Object {
116117
"Arn",
117118
],
118119
},
120+
"Update": "{\\"service\\":\\"ECS\\",\\"action\\":\\"describeTaskDefinition\\",\\"parameters\\":{\\"taskDefinition\\":\\"PHYSICAL:RESOURCEID:\\"},\\"physicalResourceId\\":{\\"responsePath\\":\\"taskDefinition.taskDefinitionArn\\"}}",
121+
},
122+
"Type": "Custom::DummyTaskDefinition",
123+
"UpdateReplacePolicy": "Delete",
124+
},
125+
"DummyTaskDefinitionExecutionRole715DBD43": Object {
126+
"Properties": Object {
127+
"AssumeRolePolicyDocument": Object {
128+
"Statement": Array [
129+
Object {
130+
"Action": "sts:AssumeRole",
131+
"Effect": "Allow",
132+
"Principal": Object {
133+
"Service": "ecs-tasks.amazonaws.com",
134+
},
135+
},
136+
],
137+
"Version": "2012-10-17",
138+
},
139+
"ManagedPolicyArns": Array [
140+
Object {
141+
"Fn::Join": Array [
142+
"",
143+
Array [
144+
"arn:",
145+
Object {
146+
"Ref": "AWS::Partition",
147+
},
148+
":iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",
149+
],
150+
],
151+
},
152+
],
153+
},
154+
"Type": "AWS::IAM::Role",
155+
},
156+
},
157+
}
158+
`;
159+
160+
exports[`with updates allowed 1`] = `
161+
Object {
162+
"Parameters": Any<Object>,
163+
"Resources": Object {
164+
"AWS679f53fac002430cb0da5b7982bd22872D164C4C": Object {
165+
"DependsOn": Array [
166+
"AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2",
167+
],
168+
"Properties": Object {
169+
"Code": Any<Object>,
170+
"Handler": "index.handler",
171+
"Role": Object {
172+
"Fn::GetAtt": Array [
173+
"AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2",
174+
"Arn",
175+
],
176+
},
177+
"Runtime": "nodejs12.x",
178+
"Timeout": 120,
179+
},
180+
"Type": "AWS::Lambda::Function",
181+
},
182+
"AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2": Object {
183+
"Properties": Object {
184+
"AssumeRolePolicyDocument": Object {
185+
"Statement": Array [
186+
Object {
187+
"Action": "sts:AssumeRole",
188+
"Effect": "Allow",
189+
"Principal": Object {
190+
"Service": "lambda.amazonaws.com",
191+
},
192+
},
193+
],
194+
"Version": "2012-10-17",
195+
},
196+
"ManagedPolicyArns": Array [
197+
Object {
198+
"Fn::Join": Array [
199+
"",
200+
Array [
201+
"arn:",
202+
Object {
203+
"Ref": "AWS::Partition",
204+
},
205+
":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
206+
],
207+
],
208+
},
209+
],
210+
},
211+
"Type": "AWS::IAM::Role",
212+
},
213+
"DummyTaskDefinitionCustomResourcePolicyB5660701": Object {
214+
"Properties": Object {
215+
"PolicyDocument": Object {
216+
"Statement": Array [
217+
Object {
218+
"Action": Array [
219+
"ecs:RegisterTaskDefinition",
220+
"ecs:DescribeTaskDefinition",
221+
"ecs:DeregisterTaskDefinition",
222+
],
223+
"Effect": "Allow",
224+
"Resource": "*",
225+
},
226+
Object {
227+
"Action": "iam:PassRole",
228+
"Effect": "Allow",
229+
"Resource": Object {
230+
"Fn::GetAtt": Array [
231+
"DummyTaskDefinitionExecutionRole715DBD43",
232+
"Arn",
233+
],
234+
},
235+
},
236+
],
237+
"Version": "2012-10-17",
238+
},
239+
"PolicyName": "DummyTaskDefinitionCustomResourcePolicyB5660701",
240+
"Roles": Array [
241+
Object {
242+
"Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2",
243+
},
244+
],
245+
},
246+
"Type": "AWS::IAM::Policy",
247+
},
248+
"DummyTaskDefinitionE3D9D432": Object {
249+
"DeletionPolicy": "Delete",
250+
"DependsOn": Array [
251+
"DummyTaskDefinitionCustomResourcePolicyB5660701",
252+
],
253+
"Properties": Object {
254+
"Create": Object {
255+
"Fn::Join": Array [
256+
"",
257+
Array [
258+
"{\\"service\\":\\"ECS\\",\\"action\\":\\"registerTaskDefinition\\",\\"parameters\\":{\\"requiresCompatibilities\\":[\\"FARGATE\\"],\\"family\\":\\"c86e1e5d419d3c124c7e40411b7e7805f91621e162\\",\\"executionRoleArn\\":\\"",
259+
Object {
260+
"Fn::GetAtt": Array [
261+
"DummyTaskDefinitionExecutionRole715DBD43",
262+
"Arn",
263+
],
264+
},
265+
"\\",\\"networkMode\\":\\"awsvpc\\",\\"cpu\\":\\"256\\",\\"memory\\":\\"512\\",\\"containerDefinitions\\":[{\\"name\\":\\"sample-website\\",\\"image\\":\\"image\\",\\"portMappings\\":[{\\"hostPort\\":80,\\"protocol\\":\\"tcp\\",\\"containerPort\\":80}]}]},\\"physicalResourceId\\":{\\"responsePath\\":\\"taskDefinition.taskDefinitionArn\\"}}",
266+
],
267+
],
268+
},
269+
"Delete": "{\\"service\\":\\"ECS\\",\\"action\\":\\"deregisterTaskDefinition\\",\\"parameters\\":{\\"taskDefinition\\":\\"PHYSICAL:RESOURCEID:\\"}}",
270+
"InstallLatestAwsSdk": true,
271+
"ServiceToken": Object {
272+
"Fn::GetAtt": Array [
273+
"AWS679f53fac002430cb0da5b7982bd22872D164C4C",
274+
"Arn",
275+
],
276+
},
277+
"Update": Object {
278+
"Fn::Join": Array [
279+
"",
280+
Array [
281+
"{\\"service\\":\\"ECS\\",\\"action\\":\\"registerTaskDefinition\\",\\"parameters\\":{\\"requiresCompatibilities\\":[\\"FARGATE\\"],\\"family\\":\\"c86e1e5d419d3c124c7e40411b7e7805f91621e162\\",\\"executionRoleArn\\":\\"",
282+
Object {
283+
"Fn::GetAtt": Array [
284+
"DummyTaskDefinitionExecutionRole715DBD43",
285+
"Arn",
286+
],
287+
},
288+
"\\",\\"networkMode\\":\\"awsvpc\\",\\"cpu\\":\\"256\\",\\"memory\\":\\"512\\",\\"containerDefinitions\\":[{\\"name\\":\\"sample-website\\",\\"image\\":\\"image\\",\\"portMappings\\":[{\\"hostPort\\":80,\\"protocol\\":\\"tcp\\",\\"containerPort\\":80}]}]},\\"physicalResourceId\\":{\\"responsePath\\":\\"taskDefinition.taskDefinitionArn\\"}}",
289+
],
290+
],
291+
},
119292
},
120293
"Type": "Custom::DummyTaskDefinition",
121294
"UpdateReplacePolicy": "Delete",

packages/cdk-blue-green-container-deployment/src/__tests__/dummy-task-definition.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,16 @@ test('default setup', (): void => {
1414
ignoreAssets: true,
1515
});
1616
});
17+
18+
test('with updates allowed', (): void => {
19+
const stack = new Stack();
20+
21+
new DummyTaskDefinition(stack, 'DummyTaskDefinition', {
22+
image: 'image',
23+
allowUpdates: true,
24+
});
25+
26+
expect(stack).toMatchCdkSnapshot({
27+
ignoreAssets: true,
28+
});
29+
});

packages/cdk-blue-green-container-deployment/src/dummy-task-definition.ts

Lines changed: 57 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { NetworkMode } from '@aws-cdk/aws-ecs';
22
import { Role, ServicePrincipal, ManagedPolicy, PolicyStatement, Effect, IRole } from '@aws-cdk/aws-iam';
33
import { Construct } from '@aws-cdk/core';
4-
import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId, PhysicalResourceIdReference } from '@aws-cdk/custom-resources';
4+
import { AwsCustomResource, AwsCustomResourcePolicy, AwsSdkCall, PhysicalResourceId, PhysicalResourceIdReference } from '@aws-cdk/custom-resources';
55

66
export interface IDummyTaskDefinition {
77
readonly executionRole: IRole;
@@ -38,6 +38,13 @@ export interface DummyTaskDefinitionProps {
3838
* @default 80
3939
*/
4040
readonly containerPort?: number;
41+
42+
/**
43+
* Allow task definition to be updated, causing new task definition to be created with new attributes.
44+
* Updates could negatively affect blue/green deployments.
45+
* @default false
46+
*/
47+
readonly allowUpdates?: boolean;
4148
}
4249

4350
export class DummyTaskDefinition extends Construct implements IDummyTaskDefinition {
@@ -62,46 +69,61 @@ export class DummyTaskDefinition extends Construct implements IDummyTaskDefiniti
6269
this.family = props.family ?? this.node.addr;
6370
this.containerName = props.containerName ?? 'sample-website';
6471
this.containerPort = props.containerPort ?? 80;
72+
const allowUpdates = !!props.allowUpdates;
73+
74+
const registerTaskDefinition: AwsSdkCall = {
75+
service: 'ECS',
76+
action: 'registerTaskDefinition',
77+
parameters: {
78+
requiresCompatibilities: ['FARGATE'],
79+
family: this.family,
80+
executionRoleArn: this.executionRole.roleArn,
81+
networkMode: NetworkMode.AWS_VPC,
82+
cpu: '256',
83+
memory: '512',
84+
containerDefinitions: [
85+
{
86+
name: this.containerName,
87+
image: props.image,
88+
portMappings: [
89+
{
90+
hostPort: this.containerPort,
91+
protocol: 'tcp',
92+
containerPort: this.containerPort,
93+
},
94+
],
95+
},
96+
],
97+
},
98+
physicalResourceId: PhysicalResourceId.fromResponse('taskDefinition.taskDefinitionArn'),
99+
};
100+
101+
const describeTaskDefinition: AwsSdkCall = {
102+
service: 'ECS',
103+
action: 'describeTaskDefinition',
104+
parameters: {
105+
taskDefinition: new PhysicalResourceIdReference(),
106+
},
107+
physicalResourceId: PhysicalResourceId.fromResponse('taskDefinition.taskDefinitionArn'),
108+
};
109+
110+
const deregisterTaskDefinition: AwsSdkCall = {
111+
service: 'ECS',
112+
action: 'deregisterTaskDefinition',
113+
parameters: {
114+
taskDefinition: new PhysicalResourceIdReference(),
115+
},
116+
};
65117

66118
const taskDefinition = new AwsCustomResource(this, 'DummyTaskDefinition', {
67119
resourceType: 'Custom::DummyTaskDefinition',
68-
onCreate: {
69-
service: 'ECS',
70-
action: 'registerTaskDefinition',
71-
parameters: {
72-
requiresCompatibilities: ['FARGATE'],
73-
family: this.family,
74-
executionRoleArn: this.executionRole.roleArn,
75-
networkMode: NetworkMode.AWS_VPC,
76-
cpu: '256',
77-
memory: '512',
78-
containerDefinitions: [
79-
{
80-
name: this.containerName,
81-
image: props.image,
82-
portMappings: [
83-
{
84-
hostPort: this.containerPort,
85-
protocol: 'tcp',
86-
containerPort: this.containerPort,
87-
},
88-
],
89-
},
90-
],
91-
},
92-
physicalResourceId: PhysicalResourceId.fromResponse('taskDefinition.taskDefinitionArn'),
93-
},
94-
onDelete: {
95-
service: 'ECS',
96-
action: 'deregisterTaskDefinition',
97-
parameters: {
98-
taskDefinition: new PhysicalResourceIdReference(),
99-
},
100-
},
120+
onCreate: registerTaskDefinition,
121+
onUpdate: allowUpdates ? registerTaskDefinition : describeTaskDefinition,
122+
onDelete: deregisterTaskDefinition,
101123
policy: AwsCustomResourcePolicy.fromStatements([
102124
new PolicyStatement({
103125
effect: Effect.ALLOW,
104-
actions: ['ecs:RegisterTaskDefinition', 'ecs:DeregisterTaskDefinition'],
126+
actions: ['ecs:RegisterTaskDefinition', 'ecs:DescribeTaskDefinition', 'ecs:DeregisterTaskDefinition'],
105127
resources: ['*'],
106128
}),
107129
new PolicyStatement({

0 commit comments

Comments
 (0)