diff --git a/awsx/ec2/subnetDistributorNew.test.ts b/awsx/ec2/subnetDistributorNew.test.ts index 413b9dbc5..f9bf44d46 100644 --- a/awsx/ec2/subnetDistributorNew.test.ts +++ b/awsx/ec2/subnetDistributorNew.test.ts @@ -14,7 +14,13 @@ import fc from "fast-check"; import { SubnetSpecInputs, SubnetTypeInputs } from "../schema-types"; -import { defaultSubnetInputs, getSubnetSpecs, nextNetmask } from "./subnetDistributorNew"; +import { + defaultSubnetInputs, + getSubnetSpecs, + nextNetmask, + validSubnetSizes, + validateAndNormalizeSubnetInputs, +} from "./subnetDistributorNew"; import { Netmask } from "netmask"; import { getOverlappingSubnets, validateNoGaps, validateSubnets } from "./vpc"; import { getSubnetSpecsLegacy } from "./subnetDistributorLegacy"; @@ -267,3 +273,137 @@ describe("validating exact layouts", () => { }); }); }); + +describe("explicit subnet layouts", () => { + it("should produce specified subnets", () => { + const result = getSubnetSpecs( + "vpcName", + "10.0.0.0/16", + ["us-east-1a", "us-east-1b"], + [ + { type: "Public", cidrBlocks: ["10.0.0.0/18", "10.0.64.0/19"] }, + { type: "Private", cidrBlocks: ["10.0.96.0/19", "10.0.128.0/20"] }, + ], + ); + expect(result).toEqual([ + { + azName: "us-east-1a", + cidrBlock: "10.0.0.0/18", + subnetName: "vpcName-public-1", + type: "Public", + }, + { + azName: "us-east-1a", + cidrBlock: "10.0.96.0/19", + subnetName: "vpcName-private-1", + type: "Private", + }, + { + azName: "us-east-1b", + cidrBlock: "10.0.64.0/19", + subnetName: "vpcName-public-2", + type: "Public", + }, + { + azName: "us-east-1b", + cidrBlock: "10.0.128.0/20", + subnetName: "vpcName-private-2", + type: "Private", + }, + ]); + }); +}); + +describe("valid subnet sizes", () => { + const sizes = validSubnetSizes; + expect(sizes.length).toBe(31); + for (let index = 0; index < sizes.length; index++) { + const size = sizes[index]; + // Index is also the netmask + expect(size).toEqual(4294967296 / 2 ** index); + } +}); + +describe("validating and normalizing inputs", () => { + it("detects invalid sizes", () => { + expect(() => validateAndNormalizeSubnetInputs([{ type: "Public", size: 100 }], 1)).toThrowError( + "The following subnet sizes are invalid: 100. Valid sizes are: ", + ); + }); + it("detects mismatched size and netmask", () => { + expect(() => + validateAndNormalizeSubnetInputs([{ type: "Public", size: 4096, cidrMask: 21 }], 1), + ).toThrowError("Subnet size 4096 does not match the expected size for a /21 subnet (2048)."); + }); + it("allows size only", () => { + const result = validateAndNormalizeSubnetInputs([{ type: "Public", size: 1024 }], 1); + expect(result!.normalizedSpecs).toEqual([{ type: "Public", size: 1024, cidrMask: 22 }]); + }); + it("allows cidrMask only", () => { + const result = validateAndNormalizeSubnetInputs([{ type: "Public", cidrMask: 23 }], 1); + expect(result!.normalizedSpecs).toEqual([{ type: "Public", size: 512, cidrMask: 23 }]); + }); + it("allows cidrMask and size when matching", () => { + const result = validateAndNormalizeSubnetInputs( + [{ type: "Public", cidrMask: 24, size: 256 }], + 1, + ); + expect(result!.normalizedSpecs).toEqual([{ type: "Public", size: 256, cidrMask: 24 }]); + }); + describe("explicit layouts", () => { + it("detects block count mismatching AZ count", () => { + expect(() => + validateAndNormalizeSubnetInputs([{ type: "Public", cidrBlocks: ["10.0.0.0/16"] }], 2), + ).toThrowError( + "The number of CIDR blocks in subnetSpecs[0] must match the number of availability zones (2).", + ); + }); + it("detects partially specified blocks", () => { + expect(() => + validateAndNormalizeSubnetInputs( + [{ type: "Public", cidrBlocks: ["10.0.0.0/16"] }, { type: "Private" }], + 1, + ), + ).toThrowError( + "If any subnet spec has explicit cidrBlocks, all subnets must have explicit cidrBlocks.", + ); + }); + it("detects cidr blocks with mismatched netmask", () => { + expect(() => + validateAndNormalizeSubnetInputs( + [{ type: "Public", cidrBlocks: ["10.0.0.0/16"], cidrMask: 17 }], + 1, + ), + ).toThrowError( + "The cidrMask in subnetSpecs[0] must match all cidrBlocks or be left undefined.", + ); + }); + it("detects cidr blocks with mismatched netmask", () => { + expect(() => + validateAndNormalizeSubnetInputs( + [{ type: "Public", cidrBlocks: ["10.0.0.0/16"], size: 1024 }], + 1, + ), + ).toThrowError("The size in subnetSpecs[0] must match all cidrBlocks or be left undefined."); + }); + it("allows all argument to be in agreement", () => { + validateAndNormalizeSubnetInputs( + [ + { + type: "Public", + cidrBlocks: ["10.0.0.0/20", "10.0.16.0/20"], + size: 4096, + cidrMask: 20, + }, + { + type: "Public", + cidrBlocks: ["10.0.32.0/21", "10.0.40.0/21"], + size: 2048, + cidrMask: 21, + }, + ], + 2, + ); + }); + }); +}); diff --git a/awsx/ec2/subnetDistributorNew.ts b/awsx/ec2/subnetDistributorNew.ts index 3a590777c..7ffac4955 100644 --- a/awsx/ec2/subnetDistributorNew.ts +++ b/awsx/ec2/subnetDistributorNew.ts @@ -61,23 +61,28 @@ export function getSubnetSpecs( let currentAzNetmask = new Netmask(`${vpcNetmask.base}/${azBitmask}`); const subnets: SubnetSpec[] = []; - let azNum = 1; - for (const azName of azNames) { + for (let azIndex = 0; azIndex < azNames.length; azIndex++) { + const azName = azNames[azIndex]; + const azNum = azIndex + 1; let currentSubnetNetmask: Netmask | undefined; for (const subnetSpec of subnetSpecs) { - if (currentSubnetNetmask === undefined) { - currentSubnetNetmask = new Netmask( - currentAzNetmask.base, - subnetSpec.cidrMask ?? defaultSubnetBitmask, - ); - } else { - currentSubnetNetmask = nextNetmask( - currentSubnetNetmask, - subnetSpec.cidrMask ?? defaultSubnetBitmask, - ); + let subnetCidr = subnetSpec.cidrBlocks?.[azIndex]; + if (subnetCidr === undefined) { + if (currentSubnetNetmask === undefined) { + currentSubnetNetmask = new Netmask( + currentAzNetmask.base, + subnetSpec.cidrMask ?? defaultSubnetBitmask, + ); + } else { + currentSubnetNetmask = nextNetmask( + currentSubnetNetmask, + subnetSpec.cidrMask ?? defaultSubnetBitmask, + ); + } + subnetCidr = currentSubnetNetmask.toString(); } - const subnetCidr = currentSubnetNetmask.toString(); - const subnetName = `${vpcName}-${subnetSpec.type.toLowerCase()}-${azNum}`; + const specName = subnetSpec.name ?? subnetSpec.type.toLowerCase(); + const subnetName = `${vpcName}-${specName}-${azNum}`; subnets.push({ cidrBlock: subnetCidr, type: subnetSpec.type, @@ -87,7 +92,6 @@ export function getSubnetSpecs( } currentAzNetmask = currentAzNetmask.next(); - azNum++; } return subnets; @@ -149,3 +153,108 @@ function nextPow2(n: number): number { return n + 1; } + +/* Ensure all inputs are consistent and fill in missing values with defaults + * Ensure any specified, netmask, size or blocks are in agreement. + */ +export function validateAndNormalizeSubnetInputs( + subnetArgs: SubnetSpecInputs[] | undefined, + availabilityZoneCount: number, +): { normalizedSpecs: SubnetSpecInputs[]; isExplicitLayout: boolean } | undefined { + if (subnetArgs === undefined) { + return undefined; + } + + const issues: string[] = []; + + // All sizes must be valid. + const invalidSizes = subnetArgs.filter( + (spec) => spec.size !== undefined && !validSubnetSizes.includes(spec.size), + ); + if (invalidSizes.length > 0) { + issues.push( + `The following subnet sizes are invalid: ${invalidSizes + .map((spec) => spec.size) + .join(", ")}. Valid sizes are: ${validSubnetSizes.join(", ")}.`, + ); + } + + const hasExplicitLayouts = subnetArgs.some((subnet) => subnet.cidrBlocks !== undefined); + if (hasExplicitLayouts) { + // If any subnet spec has explicit cidrBlocks, all subnets must have explicit cidrBlocks. + const hasMissingExplicitLayouts = subnetArgs.some((subnet) => subnet.cidrBlocks === undefined); + if (hasMissingExplicitLayouts) { + issues.push( + "If any subnet spec has explicit cidrBlocks, all subnets must have explicit cidrBlocks.", + ); + } + + // Number of cidrBlocks must match the number of availability zones. + for (let specIndex = 0; specIndex < subnetArgs.length; specIndex++) { + const spec = subnetArgs[specIndex]; + if (spec.cidrBlocks !== undefined && spec.cidrBlocks.length != availabilityZoneCount) { + issues.push( + `The number of CIDR blocks in subnetSpecs[${specIndex}] must match the number of availability zones (${availabilityZoneCount}).`, + ); + } + } + + // Any size or cidrMask must be in agreement with the cidrBlocks. + for (let specIndex = 0; specIndex < subnetArgs.length; specIndex++) { + const spec = subnetArgs[specIndex]; + if (spec.cidrBlocks === undefined) { + continue; + } + const blockMasks = spec.cidrBlocks!.map((b) => new Netmask(b)); + if (spec.cidrMask !== undefined) { + if (!blockMasks.every((b) => b.bitmask === spec.cidrMask)) { + issues.push( + `The cidrMask in subnetSpecs[${specIndex}] must match all cidrBlocks or be left undefined.`, + ); + } + } + if (spec.size !== undefined) { + if (!blockMasks.every((b) => b.size === spec.size!)) { + issues.push( + `The size in subnetSpecs[${specIndex}] must match all cidrBlocks or be left undefined.`, + ); + } + } + } + + if (issues.length === 0) { + return { normalizedSpecs: subnetArgs, isExplicitLayout: true }; + } + } else { + const normalizedSpecs = subnetArgs.map((spec) => { + // Ensure size and cidrMask are in agreement. + const cidrMask = + spec.cidrMask ?? (spec.size ? validSubnetSizes.indexOf(spec.size!) : undefined); + const expectedSize = cidrMask ? validSubnetSizes[cidrMask] : undefined; + if (spec.size !== undefined && expectedSize !== undefined && expectedSize !== spec.size) { + issues.push( + `Subnet size ${spec.size} does not match the expected size for a /${cidrMask} subnet (${expectedSize}).`, + ); + } + // Set both cidrMask and size to the resolved values, if either was provided. + return { + ...spec, + cidrMask: cidrMask, + size: expectedSize, + }; + }); + + if (issues.length === 0) { + return { normalizedSpecs, isExplicitLayout: false }; + } + } + + throw new Error(`Invalid subnet specifications:\n - ${issues.join("\n - ")}`); +} + +// The index of the array is the corresponding netmask. +export const validSubnetSizes: readonly number[] = [ + 4294967296, 2147483648, 1073741824, 536870912, 268435456, 134217728, 67108864, 33554432, 16777216, + 8388608, 4194304, 2097152, 1048576, 524288, 262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048, + 1024, 512, 256, 128, 64, 32, 16, 8, 4, +]; diff --git a/awsx/ec2/vpc.ts b/awsx/ec2/vpc.ts index 994de3df3..17c9c7e06 100644 --- a/awsx/ec2/vpc.ts +++ b/awsx/ec2/vpc.ts @@ -16,7 +16,7 @@ import * as aws from "@pulumi/aws"; import * as pulumi from "@pulumi/pulumi"; import * as schema from "../schema-types"; import { getSubnetSpecsLegacy, SubnetSpec } from "./subnetDistributorLegacy"; -import { getSubnetSpecs } from "./subnetDistributorNew"; +import { getSubnetSpecs, validateAndNormalizeSubnetInputs } from "./subnetDistributorNew"; import { Netmask } from "netmask"; interface VpcData { @@ -82,11 +82,17 @@ export class Vpc extends schema.Vpc { const cidrBlock = args.cidrBlock ?? "10.0.0.0/16"; const subnetStrategy = args.subnetStrategy ?? "Legacy"; + const parsedSpecs = validateAndNormalizeSubnetInputs( + args.subnetSpecs, + availabilityZones.length, + ); - const subnetSpecs = - subnetStrategy === "Legacy" - ? getSubnetSpecsLegacy(name, cidrBlock, availabilityZones, args.subnetSpecs) - : getSubnetSpecs(name, cidrBlock, availabilityZones, args.subnetSpecs); + const subnetSpecs = (() => { + if (parsedSpecs?.isExplicitLayout || subnetStrategy !== "Legacy") { + return getSubnetSpecs(name, cidrBlock, availabilityZones, parsedSpecs?.normalizedSpecs); + } + return getSubnetSpecsLegacy(name, cidrBlock, availabilityZones, parsedSpecs?.normalizedSpecs); + })(); validateSubnets(subnetSpecs, getOverlappingSubnets); diff --git a/awsx/schema-types.ts b/awsx/schema-types.ts index 51c6de199..2917c3a55 100644 --- a/awsx/schema-types.ts +++ b/awsx/schema-types.ts @@ -572,14 +572,18 @@ export type NatGatewayStrategyOutputs = "None" | "Single" | "OnePerAz"; export type SubnetAllocationStrategyInputs = "Legacy" | "Auto" | "Exact"; export type SubnetAllocationStrategyOutputs = "Legacy" | "Auto" | "Exact"; export interface SubnetSpecInputs { + readonly cidrBlocks?: string[]; readonly cidrMask?: number; readonly name?: string; + readonly size?: number; readonly tags?: pulumi.Input>>; readonly type: SubnetTypeInputs; } export interface SubnetSpecOutputs { + readonly cidrBlocks?: string[]; readonly cidrMask?: number; readonly name?: string; + readonly size?: number; readonly tags?: pulumi.Output>; readonly type: SubnetTypeOutputs; } diff --git a/awsx/schema.json b/awsx/schema.json index 2e1df7aa4..82f49ad98 100644 --- a/awsx/schema.json +++ b/awsx/schema.json @@ -584,16 +584,30 @@ "awsx:ec2:SubnetSpec": { "description": "Configuration for a VPC subnet.", "properties": { + "cidrBlocks": { + "type": "array", + "items": { + "type": "string", + "plain": true + }, + "plain": true, + "description": "An optional list of CIDR blocks to assign to the subnet spec for each AZ. If specified, the count must match the number of AZs being used for the VPC, and must also be specified for all other subnet specs." + }, "cidrMask": { "type": "integer", "plain": true, - "description": "The bitmask for the subnet's CIDR block. The default value is set based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone." + "description": "The netmask for the subnet's CIDR block. This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone." }, "name": { "type": "string", "plain": true, "description": "The subnet's name. Will be templated upon creation." }, + "size": { + "type": "integer", + "plain": true, + "description": "Optional size of the subnet's CIDR block - the number of hosts. This value must be a power of 2 (e.g. 256, 512, 1024, etc.). This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone." + }, "tags": { "type": "object", "additionalProperties": { diff --git a/schemagen/pkg/gen/ec2.go b/schemagen/pkg/gen/ec2.go index 158e84706..03221834a 100644 --- a/schemagen/pkg/gen/ec2.go +++ b/schemagen/pkg/gen/ec2.go @@ -319,13 +319,17 @@ func subnetSpecType() schema.ComplexTypeSpec { "cidrMask": { // The validation rules are too difficult to concisely describe here, so we'll leave that job to any // error messages generated from the component itself. - Description: "The bitmask for the subnet's CIDR block. The default value is set based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone.", + Description: "The netmask for the subnet's CIDR block. This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone.", + TypeSpec: plainInt(), + }, + "cidrBlocks": { + Description: "An optional list of CIDR blocks to assign to the subnet spec for each AZ. If specified, the count must match the number of AZs being used for the VPC, and must also be specified for all other subnet specs.", + TypeSpec: plainArrayOfPlainStrings(), + }, + "size": { + Description: "Optional size of the subnet's CIDR block - the number of hosts. This value must be a power of 2 (e.g. 256, 512, 1024, etc.). This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone.", TypeSpec: plainInt(), }, - // TODO: Add this as a follow-up feature. - // "cidrBlocks": { - // Description: "A list of CIDR blocks to assign to the subnet spec for each AZ. Cannot be specified in conjunction with `cidrMask`. The count must match the number of AZs being used for the VPC. `cidrBlocks` must be specified for all subnet specs if specified on any spec.", - // }, "tags": { TypeSpec: schema.TypeSpec{ Type: "object", diff --git a/sdk/dotnet/Ec2/Inputs/SubnetSpecArgs.cs b/sdk/dotnet/Ec2/Inputs/SubnetSpecArgs.cs index b206ca080..399d71264 100644 --- a/sdk/dotnet/Ec2/Inputs/SubnetSpecArgs.cs +++ b/sdk/dotnet/Ec2/Inputs/SubnetSpecArgs.cs @@ -15,8 +15,20 @@ namespace Pulumi.Awsx.Ec2.Inputs /// public sealed class SubnetSpecArgs : global::Pulumi.ResourceArgs { + [Input("cidrBlocks")] + private List? _cidrBlocks; + /// - /// The bitmask for the subnet's CIDR block. The default value is set based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + /// An optional list of CIDR blocks to assign to the subnet spec for each AZ. If specified, the count must match the number of AZs being used for the VPC, and must also be specified for all other subnet specs. + /// + public List CidrBlocks + { + get => _cidrBlocks ?? (_cidrBlocks = new List()); + set => _cidrBlocks = value; + } + + /// + /// The netmask for the subnet's CIDR block. This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. /// [Input("cidrMask")] public int? CidrMask { get; set; } @@ -27,6 +39,12 @@ public sealed class SubnetSpecArgs : global::Pulumi.ResourceArgs [Input("name")] public string? Name { get; set; } + /// + /// Optional size of the subnet's CIDR block - the number of hosts. This value must be a power of 2 (e.g. 256, 512, 1024, etc.). This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + /// + [Input("size")] + public int? Size { get; set; } + [Input("tags")] private InputMap? _tags; diff --git a/sdk/go/awsx/ec2/pulumiTypes.go b/sdk/go/awsx/ec2/pulumiTypes.go index dbc58a679..673a735db 100644 --- a/sdk/go/awsx/ec2/pulumiTypes.go +++ b/sdk/go/awsx/ec2/pulumiTypes.go @@ -200,10 +200,14 @@ func (o NatGatewayConfigurationPtrOutput) Strategy() NatGatewayStrategyPtrOutput // Configuration for a VPC subnet. type SubnetSpec struct { - // The bitmask for the subnet's CIDR block. The default value is set based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + // An optional list of CIDR blocks to assign to the subnet spec for each AZ. If specified, the count must match the number of AZs being used for the VPC, and must also be specified for all other subnet specs. + CidrBlocks []string `pulumi:"cidrBlocks"` + // The netmask for the subnet's CIDR block. This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. CidrMask *int `pulumi:"cidrMask"` // The subnet's name. Will be templated upon creation. Name *string `pulumi:"name"` + // Optional size of the subnet's CIDR block - the number of hosts. This value must be a power of 2 (e.g. 256, 512, 1024, etc.). This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + Size *int `pulumi:"size"` // A map of tags to assign to the resource. Tags map[string]string `pulumi:"tags"` // The type of subnet. @@ -223,10 +227,14 @@ type SubnetSpecInput interface { // Configuration for a VPC subnet. type SubnetSpecArgs struct { - // The bitmask for the subnet's CIDR block. The default value is set based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + // An optional list of CIDR blocks to assign to the subnet spec for each AZ. If specified, the count must match the number of AZs being used for the VPC, and must also be specified for all other subnet specs. + CidrBlocks []string `pulumi:"cidrBlocks"` + // The netmask for the subnet's CIDR block. This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. CidrMask *int `pulumi:"cidrMask"` // The subnet's name. Will be templated upon creation. Name *string `pulumi:"name"` + // Optional size of the subnet's CIDR block - the number of hosts. This value must be a power of 2 (e.g. 256, 512, 1024, etc.). This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + Size *int `pulumi:"size"` // A map of tags to assign to the resource. Tags pulumi.StringMapInput `pulumi:"tags"` // The type of subnet. @@ -303,7 +311,12 @@ func (o SubnetSpecOutput) ToOutput(ctx context.Context) pulumix.Output[SubnetSpe } } -// The bitmask for the subnet's CIDR block. The default value is set based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. +// An optional list of CIDR blocks to assign to the subnet spec for each AZ. If specified, the count must match the number of AZs being used for the VPC, and must also be specified for all other subnet specs. +func (o SubnetSpecOutput) CidrBlocks() pulumi.StringArrayOutput { + return o.ApplyT(func(v SubnetSpec) []string { return v.CidrBlocks }).(pulumi.StringArrayOutput) +} + +// The netmask for the subnet's CIDR block. This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. func (o SubnetSpecOutput) CidrMask() pulumi.IntPtrOutput { return o.ApplyT(func(v SubnetSpec) *int { return v.CidrMask }).(pulumi.IntPtrOutput) } @@ -313,6 +326,11 @@ func (o SubnetSpecOutput) Name() pulumi.StringPtrOutput { return o.ApplyT(func(v SubnetSpec) *string { return v.Name }).(pulumi.StringPtrOutput) } +// Optional size of the subnet's CIDR block - the number of hosts. This value must be a power of 2 (e.g. 256, 512, 1024, etc.). This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. +func (o SubnetSpecOutput) Size() pulumi.IntPtrOutput { + return o.ApplyT(func(v SubnetSpec) *int { return v.Size }).(pulumi.IntPtrOutput) +} + // A map of tags to assign to the resource. func (o SubnetSpecOutput) Tags() pulumi.StringMapOutput { return o.ApplyT(func(v SubnetSpec) map[string]string { return v.Tags }).(pulumi.StringMapOutput) diff --git a/sdk/java/src/main/java/com/pulumi/awsx/ec2/inputs/SubnetSpecArgs.java b/sdk/java/src/main/java/com/pulumi/awsx/ec2/inputs/SubnetSpecArgs.java index aeaeeb307..c9dc08a13 100644 --- a/sdk/java/src/main/java/com/pulumi/awsx/ec2/inputs/SubnetSpecArgs.java +++ b/sdk/java/src/main/java/com/pulumi/awsx/ec2/inputs/SubnetSpecArgs.java @@ -8,6 +8,7 @@ import com.pulumi.core.annotations.Import; import java.lang.Integer; import java.lang.String; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -23,14 +24,29 @@ public final class SubnetSpecArgs extends com.pulumi.resources.ResourceArgs { public static final SubnetSpecArgs Empty = new SubnetSpecArgs(); /** - * The bitmask for the subnet's CIDR block. The default value is set based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + * An optional list of CIDR blocks to assign to the subnet spec for each AZ. If specified, the count must match the number of AZs being used for the VPC, and must also be specified for all other subnet specs. + * + */ + @Import(name="cidrBlocks") + private @Nullable List cidrBlocks; + + /** + * @return An optional list of CIDR blocks to assign to the subnet spec for each AZ. If specified, the count must match the number of AZs being used for the VPC, and must also be specified for all other subnet specs. + * + */ + public Optional> cidrBlocks() { + return Optional.ofNullable(this.cidrBlocks); + } + + /** + * The netmask for the subnet's CIDR block. This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. * */ @Import(name="cidrMask") private @Nullable Integer cidrMask; /** - * @return The bitmask for the subnet's CIDR block. The default value is set based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + * @return The netmask for the subnet's CIDR block. This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. * */ public Optional cidrMask() { @@ -52,6 +68,21 @@ public Optional name() { return Optional.ofNullable(this.name); } + /** + * Optional size of the subnet's CIDR block - the number of hosts. This value must be a power of 2 (e.g. 256, 512, 1024, etc.). This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + * + */ + @Import(name="size") + private @Nullable Integer size; + + /** + * @return Optional size of the subnet's CIDR block - the number of hosts. This value must be a power of 2 (e.g. 256, 512, 1024, etc.). This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + * + */ + public Optional size() { + return Optional.ofNullable(this.size); + } + /** * A map of tags to assign to the resource. * @@ -85,8 +116,10 @@ public SubnetType type() { private SubnetSpecArgs() {} private SubnetSpecArgs(SubnetSpecArgs $) { + this.cidrBlocks = $.cidrBlocks; this.cidrMask = $.cidrMask; this.name = $.name; + this.size = $.size; this.tags = $.tags; this.type = $.type; } @@ -110,7 +143,28 @@ public Builder(SubnetSpecArgs defaults) { } /** - * @param cidrMask The bitmask for the subnet's CIDR block. The default value is set based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + * @param cidrBlocks An optional list of CIDR blocks to assign to the subnet spec for each AZ. If specified, the count must match the number of AZs being used for the VPC, and must also be specified for all other subnet specs. + * + * @return builder + * + */ + public Builder cidrBlocks(@Nullable List cidrBlocks) { + $.cidrBlocks = cidrBlocks; + return this; + } + + /** + * @param cidrBlocks An optional list of CIDR blocks to assign to the subnet spec for each AZ. If specified, the count must match the number of AZs being used for the VPC, and must also be specified for all other subnet specs. + * + * @return builder + * + */ + public Builder cidrBlocks(String... cidrBlocks) { + return cidrBlocks(List.of(cidrBlocks)); + } + + /** + * @param cidrMask The netmask for the subnet's CIDR block. This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. * * @return builder * @@ -131,6 +185,17 @@ public Builder name(@Nullable String name) { return this; } + /** + * @param size Optional size of the subnet's CIDR block - the number of hosts. This value must be a power of 2 (e.g. 256, 512, 1024, etc.). This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + * + * @return builder + * + */ + public Builder size(@Nullable Integer size) { + $.size = size; + return this; + } + /** * @param tags A map of tags to assign to the resource. * diff --git a/sdk/nodejs/types/input.ts b/sdk/nodejs/types/input.ts index 604f66bf3..99ca9369b 100644 --- a/sdk/nodejs/types/input.ts +++ b/sdk/nodejs/types/input.ts @@ -384,13 +384,21 @@ export namespace ec2 { */ export interface SubnetSpecArgs { /** - * The bitmask for the subnet's CIDR block. The default value is set based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + * An optional list of CIDR blocks to assign to the subnet spec for each AZ. If specified, the count must match the number of AZs being used for the VPC, and must also be specified for all other subnet specs. + */ + cidrBlocks?: string[]; + /** + * The netmask for the subnet's CIDR block. This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. */ cidrMask?: number; /** * The subnet's name. Will be templated upon creation. */ name?: string; + /** + * Optional size of the subnet's CIDR block - the number of hosts. This value must be a power of 2 (e.g. 256, 512, 1024, etc.). This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + */ + size?: number; /** * A map of tags to assign to the resource. */ diff --git a/sdk/python/pulumi_awsx/ec2/_inputs.py b/sdk/python/pulumi_awsx/ec2/_inputs.py index f67649695..b096565a3 100644 --- a/sdk/python/pulumi_awsx/ec2/_inputs.py +++ b/sdk/python/pulumi_awsx/ec2/_inputs.py @@ -60,21 +60,29 @@ def elastic_ip_allocation_ids(self, value: Optional[Sequence[pulumi.Input[str]]] class SubnetSpecArgs: def __init__(__self__, *, type: 'SubnetType', + cidr_blocks: Optional[Sequence[str]] = None, cidr_mask: Optional[int] = None, name: Optional[str] = None, + size: Optional[int] = None, tags: Optional[pulumi.Input[Mapping[str, pulumi.Input[str]]]] = None): """ Configuration for a VPC subnet. :param 'SubnetType' type: The type of subnet. - :param int cidr_mask: The bitmask for the subnet's CIDR block. The default value is set based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + :param Sequence[str] cidr_blocks: An optional list of CIDR blocks to assign to the subnet spec for each AZ. If specified, the count must match the number of AZs being used for the VPC, and must also be specified for all other subnet specs. + :param int cidr_mask: The netmask for the subnet's CIDR block. This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. :param str name: The subnet's name. Will be templated upon creation. + :param int size: Optional size of the subnet's CIDR block - the number of hosts. This value must be a power of 2 (e.g. 256, 512, 1024, etc.). This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. :param pulumi.Input[Mapping[str, pulumi.Input[str]]] tags: A map of tags to assign to the resource. """ pulumi.set(__self__, "type", type) + if cidr_blocks is not None: + pulumi.set(__self__, "cidr_blocks", cidr_blocks) if cidr_mask is not None: pulumi.set(__self__, "cidr_mask", cidr_mask) if name is not None: pulumi.set(__self__, "name", name) + if size is not None: + pulumi.set(__self__, "size", size) if tags is not None: pulumi.set(__self__, "tags", tags) @@ -90,11 +98,23 @@ def type(self) -> 'SubnetType': def type(self, value: 'SubnetType'): pulumi.set(self, "type", value) + @property + @pulumi.getter(name="cidrBlocks") + def cidr_blocks(self) -> Optional[Sequence[str]]: + """ + An optional list of CIDR blocks to assign to the subnet spec for each AZ. If specified, the count must match the number of AZs being used for the VPC, and must also be specified for all other subnet specs. + """ + return pulumi.get(self, "cidr_blocks") + + @cidr_blocks.setter + def cidr_blocks(self, value: Optional[Sequence[str]]): + pulumi.set(self, "cidr_blocks", value) + @property @pulumi.getter(name="cidrMask") def cidr_mask(self) -> Optional[int]: """ - The bitmask for the subnet's CIDR block. The default value is set based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + The netmask for the subnet's CIDR block. This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. """ return pulumi.get(self, "cidr_mask") @@ -114,6 +134,18 @@ def name(self) -> Optional[str]: def name(self, value: Optional[str]): pulumi.set(self, "name", value) + @property + @pulumi.getter + def size(self) -> Optional[int]: + """ + Optional size of the subnet's CIDR block - the number of hosts. This value must be a power of 2 (e.g. 256, 512, 1024, etc.). This is optional, the default value is inferred from the `cidrMask`, `cidrBlocks` or based on an even distribution of available space from the VPC's CIDR block after being divided evenly by availability zone. + """ + return pulumi.get(self, "size") + + @size.setter + def size(self, value: Optional[int]): + pulumi.set(self, "size", value) + @property @pulumi.getter def tags(self) -> Optional[pulumi.Input[Mapping[str, pulumi.Input[str]]]]: