Skip to content

Commit

Permalink
feat(cfn2ts) Add support for Aspects (#1007)
Browse files Browse the repository at this point in the history
 * The first aspects are for tags
 * TagManager is now deprecated and aspects are preferred
 * Tags can propagate to a depth by number
 * Tags can be included or excluded based on Resource Type
  • Loading branch information
moofish32 committed Dec 29, 2018
1 parent 7cd84a0 commit b05e492
Show file tree
Hide file tree
Showing 17 changed files with 720 additions and 179 deletions.
1 change: 1 addition & 0 deletions packages/@aws-cdk/assert/lib/expect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export function expect(stack: api.SynthesizedStack | cdk.Stack, skipValidation =
}
}

stack.visit();
sstack = {
name: 'test',
template: stack.toCloudFormation(),
Expand Down
13 changes: 2 additions & 11 deletions packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ export class AutoScalingGroup extends cdk.Construct implements IAutoScalingGroup
});
this.connections = new ec2.Connections({ securityGroups: [this.securityGroup] });
this.securityGroups.push(this.securityGroup);
this.tags = new TagManager(this, {initialTags: props.tags});
this.tags = new cdk.TagManager(this, {initialTags: props.tags,
tagFormatter: new cdk.AutoScalingGroupTagFormatter()});
this.tags.setTag(NAME_TAG, this.path, { overwrite: false });

this.role = new iam.Role(this, 'InstanceRole', {
Expand Down Expand Up @@ -616,16 +617,6 @@ function renderRollingUpdateConfig(config: RollingUpdateConfiguration = {}): cdk
};
}

class TagManager extends cdk.TagManager {
protected tagFormatResolve(tagGroups: cdk.TagGroups): any {
const tags = {...tagGroups.nonStickyTags, ...tagGroups.ancestorTags, ...tagGroups.stickyTags};
return Object.keys(tags).map( (key) => {
const propagateAtLaunch = !!tagGroups.propagateTags[key] || !!tagGroups.ancestorTags[key];
return {key, value: tags[key], propagateAtLaunch};
});
}
}

/**
* Render a number of seconds to a PTnX string.
*/
Expand Down
1 change: 0 additions & 1 deletion packages/@aws-cdk/aws-ec2/lib/security-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ export class SecurityGroup extends SecurityGroupBase implements ITaggable {
securityGroupIngress: new Token(() => this.directIngressRules),
securityGroupEgress: new Token(() => this.directEgressRules),
vpcId: props.vpc.vpcId,
tags: this.tags,
});

this.securityGroupId = this.securityGroup.securityGroupId;
Expand Down
49 changes: 21 additions & 28 deletions packages/@aws-cdk/aws-ec2/lib/vpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ export interface SubnetConfiguration {
*
* }
*/
export class VpcNetwork extends VpcNetworkBase implements cdk.ITaggable {
export class VpcNetwork extends VpcNetworkBase {
/**
* @returns The IPv4 CidrBlock as returned by the VPC
*/
Expand Down Expand Up @@ -254,11 +254,6 @@ export class VpcNetwork extends VpcNetworkBase implements cdk.ITaggable {
*/
public readonly availabilityZones: string[];

/**
* Manage tags for this construct and children
*/
public readonly tags: cdk.TagManager;

/**
* The VPC resource
*/
Expand Down Expand Up @@ -293,8 +288,12 @@ export class VpcNetwork extends VpcNetworkBase implements cdk.ITaggable {
throw new Error('To use DNS Hostnames, DNS Support must be enabled, however, it was explicitly disabled.');
}

this.tags = new cdk.TagManager(this, { initialTags: props.tags});
this.tags.setTag(NAME_TAG, this.path, { overwrite: false });
// set first and let initial tags overwrite
this.apply(new cdk.TagAspect(NAME_TAG, this.path));
const tags = props.tags || {};
for (const key of Object.keys(tags)) {
this.apply(new cdk.TagAspect(key, tags[key]));
}

const cidrBlock = ifUndefined(props.cidr, VpcNetwork.DEFAULT_CIDR_RANGE);
this.networkBuilder = new NetworkBuilder(cidrBlock);
Expand All @@ -309,7 +308,6 @@ export class VpcNetwork extends VpcNetworkBase implements cdk.ITaggable {
enableDnsHostnames,
enableDnsSupport,
instanceTenancy,
tags: this.tags,
});

this.availabilityZones = new cdk.AvailabilityZoneProvider(this).availabilityZones;
Expand All @@ -330,9 +328,7 @@ export class VpcNetwork extends VpcNetworkBase implements cdk.ITaggable {

// Create an Internet Gateway and attach it if necessary
if (allowOutbound) {
const igw = new CfnInternetGateway(this, 'IGW', {
tags: new cdk.TagManager(this),
});
const igw = new CfnInternetGateway(this, 'IGW');
this.internetDependencies.push(igw);
const att = new CfnVPCGatewayAttachment(this, 'VPCGW', {
internetGatewayId: igw.ref,
Expand Down Expand Up @@ -456,7 +452,6 @@ export class VpcNetwork extends VpcNetworkBase implements cdk.ITaggable {
break;
case SubnetType.Isolated:
const isolatedSubnet = new VpcPrivateSubnet(this, name, subnetProps);
isolatedSubnet.tags.setTag(SUBNETTYPE_TAG, subnetTypeTagValue(subnetConfig.subnetType));
this.isolatedSubnets.push(isolatedSubnet);
subnet = isolatedSubnet;
break;
Expand All @@ -465,8 +460,10 @@ export class VpcNetwork extends VpcNetworkBase implements cdk.ITaggable {
}

// These values will be used to recover the config upon provider import
subnet.tags.setTag(SUBNETNAME_TAG, subnetConfig.name, { propagate: false });
subnet.tags.setTag(SUBNETTYPE_TAG, subnetTypeTagValue(subnetConfig.subnetType), { propagate: false });
const include = [CfnSubnet.resourceTypeName];
subnet.apply(new cdk.TagAspect(SUBNETNAME_TAG, subnetConfig.name, { include }));
subnet.apply(new cdk.TagAspect(
SUBNETTYPE_TAG, subnetTypeTagValue(subnetConfig.subnetType), { include }));
});
}
}
Expand Down Expand Up @@ -518,7 +515,7 @@ export interface VpcSubnetProps {
/**
* Represents a new VPC subnet resource
*/
export class VpcSubnet extends cdk.Construct implements IVpcSubnet, cdk.ITaggable, cdk.IDependable {
export class VpcSubnet extends cdk.Construct implements IVpcSubnet, cdk.IDependable {
public static import(parent: cdk.Construct, name: string, props: VpcSubnetImportProps): IVpcSubnet {
return new ImportedVpcSubnet(parent, name, props);
}
Expand All @@ -533,11 +530,6 @@ export class VpcSubnet extends cdk.Construct implements IVpcSubnet, cdk.ITaggabl
*/
public readonly subnetId: string;

/**
* Manage tags for Construct and propagate to children
*/
public readonly tags: cdk.TagManager;

/**
* Parts of this VPC subnet
*/
Expand All @@ -550,21 +542,23 @@ export class VpcSubnet extends cdk.Construct implements IVpcSubnet, cdk.ITaggabl

constructor(parent: cdk.Construct, name: string, props: VpcSubnetProps) {
super(parent, name);
this.tags = new cdk.TagManager(this, {initialTags: props.tags});
this.tags.setTag(NAME_TAG, this.path, {overwrite: false});
// set first and let initial tags overwrite
this.apply(new cdk.TagAspect(NAME_TAG, this.path));
const tags = props.tags || {};
for (const key of Object.keys(tags)) {
this.apply(new cdk.TagAspect(key, tags[key]));
}

this.availabilityZone = props.availabilityZone;
const subnet = new CfnSubnet(this, 'Subnet', {
vpcId: props.vpcId,
cidrBlock: props.cidrBlock,
availabilityZone: props.availabilityZone,
mapPublicIpOnLaunch: props.mapPublicIpOnLaunch,
tags: this.tags,
});
this.subnetId = subnet.subnetId;
const table = new CfnRouteTable(this, 'RouteTable', {
vpcId: props.vpcId,
tags: new cdk.TagManager(this),
});
this.routeTableId = table.ref;

Expand Down Expand Up @@ -636,9 +630,8 @@ export class VpcPublicSubnet extends VpcSubnet {
const ngw = new CfnNatGateway(this, `NATGateway`, {
subnetId: this.subnetId,
allocationId: new CfnEIP(this, `EIP`, {
domain: 'vpc'
domain: 'vpc',
}).eipAllocationId,
tags: new cdk.TagManager(this),
});
return ngw.natGatewayId;
}
Expand Down Expand Up @@ -708,4 +701,4 @@ export class ImportedVpcSubnet extends cdk.Construct implements IVpcSubnet {
public export() {
return this.props;
}
}
}
75 changes: 38 additions & 37 deletions packages/@aws-cdk/aws-ec2/test/test.vpc.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { countResources, expect, haveResource, haveResourceLike, isSuperObject } from '@aws-cdk/assert';
import { AvailabilityZoneProvider, Construct, resolve, Stack, Tags } from '@aws-cdk/cdk';
import { AvailabilityZoneProvider, Construct, resolve, Stack, TagAspect, Tags } from '@aws-cdk/cdk';
import { Test } from 'nodeunit';
import { DefaultInstanceTenancy, IVpcNetwork, SubnetType, VpcNetwork } from '../lib';
import { CfnVPC, DefaultInstanceTenancy, IVpcNetwork, SubnetType, VpcNetwork } from '../lib';

export = {
"When creating a VPC": {
Expand All @@ -28,8 +28,10 @@ export = {
'the Name tag is defaulted to path'(test: Test) {
const stack = getTestStack();
new VpcNetwork(stack, 'TheVPC');
expect(stack).to(haveResource('AWS::EC2::VPC',
hasTags( [ {Key: 'Name', Value: 'TheVPC'} ])));
expect(stack).to(
haveResource('AWS::EC2::VPC',
hasTags( [ {Key: 'Name', Value: 'TheVPC'} ]))
);
test.done();
},

Expand Down Expand Up @@ -124,25 +126,25 @@ export = {
new VpcNetwork(stack, 'TheVPC', {
cidr: '10.0.0.0/21',
subnetConfiguration: [
{
cidrMask: 24,
name: 'ingress',
subnetType: SubnetType.Public,
tags: {
type: 'Public',
init: 'No',
{
cidrMask: 24,
name: 'ingress',
subnetType: SubnetType.Public,
tags: {
type: 'Public',
init: 'No',
},
},
},
{
cidrMask: 24,
name: 'application',
subnetType: SubnetType.Private,
},
{
cidrMask: 28,
name: 'rds',
subnetType: SubnetType.Isolated,
}
{
cidrMask: 24,
name: 'application',
subnetType: SubnetType.Private,
},
{
cidrMask: 28,
name: 'rds',
subnetType: SubnetType.Isolated,
}
],
maxAZs: 3
});
Expand All @@ -151,12 +153,12 @@ export = {
expect(stack).to(countResources("AWS::EC2::Subnet", 9));
for (let i = 0; i < 6; i++) {
expect(stack).to(haveResource("AWS::EC2::Subnet", {
CidrBlock: `10.0.${i}.0/24`
CidrBlock: `10.0.${i}.0/24`
}));
}
for (let i = 0; i < 3; i++) {
expect(stack).to(haveResource("AWS::EC2::Subnet", {
CidrBlock: `10.0.6.${i * 16}/28`
CidrBlock: `10.0.6.${i * 16}/28`
}));
}
expect(stack).to(haveResource("AWS::EC2::Subnet", hasTags(
Expand Down Expand Up @@ -289,14 +291,10 @@ export = {
});
expect(stack).to(countResources("AWS::EC2::NatGateway", 3));
for (let i = 1; i < 4; i++) {
expect(stack).to(haveResource("AWS::EC2::NatGateway", {
Tags: [
{
Key: 'Name',
Value: `VPC/egressSubnet${i}`,
}
]
}));
expect(stack).to(haveResource('AWS::EC2::Subnet', hasTags([{
Key: 'Name',
Value: `VPC/egressSubnet${i}`,
}])));
}
test.done();
},
Expand Down Expand Up @@ -345,9 +343,9 @@ export = {
};
const allTags: Tags = {...tags, ...noPropTags};

const vpc = new VpcNetwork(stack, 'TheVPC', { tags: allTags });
const vpc = new VpcNetwork(stack, 'TheVPC', { tags });
// overwrite to set propagate
vpc.tags.setTag('BusinessUnit', 'Marketing', {propagate: false});
vpc.apply(new TagAspect('BusinessUnit', 'Marketing', {include: [CfnVPC.resourceTypeName]}));
expect(stack).to(haveResource("AWS::EC2::VPC", hasTags(toCfnTags(allTags))));
const taggables = ['Subnet', 'InternetGateway', 'NatGateway', 'RouteTable'];
const propTags = toCfnTags(tags);
Expand Down Expand Up @@ -377,7 +375,7 @@ export = {
const vpc = new VpcNetwork(stack, 'TheVPC');
const tag = {Key: 'Late', Value: 'Adder'};
expect(stack).notTo(haveResource('AWS::EC2::VPC', hasTags([tag])));
vpc.tags.setTag(tag.Key, tag.Value);
vpc.apply(new TagAspect(tag.Key, tag.Value));
expect(stack).to(haveResource('AWS::EC2::VPC', hasTags([tag])));
test.done();
},
Expand Down Expand Up @@ -565,8 +563,11 @@ function hasTags(expectedTags: Array<{Key: string, Value: string}>): (props: any
});
return actualTags.length === expectedTags.length;
} catch (e) {
// tslint:disable-next-line:no-console
console.error('Invalid Tags array in ', props);
// tslint:disable:no-console
console.error('Tags are incorrect');
console.error('found tags ', props.Tags);
console.error('expected tags ', expectedTags);
// tslint:enable:no-console
throw e;
}
};
Expand Down
5 changes: 4 additions & 1 deletion packages/@aws-cdk/cdk/lib/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ export class App extends Root {
region
};

// visit all aspects
this.visit();

const missing = Object.keys(stack.missingContext).length ? stack.missingContext : undefined;
return {
name: stack.id,
Expand Down Expand Up @@ -226,4 +229,4 @@ function getJsiiAgentVersion() {
}

return jsiiAgent;
}
}
Loading

0 comments on commit b05e492

Please sign in to comment.