Skip to content

Commit

Permalink
(feat): add tagging for VPC and components
Browse files Browse the repository at this point in the history
  • Loading branch information
shikha372 committed Dec 2, 2024
1 parent 6877c6a commit 74d925d
Show file tree
Hide file tree
Showing 15 changed files with 1,417 additions and 10 deletions.
25 changes: 23 additions & 2 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 @@ -138,6 +138,9 @@ export interface PoolOptions {
readonly awsService?: AwsServiceName;
}

const NAME_TAG: string = 'NAME';
//const IPAM_TAG: string = 'IPAM';

/**
* Properties for creating an IPAM pool.
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-ipampool.html
Expand Down Expand Up @@ -343,6 +346,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
if (props.ipamPoolName) {
Tags.of(this).add(NAME_TAG, props.ipamPoolName);
}

this._ipamPool = new CfnIPAMPool(this, id, {
addressFamily: props.addressFamily,
provisionedCidrs: props.ipv4ProvisionedCidrs?.map(cidr => ({ cidr })),
Expand Down Expand Up @@ -413,6 +421,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 @@ -440,6 +449,7 @@ class IpamScopeBase implements IIpamScopeBase {
readonly scopeType?: IpamScopeType,
) {
this.scopeType = IpamScopeType.DEFAULT;
//Tags.of(this).add(NAME_TAG, 'DefaultIpamScope');
if (!props.ipamScopeId) {
throw new Error('ipamScopeId is required');
} else {
Expand Down Expand Up @@ -494,14 +504,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 @@ -531,6 +551,7 @@ export class Ipam extends Resource {
public addScope(scope: Construct, id: string, options: IpamScopeOptions): IIpamScopeBase {
const ipamScope = new IpamScope(scope, id, {
...options,
ipamScopeName: options.ipamScopeName,
ipamId: this.ipamId,
ipamOperatingRegions: this.operatingRegions,
});
Expand Down
39 changes: 36 additions & 3 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 Down Expand Up @@ -409,6 +427,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 Down Expand Up @@ -476,6 +498,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 @@ -701,6 +726,9 @@ export class Route extends Resource implements IRouteV2 {
}
this.targetRouterType = this.target.gateway ? this.target.gateway.routerType : RouterType.VPC_ENDPOINT;

if (props.routeName) {
Tags.of(this).add(NAME_TAG, props.routeName);
}
// 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 +789,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 +802,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
34 changes: 34 additions & 0 deletions packages/@aws-cdk/aws-ec2-alpha/lib/vpc-v2-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ export interface EgressOnlyInternetGatewayOptions {
* @default - '::/0' all Ipv6 traffic
*/
readonly destination?: string;

/**
* The resource name of the egress-only internet gateway.
* Provided name will be used for tagging
*
* @default - no name tag associated and provisioned without a resource name
*/
readonly egressOnlyInternetGatewayName?: string;
}

/**
Expand All @@ -44,6 +52,14 @@ export interface InternetGatewayOptions{
* @default - '::/0' all Ipv6 traffic
*/
readonly ipv6Destination?: string;

/**
* The resource name of the internet gateway.
* Provided name will be used for tagging
*
* @default - provisioned without a resource name
*/
readonly internetGatewayName?: string;
}

/**
Expand Down Expand Up @@ -119,6 +135,12 @@ export interface IVpcV2 extends IVpc {
*/
readonly ipv4IpamProvisionedCidrs?: string[];

/**
* VpcName to be used for tagging its components
* @attribute
*/
readonly vpcName?: string;

/**
* Add an Egress only Internet Gateway to current VPC.
* Can only be used for ipv6 enabled VPCs.
Expand Down Expand Up @@ -234,6 +256,11 @@ export abstract class VpcV2Base extends Resource implements IVpcV2 {
*/
public abstract readonly ipv4CidrBlock: string;

/**
* VpcName to be used for tagging its components
*/
public abstract readonly vpcName?: string;

/**
* Region for this VPC
*/
Expand Down Expand Up @@ -331,6 +358,7 @@ export abstract class VpcV2Base extends Resource implements IVpcV2 {
* Adds VPNGAtewayV2 to this VPC
*/
public enableVpnGatewayV2(options: VPNGatewayV2Options): VPNGatewayV2 {

if (this.vpnGatewayId) {
throw new Error('The VPN Gateway has already been enabled.');
}
Expand Down Expand Up @@ -393,8 +421,10 @@ export abstract class VpcV2Base extends Resource implements IVpcV2 {
* @default - in case of no input subnets, no route is created
*/
public addEgressOnlyInternetGateway(options?: EgressOnlyInternetGatewayOptions): void {

const egw = new EgressOnlyInternetGateway(this, 'EgressOnlyGW', {
vpc: this,
egressOnlyInternetGatewayName: options?.egressOnlyInternetGatewayName,
});

let useIpv6;
Expand Down Expand Up @@ -425,6 +455,7 @@ export abstract class VpcV2Base extends Resource implements IVpcV2 {
routeTable: subnet.routeTable,
destination: destinationIpv6, // IPv6 default route
target: { gateway: egw },
routeName: 'CDKEIGWRoute',
});
}

Expand All @@ -440,6 +471,7 @@ export abstract class VpcV2Base extends Resource implements IVpcV2 {

const igw = new InternetGateway(this, 'InternetGateway', {
vpc: this,
internetGatewayName: options?.internetGatewayName,
});

this._internetConnectivityEstablished.add(igw);
Expand Down Expand Up @@ -467,13 +499,15 @@ export abstract class VpcV2Base extends Resource implements IVpcV2 {
routeTable: subnet.routeTable,
destination: options?.ipv6Destination ?? '::/0',
target: { gateway: igw },
routeName: 'CDKDefaultIPv6Route',
});
}
//Add default route to IGW for IPv4
new Route(this, `${subnet.node.id}-DefaultRoute`, {
routeTable: subnet.routeTable,
destination: options?.ipv4Destination ?? '0.0.0.0/0',
target: { gateway: igw },
routeName: 'CDKDefaultIPv4Route',
});
}

Expand Down
Loading

0 comments on commit 74d925d

Please sign in to comment.