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

feat(vpc-v2): add add methods to RouteTable and SubnetV2 #31072

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
31d3f48
Add RouteTable addRoute method
Aug 9, 2024
727b164
Update packages/@aws-cdk/aws-ec2-alpha/lib/route.ts
shikha372 Aug 9, 2024
cb8c941
Change CfnRoute to Route L2
Aug 12, 2024
d21be53
Update README.md
Aug 12, 2024
42830e7
Merge branch 'main' into vpcv2-rt-addroute
Leo10Gama Aug 12, 2024
2f48ab2
Update integ test to use only one EIGW
Aug 12, 2024
f904a97
Add subnet associateRouteTable method
Aug 13, 2024
b52d498
Appease the linter
Aug 13, 2024
1aef528
Update subnet with public routeTable again
Aug 13, 2024
9b15a4b
Update subnet-v2.ts
shikha372 Aug 14, 2024
bc56a77
Update subnet-v2.ts
shikha372 Aug 14, 2024
cc8db35
Extend IRouteTable into IRouteTableV2
Aug 14, 2024
285da27
Merge branch 'main' into vpcv2-rt-addroute
shikha372 Aug 14, 2024
98f9d53
ok so route table v2 was not a great idea lol
Aug 14, 2024
b3e08c1
Merge branch 'main' into vpcv2-rt-addroute
Leo10Gama Aug 14, 2024
1211fde
Update testing
Aug 15, 2024
ca9c385
Merge branch 'main' into vpcv2-rt-addroute
shikha372 Aug 15, 2024
eaa7ccb
add method associateRouteTable
shikha372 Aug 14, 2024
a25bb78
fixing route class
shikha372 Aug 15, 2024
1721026
making ipam props private
shikha372 Aug 15, 2024
bc393c2
successful build
shikha372 Aug 15, 2024
aed940f
adding validation for ipv4
shikha372 Aug 15, 2024
499c6c8
fixing egw route and subnet snapshot
shikha372 Aug 16, 2024
f296f3e
fixing readme and route unit test
shikha372 Aug 16, 2024
0002de5
fixing vpc snapshot
shikha372 Aug 16, 2024
909f7da
Update route snapshot
Aug 16, 2024
1b907c1
Update route snapshot
Aug 16, 2024
0dba8bb
Merge branch 'main' into vpcv2-rt-addroute
shikha372 Aug 23, 2024
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
18 changes: 18 additions & 0 deletions packages/@aws-cdk/aws-ec2-alpha/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,24 @@ new vpc_v2.Route(this, 'IgwRoute', {
});
```

Alternatively, `Route`s can be created via a method in the `RouteTable` class. An example using the `EgressOnlyInternetGateway` construct can be seen below:
Note: `EgressOnlyInternetGateway` can only be used to set up outbound IPv6 routing.

```ts
import * as vpc_v2 from '@aws-cdk/aws-ec2-alpha';

const myVpc = new vpc_v2.VpcV2(stack, 'Vpc', {...});
const routeTable = new vpc_v2.RouteTable(stack, 'RouteTable', {
vpc: vpc.myVpc,
});
const subnet = new vpc_v2.SubnetV2(stack, 'Subnet', {...});

const eigw = new vpc_v2.EgressOnlyInternetGateway(stack, 'EIGW', {
vpcId: vpc.myVpc,
});
routeTable.addRoute('::/0', { gateway: eigw });
```

Other route targets may require a deeper set of parameters to set up properly. For instance, the example below illustrates how to set up a `NatGateway`:

```ts
Expand Down
41 changes: 36 additions & 5 deletions packages/@aws-cdk/aws-ec2-alpha/lib/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { CfnEIP, CfnEgressOnlyInternetGateway, CfnInternetGateway, CfnNatGateway
import { Construct, IDependable } from 'constructs';
import { Duration, Resource } from 'aws-cdk-lib/core';
import { IVpcV2 } from './vpc-v2-base';
import { NetworkUtils } from './util';

/**
* Indicates whether the NAT gateway supports public or private connectivity.
Expand Down Expand Up @@ -408,7 +409,7 @@ export class RouteTargetType {
/**
* Interface to define a route.
*/
export interface IRouteV2 {
interface IRoute {
/**
* The ID of the route table for the route.
* @attribute routeTable
Expand All @@ -432,7 +433,7 @@ export interface IRouteV2 {
/**
* Properties to define a route.
*/
export interface RouteProps {
interface RouteProps {
/**
* The ID of the route table for the route.
* @attribute routeTable
Expand Down Expand Up @@ -462,7 +463,7 @@ export interface RouteProps {
* Creates a new route with added functionality.
* @resource AWS::EC2::Route
*/
export class Route extends Resource implements IRouteV2 {
class Route extends Resource implements IRoute {
/**
* The IPv4 or IPv6 CIDR block used for the destination match.
*
Expand Down Expand Up @@ -491,21 +492,34 @@ export class Route extends Resource implements IRouteV2 {
*/
public readonly resource?: CfnRoute;

/**
* Destination cidr block for ipv4 or ipv6
*/
private destinationIpv6Cidr?: string;

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

this.destination = props.destination;
this.target = props.target;
this.routeTable = props.routeTable;
this.destination = props.destination;
const isDestinationIpv4 = NetworkUtils.validIp(props.destination);
if (!isDestinationIpv4) {
//TODO Validate for IPv6 CIDR range
this.destinationIpv6Cidr = props.destination;
}

if (this.target.gateway?.routerType == RouterType.EGRESS_ONLY_INTERNET_GATEWAY && isDestinationIpv4) {
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', {
routeTableId: this.routeTable.routeTableId,
destinationCidrBlock: this.destination,
destinationIpv6CidrBlock: this.destination,
destinationIpv6CidrBlock: this.destinationIpv6Cidr,
[routerTypeToPropName(this.targetRouterType)]: this.target.gateway ? this.target.gateway.routerTargetId :
this.target.endpoint ? this.target.endpoint.vpcEndpointId : null,
});
Expand Down Expand Up @@ -569,6 +583,23 @@ export class RouteTable extends Resource implements IRouteTable, IDependable {

this.routeTableId = this.resource.attrRouteTableId;
}

/**
* Adds a new custom route to the route table.
* @param destination The IPv4 or IPv6 CIDR block used for the destination match.
* @param target The gateway or endpoint targeted by the route.
*/
public addRoute(id: string, destination: string, target: RouteTargetType) {
if (!target.gateway && !target.endpoint) {
throw new Error('Target is defined without a gateway or endpoint.');
}

new Route(this, id, {
routeTable: this,
destination: destination,
target: target,
});
}
}

function routerTypeToPropName(routerType: RouterType) {
Expand Down
42 changes: 31 additions & 11 deletions packages/@aws-cdk/aws-ec2-alpha/lib/subnet-v2.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Resource, Names, Lazy } from 'aws-cdk-lib';
import { CfnRouteTable, CfnSubnet, CfnSubnetRouteTableAssociation, INetworkAcl, IRouteTable, ISubnet, NetworkAcl, SubnetNetworkAclAssociation, SubnetType } from 'aws-cdk-lib/aws-ec2';
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';
import { CidrBlock, CidrBlockIpv6 } from './util';
import { RouteTable } from './route';

/**
* Interface to define subnet CIDR
Expand Down Expand Up @@ -145,11 +146,6 @@ export class SubnetV2 extends Resource implements ISubnetV2 {
*/
public readonly ipv6CidrBlock?: string;

/**
* The route table for this subnet
*/
public readonly routeTable: IRouteTable;

/**
* The type of subnet (public or private) that this subnet represents.
* @attribute SubnetType
Expand All @@ -158,6 +154,10 @@ export class SubnetV2 extends Resource implements ISubnetV2 {

private _networkAcl: INetworkAcl;

private _routeTable: IRouteTable;

private routeTableAssociation: CfnSubnetRouteTableAssociation;

/**
* Constructs a new SubnetV2 instance.
* @param scope The parent Construct that this resource will be part of.
Expand Down Expand Up @@ -214,19 +214,22 @@ export class SubnetV2 extends Resource implements ISubnetV2 {
this._networkAcl = NetworkAcl.fromNetworkAclId(this, 'Acl', subnet.attrNetworkAclAssociationId);

if (props.routeTable) {
this.routeTable = props.routeTable;
this._routeTable = props.routeTable;
} else {
const defaultTable = new CfnRouteTable(this, 'RouteTable', {
vpcId: props.vpc.vpcId,
// Assigning a default route table
this._routeTable = new RouteTable(this, 'RouteTable', {
vpc: props.vpc,
});
this.routeTable = { routeTableId: defaultTable.ref };
}

const routeAssoc = new CfnSubnetRouteTableAssociation(this, 'RouteTableAssociation', {
subnetId: this.subnetId,
routeTableId: this.routeTable.routeTableId,
routeTableId: this._routeTable.routeTableId,
});

this.routeTableAssociation = routeAssoc;
this._internetConnectivityEstablished.add(routeAssoc);

this.internetConnectivityEstablished = this._internetConnectivityEstablished;

this.subnetType = props.subnetType;
Expand All @@ -250,6 +253,23 @@ export class SubnetV2 extends Resource implements ISubnetV2 {
subnet: this,
});
}

/**
* Return the Route Table associated with this subnet
*/
public get routeTable(): IRouteTable {
return this._routeTable;
}

/**
* Associate a Route Table with this subnet.
* @param routeTableProps The Route Table to associate with this subnet.
*/
public associateRouteTable(routeTableProps: IRouteTable) {
this._routeTable = routeTableProps;
this.routeTableAssociation.addPropertyOverride('RouteTableId', routeTableProps.routeTableId);
Copy link
Member Author

Choose a reason for hiding this comment

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

Currently we are doing an override rather than creating a new CfnSubnetRouteTableAssociation L1. If we create a new one, we would have to find some way to remove the old association L1, otherwise they will both show up in the template, and may confuse users who synthesize and see two associations for one table. The override allows us to use the same L1 object, just alter which route table it points to.

}

/**
* Returns the Network ACL associated with this subnet.
*/
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"Type": "AWS::EC2::Subnet",
"Properties": {
"AssignIpv6AddressOnCreation": false,
"AvailabilityZone": "us-west-1a",
"AvailabilityZone": "us-east-1a",
"CidrBlock": "10.0.0.0/24",
"Ipv6CidrBlock": {
"Fn::Select": [
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"Type": "AWS::EC2::Subnet",
"Properties": {
"AssignIpv6AddressOnCreation": false,
"AvailabilityZone": "us-west-1a",
"AvailabilityZone": "us-east-1a",
"CidrBlock": "10.0.0.0/24",
"Ipv6CidrBlock": {
"Fn::Select": [
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,30 @@
}
}
},
"TestRoottableeigwRouteF867084E": {
"Type": "AWS::EC2::Route",
"Properties": {
"DestinationCidrBlock": "::/0",
"DestinationIpv6CidrBlock": "::/0",
"EgressOnlyInternetGatewayId": {
"Fn::GetAtt": [
"testEOIGWEIGW54CCAD37",
"Id"
]
},
"RouteTableId": {
"Fn::GetAtt": [
"TestRoottableRouteTableFA28AA38",
"RouteTableId"
]
}
}
},
"eigwSubnetCC28B9F9": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"AssignIpv6AddressOnCreation": false,
"AvailabilityZone": "us-west-1a",
"AvailabilityZone": "us-east-1a",
"CidrBlock": "10.0.0.0/24",
"VpcId": {
"Fn::GetAtt": [
Expand Down Expand Up @@ -76,25 +95,6 @@
]
}
}
},
"testEIGWRouteEB4FE8D5": {
"Type": "AWS::EC2::Route",
"Properties": {
"DestinationCidrBlock": "0.0.0.0/0",
"DestinationIpv6CidrBlock": "0.0.0.0/0",
"EgressOnlyInternetGatewayId": {
"Fn::GetAtt": [
"testEOIGWEIGW54CCAD37",
"Id"
]
},
"RouteTableId": {
"Fn::GetAtt": [
"TestRoottableRouteTableFA28AA38",
"RouteTableId"
]
}
}
}
},
"Parameters": {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading