1
- // Copyright 2016-2022 , Pulumi Corporation.
1
+ // Copyright 2016-2024 , Pulumi Corporation.
2
2
//
3
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
4
// you may not use this file except in compliance with the License.
16
16
// and used in accordance with MPL v2.0 license
17
17
18
18
import * as pulumi from "@pulumi/pulumi" ;
19
- import { SubnetSpecInputs , SubnetTypeInputs } from "../schema-types" ;
19
+ import { SubnetSpecInputs } from "../schema-types" ;
20
20
import { Netmask } from "netmask" ;
21
+ import { SubnetSpec , SubnetSpecPartial } from "./subnetSpecs" ;
21
22
22
- export interface SubnetSpec {
23
- cidrBlock : string ;
24
- type : SubnetTypeInputs ;
25
- azName : string ;
26
- subnetName : string ;
27
- tags ?: pulumi . Input < {
28
- [ key : string ] : pulumi . Input < string > ;
29
- } > ;
23
+ export function getSubnetSpecs (
24
+ vpcName : string ,
25
+ vpcCidr : pulumi . Input < string > ,
26
+ azNames : string [ ] ,
27
+ subnetInputs : SubnetSpecInputs [ ] | undefined ,
28
+ azCidrMask ?: number ,
29
+ ) : SubnetSpecPartial [ ] {
30
+ const allocatedCidrBlocks = inputApply (
31
+ vpcCidr ,
32
+ ( vpcCidr ) => allocateSubnetCidrBlocks ( vpcName , vpcCidr , azNames , subnetInputs , azCidrMask ) ,
33
+ ( x ) => x ,
34
+ ( x ) => x ,
35
+ ) ;
36
+ const subnetSpecs = subnetInputs ?? defaultSubnetInputsBare ( ) ;
37
+ return azNames . flatMap ( ( azName , azIndex ) => {
38
+ const azNum = azIndex + 1 ;
39
+ return subnetSpecs . map ( ( subnetSpec , subnetIndex ) => {
40
+ const subnetAllocID = subnetAllocationID ( vpcName , subnetSpec , azNum , subnetIndex ) ;
41
+ const cidrBlock = inputApply (
42
+ allocatedCidrBlocks ,
43
+ ( t ) => t [ subnetAllocID ] . cidrBlock ,
44
+ ( x ) => x ,
45
+ ( x ) => x ,
46
+ ) ;
47
+ return {
48
+ cidrBlock,
49
+ type : subnetSpec . type ,
50
+ azName,
51
+ subnetName : subnetName ( vpcName , subnetSpec , azNum ) ,
52
+ tags : subnetSpec . tags ,
53
+ } ;
54
+ } ) ;
55
+ } ) ;
30
56
}
31
57
32
- export function getSubnetSpecs (
58
+ type SubnetAllocationID = string ;
59
+
60
+ function subnetAllocationID (
61
+ vpcName : string ,
62
+ subnetSpec : SubnetSpecInputs ,
63
+ azNum : number ,
64
+ subnetSpecIndex : number ,
65
+ ) : SubnetAllocationID {
66
+ const name = subnetName ( vpcName , subnetSpec , azNum ) ;
67
+ return `${ name } #${ subnetSpecIndex } ` ;
68
+ }
69
+
70
+ function allocateSubnetCidrBlocks (
33
71
vpcName : string ,
34
72
vpcCidr : string ,
35
73
azNames : string [ ] ,
36
74
subnetInputs : SubnetSpecInputs [ ] | undefined ,
37
75
azCidrMask ?: number ,
38
- ) : SubnetSpec [ ] {
76
+ ) : Record < SubnetAllocationID , { cidrBlock : pulumi . Input < string > } > {
77
+ const allocation : Record < string , { cidrBlock : pulumi . Input < string > } > = { } ;
39
78
const vpcNetmask = new Netmask ( vpcCidr ) ;
40
79
const azBitmask = azCidrMask ?? vpcNetmask . bitmask + newBits ( azNames . length ) ;
41
80
@@ -60,11 +99,11 @@ export function getSubnetSpecs(
60
99
}
61
100
62
101
let currentAzNetmask = new Netmask ( `${ vpcNetmask . base } /${ azBitmask } ` ) ;
63
- const subnets : SubnetSpec [ ] = [ ] ;
102
+
64
103
for ( let azIndex = 0 ; azIndex < azNames . length ; azIndex ++ ) {
65
- const azName = azNames [ azIndex ] ;
66
104
const azNum = azIndex + 1 ;
67
105
let currentSubnetNetmask : Netmask | undefined ;
106
+ let subnetIndex = 0 ;
68
107
for ( const subnetSpec of subnetSpecs ) {
69
108
if ( currentSubnetNetmask === undefined ) {
70
109
currentSubnetNetmask = new Netmask (
@@ -78,19 +117,22 @@ export function getSubnetSpecs(
78
117
) ;
79
118
}
80
119
const subnetCidr = currentSubnetNetmask . toString ( ) ;
81
- subnets . push ( {
120
+ const subnetAllocID = subnetAllocationID ( vpcName , subnetSpec , azNum , subnetIndex ) ;
121
+ allocation [ subnetAllocID ] = {
82
122
cidrBlock : subnetCidr ,
83
- type : subnetSpec . type ,
84
- azName,
85
- subnetName : subnetName ( vpcName , subnetSpec , azNum ) ,
86
- tags : subnetSpec . tags ,
87
- } ) ;
123
+ } ;
124
+
125
+ subnetIndex ++ ;
88
126
}
89
127
90
128
currentAzNetmask = currentAzNetmask . next ( ) ;
91
129
}
92
130
93
- return subnets ;
131
+ return allocation ;
132
+ }
133
+
134
+ function defaultSubnetInputsBare ( ) : SubnetSpecInputs [ ] {
135
+ return [ { type : "Private" } , { type : "Public" } ] ;
94
136
}
95
137
96
138
export function defaultSubnetInputs ( azBitmask : number ) : SubnetSpecInputs [ ] {
@@ -110,16 +152,10 @@ export function defaultSubnetInputs(azBitmask: number): SubnetSpecInputs[] {
110
152
// Even if we've got more than /16, only use the first /16 for the default subnets.
111
153
// Leave the rest for the user to add later if needed.
112
154
const maxBitmask = Math . max ( azBitmask , 16 ) ;
113
- return [
114
- {
115
- type : "Private" ,
116
- cidrMask : maxBitmask + 1 ,
117
- } ,
118
- {
119
- type : "Public" ,
120
- cidrMask : maxBitmask + 2 ,
121
- } ,
122
- ] ;
155
+ return defaultSubnetInputsBare ( ) . map ( ( t , i ) => ( {
156
+ type : t . type ,
157
+ cidrMask : maxBitmask + i + 1 ,
158
+ } ) ) ;
123
159
}
124
160
125
161
export function nextNetmask ( previous : Netmask , nextBitmask : number ) : Netmask {
@@ -285,3 +321,18 @@ export const validSubnetSizes: readonly number[] = [
285
321
8388608 , 4194304 , 2097152 , 1048576 , 524288 , 262144 , 131072 , 65536 , 32768 , 16384 , 8192 , 4096 , 2048 ,
286
322
1024 , 512 , 256 , 128 , 64 , 32 , 16 , 8 , 4 ,
287
323
] ;
324
+
325
+ // This utility function is like pulumi.output(x).apply(fn) but tries to stay in the Input layer so that prompt
326
+ // validations and test cases are not disturbed. wrap* functions are usually identity. Ideally something like this could
327
+ // be handled in the core Pulumi Node SDK.
328
+ function inputApply < T , U > (
329
+ x : pulumi . Input < T > ,
330
+ fn : ( value : T ) => pulumi . Input < U > ,
331
+ wrapT : ( value : pulumi . Unwrap < T > ) => T ,
332
+ wrapU : ( value : pulumi . Unwrap < U > ) => U ,
333
+ ) : pulumi . Input < U > {
334
+ if ( x instanceof Promise || pulumi . Output . isInstance ( x ) ) {
335
+ return pulumi . output ( x ) . apply ( ( x ) => pulumi . output ( fn ( wrapT ( x ) ) ) . apply ( wrapU ) ) ;
336
+ }
337
+ return fn ( x ) ;
338
+ }
0 commit comments