Skip to content

Commit 1e81053

Browse files
iamhopaul123mergify[bot]
authored andcommitted
feat(ecs): support ecs tag propagation and ecs managed tags (#3420)
* Added two new properties for ECS Service * Fix comment for PropagateTags * Remove Name-path tag for ECS Service * Fix properties discription * Add unit test and fix integ test * Fix integ test for ecs-pattern * fix pipeline ecs integ test * Update snapshot for synth.test.js * Change enum type name and add no_propagate option * Change enum name and fix no propagate setting in fargate service * Change default value for propagateTags in comment * Add design doc * Fix comments and tests and refactor propagatetags logic * Fix propagateTags and enableECSManagedTags comments * Sync design doc
1 parent 2590327 commit 1e81053

18 files changed

+376
-17
lines changed
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
# AWS ECS - Tagging Support
2+
3+
Amazon ECS supports tagging for all the ECS resources (see [here](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-using-tags.html)). Note that ECS provides a property of ECS service named `PropagateTags` to support propagating tags from either task definitions or services to tasks (tasks cannot be tagged using CDK without setting this parameter). Currently this property is not supported in CDK so that the tags are not propagated by default.
4+
5+
In addition, `EnableECSManagedTags` is provided as another property so that ECS managed tags can be supported and used to tag ECS tasks. However, currently users cannot set `EnableECSManagedTags` and the default value is `false`.
6+
7+
## General approach
8+
9+
The new `BaseService` class will include two more base properties:
10+
11+
* propagateTags
12+
* enableECSManagedTags
13+
14+
`propagateTags` specifies whether to propagate the tags from the task definition or the service to ECS tasks and `enableECSManagedTags` specifies whether to enable Amazon ECS managed tags for the tasks within the service. Also, for `Ec2Service` and `FargateService` we will have the corresponding two new properties exposed to users:
15+
16+
* propagateTaskTagsFrom (`SERVICE` | `TASK_DEFINITION` | `NONE`)
17+
* enableECSManagedTags (`true` | `false`)
18+
19+
\*`propagateTaskTagsFrom` has a default value of `SERVICE` and `enableECSManagedTags` has a default value of `true` \
20+
\*`propagateTaskTagsFrom` takes enum type `PropagatedTagSource`.\
21+
\*Note that the reason why we define `propagateTaskTagsFrom` is because we want to have a different name for `propagateTags` to eliminate the naming confusion.
22+
23+
In addition, for the `aws-ecs-patterns` module we want it to be convenient, but in this case, the `aws-ecs-patterns` module is opinionated. As a result, we want `SERVICE` and `true` to be set by default, not just for constructs in the `aws-ecs-patterns` module.
24+
25+
## Code changes
26+
27+
Given the above, we should make the following changes on ECS:
28+
29+
1. Add an enum type `PropagatedTagSource` to support `propagateTaskTagsFrom`.
30+
2. Add `propagateTags` and `enableECSManagedTags` properties to `BaseServiceOptions`.
31+
3. Add `propagateTaskTagsFrom` properties to `Ec2ServiceProps` and `FargateServiceProps`.
32+
33+
### Part 1: Add enum type `PropagatedTagSource` to support `propagateTaskTagsFrom`
34+
35+
``` ts
36+
export enum PropagatedTagSource {
37+
/**
38+
* Propagate tags from service
39+
*/
40+
SERVICE = 'SERVICE',
41+
42+
/**
43+
* Propagate tags from task definition
44+
*/
45+
TASK_DEFINITION = 'TASK_DEFINITION',
46+
47+
/**
48+
* Do not propagate
49+
*/
50+
NONE = 'NONE'
51+
}
52+
```
53+
54+
### Part 2: Add `propagateTags` and `enableECSManagedTags` properties to `BaseServiceOptions`
55+
56+
```ts
57+
export interface BaseServiceOptions {
58+
59+
...
60+
61+
/**
62+
* Specifies whether to propagate the tags from the task definition or the service to the tasks in the service
63+
*
64+
* Valid values are: PropagateTagFromType.SERVICE or PropagateTagFromType.TASK_DEFINITION
65+
*
66+
* @default - PropagatedTagSource.SERVICE if EC2 or Fargate Service, otherwise PropagatedTagSource.NONE.
67+
*/
68+
readonly propagateTags?: PropagatedTagSource;
69+
70+
/**
71+
* Specifies whether to enable Amazon ECS managed tags for the tasks within the service. For more information, see
72+
* [Tagging Your Amazon ECS Resources](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-using-tags.html)
73+
*
74+
* @default true
75+
*/
76+
readonly enableECSManagedTags?: boolean;
77+
}
78+
```
79+
80+
``` ts
81+
/**
82+
* The base class for Ec2Service and FargateService services.
83+
*/
84+
export abstract class BaseService extends Resource
85+
implements IService, elbv2.IApplicationLoadBalancerTarget, elbv2.INetworkLoadBalancerTarget {
86+
87+
...
88+
89+
/**
90+
* Constructs a new instance of the BaseService class.
91+
*/
92+
constructor(scope: Construct,
93+
id: string,
94+
props: BaseServiceProps,
95+
additionalProps: any,
96+
taskDefinition: TaskDefinition) {
97+
98+
...
99+
100+
this.resource = new CfnService(this, "Service", {
101+
desiredCount: props.desiredCount,
102+
serviceName: this.physicalName,
103+
loadBalancers: Lazy.anyValue({ produce: () => this.loadBalancers }),
104+
deploymentConfiguration: {
105+
maximumPercent: props.maxHealthyPercent || 200,
106+
minimumHealthyPercent: props.minHealthyPercent === undefined ? 50 : props.minHealthyPercent
107+
},
108+
propagateTags: props.propagateTags === PropagatedTagSource.NONE ? undefined : props.propagateTags,
109+
enableEcsManagedTags: props.enableECSManagedTags === undefined ? true : props.enableECSManagedTags,
110+
launchType: props.launchType,
111+
healthCheckGracePeriodSeconds: this.evaluateHealthGracePeriod(props.healthCheckGracePeriod),
112+
/* role: never specified, supplanted by Service Linked Role */
113+
networkConfiguration: Lazy.anyValue({ produce: () => this.networkConfiguration }),
114+
serviceRegistries: Lazy.anyValue({ produce: () => this.serviceRegistries }),
115+
...additionalProps
116+
});
117+
118+
...
119+
120+
}
121+
122+
...
123+
124+
}
125+
```
126+
127+
### Part 3: Add `propagateTaskTagsFrom` properties to `Ec2ServiceProps` and `FargateServiceProps`
128+
129+
``` ts
130+
export interface Ec2ServiceProps extends BaseServiceOptions {
131+
132+
...
133+
134+
/**
135+
* Specifies whether to propagate the tags from the task definition or the service to the tasks in the service.
136+
* Tags can only be propagated to the tasks within the service during service creation.
137+
*
138+
* @default PropagatedTagSource.SERVICE
139+
*/
140+
readonly propagateTaskTagsFrom?: PropagatedTagSource;
141+
}
142+
```
143+
144+
``` ts
145+
/**
146+
* This creates a service using the EC2 launch type on an ECS cluster.
147+
*
148+
* @resource AWS::ECS::Service
149+
*/
150+
export class Ec2Service extends BaseService implements IEc2Service, elb.ILoadBalancerTarget {
151+
152+
...
153+
154+
/**
155+
* Constructs a new instance of the Ec2Service class.
156+
*/
157+
constructor(scope: Construct, id: string, props: Ec2ServiceProps) {
158+
159+
...
160+
161+
super(scope, id, {
162+
...props,
163+
// If daemon, desiredCount must be undefined and that's what we want. Otherwise, default to 1.
164+
desiredCount: props.daemon || props.desiredCount !== undefined ? props.desiredCount : 1,
165+
maxHealthyPercent: props.daemon && props.maxHealthyPercent === undefined ? 100 : props.maxHealthyPercent,
166+
minHealthyPercent: props.daemon && props.minHealthyPercent === undefined ? 0 : props.minHealthyPercent,
167+
launchType: LaunchType.EC2,
168+
propagateTags: props.propagateTaskTagsFrom === undefined ? PropagatedTagSource.SERVICE : props.propagateTaskTagsFrom,
169+
enableECSManagedTags: props.enableECSManagedTags,
170+
},
171+
{
172+
cluster: props.cluster.clusterName,
173+
taskDefinition: props.taskDefinition.taskDefinitionArn,
174+
placementConstraints: Lazy.anyValue({ produce: () => this.constraints }, { omitEmptyArray: true }),
175+
placementStrategies: Lazy.anyValue({ produce: () => this.strategies }, { omitEmptyArray: true }),
176+
schedulingStrategy: props.daemon ? 'DAEMON' : 'REPLICA',
177+
}, props.taskDefinition);
178+
179+
...
180+
181+
}
182+
183+
...
184+
185+
}
186+
```
187+
188+
``` ts
189+
export interface FargateServiceProps extends BaseServiceOptions {
190+
191+
...
192+
193+
/**
194+
* Specifies whether to propagate the tags from the task definition or the service to the tasks in the service.
195+
* Tags can only be propagated to the tasks within the service during service creation.
196+
*
197+
* @default PropagatedTagSource.SERVICE
198+
*/
199+
readonly propagateTaskTagsFrom?: PropagatedTagSource;
200+
}
201+
```
202+
203+
204+
``` ts
205+
/**
206+
* This creates a service using the Fargate launch type on an ECS cluster.
207+
*
208+
* @resource AWS::ECS::Service
209+
*/
210+
export class FargateService extends BaseService implements IFargateService {
211+
212+
...
213+
214+
/**
215+
* Constructs a new instance of the FargateService class.
216+
*/
217+
constructor(scope: cdk.Construct, id: string, props: FargateServiceProps) {
218+
219+
...
220+
221+
super(scope, id, {
222+
...props,
223+
desiredCount: props.desiredCount !== undefined ? props.desiredCount : 1,
224+
launchType: LaunchType.FARGATE,
225+
propagateTags: props.propagateTaskTagsFrom === undefined ? PropagatedTagSource.SERVICE : props.propagateTaskTagsFrom,
226+
enableECSManagedTags: props.enableECSManagedTags,
227+
}, {
228+
cluster: props.cluster.clusterName,
229+
taskDefinition: props.taskDefinition.taskDefinitionArn,
230+
platformVersion: props.platformVersion,
231+
}, props.taskDefinition);
232+
233+
...
234+
235+
}
236+
237+
...
238+
239+
}
240+
```
241+
242+
The `Ec2Service` and `FargateService` constructs will have two new properties:
243+
244+
* propagateTaskTagsFrom - Propagate tags from either ECS Task Definition or Service to Task.
245+
* enableECSManagedTags - Enable ECS managed tags to ECS Task.
246+
247+
An example use case to create an EC2/Fargate service:
248+
249+
```ts
250+
// Create Service
251+
const service = new ecs.Ec2Service(stack, "Service", {
252+
cluster,
253+
taskDefinition,
254+
propagateTaskTagsFrom: ecs.PropagatedTagSource.TASK_DEFINITION,
255+
enableECSManagedTags: true,
256+
});
257+
```
258+
259+
``` ts
260+
const service = new ecs.FargateService(stack, "Service", {
261+
cluster,
262+
taskDefinition,
263+
propagateTaskTagsFrom: ecs.PropagatedTagSource.TASK_DEFINITION,
264+
enableECSManagedTags: false,
265+
});
266+
```

packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecs-deploy.expected.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,9 @@
272272
}
273273
]
274274
}
275-
}
275+
},
276+
"EnableECSManagedTags": true,
277+
"PropagateTags": "SERVICE"
276278
}
277279
},
278280
"FargateServiceSecurityGroup0A0E79CB": {

packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.asset-image.expected.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,9 @@
776776
}
777777
]
778778
}
779-
}
779+
},
780+
"EnableECSManagedTags": true,
781+
"PropagateTags": "SERVICE"
780782
},
781783
"DependsOn": [
782784
"FargateServiceLBPublicListenerECSGroupBE57E081",

packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.executionrole.expected.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,9 @@
606606
}
607607
]
608608
}
609-
}
609+
},
610+
"EnableECSManagedTags": true,
611+
"PropagateTags": "SERVICE"
610612
},
611613
"DependsOn": [
612614
"L3LBPublicListenerECSGroup648EEA11",

packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.expected.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,9 @@
257257
}
258258
]
259259
}
260-
}
260+
},
261+
"EnableECSManagedTags": true,
262+
"PropagateTags": "SERVICE"
261263
},
262264
"DependsOn": [
263265
"L3LBPublicListenerECSGroup648EEA11",
@@ -904,7 +906,9 @@
904906
}
905907
]
906908
}
907-
}
909+
},
910+
"EnableECSManagedTags": true,
911+
"PropagateTags": "SERVICE"
908912
},
909913
"DependsOn": [
910914
"L3bLBPublicListenerECSGroup0070C5CA",

packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.expected.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,9 @@
600600
}
601601
]
602602
}
603-
}
603+
},
604+
"EnableECSManagedTags": true,
605+
"PropagateTags": "SERVICE"
604606
},
605607
"DependsOn": [
606608
"L3LBPublicListenerECSGroup648EEA11",
@@ -1247,7 +1249,9 @@
12471249
}
12481250
]
12491251
}
1250-
}
1252+
},
1253+
"EnableECSManagedTags": true,
1254+
"PropagateTags": "SERVICE"
12511255
},
12521256
"DependsOn": [
12531257
"L3bLBPublicListenerECSGroup0070C5CA",
@@ -1551,7 +1555,9 @@
15511555
}
15521556
]
15531557
}
1554-
}
1558+
},
1559+
"EnableECSManagedTags": true,
1560+
"PropagateTags": "SERVICE"
15551561
},
15561562
"DependsOn": [
15571563
"L3cLBPublicListenerECSGroup62D7B705",

packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3.expected.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,8 @@
583583
}
584584
}
585585
],
586+
"EnableECSManagedTags": true,
587+
"PropagateTags": "SERVICE",
586588
"NetworkConfiguration": {
587589
"AwsvpcConfiguration": {
588590
"AssignPublicIp": "DISABLED",

0 commit comments

Comments
 (0)