@@ -5,7 +5,7 @@ import { CfnEIP, CfnInternetGateway, CfnNatGateway, CfnRoute, CfnVPNGateway, Cfn
5
5
import { CfnRouteTable , CfnSubnet , CfnSubnetRouteTableAssociation , CfnVPC , CfnVPCGatewayAttachment } from './ec2.generated' ;
6
6
import { INetworkAcl , NetworkAcl , SubnetNetworkAclAssociation } from './network-acl' ;
7
7
import { NetworkBuilder } from './network-util' ;
8
- import { allRouteTableIds , defaultSubnetName , ImportSubnetGroup , subnetId , subnetName } from './util' ;
8
+ import { allRouteTableIds , defaultSubnetName , ImportSubnetGroup , subnetGroupNameFromConstructId , subnetId } from './util' ;
9
9
import { GatewayVpcEndpoint , GatewayVpcEndpointAwsService , GatewayVpcEndpointOptions } from './vpc-endpoint' ;
10
10
import { InterfaceVpcEndpoint , InterfaceVpcEndpointOptions } from './vpc-endpoint' ;
11
11
import { VpcLookupOptions } from './vpc-lookup' ;
@@ -162,22 +162,40 @@ export enum SubnetType {
162
162
*/
163
163
export interface SubnetSelection {
164
164
/**
165
- * Place the instances in the subnets of the given type
165
+ * Select all subnets of the given type
166
166
*
167
- * At most one of `subnetType` and `subnetName ` can be supplied.
167
+ * At most one of `subnetType` and `subnetGroupName ` can be supplied.
168
168
*
169
169
* @default SubnetType.PRIVATE
170
170
*/
171
171
readonly subnetType ?: SubnetType ;
172
172
173
173
/**
174
- * Place the instances in the subnets with the given name
174
+ * Select the subnet group with the given name
175
175
*
176
- * (This is the name supplied in subnetConfiguration).
176
+ * Select the subnet group with the given name. This only needs
177
+ * to be used if you have multiple subnet groups of the same type
178
+ * and you need to distinguish between them. Otherwise, prefer
179
+ * `subnetType`.
177
180
*
178
- * At most one of `subnetType` and `subnetName` can be supplied.
181
+ * This field does not select individual subnets, it selects all subnets that
182
+ * share the given subnet group name. This is the name supplied in
183
+ * `subnetConfiguration`.
179
184
*
180
- * @default name
185
+ * At most one of `subnetType` and `subnetGroupName` can be supplied.
186
+ *
187
+ * @default - Selection by type instead of by name
188
+ */
189
+ readonly subnetGroupName ?: string ;
190
+
191
+ /**
192
+ * Alias for `subnetGroupName`
193
+ *
194
+ * Select the subnet group with the given name. This only needs
195
+ * to be used if you have multiple subnet groups of the same type
196
+ * and you need to distinguish between them.
197
+ *
198
+ * @deprecated Use `subnetGroupName` instead
181
199
*/
182
200
readonly subnetName ?: string ;
183
201
@@ -315,26 +333,45 @@ abstract class VpcBase extends Resource implements IVpc {
315
333
*/
316
334
protected selectSubnetObjects ( selection : SubnetSelection = { } ) : ISubnet [ ] {
317
335
selection = reifySelectionDefaults ( selection ) ;
318
- let subnets : ISubnet [ ] = [ ] ;
319
-
320
- if ( selection . subnetName !== undefined ) { // Select by name
321
- const allSubnets = [ ...this . publicSubnets , ...this . privateSubnets , ...this . isolatedSubnets ] ;
322
- subnets = allSubnets . filter ( s => subnetName ( s ) === selection . subnetName ) ;
323
- } else { // Select by type
324
- subnets = {
325
- [ SubnetType . ISOLATED ] : this . isolatedSubnets ,
326
- [ SubnetType . PRIVATE ] : this . privateSubnets ,
327
- [ SubnetType . PUBLIC ] : this . publicSubnets ,
328
- } [ selection . subnetType || SubnetType . PRIVATE ] ;
329
-
330
- if ( selection . onePerAz && subnets . length > 0 ) {
331
- // Restrict to at most one subnet group
332
- subnets = subnets . filter ( s => subnetName ( s ) === subnetName ( subnets [ 0 ] ) ) ;
333
- }
336
+
337
+ if ( selection . subnetGroupName !== undefined ) { // Select by name
338
+ return this . selectSubnetObjectsByName ( selection . subnetGroupName ) ;
339
+
340
+ } else {
341
+ const type = selection . subnetType || SubnetType . PRIVATE ;
342
+ return this . selectSubnetObjectsByType ( type , ! ! selection . onePerAz ) ;
343
+ }
344
+ }
345
+
346
+ private selectSubnetObjectsByName ( groupName : string ) {
347
+ const allSubnets = [ ...this . publicSubnets , ...this . privateSubnets , ...this . isolatedSubnets ] ;
348
+ const subnets = allSubnets . filter ( s => subnetGroupNameFromConstructId ( s ) === groupName ) ;
349
+
350
+ if ( subnets . length === 0 ) {
351
+ const names = Array . from ( new Set ( allSubnets . map ( subnetGroupNameFromConstructId ) ) ) ;
352
+ throw new Error ( `There are no subnet groups with name '${ groupName } ' in this VPC. Available names: ${ names } ` ) ;
353
+ }
354
+
355
+ return subnets ;
356
+ }
357
+
358
+ private selectSubnetObjectsByType ( subnetType : SubnetType , onePerAz : boolean ) {
359
+ const allSubnets = {
360
+ [ SubnetType . ISOLATED ] : this . isolatedSubnets ,
361
+ [ SubnetType . PRIVATE ] : this . privateSubnets ,
362
+ [ SubnetType . PUBLIC ] : this . publicSubnets ,
363
+ } ;
364
+
365
+ let subnets = allSubnets [ subnetType ] ;
366
+
367
+ if ( onePerAz && subnets . length > 0 ) {
368
+ // Restrict to at most one subnet group
369
+ subnets = subnets . filter ( s => subnetGroupNameFromConstructId ( s ) === subnetGroupNameFromConstructId ( subnets [ 0 ] ) ) ;
334
370
}
335
371
336
372
if ( subnets . length === 0 ) {
337
- throw new Error ( `There are no ${ describeSelection ( selection ) } in this VPC. Use a different VPC subnet selection.` ) ;
373
+ const availableTypes = Object . entries ( allSubnets ) . filter ( ( [ _ , subs ] ) => subs . length > 0 ) . map ( ( [ typeName , _ ] ) => typeName ) ;
374
+ throw new Error ( `There are no '${ subnetType } ' subnet groups in this VPC. Available types: ${ availableTypes } ` ) ;
338
375
}
339
376
340
377
return subnets ;
@@ -1407,30 +1444,24 @@ class ImportedVpc extends VpcBase {
1407
1444
* Returns "private subnets" by default.
1408
1445
*/
1409
1446
function reifySelectionDefaults ( placement : SubnetSelection ) : SubnetSelection {
1410
- if ( placement . subnetType !== undefined && placement . subnetName !== undefined ) {
1411
- throw new Error ( 'Only one of subnetType and subnetName can be supplied' ) ;
1447
+ if ( placement . subnetName !== undefined ) {
1448
+ if ( placement . subnetGroupName !== undefined ) {
1449
+ throw new Error ( `Please use only 'subnetGroupName' ('subnetName' is deprecated and has the same behavior)` ) ;
1450
+ }
1451
+ placement = { ...placement , subnetGroupName : placement . subnetName } ;
1412
1452
}
1413
1453
1414
- if ( placement . subnetType === undefined && placement . subnetName === undefined ) {
1454
+ if ( placement . subnetType !== undefined && placement . subnetGroupName !== undefined ) {
1455
+ throw new Error ( `Only one of 'subnetType' and 'subnetGroupName' can be supplied` ) ;
1456
+ }
1457
+
1458
+ if ( placement . subnetType === undefined && placement . subnetGroupName === undefined ) {
1415
1459
return { subnetType : SubnetType . PRIVATE , onePerAz : placement . onePerAz } ;
1416
1460
}
1417
1461
1418
1462
return placement ;
1419
1463
}
1420
1464
1421
- /**
1422
- * Describe the given placement strategy
1423
- */
1424
- function describeSelection ( placement : SubnetSelection ) : string {
1425
- if ( placement . subnetType !== undefined ) {
1426
- return `'${ defaultSubnetName ( placement . subnetType ) } ' subnets` ;
1427
- }
1428
- if ( placement . subnetName !== undefined ) {
1429
- return `subnets named '${ placement . subnetName } '` ;
1430
- }
1431
- return JSON . stringify ( placement ) ;
1432
- }
1433
-
1434
1465
class CompositeDependable implements IDependable {
1435
1466
private readonly dependables = new Array < IDependable > ( ) ;
1436
1467
0 commit comments