Skip to content

Commit

Permalink
Allow using specific zones when creating a VPC. (#638)
Browse files Browse the repository at this point in the history
  • Loading branch information
seivan authored Nov 24, 2021
1 parent 1baa616 commit 48df96d
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 22 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ CHANGELOG
=========

## HEAD (Unreleased)

* Introduce `requestedAvailabilityZone` on `ec2.vps.VpcArgs` that takes `number | "all" | string[]`, to allow specific zones for creating a VPC.
* Extend the `volumeSize` of the default root block device in ECS
autoscaling launch configuration to 32 GB to accomodate the latest
default AMI snapshot size
Expand Down
12 changes: 6 additions & 6 deletions nodejs/awsx/ec2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,21 @@ const vpc = new awsx.ec2.Vpc("custom", {
});
```

This range will then be partitioned accordingly into the VPC depending on the other arguments provided. The additional arguments that affect this partitioning are `subnets` and `numberOfAvailabilityZones`.
This range will then be partitioned accordingly into the VPC depending on the other arguments provided. The additional arguments that affect this partitioning are `subnets` and `requestedAvailabilityZones`.

### Availability Zones

Availability Zones are distinct locations that are engineered to be isolated from failures in other Availability Zones. By launching instances in separate Availability Zones, you can protect your applications from the failure of a single location

If not provided `numberOfAvailabilityZones` will default to `2`, but a different value can be specified like so if appropriate for your region:
Not providing a list of zones for `requestedAvailabilityZones` will default to `2`, but a different value can be specified like so if appropriate for your region:

```ts
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

const vpc = new awsx.ec2.Vpc("custom", {
cidrBlock: "10.0.0.0/16",
numberOfAvailabilityZones: 3,
requestedAvailabilityZones: 3,
});
```

Expand Down Expand Up @@ -77,7 +77,7 @@ import * as awsx from "@pulumi/awsx";

const vpc = new awsx.ec2.Vpc("custom", {
cidrBlock: "10.0.0.0/16",
numberOfAvailabilityZones: 3,
requestedAvailabilityZones: 3,
subnets: [{ type: "public" }, { type: "private" }, { type: isolated }],
});
```
Expand All @@ -90,7 +90,7 @@ import * as awsx from "@pulumi/awsx";

const vpc = new awsx.ec2.Vpc("custom", {
cidrBlock: "10.0.0.0/16",
numberOfAvailabilityZones: 3,
requestedAvailabilityZones: 3,
subnets: [
{ type: "public" },
{ type: "private" },
Expand All @@ -113,7 +113,7 @@ import * as awsx from "@pulumi/awsx";

const vpc = new awsx.ec2.Vpc("custom", {
cidrBlock: "10.0.0.0/16",
numberOfAvailabilityZones: 3,
requestedAvailabilityZones: 3,
numberOfNatGateways: 1,
});
```
Expand Down
35 changes: 22 additions & 13 deletions nodejs/awsx/ec2/vpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ export class Vpc extends pulumi.ComponentResource<VpcData> {
/** @internal */
public async initializeVpcArgs(name: string, args: x.ec2.VpcArgs, opts: pulumi.ComponentResourceOptions): Promise<VpcData> {
const provider = Vpc.getProvider(opts);
const availabilityZones = await getAvailabilityZones(opts.parent, provider, args.numberOfAvailabilityZones);
const availabilityZones = await getAvailabilityZones(opts.parent, provider, args.requestedAvailabilityZones ?? args.numberOfAvailabilityZones);

return new VpcData(name, this, {
...args,
Expand Down Expand Up @@ -504,23 +504,30 @@ utils.Capture(Vpc.prototype).initializeVpcArgs.doNotCapture = true;
async function getAvailabilityZones(
parent: pulumi.Resource | undefined,
provider: pulumi.ProviderResource | undefined,
requestedCount: "all" | number | undefined): Promise<topology.AvailabilityZoneDescription[]> {
requestedZones: VpcArgs["requestedAvailabilityZones"] = 2): Promise<topology.AvailabilityZoneDescription[]> {

const result = await aws.getAvailabilityZones(/*args:*/ undefined, { provider, async: true });
if (result.names.length !== result.zoneIds.length) {
throw new pulumi.ResourceError("Availability zones for region had mismatched names and ids.", parent);
}

const descriptions: topology.AvailabilityZoneDescription[] = [];
for (let i = 0, n = result.names.length; i < n; i++) {
descriptions.push({ name: result.names[i], id: result.zoneIds[i] });
}

const count =
typeof requestedCount === "number" ? requestedCount :
requestedCount === "all" ? descriptions.length : 2;
const descriptions = result.names.map((name, idx) => ({ name, id: result.zoneIds[idx] }) );

if (Array.isArray(requestedZones) || typeof requestedZones === "object" ) {
return new Promise((resolve, reject) => {
pulumi.Output.create(requestedZones).apply(requestedZones => {
const mappedZones = descriptions.filter(zone => requestedZones.includes(zone.name));
mappedZones.length === requestedZones.length ?
resolve(mappedZones) :
reject(new pulumi.ResourceError("Availability zones did not match requested zones", parent));
});
});
}
else {
return descriptions.slice(0, requestedZones === "all" ? descriptions.length : requestedZones);
}

return descriptions.slice(0, count);
}

function getExistingSubnets(vpcData: VpcData, vpc: Vpc, vpcName: string, type: VpcSubnetType, inputs: pulumi.Input<string>[] = []) {
Expand Down Expand Up @@ -702,10 +709,12 @@ export interface VpcArgs {
subnets?: VpcSubnetArgs[];

/**
* The maximum number of availability zones to use in the current region. Defaults to `2` if
* unspecified. Use `"all"` to use all the availability zones in the current region.
* The names of the availability zones to use in the current region. Defaults to `2` if
* unspecified. Use `"all"` to use all the availability zones in the current region.
*/
numberOfAvailabilityZones?: number | "all";
requestedAvailabilityZones?: number | "all" | [string, ...string[]] | pulumi.Input<string[]>;

numberOfAvailabilityZones?: VpcArgs["requestedAvailabilityZones"];

/**
* The max number of NAT gateways to create if there are any private subnets created. A NAT
Expand Down
21 changes: 20 additions & 1 deletion nodejs/examples/vpc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";
import * as random from "@pulumi/random";

const config = new pulumi.Config("aws");
const providerOpts = { provider: new aws.Provider("prov", { region: <aws.Region>config.require("envRegion") }) };
Expand Down Expand Up @@ -53,4 +54,22 @@ const vpcWithLocations = new awsx.ec2.Vpc("custom6", {
{ type: "isolated", name: "db", location: "10.0.2.0/24" },
{ type: "isolated", name: "redis", location: "10.0.3.0/24" },
],
}, providerOpts);
}, providerOpts);



const allZones = aws.getAvailabilityZones(undefined, { provider: providerOpts.provider, async: true }).then(allZones => allZones.names)
const selectedZones = new random.RandomShuffle("custom7_az", {
inputs: allZones,
resultCount: allZones.then(z => z.length / 2)
}).results;

const vpcWithSpecificZones = new awsx.ec2.Vpc("custom7", {
requestedAvailabilityZones: selectedZones,
subnets: [
{ type: "public" },
{ type: "private" },
{ type: "isolated", name: "db" },
{ type: "isolated", name: "redis" },
],
}, providerOpts);
3 changes: 2 additions & 1 deletion nodejs/examples/vpc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
},
"dependencies": {
"@pulumi/pulumi": "^3.0.0",
"@pulumi/aws": "^4.0.0"
"@pulumi/aws": "^4.0.0",
"@pulumi/random": "^4.0.0"
},
"devDependencies": {
"@types/node": "^8.0.0"
Expand Down

0 comments on commit 48df96d

Please sign in to comment.