Skip to content

Commit f7c8531

Browse files
moofish32Elad Ben-Israel
authored andcommitted
feat(cdk): aspect framework and tag implementation (#1451)
A generalized aspect framework is added. Aspects can be used to affect the construct tree without modifying the class hierarchy. This framework is designed to be generic for future use cases. Tagging is the first implementation. Tagging has been reimplemented to leverage the aspect framework and simplify the original tag design. Tag Manager still exists, but is no longer intended for use by L2 construct authors. There are two new classes `cdk.Tag` and `cdk.RemoveTag`. As new resources are added tag support will be automatic as long as they implement one of the existing tag specifications. All L2 constructs have removed the TagManager. Code generation has been modified to add tag support to any CloudFormation Resource with a matching specification, by creating a Tag Manager for that resource as a `tags` attribute. The schema code now includes the ability to detect 3 forms of tags which include the current CloudFormation Resources. BREAKING CHANGE: if you are using TagManager the API for this object has completely changed. You should no longer use TagManager directly, but instead replace this with Tag Aspects. `cdk.Tag` has been renamed to `cdk.CfnTag` to enable `cdk.Tag` to be the Tag Aspect. Fixes #1136 Fixes #1497 Related #360
1 parent 36cfca8 commit f7c8531

36 files changed

+1711
-1473
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"app": "node index"
3+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import ec2 = require('@aws-cdk/aws-ec2');
2+
import ecs = require('@aws-cdk/aws-ecs');
3+
import cdk = require('@aws-cdk/cdk');
4+
5+
const COST_CENTER_KEY = 'CostCenter';
6+
7+
class MarketingDepartmentStack extends cdk.Stack {
8+
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
9+
super(scope, id, props);
10+
11+
// Create VPC and Fargate Cluster
12+
// NOTE: Limit AZs to avoid reaching resource quotas
13+
const vpc = new ec2.VpcNetwork(this, 'MyVpc', { maxAZs: 3 });
14+
15+
// override cost center to platform
16+
vpc.apply(new cdk.Tag(COST_CENTER_KEY, 'Platform'));
17+
18+
const cluster = new ecs.Cluster(this, 'Cluster', { vpc });
19+
20+
// Create a load-balanced Fargate service and make it public
21+
const b2b = new ecs.LoadBalancedFargateService(this, 'B2BService', {
22+
cluster, // Required
23+
cpu: '512', // Default is 256
24+
desiredCount: 6, // Default is 1
25+
image: ecs.ContainerImage.fromDockerHub('amazon/amazon-ecs-sample'), // Required
26+
memoryMiB: '2048', // Default is 512
27+
publicLoadBalancer: true // Default is false
28+
});
29+
30+
// Create a load-balanced Fargate service and make it public
31+
const b2c = new ecs.LoadBalancedFargateService(this, 'B2CService', {
32+
cluster, // Required
33+
cpu: '512', // Default is 256
34+
desiredCount: 6, // Default is 1
35+
image: ecs.ContainerImage.fromDockerHub('amazon/amazon-ecs-sample'), // Required
36+
memoryMiB: '2048', // Default is 512
37+
publicLoadBalancer: true // Default is false
38+
});
39+
40+
// Output the DNS where you can access your service
41+
new cdk.Output(this, 'B2BLoadBalancerDNS', { value: b2b.loadBalancer.dnsName });
42+
new cdk.Output(this, 'B2CLoadBalancerDNS', { value: b2c.loadBalancer.dnsName });
43+
}
44+
}
45+
46+
const app = new cdk.App();
47+
48+
// by default bill everything to marketing overrides are in the stack
49+
app.apply(new cdk.Tag(COST_CENTER_KEY, 'Marketing'));
50+
51+
new MarketingDepartmentStack(app, 'Bonjour');
52+
53+
app.run();

packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,6 @@ export interface AutoScalingGroupProps {
137137
*/
138138
resourceSignalTimeoutSec?: number;
139139

140-
/**
141-
* The AWS resource tags to associate with the ASG.
142-
*/
143-
tags?: cdk.Tags;
144-
145140
/**
146141
* Default scaling cooldown for this AutoScalingGroup
147142
*
@@ -169,7 +164,7 @@ export interface AutoScalingGroupProps {
169164
*
170165
* The ASG spans all availability zones.
171166
*/
172-
export class AutoScalingGroup extends cdk.Construct implements IAutoScalingGroup, cdk.ITaggable, elb.ILoadBalancerTarget, ec2.IConnectable,
167+
export class AutoScalingGroup extends cdk.Construct implements IAutoScalingGroup, elb.ILoadBalancerTarget, ec2.IConnectable,
173168
elbv2.IApplicationLoadBalancerTarget, elbv2.INetworkLoadBalancerTarget {
174169
/**
175170
* The type of OS instances of this fleet are running.
@@ -186,11 +181,6 @@ export class AutoScalingGroup extends cdk.Construct implements IAutoScalingGroup
186181
*/
187182
public readonly role: iam.Role;
188183

189-
/**
190-
* Manage tags for this construct and children
191-
*/
192-
public readonly tags: cdk.TagManager;
193-
194184
/**
195185
* Name of the AutoScalingGroup
196186
*/
@@ -217,8 +207,7 @@ export class AutoScalingGroup extends cdk.Construct implements IAutoScalingGroup
217207
});
218208
this.connections = new ec2.Connections({ securityGroups: [this.securityGroup] });
219209
this.securityGroups.push(this.securityGroup);
220-
this.tags = new TagManager(this, {initialTags: props.tags});
221-
this.tags.setTag(NAME_TAG, this.node.path, { overwrite: false });
210+
this.apply(new cdk.Tag(NAME_TAG, this.node.path));
222211

223212
this.role = new iam.Role(this, 'InstanceRole', {
224213
assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com')
@@ -264,7 +253,6 @@ export class AutoScalingGroup extends cdk.Construct implements IAutoScalingGroup
264253
launchConfigurationName: launchConfig.ref,
265254
loadBalancerNames: new cdk.Token(() => this.loadBalancerNames.length > 0 ? this.loadBalancerNames : undefined),
266255
targetGroupArns: new cdk.Token(() => this.targetGroupArns.length > 0 ? this.targetGroupArns : undefined),
267-
tags: this.tags,
268256
};
269257

270258
if (props.notificationsTopic) {
@@ -623,16 +611,6 @@ function renderRollingUpdateConfig(config: RollingUpdateConfiguration = {}): cdk
623611
};
624612
}
625613

626-
class TagManager extends cdk.TagManager {
627-
protected tagFormatResolve(tagGroups: cdk.TagGroups): any {
628-
const tags = {...tagGroups.nonStickyTags, ...tagGroups.ancestorTags, ...tagGroups.stickyTags};
629-
return Object.keys(tags).map( (key) => {
630-
const propagateAtLaunch = !!tagGroups.propagateTags[key] || !!tagGroups.ancestorTags[key];
631-
return {key, value: tags[key], propagateAtLaunch};
632-
});
633-
}
634-
}
635-
636614
/**
637615
* Render a number of seconds to a PTnX string.
638616
*/

packages/@aws-cdk/aws-autoscaling/test/test.auto-scaling-group.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import autoscaling = require('../lib');
99

1010
export = {
1111
'default fleet'(test: Test) {
12-
const stack = new cdk.Stack(undefined, 'MyStack', { env: { region: 'us-east-1', account: '1234' }});
12+
const stack = getTestStack();
1313
const vpc = mockVpc(stack);
1414

1515
new autoscaling.AutoScalingGroup(stack, 'MyFleet', {
@@ -365,7 +365,8 @@ export = {
365365
},
366366
'can set tags'(test: Test) {
367367
// GIVEN
368-
const stack = new cdk.Stack(undefined, 'MyStack', { env: { region: 'us-east-1', account: '1234' }});
368+
const stack = getTestStack();
369+
// new cdk.Stack(undefined, 'MyStack', { env: { region: 'us-east-1', account: '1234' }});
369370
const vpc = mockVpc(stack);
370371

371372
// WHEN
@@ -378,27 +379,27 @@ export = {
378379
minSuccessfulInstancesPercent: 50,
379380
pauseTimeSec: 345
380381
},
381-
tags: {superfood: 'acai'},
382382
});
383-
asg.tags.setTag('notsuper', 'caramel', {propagate: false});
383+
asg.apply( new cdk.Tag('superfood', 'acai'));
384+
asg.apply( new cdk.Tag('notsuper', 'caramel', { applyToLaunchedInstances: false }));
384385

385386
// THEN
386387
expect(stack).to(haveResource("AWS::AutoScaling::AutoScalingGroup", {
387388
Tags: [
388389
{
389-
Key: 'superfood',
390-
Value: 'acai',
390+
Key: 'Name',
391391
PropagateAtLaunch: true,
392+
Value: 'MyFleet',
392393
},
393394
{
394-
Key: 'Name',
395-
Value: 'MyFleet',
395+
Key: 'superfood',
396396
PropagateAtLaunch: true,
397+
Value: 'acai',
397398
},
398399
{
399400
Key: 'notsuper',
400-
Value: 'caramel',
401401
PropagateAtLaunch: false,
402+
Value: 'caramel',
402403
},
403404
]
404405
}));
@@ -494,3 +495,7 @@ function mockSecurityGroup(stack: cdk.Stack) {
494495
securityGroupId: 'most-secure',
495496
});
496497
}
498+
499+
function getTestStack(): cdk.Stack {
500+
return new cdk.Stack(undefined, 'TestStack', { env: { account: '1234', region: 'us-east-1' } });
501+
}

packages/@aws-cdk/aws-autoscaling/test/test.scheduled-action.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { expect, haveResource, MatchStyle } from '@aws-cdk/assert';
1+
import { expect, haveResource, MatchStyle, } from '@aws-cdk/assert';
22
import ec2 = require('@aws-cdk/aws-ec2');
33
import cdk = require('@aws-cdk/cdk');
44
import { Test } from 'nodeunit';
@@ -111,4 +111,4 @@ function makeAutoScalingGroup(scope: cdk.Construct) {
111111
machineImage: new ec2.AmazonLinuxImage(),
112112
updateType: autoscaling.UpdateType.RollingUpdate,
113113
});
114-
}
114+
}

packages/@aws-cdk/aws-dynamodb/lib/table.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import appscaling = require('@aws-cdk/aws-applicationautoscaling');
22
import iam = require('@aws-cdk/aws-iam');
33
import cdk = require('@aws-cdk/cdk');
4-
import { Construct, TagManager, Tags, Token } from '@aws-cdk/cdk';
4+
import { Construct, Token } from '@aws-cdk/cdk';
55
import { CfnTable } from './dynamodb.generated';
66
import { EnableScalingProps, IScalableTableAttribute } from './scalable-attribute-api';
77
import { ScalableTableAttribute } from './scalable-table-attribute';
@@ -94,12 +94,6 @@ export interface TableProps {
9494
*/
9595
streamSpecification?: StreamViewType;
9696

97-
/**
98-
* The AWS resource tags to associate with the table.
99-
* @default undefined
100-
*/
101-
tags?: Tags;
102-
10397
/**
10498
* The name of TTL attribute.
10599
* @default undefined, TTL is disabled
@@ -234,7 +228,6 @@ export class Table extends Construct {
234228
},
235229
sseSpecification: props.sseEnabled ? { sseEnabled: props.sseEnabled } : undefined,
236230
streamSpecification: props.streamSpecification ? { streamViewType: props.streamSpecification } : undefined,
237-
tags: new TagManager(this, { initialTags: props.tags }),
238231
timeToLiveSpecification: props.ttlAttributeName ? { attributeName: props.ttlAttributeName, enabled: true } : undefined
239232
});
240233

packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { App, Stack } from '@aws-cdk/cdk';
1+
import { App, Stack, Tag } from '@aws-cdk/cdk';
22
import { Attribute, AttributeType, BillingMode, ProjectionType, StreamViewType, Table } from '../lib';
33

44
// CDK parameters
@@ -48,11 +48,12 @@ const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL
4848
pitrEnabled: true,
4949
sseEnabled: true,
5050
streamSpecification: StreamViewType.KeysOnly,
51-
tags: { Environment: 'Production' },
5251
billingMode: BillingMode.PayPerRequest,
5352
ttlAttributeName: 'timeToLive'
5453
});
5554

55+
tableWithGlobalAndLocalSecondaryIndex.apply(new Tag('Environment', 'Production'));
56+
5657
tableWithGlobalAndLocalSecondaryIndex.addPartitionKey(TABLE_PARTITION_KEY);
5758
tableWithGlobalAndLocalSecondaryIndex.addSortKey(TABLE_SORT_KEY);
5859
tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({

packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import iam = require('@aws-cdk/aws-iam');
2-
import { App, Stack } from '@aws-cdk/cdk';
2+
import { App, Stack, Tag } from '@aws-cdk/cdk';
33
import { Attribute, AttributeType, ProjectionType, StreamViewType, Table } from '../lib';
44

55
// CDK parameters
@@ -48,10 +48,10 @@ const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL
4848
pitrEnabled: true,
4949
sseEnabled: true,
5050
streamSpecification: StreamViewType.KeysOnly,
51-
tags: { Environment: 'Production' },
5251
ttlAttributeName: 'timeToLive'
5352
});
5453

54+
tableWithGlobalAndLocalSecondaryIndex.apply(new Tag('Environment', 'Production'));
5555
tableWithGlobalAndLocalSecondaryIndex.addPartitionKey(TABLE_PARTITION_KEY);
5656
tableWithGlobalAndLocalSecondaryIndex.addSortKey(TABLE_SORT_KEY);
5757
tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({

0 commit comments

Comments
 (0)