Skip to content

Commit

Permalink
feat(ec2): availabilityZone is optional when importing subnet
Browse files Browse the repository at this point in the history
availabilityZone attribute inside SubnetAttributes is only used for subnet selection.
AZ restrictions are not mandatory so making availabilityZone as optional.
Also as AZ is optional we should be able to search subnet using only subnet id.
Added fromSubnetId as well.

fixes #6607
  • Loading branch information
nirvana124 authored Mar 17, 2020
1 parent 43a3420 commit d10fe67
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 5 deletions.
26 changes: 24 additions & 2 deletions packages/@aws-cdk/aws-ec2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ new ec2.FlowLog(this, 'FlowLog', {
## User Data
User data enables you to run a script when your instances start up. In order to configure these scripts you can add commands directly to the script
or you can use the UserData's convenience functions to aid in the creation of your script.

A user data could be configured to run a script found in an asset through the following:
```ts
const asset = new Asset(this, 'Asset', {path: path.join(__dirname, 'configure.sh')});
Expand All @@ -576,4 +576,26 @@ instance.userData.addExecuteFileCommand({
arguments: '--verbose -y'
});
asset.grantRead( instance.role );
```
```

## Importing existing subnet

To import an existing Subnet, call `Subnet.fromSubnetAttributes()` or
`Subnet.fromSubnetId()`. Only if you supply the subnet's Availability Zone
and Route Table Ids when calling `Subnet.fromSubnetAttributes()` will you be
able to use the CDK features that use these values (such as selecting one
subnet per AZ).

Importing an existing subnet looks like this:

```ts
// Supply all properties
const subnet = Subnet.fromSubnetAttributes(this, 'SubnetFromAttributes', {
subnetId: 's-1234',
availabilityZone: 'pub-az-4465',
routeTableId: 'rt-145'
});

// Supply only subnet id
const subnet = Subnet.fromSubnetId(this, 'SubnetFromId', 's-1234');
```
27 changes: 24 additions & 3 deletions packages/@aws-cdk/aws-ec2/lib/vpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -563,8 +563,10 @@ export interface VpcAttributes {
export interface SubnetAttributes {
/**
* The Availability Zone the subnet is located in
*
* @default - No AZ information, cannot use AZ selection features
*/
readonly availabilityZone: string;
readonly availabilityZone?: string;

/**
* The subnetId for this particular subnet
Expand All @@ -573,6 +575,8 @@ export interface SubnetAttributes {

/**
* The ID of the route table for this particular subnet
*
* @default - No route table information, cannot create VPC endpoints
*/
readonly routeTableId?: string;
}
Expand Down Expand Up @@ -1316,6 +1320,15 @@ export class Subnet extends Resource implements ISubnet {
return new ImportedSubnet(scope, id, attrs);
}

/**
* Import existing subnet from id.
*/
// tslint:disable:no-shadowed-variable
public static fromSubnetId(scope: Construct, id: string, subnetId: string): ISubnet {
return this.fromSubnetAttributes(scope, id, { subnetId });
}
// tslint:enable:no-shadowed-variable

/**
* The Availability Zone the subnet is located in
*/
Expand Down Expand Up @@ -1770,9 +1783,9 @@ function tap<T>(x: T, fn: (x: T) => void): T {

class ImportedSubnet extends Resource implements ISubnet, IPublicSubnet, IPrivateSubnet {
public readonly internetConnectivityEstablished: IDependable = new ConcreteDependable();
public readonly availabilityZone: string;
public readonly subnetId: string;
public readonly routeTable: IRouteTable;
private readonly _availabilityZone?: string;

constructor(scope: Construct, id: string, attrs: SubnetAttributes) {
super(scope, id);
Expand All @@ -1785,14 +1798,22 @@ class ImportedSubnet extends Resource implements ISubnet, IPublicSubnet, IPrivat
scope.node.addWarning(`No routeTableId was provided to the subnet ${ref}. Attempting to read its .routeTable.routeTableId will return null/undefined. (More info: https://github.com/aws/aws-cdk/pull/3171)`);
}

this.availabilityZone = attrs.availabilityZone;
this._availabilityZone = attrs.availabilityZone;
this.subnetId = attrs.subnetId;
this.routeTable = {
// Forcing routeTableId to pretend non-null to maintain backwards-compatibility. See https://github.com/aws/aws-cdk/pull/3171
routeTableId: attrs.routeTableId!
};
}

public get availabilityZone(): string {
if (!this._availabilityZone) {
// tslint:disable-next-line: max-line-length
throw new Error("You cannot reference a Subnet's availability zone if it was not supplied. Add the availabilityZone when importing using Subnet.fromSubnetAttributes()");
}
return this._availabilityZone;
}

public associateNetworkAcl(id: string, networkAcl: INetworkAcl): void {
const scope = Construct.isConstruct(networkAcl) ? networkAcl : this;
const other = Construct.isConstruct(networkAcl) ? this : networkAcl;
Expand Down
52 changes: 52 additions & 0 deletions packages/@aws-cdk/aws-ec2/test/test.vpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,58 @@ export = {
test.deepEqual(subnetIds.length, 1);
test.deepEqual(subnetIds[0], subnet.subnetId);
test.done();
},

'subnet created from subnetId'(test: Test) {
// GIVEN
const stack = getTestStack();

// WHEN
const subnet = Subnet.fromSubnetId(stack, 'subnet1', 'pub-1');

// THEN
test.deepEqual(subnet.subnetId, 'pub-1');
test.done();
},

'Referencing AZ throws error when subnet created from subnetId'(test: Test) {
// GIVEN
const stack = getTestStack();

// WHEN
const subnet = Subnet.fromSubnetId(stack, 'subnet1', 'pub-1');

// THEN
// tslint:disable-next-line: max-line-length
test.throws(() => subnet.availabilityZone, "You cannot reference a Subnet's availability zone if it was not supplied. Add the availabilityZone when importing using Subnet.fromSubnetAttributes()");
test.done();
},

'Referencing AZ throws error when subnet created from attributes without az'(test: Test) {
// GIVEN
const stack = getTestStack();

// WHEN
const subnet = Subnet.fromSubnetAttributes(stack, 'subnet1', { subnetId : 'pub-1', availabilityZone: '' });

// THEN
test.deepEqual(subnet.subnetId, 'pub-1');
// tslint:disable-next-line: max-line-length
test.throws(() => subnet.availabilityZone, "You cannot reference a Subnet's availability zone if it was not supplied. Add the availabilityZone when importing using Subnet.fromSubnetAttributes()");
test.done();
},

'AZ have value when subnet created from attributes with az'(test: Test) {
// GIVEN
const stack = getTestStack();

// WHEN
const subnet = Subnet.fromSubnetAttributes(stack, 'subnet1', { subnetId : 'pub-1', availabilityZone: 'az-1234' });

// THEN
test.deepEqual(subnet.subnetId, 'pub-1');
test.deepEqual(subnet.availabilityZone, 'az-1234');
test.done();
}

},
Expand Down

0 comments on commit d10fe67

Please sign in to comment.