Skip to content
2 changes: 1 addition & 1 deletion examples/cdk-examples-typescript/neptune-demo/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class NeptuneDemoStack extends cdk.Stack {
instanceProps: {
instanceType: new ec2.InstanceTypePair(ec2.InstanceClass.Burstable2, ec2.InstanceSize.Small),
vpc,
vpcPlacement: { usePublicSubnets: true },
vpcPlacement: { subnetsToUse: ec2.SubnetType.Public },
},
masterUser: {
// This would normally be imported from SSM parmeter store encrypted string,
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/assets/lib/asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export class Asset extends cdk.Construct {
description: `S3 key for asset version "${this.path}"`
});

this.s3BucketName = bucketParam.value;
this.s3BucketName = new s3.BucketName(bucketParam.value);
this.s3Prefix = new cdk.FnSelect(0, new cdk.FnSplit(cxapi.ASSET_PREFIX_SEPARATOR, keyParam.value));
const s3Filename = new cdk.FnSelect(1, new cdk.FnSplit(cxapi.ASSET_PREFIX_SEPARATOR, keyParam.value));
this.s3ObjectKey = new s3.ObjectKey(new cdk.FnConcat(this.s3Prefix, s3Filename));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ function mockVpc(stack: cdk.Stack) {
availabilityZones: [ 'az1' ],
publicSubnetIds: [ new ec2.SubnetId('pub1') ],
privateSubnetIds: [ new ec2.SubnetId('pri1') ],
isolatedSubnetIds: [],
});
}

Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-codebuild/lib/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,11 +303,11 @@ class ImportedProjectRef extends ProjectRef {
constructor(parent: cdk.Construct, name: string, props: ProjectRefProps) {
super(parent, name);

this.projectArn = cdk.Arn.fromComponents({
this.projectArn = new ProjectArn(cdk.Arn.fromComponents({
service: 'codebuild',
resource: 'project',
resourceName: props.projectName,
});
}));
this.projectName = props.projectName;
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-codecommit/lib/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,10 @@ class ImportedRepositoryRef extends RepositoryRef {
constructor(parent: cdk.Construct, name: string, props: RepositoryRefProps) {
super(parent, name);

this.repositoryArn = cdk.Arn.fromComponents({
this.repositoryArn = new RepositoryArn(cdk.Arn.fromComponents({
service: 'codecommit',
resource: props.repositoryName,
});
}));
this.repositoryName = props.repositoryName;
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-codedeploy/lib/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export abstract class ServerApplicationRef extends cdk.Construct {

public export(): ServerApplicationRefProps {
return {
applicationName: new cdk.Output(this, 'ApplicationName', { value: this.applicationName }).makeImportValue(),
applicationName: new ApplicationName(new cdk.Output(this, 'ApplicationName', { value: this.applicationName }).makeImportValue()),
};
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ export abstract class ServerDeploymentGroupRef extends cdk.Construct {
public export(): ServerDeploymentGroupRefProps {
return {
application: this.application,
deploymentGroupName: new cdk.Output(this, 'DeploymentGroupName', {
deploymentGroupName: new DeploymentGroupName(new cdk.Output(this, 'DeploymentGroupName', {
value: this.deploymentGroupName
}).makeImportValue(),
}).makeImportValue()),
};
}
}
Expand Down
156 changes: 156 additions & 0 deletions packages/@aws-cdk/aws-ec2/lib/util.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import cdk = require('@aws-cdk/cdk');
import { SubnetId } from './ec2.generated';
import { SubnetType, VpcSubnetRef } from "./vpc-ref";

/**
* Turn an arbitrary string into one that can be used as a CloudFormation identifier by stripping special characters
*
Expand All @@ -6,3 +10,155 @@
export function slugify(x: string): string {
return x.replace(/[^a-zA-Z0-9]/g, '');
}

/**
* The default names for every subnet type
*/
export const DEFAULT_SUBNET_NAME = {
[SubnetType.Public]: 'Public',
[SubnetType.Private]: 'Private',
[SubnetType.Isolated]: 'Isolated',
};

/**
* Return a subnet name from its construct ID
*
* All subnet names look like NAME <> "Subnet" <> INDEX
*/
export function subnetName(subnet: VpcSubnetRef) {
return subnet.id.replace(/Subnet\d+$/, '');
}

/**
* Make the subnet construct ID from a name and number
*/
export function subnetId(name: string, i: number) {
return `${name}Subnet${i + 1}`;
}

/**
* Helper class to export/import groups of subnets
*/
export class ExportSubnetGroup {
public readonly ids?: SubnetId[];
public readonly names?: string[];

private readonly groups: number;

constructor(
parent: cdk.Construct,
exportName: string,
private readonly subnets: VpcSubnetRef[],
private readonly type: SubnetType,
private readonly azs: number) {

this.groups = subnets.length / azs;

// ASSERTION
if (Math.floor(this.groups) !== this.groups) {
throw new Error(`Number of subnets (${subnets.length}) must be a multiple of number of availability zones (${azs})`);
}

this.ids = this.exportIds(parent, exportName);
this.names = this.exportNames();
}

private exportIds(parent: cdk.Construct, name: string): SubnetId[] | undefined {
if (this.subnets.length === 0) { return undefined; }
return new cdk.StringListOutput(parent, name, { values: this.subnets.map(s => s.subnetId) }).makeImportValues().map(x => new SubnetId(x));
}

/**
* Return the list of subnet names if they're not equal to the default
*/
private exportNames(): string[] | undefined {
if (this.subnets.length === 0) { return undefined; }
const netNames = this.subnets.map(subnetName);

// Do some assertion that the 'netNames' array is laid out like this:
//
// [ INGRESS, INGRESS, INGRESS, EGRESS, EGRESS, EGRESS, ... ]
for (let i = 0; i < netNames.length; i++) {
const k = Math.floor(i / this.azs);
if (netNames[i] !== netNames[k * this.azs]) {
throw new Error(`Subnets must be grouped by name, got: ${JSON.stringify(netNames)}`);
}
}

// Splat down to [ INGRESS, EGRESS, ... ]
const groupNames = range(this.groups).map(i => netNames[i * this.azs]);
if (groupNames.length === 1 && groupNames[0] === DEFAULT_SUBNET_NAME[this.type]) { return undefined; }

return groupNames;
}
}

export class ImportSubnetGroup {
private readonly subnetIds: SubnetId[];
private readonly names: string[];
private readonly groups: number;

constructor(
subnetIds: SubnetId[] | undefined,
names: string[] | undefined,
type: SubnetType,
private readonly availabilityZones: string[],
idField: string,
nameField: string) {

this.subnetIds = subnetIds || [];
this.groups = this.subnetIds.length / this.availabilityZones.length;

if (Math.floor(this.groups) !== this.groups) {
// tslint:disable-next-line:max-line-length
throw new Error(`Amount of ${idField} (${this.subnetIds.length}) must be a multiple of availability zones (${this.availabilityZones.length}).`);
}

this.names = this.normalizeNames(names, DEFAULT_SUBNET_NAME[type], nameField);
}

public import(parent: cdk.Construct): VpcSubnetRef[] {
return range(this.subnetIds.length).map(i => {
const k = Math.floor(i / this.availabilityZones.length);
return VpcSubnetRef.import(parent, subnetId(this.names[k], i), {
availabilityZone: this.pickAZ(i),
subnetId: this.subnetIds[i]
});
});
}

/**
* Return a list with a name for every subnet
*/
private normalizeNames(names: string[] | undefined, defaultName: string, fieldName: string) {
// If not given, return default
if (names === undefined || names.length === 0) {
return [defaultName];
}

// If given, must match given subnets
if (names.length !== this.groups) {
throw new Error(`${fieldName} must have an entry for every corresponding subnet group, got: ${JSON.stringify(names)}`);
}

return names;
}

/**
* Return the i'th AZ
*/
private pickAZ(i: number) {
return this.availabilityZones[i % this.availabilityZones.length];
}
}

/**
* Generate the list of numbers of [0..n)
*/
export function range(n: number): number[] {
const ret: number[] = [];
for (let i = 0; i < n; i++) {
ret.push(i);
}
return ret;
}
Loading