Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(VpcV2): add default name tag for VPC and components #32360

Merged
merged 7 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions packages/@aws-cdk/aws-ec2-alpha/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -645,3 +645,22 @@ SubnetV2.fromSubnetV2Attributes(this, 'ImportedSubnet', {
```

By importing existing VPCs and subnets, you can easily integrate your existing AWS infrastructure with new resources created through CDK. This is particularly useful when you need to work with pre-existing network configurations or when you're migrating existing infrastructure to CDK.

### Tagging VPC and its components

By default, when a resource name is given to the construct, it automatically adds a tag with the key `Name` and the value set to the provided resource name. To add additional custom tags, use the Tag Manager, like this: `Tags.of(myConstruct).add('key', 'value');`.

For example, if the `vpcName` is set to `TestVpc`, the following code will add a tag to the VPC with `key: Name` and `value: TestVpc`.

```ts

const vpc = new VpcV2(this, 'VPC-integ-test-tag', {
primaryAddressBlock: IpAddresses.ipv4('10.1.0.0/16'),
enableDnsHostnames: true,
enableDnsSupport: true,
vpcName: 'CDKintegTestVPC',
});

// Add custom tags if needed
Tags.of(vpc).add('Environment', 'Production');
```
38 changes: 28 additions & 10 deletions packages/@aws-cdk/aws-ec2-alpha/lib/ipam.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CfnIPAM, CfnIPAMPool, CfnIPAMPoolCidr, CfnIPAMScope } from 'aws-cdk-lib/aws-ec2';
import { Construct } from 'constructs';
import { Lazy, Names, Resource, Stack } from 'aws-cdk-lib';
import { Lazy, Names, Resource, Stack, Tags } from 'aws-cdk-lib';

/**
* Represents the address family for IP addresses in an IPAM pool.
Expand Down Expand Up @@ -136,8 +136,17 @@ export interface PoolOptions {
* @default - required in case of an IPv6, throws an error if not provided.
*/
readonly awsService?: AwsServiceName;

/**
* IPAM Pool resource name to be used for tagging
*
* @default - autogenerated by CDK if not provided
*/
readonly ipamPoolName?: string;
}

const NAME_TAG: string = 'Name';

/**
* Properties for creating an IPAM pool.
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-ipampool.html
Expand All @@ -147,13 +156,6 @@ interface IpamPoolProps extends PoolOptions {
* Scope id where pool needs to be created
*/
readonly ipamScopeId: string;

/**
* IPAM resource name
*
* @default - autogenerated by CDK if not provided
*/
readonly ipamPoolName?: string;
}

/**
Expand Down Expand Up @@ -343,6 +345,11 @@ class IpamPool extends Resource implements IIpamPool {
throw new Error('awsService is required when addressFamily is set to ipv6');
}

//Add tags to the IPAM Pool if name is provided
shikha372 marked this conversation as resolved.
Show resolved Hide resolved
if (props.ipamPoolName) {
Tags.of(this).add(NAME_TAG, props.ipamPoolName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if users want to add a custom tag that also called this name?

Copy link
Contributor Author

@shikha372 shikha372 Dec 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is added according to the resource name provided, even if they want to add NAME tag i wonder they would like it to rename it to some other value than the actual name of the resource.

}

this._ipamPool = new CfnIPAMPool(this, id, {
addressFamily: props.addressFamily,
provisionedCidrs: props.ipv4ProvisionedCidrs?.map(cidr => ({ cidr })),
Expand Down Expand Up @@ -413,6 +420,7 @@ class IpamScope extends Resource implements IIpamScopeBase {
this._ipamScope = new CfnIPAMScope(scope, 'IpamScope', {
ipamId: props.ipamId,
});
Tags.of(this._ipamScope).add(NAME_TAG, props.ipamScopeName ?? 'CustomIpamScope');
this.scopeId = this._ipamScope.attrIpamScopeId;
this.scopeType = IpamScopeType.CUSTOM;
this.scope = scope;
Expand Down Expand Up @@ -494,14 +502,24 @@ export class Ipam extends Resource {
*/
public readonly scopes: IIpamScopeBase[] = [];

/**
* IPAM name to be used for tagging
* @default no tag specified
* @attribute IpamName
*/
public readonly ipamName?: string;

constructor(scope: Construct, id: string, props?: IpamProps) {
super(scope, id);

if (props?.ipamName) {
Tags.of(this).add(NAME_TAG, props.ipamName);
}
if (!props?.operatingRegion && !Stack.of(this).region) {
throw new Error('Please provide at least one operating region');
}

this.operatingRegions = props?.operatingRegion ?? [Stack.of(this).region];
this.ipamName = props?.ipamName;

this._ipam = new CfnIPAM(this, 'Ipam', {
operatingRegions: this.operatingRegions ? this.operatingRegions.map(region => ({ regionName: region })) : [],
Expand Down Expand Up @@ -560,7 +578,7 @@ function createIpamPool(
}

return new IpamPool(scope, id, {
ipamPoolName: id,
ipamPoolName: poolOptions.ipamPoolName,
addressFamily: poolOptions.addressFamily,
ipv4ProvisionedCidrs: poolOptions.ipv4ProvisionedCidrs,
ipamScopeId: scopeId,
Expand Down
49 changes: 43 additions & 6 deletions packages/@aws-cdk/aws-ec2-alpha/lib/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CfnEIP, CfnEgressOnlyInternetGateway, CfnInternetGateway, CfnNatGateway, CfnVPCPeeringConnection, CfnRoute, CfnRouteTable, CfnVPCGatewayAttachment, CfnVPNGateway, CfnVPNGatewayRoutePropagation, GatewayVpcEndpoint, IRouteTable, IVpcEndpoint, RouterType } from 'aws-cdk-lib/aws-ec2';
import { Construct, IDependable } from 'constructs';
import { Annotations, Duration, IResource, Resource } from 'aws-cdk-lib/core';
import { Annotations, Duration, IResource, Resource, Tags } from 'aws-cdk-lib/core';
import { IVpcV2, VPNGatewayV2Options } from './vpc-v2-base';
import { NetworkUtils, allRouteTableIds, CidrBlock } from './util';
import { ISubnetV2 } from './subnet-v2';
Expand Down Expand Up @@ -209,6 +209,11 @@ export interface VPCPeeringConnectionProps extends VPCPeeringConnectionOptions {
readonly requestorVpc: IVpcV2;
}

/**
* Name tag constant
*/
const NAME_TAG: string = 'Name';

/**
* Creates an egress-only internet gateway
* @resource AWS::EC2::EgressOnlyInternetGateway
Expand All @@ -232,6 +237,9 @@ export class EgressOnlyInternetGateway extends Resource implements IRouteTarget
constructor(scope: Construct, id: string, props: EgressOnlyInternetGatewayProps) {
super(scope, id);

if (props.egressOnlyInternetGatewayName) {
Tags.of(this).add(NAME_TAG, props.egressOnlyInternetGatewayName);
}
this.routerType = RouterType.EGRESS_ONLY_INTERNET_GATEWAY;

this.resource = new CfnEgressOnlyInternetGateway(this, 'EIGW', {
Expand Down Expand Up @@ -279,6 +287,10 @@ export class InternetGateway extends Resource implements IRouteTarget {
this.routerTargetId = this.resource.attrInternetGatewayId;
this.vpcId = props.vpc.vpcId;

if (props.internetGatewayName) {
Tags.of(this).add(NAME_TAG, props.internetGatewayName);
}

new CfnVPCGatewayAttachment(this, 'GWAttachment', {
vpcId: this.vpcId,
internetGatewayId: this.routerTargetId,
Expand Down Expand Up @@ -322,7 +334,9 @@ export class VPNGatewayV2 extends Resource implements IRouteTarget {
private readonly _routePropagation: CfnVPNGatewayRoutePropagation;

constructor(scope: Construct, id: string, props: VPNGatewayV2Props) {
super(scope, id);
super(scope, id, {
physicalName: props.vpnGatewayName,
});

this.routerType = RouterType.GATEWAY;

Expand All @@ -340,6 +354,10 @@ export class VPNGatewayV2 extends Resource implements IRouteTarget {
vpnGatewayId: this.resource.attrVpnGatewayId,
});

if (props.vpnGatewayName) {
Tags.of(this).add(NAME_TAG, props.vpnGatewayName);
}

// Propagate routes on route tables associated with the right subnets
const vpnRoutePropagation = props.vpnRoutePropagation ?? [];
const subnets = vpnRoutePropagation.map(s => props.vpc.selectSubnets(s).subnets).flat();
Expand All @@ -365,15 +383,22 @@ export class VPNGatewayV2 extends Resource implements IRouteTarget {
* @resource AWS::EC2::NatGateway
*/
export class NatGateway extends Resource implements IRouteTarget {

/**
* Id of the NatGateway
* @attribute
*/
public readonly natGatewayId: string;

/**
* The type of router used in the route.
*/
readonly routerType: RouterType;
public readonly routerType: RouterType;

/**
* The ID of the route target.
*/
readonly routerTargetId: string;
public readonly routerTargetId: string;

/**
* Indicates whether the NAT gateway supports public or private connectivity.
Expand Down Expand Up @@ -409,6 +434,10 @@ export class NatGateway extends Resource implements IRouteTarget {
}
}

if (props.natGatewayName) {
Tags.of(this).add(NAME_TAG, props?.natGatewayName);
}

// If user does not provide EIP, generate one for them
var aId: string | undefined;
if (this.connectivityType === NatConnectivityType.PUBLIC) {
Expand All @@ -429,6 +458,7 @@ export class NatGateway extends Resource implements IRouteTarget {
secondaryAllocationIds: props.secondaryAllocationIds,
...props,
});
this.natGatewayId = this.resource.attrNatGatewayId;

this.routerTargetId = this.resource.attrNatGatewayId;
this.node.defaultChild = this.resource;
Expand Down Expand Up @@ -476,6 +506,9 @@ export class VPCPeeringConnection extends Resource implements IRouteTarget {
if (overlap) {
throw new Error('CIDR block should not overlap with each other for establishing a peering connection');
}
if (props.vpcPeeringConnectionName) {
Tags.of(this).add(NAME_TAG, props.vpcPeeringConnectionName);
}

this.resource = new CfnVPCPeeringConnection(this, 'VPCPeeringConnection', {
vpcId: props.requestorVpc.vpcId,
Expand Down Expand Up @@ -700,7 +733,6 @@ export class Route extends Resource implements IRouteV2 {
throw new Error('Egress only internet gateway does not support IPv4 routing');
}
this.targetRouterType = this.target.gateway ? this.target.gateway.routerType : RouterType.VPC_ENDPOINT;

// Gateway generates route automatically via its RouteTable, thus we don't need to generate the resource for it
if (!(this.target.endpoint instanceof GatewayVpcEndpoint)) {
this.resource = new CfnRoute(this, 'Route', {
Expand Down Expand Up @@ -761,6 +793,9 @@ export class RouteTable extends Resource implements IRouteTable {
this.resource = new CfnRouteTable(this, 'RouteTable', {
vpcId: props.vpc.vpcId,
});
if (props.routeTableName) {
Tags.of(this).add(NAME_TAG, props.routeTableName);
}
this.node.defaultChild = this.resource;

this.routeTableId = this.resource.attrRouteTableId;
Expand All @@ -771,12 +806,14 @@ export class RouteTable extends Resource implements IRouteTable {
*
* @param destination The IPv4 or IPv6 CIDR block used for the destination match.
* @param target The gateway or endpoint targeted by the route.
* @param routeName The resource name of the route.
*/
public addRoute(id: string, destination: string, target: RouteTargetType) {
public addRoute(id: string, destination: string, target: RouteTargetType, routeName?: string) {
new Route(this, id, {
routeTable: this,
destination: destination,
target: target,
routeName: routeName,
});
}
}
Expand Down
21 changes: 20 additions & 1 deletion packages/@aws-cdk/aws-ec2-alpha/lib/subnet-v2.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Resource, Names, Lazy } from 'aws-cdk-lib';
import { Resource, Names, Lazy, Tags } from 'aws-cdk-lib';
import { CfnSubnet, CfnSubnetRouteTableAssociation, INetworkAcl, IRouteTable, ISubnet, NetworkAcl, SubnetNetworkAclAssociation, SubnetType } from 'aws-cdk-lib/aws-ec2';
import { Construct, DependencyGroup, IDependable } from 'constructs';
import { IVpcV2 } from './vpc-v2-base';
Expand Down Expand Up @@ -27,6 +27,16 @@ export class IpCidr implements ICidr {
}
}

/**
* Name tag constant
*/
const NAME_TAG: string = 'Name';

/**
* VPC Name tag constant
*/
const VPCNAME_TAG: string = 'VpcName';

/**
* Properties to define subnet for VPC.
*/
Expand Down Expand Up @@ -282,12 +292,21 @@ export class SubnetV2 extends Resource implements ISubnetV2 {

this._networkAcl = NetworkAcl.fromNetworkAclId(this, 'Acl', subnet.attrNetworkAclAssociationId);

if (props.subnetName) {
Tags.of(this).add(NAME_TAG, props.subnetName);
}

if (props.vpc.vpcName) {
Tags.of(this).add(VPCNAME_TAG, props.vpc.vpcName);
}

if (props.routeTable) {
this._routeTable = props.routeTable;
} else {
// Assigning a default route table
this._routeTable = new RouteTable(this, 'RouteTable', {
vpc: props.vpc,
routeTableName: 'DefaultCDKRouteTable',
});
}

Expand Down
Loading
Loading