From 9066dc9a9a2bbe1c7a8c106323edada1d7e8c4a1 Mon Sep 17 00:00:00 2001 From: robertd Date: Thu, 18 Feb 2021 18:14:15 -0700 Subject: [PATCH 01/15] feat(elasticloadbalancingv2): Add support for application cookies --- .../aws-elasticloadbalancingv2/README.md | 27 + .../lib/alb/application-listener.ts | 40 ++ .../lib/alb/application-target-group.ts | 72 ++ .../test/alb/listener.test.ts | 53 +- .../test/alb/target-group.test.ts | 129 ++++ .../test/integ.alb.stickiness.expected.json | 672 ++++++++++++++++++ .../test/integ.alb.stickiness.ts | 76 ++ 7 files changed, 1061 insertions(+), 8 deletions(-) create mode 100644 packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.expected.json create mode 100644 packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.ts diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md index ac397ba62bd94..12f12f0fb489b 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md @@ -243,6 +243,33 @@ const group = listener.addTargets('AppFleet', { group.addTarget(asg2); ``` +### Sticky sessions for your Application Load Balancer + +By default, an Application Load Balancer routes each request independently to a registered target based on the chosen load-balancing algorithm. However, you can use the sticky session feature (also known as session affinity) to enable the load balancer to bind a user's session to a specific target. This ensures that all requests from the user during the session are sent to the same target. This feature is useful for servers that maintain state information in order to provide a continuous experience to clients. To use sticky sessions, the client must support cookies. + +Application Load Balancers support both duration-based cookies (`lb_cookie`) and application-based cookies (`app_cookie`). The key to managing sticky sessions is determining how long your load balancer should consistently route the user's request to the same target. Sticky sessions are enabled at the target group level. You can use a combination of duration-based stickiness, application-based stickiness, and no stickiness across all of your target groups. + +```ts +// Target group with load balancer cookie duration +const tg1 = new elbv2.ApplicationTargetGroup(stack, 'TG1', { + targetType: elbv2.TargetType.INSTANCE, + port: 80, + loadBalancerStickinessCookieDuration: cdk.Duration.hours(1), + vpc, +}); + +// Target group with application cookie duration +const tg2 = new elbv2.ApplicationTargetGroup(stack, 'TG2', { + targetType: elbv2.TargetType.INSTANCE, + port: 80, + appStickinessCookieDuration: cdk.Duration.hours(1), + appCookieName: 'MyDeliciousCookie', + vpc, +}); +``` + +For more information see: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/sticky-sessions.html#application-based-stickiness + ## Using Lambda Targets To use a Lambda Function as a target, use the integration class in the diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts index 1cd8a91c932aa..08c4ca7da41ff 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts @@ -363,6 +363,9 @@ export class ApplicationListener extends BaseListener implements IApplicationLis protocol: props.protocol, slowStart: props.slowStart, stickinessCookieDuration: props.stickinessCookieDuration, + loadBalancerStickinessCookieDuration: props.loadBalancerStickinessCookieDuration, + appCookieName: props.appCookieName, + appStickinessCookieDuration: props.appStickinessCookieDuration, targetGroupName: props.targetGroupName, targets: props.targets, vpc: this.loadBalancer.vpc, @@ -810,9 +813,46 @@ export interface AddApplicationTargetsProps extends AddRuleProps { * 1 second and the maximum value is 7 days (604800 seconds). * * @default Stickiness disabled + * @deprecated Use loadBalancerStickinessCookieDuration or appStickinessCookieDuration */ readonly stickinessCookieDuration?: Duration; + /** + * The load balancer stickiness cookie expiration period. + * + * Setting this value enables load balancer stickiness. + * + * After this period, the cookie is considered stale. The minimum value is + * 1 second and the maximum value is 7 days (604800 seconds). + * + * @default Stickiness disabled + */ + readonly loadBalancerStickinessCookieDuration?: Duration; + + /** + * The load balancer stickiness cookie expiration period. + * + * Setting this value enables load balancer stickiness. + * + * After this period, the cookie is considered stale. The minimum value is + * 1 second and the maximum value is 7 days (604800 seconds). + * + * @default Stickiness disabled + */ + readonly appStickinessCookieDuration?: Duration; + + /** + * The app cookie name. + * + * Indicates the name of the application-based cookie. Required if appStickinessCookieDuration is set. + * + * Names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, + * and AWSALBTG; they're reserved for use by the load balancer. + * + * @default No app cookie name + */ + readonly appCookieName?: string; + /** * The targets to add to this target group. * diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts index a1d3de25bf82d..86c393476cfaf 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts @@ -54,6 +54,7 @@ export interface ApplicationTargetGroupProps extends BaseTargetGroupProps { * 1 second and the maximum value is 7 days (604800 seconds). * * @default Duration.days(1) + * @deprecated Use loadBalancerStickinessCookieDuration or appStickinessCookieDuration */ readonly stickinessCookieDuration?: Duration; @@ -67,6 +68,42 @@ export interface ApplicationTargetGroupProps extends BaseTargetGroupProps { * @default - No targets. */ readonly targets?: IApplicationLoadBalancerTarget[]; + + /** + * The load balancer cookie stickiness expiration period. + * + * Setting this value enables load balancer stickiness. + * + * After this period, the cookie is considered stale. The minimum value is + * 1 second and the maximum value is 7 days (604800 seconds). + * + * @default Duration.days(1) + */ + readonly loadBalancerStickinessCookieDuration?: Duration; + + /** + * The app cookie stickiness expiration period. + * + * Setting this value enables app stickiness. + * + * After this period, the cookie is considered stale. The minimum value is + * 1 second and the maximum value is 7 days (604800 seconds). + * + * @default Duration.days(1) + */ + readonly appStickinessCookieDuration?: Duration; + + /** + * The app cookie name. + * + * Indicates the name of the application-based cookie. Required if appStickinessCookieDuration is set. + * + * Names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, + * and AWSALBTG; they're reserved for use by the load balancer. + * + * @default No app cookie name + */ + readonly appCookieName?: string; } /** @@ -114,6 +151,18 @@ export class ApplicationTargetGroup extends TargetGroupBase implements IApplicat if (props.stickinessCookieDuration !== undefined) { this.enableCookieStickiness(props.stickinessCookieDuration); } + if (props.appStickinessCookieDuration && props.loadBalancerStickinessCookieDuration) { + throw new Error('You can only specify one stickiness type for Application Load Balancer.'); + } + if (props.loadBalancerStickinessCookieDuration) { + this.enableLoadBalancerCookieStickiness(props.loadBalancerStickinessCookieDuration); + } + if (props.appStickinessCookieDuration) { + if (!props.appCookieName) { + throw new Error('When setting appStickinessCookieDuration you must provide appCookieName property.'); + } + this.enableAppCookieStickiness(props.appStickinessCookieDuration, props.appCookieName); + } this.addTarget(...(props.targets || [])); } } @@ -130,6 +179,7 @@ export class ApplicationTargetGroup extends TargetGroupBase implements IApplicat /** * Enable sticky routing via a cookie to members of this target group + * @deprecated - use enableLoadBalancerCookieStickiness */ public enableCookieStickiness(duration: Duration) { this.setAttribute('stickiness.enabled', 'true'); @@ -137,6 +187,28 @@ export class ApplicationTargetGroup extends TargetGroupBase implements IApplicat this.setAttribute('stickiness.lb_cookie.duration_seconds', duration.toSeconds().toString()); } + /** + * Enable load balancer sticky routing via a cookie to members of this target group + */ + public enableLoadBalancerCookieStickiness(duration: Duration) { + this.setAttribute('stickiness.enabled', 'true'); + this.setAttribute('stickiness.type', 'lb_cookie'); + this.setAttribute('stickiness.lb_cookie.duration_seconds', duration.toSeconds().toString()); + } + + /** + * Enable application sticky routing via a cookie to members of this target group + */ + public enableAppCookieStickiness(duration: Duration, cookieName: string) { + if (cookieName.startsWith('AWSALB') || cookieName.startsWith('AWSALBAPP') || cookieName.startsWith('AWSALBTG')) { + throw new Error("App cookie names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, and AWSALBTG; they're reserved for use by the load balancer."); + } + this.setAttribute('stickiness.enabled', 'true'); + this.setAttribute('stickiness.type', 'app_cookie'); + this.setAttribute('stickiness.app_cookie.cookie_name', cookieName); + this.setAttribute('stickiness.app_cookie.duration_seconds', duration.toSeconds().toString()); + } + /** * Register a connectable as a member of this target group. * diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts index b9de0961423ec..b1f8da2c651d6 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts @@ -71,7 +71,7 @@ describe('tests', () => { }); }); - test('Listener default to open - IPv4 and IPv6 (dualstack)', () => { + test('Listener default to open - IPv4 and IPv6 (dual stack)', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'Stack'); @@ -316,7 +316,7 @@ describe('tests', () => { }); }); - test('Enable stickiness for targets', () => { + test('Enable alb stickiness for targets', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'Stack'); @@ -328,7 +328,7 @@ describe('tests', () => { port: 80, targets: [new FakeSelfRegisteringTarget(stack, 'Target', vpc)], }); - group.enableCookieStickiness(cdk.Duration.hours(1)); + group.enableLoadBalancerCookieStickiness(cdk.Duration.hours(1)); // THEN expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { @@ -349,6 +349,43 @@ describe('tests', () => { }); }); + test('Enable app stickiness for targets', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Stack'); + const lb = new elbv2.ApplicationLoadBalancer(stack, 'LB', { vpc }); + const listener = lb.addListener('Listener', { port: 80 }); + + // WHEN + const group = listener.addTargets('Group', { + port: 80, + targets: [new FakeSelfRegisteringTarget(stack, 'Target', vpc)], + }); + group.enableAppCookieStickiness(cdk.Duration.hours(1), 'MyDeliciousCookie'); + + // THEN + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + TargetGroupAttributes: [ + { + Key: 'stickiness.enabled', + Value: 'true', + }, + { + Key: 'stickiness.type', + Value: 'app_cookie', + }, + { + Key: 'stickiness.app_cookie.cookie_name', + Value: 'MyDeliciousCookie', + }, + { + Key: 'stickiness.app_cookie.duration_seconds', + Value: '3600', + }, + ], + }); + }); + test('Enable health check for targets', () => { // GIVEN const stack = new cdk.Stack(); @@ -823,7 +860,7 @@ describe('tests', () => { }); }); - test('Throws when specifying both target groups and fixed reponse', () => { + test('Throws when specifying both target groups and fixed response', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -868,7 +905,7 @@ describe('tests', () => { })).toThrowError('Priority must have value greater than or equal to 1'); }); - test('Throws when specifying both target groups and redirect reponse', () => { + test('Throws when specifying both target groups and redirect response', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -970,7 +1007,7 @@ describe('tests', () => { }); }); - test('Can add additional certificates via addCertficateArns to application listener', () => { + test('Can add additional certificates via addCertificateArns to application listener', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'Stack'); @@ -1050,7 +1087,7 @@ describe('tests', () => { })).toThrowError('Both `pathPatterns` and `pathPattern` are specified, specify only one'); }); - test('Add additonal condition to listener rule', () => { + test('Add additional condition to listener rule', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'Stack'); @@ -1244,7 +1281,7 @@ describe('tests', () => { }); }); - test('Can exist together legacy style conditions and modan style conditions', () => { + test('Can exist together legacy style conditions and modern style conditions', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'Stack'); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts index 1d8df0a706d9c..24d696d7df9f1 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts @@ -88,4 +88,133 @@ describe('tests', () => { UnhealthyThresholdCount: 27, }); }); + + test('Load balancer cookie stickiness - deprecated', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + stickinessCookieDuration: cdk.Duration.minutes(5), + vpc, + }); + + // THEN + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + TargetGroupAttributes: [ + { + Key: 'stickiness.enabled', + Value: 'true', + }, + { + Key: 'stickiness.type', + Value: 'lb_cookie', + }, + { + Key: 'stickiness.lb_cookie.duration_seconds', + Value: '300', + }, + ], + }); + }); + + test('Load balancer cookie stickiness', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + loadBalancerStickinessCookieDuration: cdk.Duration.minutes(5), + vpc, + }); + + // THEN + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + TargetGroupAttributes: [ + { + Key: 'stickiness.enabled', + Value: 'true', + }, + { + Key: 'stickiness.type', + Value: 'lb_cookie', + }, + { + Key: 'stickiness.lb_cookie.duration_seconds', + Value: '300', + }, + ], + }); + }); + + test('Bad app cookie example - missing cookie name', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // THEN + expect(() => { + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + appStickinessCookieDuration: cdk.Duration.minutes(5), + vpc, + }); + }).toThrow(/When setting appStickinessCookieDuration you must provide appCookieName property./); + }); + + test('App cookie stickiness', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + appStickinessCookieDuration: cdk.Duration.minutes(5), + appCookieName: 'MyDeliciousCookie', + vpc, + }); + + // THEN + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + TargetGroupAttributes: [ + { + Key: 'stickiness.enabled', + Value: 'true', + }, + { + Key: 'stickiness.type', + Value: 'app_cookie', + }, + { + Key: 'stickiness.app_cookie.cookie_name', + Value: 'MyDeliciousCookie', + }, + { + Key: 'stickiness.app_cookie.duration_seconds', + Value: '300', + }, + ], + }); + }); + + test('Fail when LB and APP cookie are set', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // THEN + expect(() => { + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + appStickinessCookieDuration: cdk.Duration.minutes(5), + loadBalancerStickinessCookieDuration: cdk.Duration.minutes(5), + vpc, + }); + }).toThrow(/You can only specify one stickiness type for Application Load Balancer./); + }); }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.expected.json new file mode 100644 index 0000000000000..bb11c9769fa2b --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.expected.json @@ -0,0 +1,672 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC" + } + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableAssociation0B0896DC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "VPCPublicSubnet1DefaultRoute91CEF279": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet1EIP6AD938E8": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTableAssociation5A808732": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "VPCPublicSubnet2DefaultRouteB7481BBA": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet2EIP4947BC00": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPrivateSubnet1Subnet8BCA10E0": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableAssociation347902D1": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + } + } + }, + "VPCPrivateSubnet1DefaultRouteAE1D6490": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" + } + } + }, + "VPCPrivateSubnet2SubnetCFCDAA7A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTableAssociation0C73D413": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + } + }, + "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" + } + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "LB14381084D": { + "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Properties": { + "LoadBalancerAttributes": [ + { + "Key": "deletion_protection.enabled", + "Value": "false" + } + ], + "Scheme": "internet-facing", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "LB1SecurityGroupBAD3FD3E", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + ], + "Type": "application" + }, + "DependsOn": [ + "VPCPublicSubnet1DefaultRoute91CEF279", + "VPCPublicSubnet2DefaultRouteB7481BBA" + ] + }, + "LB1SecurityGroupBAD3FD3E": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Automatically created Security Group for ELB awscdkelbv2integLB1897DE5F5", + "SecurityGroupEgress": [ + { + "CidrIp": "255.255.255.255/32", + "Description": "Disallow all traffic", + "FromPort": 252, + "IpProtocol": "icmp", + "ToPort": 86 + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow from anyone on port 80", + "FromPort": 80, + "IpProtocol": "tcp", + "ToPort": 80 + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "LB1Listener15311434D": { + "Type": "AWS::ElasticLoadBalancingV2::Listener", + "Properties": { + "DefaultActions": [ + { + "TargetGroupArn": { + "Ref": "TG1F782B27A" + }, + "Type": "forward" + } + ], + "LoadBalancerArn": { + "Ref": "LB14381084D" + }, + "Port": 80, + "Protocol": "HTTP" + } + }, + "TG1F782B27A": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "Port": 80, + "Protocol": "HTTP", + "TargetGroupAttributes": [ + { + "Key": "stickiness.enabled", + "Value": "true" + }, + { + "Key": "stickiness.type", + "Value": "lb_cookie" + }, + { + "Key": "stickiness.lb_cookie.duration_seconds", + "Value": "3600" + } + ], + "TargetType": "instance", + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "LB2D6E7799C": { + "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Properties": { + "LoadBalancerAttributes": [ + { + "Key": "deletion_protection.enabled", + "Value": "false" + } + ], + "Scheme": "internet-facing", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "LB2SecurityGroup890F4405", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + ], + "Type": "application" + }, + "DependsOn": [ + "VPCPublicSubnet1DefaultRoute91CEF279", + "VPCPublicSubnet2DefaultRouteB7481BBA" + ] + }, + "LB2SecurityGroup890F4405": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Automatically created Security Group for ELB awscdkelbv2integLB21FE7870D", + "SecurityGroupEgress": [ + { + "CidrIp": "255.255.255.255/32", + "Description": "Disallow all traffic", + "FromPort": 252, + "IpProtocol": "icmp", + "ToPort": 86 + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow from anyone on port 80", + "FromPort": 80, + "IpProtocol": "tcp", + "ToPort": 80 + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "LB2Listener21DD466FB": { + "Type": "AWS::ElasticLoadBalancingV2::Listener", + "Properties": { + "DefaultActions": [ + { + "TargetGroupArn": { + "Ref": "TG2B005835E" + }, + "Type": "forward" + } + ], + "LoadBalancerArn": { + "Ref": "LB2D6E7799C" + }, + "Port": 80, + "Protocol": "HTTP" + } + }, + "TG2B005835E": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "Port": 80, + "Protocol": "HTTP", + "TargetGroupAttributes": [ + { + "Key": "stickiness.enabled", + "Value": "true" + }, + { + "Key": "stickiness.type", + "Value": "lb_cookie" + }, + { + "Key": "stickiness.lb_cookie.duration_seconds", + "Value": "3600" + } + ], + "TargetType": "instance", + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "LB3FEDE0043": { + "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Properties": { + "LoadBalancerAttributes": [ + { + "Key": "deletion_protection.enabled", + "Value": "false" + } + ], + "Scheme": "internet-facing", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "LB3SecurityGroup042865F6", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + ], + "Type": "application" + }, + "DependsOn": [ + "VPCPublicSubnet1DefaultRoute91CEF279", + "VPCPublicSubnet2DefaultRouteB7481BBA" + ] + }, + "LB3SecurityGroup042865F6": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Automatically created Security Group for ELB awscdkelbv2integLB3D8963BBE", + "SecurityGroupEgress": [ + { + "CidrIp": "255.255.255.255/32", + "Description": "Disallow all traffic", + "FromPort": 252, + "IpProtocol": "icmp", + "ToPort": 86 + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow from anyone on port 80", + "FromPort": 80, + "IpProtocol": "tcp", + "ToPort": 80 + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "LB3Listener3B73BDE3E": { + "Type": "AWS::ElasticLoadBalancingV2::Listener", + "Properties": { + "DefaultActions": [ + { + "TargetGroupArn": { + "Ref": "TG3D0A4B3B3" + }, + "Type": "forward" + } + ], + "LoadBalancerArn": { + "Ref": "LB3FEDE0043" + }, + "Port": 80, + "Protocol": "HTTP" + } + }, + "TG3D0A4B3B3": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "Port": 80, + "Protocol": "HTTP", + "TargetGroupAttributes": [ + { + "Key": "stickiness.enabled", + "Value": "true" + }, + { + "Key": "stickiness.type", + "Value": "app_cookie" + }, + { + "Key": "stickiness.app_cookie.cookie_name", + "Value": "MyDeliciousCookie" + }, + { + "Key": "stickiness.app_cookie.duration_seconds", + "Value": "3600" + } + ], + "TargetType": "instance", + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + } + } + } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.ts new file mode 100644 index 0000000000000..8c9bcdf3be6e1 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.ts @@ -0,0 +1,76 @@ +#!/usr/bin/env node +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import * as elbv2 from '../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-cdk-elbv2-integ'); + +const vpc = new ec2.Vpc(stack, 'VPC', { + maxAzs: 2, +}); + +const lb1 = new elbv2.ApplicationLoadBalancer(stack, 'LB1', { + vpc, + internetFacing: true, +}); + +const listener1 = lb1.addListener('Listener1', { + port: 80, +}); + +// Deprecated +const tg1 = new elbv2.ApplicationTargetGroup(stack, 'TG1', { + targetType: elbv2.TargetType.INSTANCE, + port: 80, + stickinessCookieDuration: cdk.Duration.hours(1), + vpc, +}); + +listener1.addTargetGroups('TG1', { + targetGroups: [tg1], +}); + + +const lb2 = new elbv2.ApplicationLoadBalancer(stack, 'LB2', { + vpc, + internetFacing: true, +}); + +const listener2 = lb2.addListener('Listener2', { + port: 80, +}); + +const tg2 = new elbv2.ApplicationTargetGroup(stack, 'TG2', { + targetType: elbv2.TargetType.INSTANCE, + port: 80, + loadBalancerStickinessCookieDuration: cdk.Duration.hours(1), + vpc, +}); + +listener2.addTargetGroups('TG2', { + targetGroups: [tg2], +}); + +const lb3 = new elbv2.ApplicationLoadBalancer(stack, 'LB3', { + vpc, + internetFacing: true, +}); + +const listener3 = lb3.addListener('Listener3', { + port: 80, +}); + +const tg3 = new elbv2.ApplicationTargetGroup(stack, 'TG3', { + targetType: elbv2.TargetType.INSTANCE, + port: 80, + appStickinessCookieDuration: cdk.Duration.hours(1), + appCookieName: 'MyDeliciousCookie', + vpc, +}); + +listener3.addTargetGroups('TG3', { + targetGroups: [tg3], +}); + +app.synth(); From d26334cafeb6d5642db28732b5cb07cdd66e816e Mon Sep 17 00:00:00 2001 From: robertd Date: Tue, 23 Feb 2021 12:28:40 -0700 Subject: [PATCH 02/15] refactor to use overloaded method --- .../lib/alb/application-listener.ts | 37 +- .../lib/alb/application-target-group.ts | 95 +- .../test/alb/listener.test.ts | 4 +- .../test/alb/target-group.test.ts | 80 +- .../test/integ.alb.stickiness.expected.json | 1139 ++++++++--------- .../test/integ.alb.stickiness.ts | 28 +- 6 files changed, 593 insertions(+), 790 deletions(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts index 08c4ca7da41ff..59e86bafdafb4 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts @@ -363,9 +363,7 @@ export class ApplicationListener extends BaseListener implements IApplicationLis protocol: props.protocol, slowStart: props.slowStart, stickinessCookieDuration: props.stickinessCookieDuration, - loadBalancerStickinessCookieDuration: props.loadBalancerStickinessCookieDuration, - appCookieName: props.appCookieName, - appStickinessCookieDuration: props.appStickinessCookieDuration, + stickinessCookieName: props.stickinessCookieName, targetGroupName: props.targetGroupName, targets: props.targets, vpc: this.loadBalancer.vpc, @@ -813,45 +811,24 @@ export interface AddApplicationTargetsProps extends AddRuleProps { * 1 second and the maximum value is 7 days (604800 seconds). * * @default Stickiness disabled - * @deprecated Use loadBalancerStickinessCookieDuration or appStickinessCookieDuration */ readonly stickinessCookieDuration?: Duration; - /** - * The load balancer stickiness cookie expiration period. - * - * Setting this value enables load balancer stickiness. - * - * After this period, the cookie is considered stale. The minimum value is - * 1 second and the maximum value is 7 days (604800 seconds). - * - * @default Stickiness disabled - */ - readonly loadBalancerStickinessCookieDuration?: Duration; - - /** - * The load balancer stickiness cookie expiration period. - * - * Setting this value enables load balancer stickiness. - * - * After this period, the cookie is considered stale. The minimum value is - * 1 second and the maximum value is 7 days (604800 seconds). - * - * @default Stickiness disabled - */ - readonly appStickinessCookieDuration?: Duration; - /** * The app cookie name. * - * Indicates the name of the application-based cookie. Required if appStickinessCookieDuration is set. + * Indicates the name of the application-based stickiness cookie. * * Names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, * and AWSALBTG; they're reserved for use by the load balancer. * + * Note: If you provide cookieName parameter application-based stickiness attributes (`app_cookie`) will be applied, + * otherwise it defaults to duration-based stickiness attributes (`lb_cookie`). + * * @default No app cookie name + * @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/sticky-sessions.html */ - readonly appCookieName?: string; + readonly stickinessCookieName?: string; /** * The targets to add to this target group. diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts index 86c393476cfaf..3632bfca75238 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts @@ -54,7 +54,6 @@ export interface ApplicationTargetGroupProps extends BaseTargetGroupProps { * 1 second and the maximum value is 7 days (604800 seconds). * * @default Duration.days(1) - * @deprecated Use loadBalancerStickinessCookieDuration or appStickinessCookieDuration */ readonly stickinessCookieDuration?: Duration; @@ -69,41 +68,21 @@ export interface ApplicationTargetGroupProps extends BaseTargetGroupProps { */ readonly targets?: IApplicationLoadBalancerTarget[]; - /** - * The load balancer cookie stickiness expiration period. - * - * Setting this value enables load balancer stickiness. - * - * After this period, the cookie is considered stale. The minimum value is - * 1 second and the maximum value is 7 days (604800 seconds). - * - * @default Duration.days(1) - */ - readonly loadBalancerStickinessCookieDuration?: Duration; - - /** - * The app cookie stickiness expiration period. - * - * Setting this value enables app stickiness. - * - * After this period, the cookie is considered stale. The minimum value is - * 1 second and the maximum value is 7 days (604800 seconds). - * - * @default Duration.days(1) - */ - readonly appStickinessCookieDuration?: Duration; - /** * The app cookie name. * - * Indicates the name of the application-based cookie. Required if appStickinessCookieDuration is set. + * Indicates the name of the application-based stickiness cookie. * * Names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, * and AWSALBTG; they're reserved for use by the load balancer. * + * Note: If you provide cookieName parameter application-based stickiness attributes (`app_cookie`) will be applied, + * otherwise it defaults to duration-based stickiness attributes (`lb_cookie`). + * * @default No app cookie name + * @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/sticky-sessions.html */ - readonly appCookieName?: string; + readonly stickinessCookieName?: string; } /** @@ -148,20 +127,16 @@ export class ApplicationTargetGroup extends TargetGroupBase implements IApplicat if (props.slowStart !== undefined) { this.setAttribute('slow_start.duration_seconds', props.slowStart.toSeconds().toString()); } - if (props.stickinessCookieDuration !== undefined) { - this.enableCookieStickiness(props.stickinessCookieDuration); - } - if (props.appStickinessCookieDuration && props.loadBalancerStickinessCookieDuration) { - throw new Error('You can only specify one stickiness type for Application Load Balancer.'); - } - if (props.loadBalancerStickinessCookieDuration) { - this.enableLoadBalancerCookieStickiness(props.loadBalancerStickinessCookieDuration); - } - if (props.appStickinessCookieDuration) { - if (!props.appCookieName) { - throw new Error('When setting appStickinessCookieDuration you must provide appCookieName property.'); + if (props.stickinessCookieName !== undefined) { + if (props.stickinessCookieName.startsWith('AWSALB') || props.stickinessCookieName.startsWith('AWSALBAPP') || props.stickinessCookieName.startsWith('AWSALBTG')) { + throw new Error('App cookie names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, and AWSALBTG; they\'re reserved for use by the load balancer.'); + } + if (props.stickinessCookieName === '') { + throw new Error('App cookie name cannot be an empty string.'); } - this.enableAppCookieStickiness(props.appStickinessCookieDuration, props.appCookieName); + } + if (props.stickinessCookieDuration) { + this.enableCookieStickiness(props.stickinessCookieDuration, props.stickinessCookieName); } this.addTarget(...(props.targets || [])); } @@ -178,35 +153,23 @@ export class ApplicationTargetGroup extends TargetGroupBase implements IApplicat } /** - * Enable sticky routing via a cookie to members of this target group - * @deprecated - use enableLoadBalancerCookieStickiness - */ - public enableCookieStickiness(duration: Duration) { - this.setAttribute('stickiness.enabled', 'true'); - this.setAttribute('stickiness.type', 'lb_cookie'); - this.setAttribute('stickiness.lb_cookie.duration_seconds', duration.toSeconds().toString()); - } - - /** - * Enable load balancer sticky routing via a cookie to members of this target group + * Enable sticky routing via a cookie to members of this target group. + * + * Note: If you provide cookieName parameter application-based stickiness attributes (`app_cookie`) will be applied, + * otherwise it defaults to duration-based stickiness attributes (`lb_cookie`). + * + * @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/sticky-sessions.html */ - public enableLoadBalancerCookieStickiness(duration: Duration) { + public enableCookieStickiness(duration: Duration, cookieName?: string) { this.setAttribute('stickiness.enabled', 'true'); - this.setAttribute('stickiness.type', 'lb_cookie'); - this.setAttribute('stickiness.lb_cookie.duration_seconds', duration.toSeconds().toString()); - } - - /** - * Enable application sticky routing via a cookie to members of this target group - */ - public enableAppCookieStickiness(duration: Duration, cookieName: string) { - if (cookieName.startsWith('AWSALB') || cookieName.startsWith('AWSALBAPP') || cookieName.startsWith('AWSALBTG')) { - throw new Error("App cookie names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, and AWSALBTG; they're reserved for use by the load balancer."); + if (cookieName) { + this.setAttribute('stickiness.type', 'app_cookie'); + this.setAttribute('stickiness.app_cookie.cookie_name', cookieName); + this.setAttribute('stickiness.app_cookie.duration_seconds', duration.toSeconds().toString()); + } else { + this.setAttribute('stickiness.type', 'lb_cookie'); + this.setAttribute('stickiness.lb_cookie.duration_seconds', duration.toSeconds().toString()); } - this.setAttribute('stickiness.enabled', 'true'); - this.setAttribute('stickiness.type', 'app_cookie'); - this.setAttribute('stickiness.app_cookie.cookie_name', cookieName); - this.setAttribute('stickiness.app_cookie.duration_seconds', duration.toSeconds().toString()); } /** diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts index b1f8da2c651d6..231279ffb932e 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/listener.test.ts @@ -328,7 +328,7 @@ describe('tests', () => { port: 80, targets: [new FakeSelfRegisteringTarget(stack, 'Target', vpc)], }); - group.enableLoadBalancerCookieStickiness(cdk.Duration.hours(1)); + group.enableCookieStickiness(cdk.Duration.hours(1)); // THEN expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { @@ -361,7 +361,7 @@ describe('tests', () => { port: 80, targets: [new FakeSelfRegisteringTarget(stack, 'Target', vpc)], }); - group.enableAppCookieStickiness(cdk.Duration.hours(1), 'MyDeliciousCookie'); + group.enableCookieStickiness(cdk.Duration.hours(1), 'MyDeliciousCookie'); // THEN expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts index 24d696d7df9f1..d7a16f3d53d09 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts @@ -89,7 +89,7 @@ describe('tests', () => { }); }); - test('Load balancer cookie stickiness - deprecated', () => { + test('Load balancer duration cookie stickiness', () => { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'Stack'); @@ -120,7 +120,7 @@ describe('tests', () => { }); }); - test('Load balancer cookie stickiness', () => { + test('Load balancer app cookie stickiness', () => { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'Stack'); @@ -128,7 +128,8 @@ describe('tests', () => { // WHEN new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { - loadBalancerStickinessCookieDuration: cdk.Duration.minutes(5), + stickinessCookieDuration: cdk.Duration.minutes(5), + stickinessCookieName: 'MyDeliciousCookie', vpc, }); @@ -141,17 +142,21 @@ describe('tests', () => { }, { Key: 'stickiness.type', - Value: 'lb_cookie', + Value: 'app_cookie', }, { - Key: 'stickiness.lb_cookie.duration_seconds', + Key: 'stickiness.app_cookie.cookie_name', + Value: 'MyDeliciousCookie', + }, + { + Key: 'stickiness.app_cookie.duration_seconds', Value: '300', }, ], }); }); - test('Bad app cookie example - missing cookie name', () => { + test('Bad stickiness cookie names example', () => { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'Stack'); @@ -159,50 +164,31 @@ describe('tests', () => { // THEN expect(() => { - new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { - appStickinessCookieDuration: cdk.Duration.minutes(5), + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup1', { + stickinessCookieDuration: cdk.Duration.minutes(5), + stickinessCookieName: 'AWSALBCookieName', vpc, }); - }).toThrow(/When setting appStickinessCookieDuration you must provide appCookieName property./); - }); - - test('App cookie stickiness', () => { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Stack'); - const vpc = new ec2.Vpc(stack, 'VPC', {}); + }).toThrow(/App cookie names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, and AWSALBTG; they're reserved for use by the load balancer./); - // WHEN - new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { - appStickinessCookieDuration: cdk.Duration.minutes(5), - appCookieName: 'MyDeliciousCookie', - vpc, - }); + expect(() => { + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup2', { + stickinessCookieDuration: cdk.Duration.minutes(5), + stickinessCookieName: 'AWSALBstickinessCookieName', + vpc, + }); + }).toThrow(/App cookie names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, and AWSALBTG; they're reserved for use by the load balancer./); - // THEN - expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { - TargetGroupAttributes: [ - { - Key: 'stickiness.enabled', - Value: 'true', - }, - { - Key: 'stickiness.type', - Value: 'app_cookie', - }, - { - Key: 'stickiness.app_cookie.cookie_name', - Value: 'MyDeliciousCookie', - }, - { - Key: 'stickiness.app_cookie.duration_seconds', - Value: '300', - }, - ], - }); + expect(() => { + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup3', { + stickinessCookieDuration: cdk.Duration.minutes(5), + stickinessCookieName: 'AWSALBTGCookieName', + vpc, + }); + }).toThrow(/App cookie names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, and AWSALBTG; they're reserved for use by the load balancer./); }); - test('Fail when LB and APP cookie are set', () => { + test('Empty stickiness cookie name', () => { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'Stack'); @@ -211,10 +197,10 @@ describe('tests', () => { // THEN expect(() => { new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { - appStickinessCookieDuration: cdk.Duration.minutes(5), - loadBalancerStickinessCookieDuration: cdk.Duration.minutes(5), + stickinessCookieDuration: cdk.Duration.minutes(5), + stickinessCookieName: '', vpc, }); - }).toThrow(/You can only specify one stickiness type for Application Load Balancer./); + }).toThrow(/App cookie name cannot be an empty string./); }); }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.expected.json index bb11c9769fa2b..ef4694bca0e8e 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.expected.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.expected.json @@ -1,672 +1,569 @@ { - "Resources": { - "VPCB9E5F0B4": { - "Type": "AWS::EC2::VPC", - "Properties": { - "CidrBlock": "10.0.0.0/16", - "EnableDnsHostnames": true, - "EnableDnsSupport": true, - "InstanceTenancy": "default", - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC" - } - ] - } - }, - "VPCPublicSubnet1SubnetB4246D30": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.0.0/18", - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "AvailabilityZone": "test-region-1a", - "MapPublicIpOnLaunch": true, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Public" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Public" - }, - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" - } - ] - } - }, - "VPCPublicSubnet1RouteTableFEE4B781": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" - } - ] - } - }, - "VPCPublicSubnet1RouteTableAssociation0B0896DC": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VPCPublicSubnet1RouteTableFEE4B781" - }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC" } - } - }, - "VPCPublicSubnet1DefaultRoute91CEF279": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" }, - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": { - "Ref": "VPCIGWB7E252D3" + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" } + ] + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" }, - "DependsOn": [ - "VPCVPCGW99B986DC" + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" + } ] - }, - "VPCPublicSubnet1EIP6AD938E8": { - "Type": "AWS::EC2::EIP", - "Properties": { - "Domain": "vpc", - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" - } - ] - } - }, - "VPCPublicSubnet1NATGatewayE0556630": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "VPCPublicSubnet1EIP6AD938E8", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" - } - ] + } + }, + "VPCPublicSubnet1RouteTableAssociation0B0896DC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" } - }, - "VPCPublicSubnet2Subnet74179F39": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.64.0/18", - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "AvailabilityZone": "test-region-1b", - "MapPublicIpOnLaunch": true, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Public" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Public" - }, - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" - } - ] + } + }, + "VPCPublicSubnet1DefaultRoute91CEF279": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" } }, - "VPCPublicSubnet2RouteTable6F1A15F1": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" - } + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet1EIP6AD938E8": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" ] - } - }, - "VPCPublicSubnet2RouteTableAssociation5A808732": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" - }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" } - } - }, - "VPCPublicSubnet2DefaultRouteB7481BBA": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + ] + } + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" }, - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": { - "Ref": "VPCIGWB7E252D3" + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" } + ] + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" }, - "DependsOn": [ - "VPCVPCGW99B986DC" + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" + } ] - }, - "VPCPublicSubnet2EIP4947BC00": { - "Type": "AWS::EC2::EIP", - "Properties": { - "Domain": "vpc", - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" - } - ] + } + }, + "VPCPublicSubnet2RouteTableAssociation5A808732": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" } - }, - "VPCPublicSubnet2NATGateway3C070193": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "VPCPublicSubnet2EIP4947BC00", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" - } - ] + } + }, + "VPCPublicSubnet2DefaultRouteB7481BBA": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" } }, - "VPCPrivateSubnet1Subnet8BCA10E0": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.128.0/18", - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "AvailabilityZone": "test-region-1a", - "MapPublicIpOnLaunch": false, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Private" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Private" - }, - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet1" - } + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet2EIP4947BC00": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" ] - } - }, - "VPCPrivateSubnet1RouteTableBE8A6027": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPrivateSubnet1Subnet8BCA10E0": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet1" - } - ] - } - }, - "VPCPrivateSubnet1RouteTableAssociation347902D1": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" }, - "SubnetId": { - "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet1" } - } - }, - "VPCPrivateSubnet1DefaultRouteAE1D6490": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": "VPCPublicSubnet1NATGatewayE0556630" + ] + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet1" } + ] + } + }, + "VPCPrivateSubnet1RouteTableAssociation347902D1": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" } - }, - "VPCPrivateSubnet2SubnetCFCDAA7A": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.192.0/18", - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "AvailabilityZone": "test-region-1b", - "MapPublicIpOnLaunch": false, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Private" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Private" - }, - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet2" - } - ] + } + }, + "VPCPrivateSubnet1DefaultRouteAE1D6490": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" } - }, - "VPCPrivateSubnet2RouteTable0A19E10E": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" + } + }, + "VPCPrivateSubnet2SubnetCFCDAA7A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet2" - } - ] - } - }, - "VPCPrivateSubnet2RouteTableAssociation0C73D413": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" }, - "SubnetId": { - "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet2" } - } - }, - "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": "VPCPublicSubnet2NATGateway3C070193" + ] + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet2" } + ] + } + }, + "VPCPrivateSubnet2RouteTableAssociation0C73D413": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" } - }, - "VPCIGWB7E252D3": { - "Type": "AWS::EC2::InternetGateway", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC" - } - ] + } + }, + "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" } - }, - "VPCVPCGW99B986DC": { - "Type": "AWS::EC2::VPCGatewayAttachment", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "InternetGatewayId": { - "Ref": "VPCIGWB7E252D3" + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-elbv2-integ/VPC" } - } - }, - "LB14381084D": { - "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", - "Properties": { - "LoadBalancerAttributes": [ - { - "Key": "deletion_protection.enabled", - "Value": "false" - } - ], - "Scheme": "internet-facing", - "SecurityGroups": [ - { - "Fn::GetAtt": [ - "LB1SecurityGroupBAD3FD3E", - "GroupId" - ] - } - ], - "Subnets": [ - { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, - { - "Ref": "VPCPublicSubnet2Subnet74179F39" - } - ], - "Type": "application" - }, - "DependsOn": [ - "VPCPublicSubnet1DefaultRoute91CEF279", - "VPCPublicSubnet2DefaultRouteB7481BBA" ] - }, - "LB1SecurityGroupBAD3FD3E": { - "Type": "AWS::EC2::SecurityGroup", - "Properties": { - "GroupDescription": "Automatically created Security Group for ELB awscdkelbv2integLB1897DE5F5", - "SecurityGroupEgress": [ - { - "CidrIp": "255.255.255.255/32", - "Description": "Disallow all traffic", - "FromPort": 252, - "IpProtocol": "icmp", - "ToPort": 86 - } - ], - "SecurityGroupIngress": [ - { - "CidrIp": "0.0.0.0/0", - "Description": "Allow from anyone on port 80", - "FromPort": 80, - "IpProtocol": "tcp", - "ToPort": 80 - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" } - }, - "LB1Listener15311434D": { - "Type": "AWS::ElasticLoadBalancingV2::Listener", - "Properties": { - "DefaultActions": [ - { - "TargetGroupArn": { - "Ref": "TG1F782B27A" - }, - "Type": "forward" - } - ], - "LoadBalancerArn": { - "Ref": "LB14381084D" + } + }, + "LB14381084D": { + "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Properties": { + "LoadBalancerAttributes": [ + { + "Key": "deletion_protection.enabled", + "Value": "false" + } + ], + "Scheme": "internet-facing", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "LB1SecurityGroupBAD3FD3E", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VPCPublicSubnet1SubnetB4246D30" }, - "Port": 80, - "Protocol": "HTTP" - } - }, - "TG1F782B27A": { - "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", - "Properties": { - "Port": 80, - "Protocol": "HTTP", - "TargetGroupAttributes": [ - { - "Key": "stickiness.enabled", - "Value": "true" - }, - { - "Key": "stickiness.type", - "Value": "lb_cookie" - }, - { - "Key": "stickiness.lb_cookie.duration_seconds", - "Value": "3600" - } - ], - "TargetType": "instance", - "VpcId": { - "Ref": "VPCB9E5F0B4" + { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + ], + "Type": "application" + }, + "DependsOn": [ + "VPCPublicSubnet1DefaultRoute91CEF279", + "VPCPublicSubnet2DefaultRouteB7481BBA" + ] + }, + "LB1SecurityGroupBAD3FD3E": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Automatically created Security Group for ELB awscdkelbv2integLB1897DE5F5", + "SecurityGroupEgress": [ + { + "CidrIp": "255.255.255.255/32", + "Description": "Disallow all traffic", + "FromPort": 252, + "IpProtocol": "icmp", + "ToPort": 86 + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow from anyone on port 80", + "FromPort": 80, + "IpProtocol": "tcp", + "ToPort": 80 } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" } - }, - "LB2D6E7799C": { - "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", - "Properties": { - "LoadBalancerAttributes": [ - { - "Key": "deletion_protection.enabled", - "Value": "false" - } - ], - "Scheme": "internet-facing", - "SecurityGroups": [ - { - "Fn::GetAtt": [ - "LB2SecurityGroup890F4405", - "GroupId" - ] - } - ], - "Subnets": [ - { - "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + }, + "LB1Listener15311434D": { + "Type": "AWS::ElasticLoadBalancingV2::Listener", + "Properties": { + "DefaultActions": [ + { + "TargetGroupArn": { + "Ref": "TG1F782B27A" }, - { - "Ref": "VPCPublicSubnet2Subnet74179F39" - } - ], - "Type": "application" + "Type": "forward" + } + ], + "LoadBalancerArn": { + "Ref": "LB14381084D" }, - "DependsOn": [ - "VPCPublicSubnet1DefaultRoute91CEF279", - "VPCPublicSubnet2DefaultRouteB7481BBA" - ] - }, - "LB2SecurityGroup890F4405": { - "Type": "AWS::EC2::SecurityGroup", - "Properties": { - "GroupDescription": "Automatically created Security Group for ELB awscdkelbv2integLB21FE7870D", - "SecurityGroupEgress": [ - { - "CidrIp": "255.255.255.255/32", - "Description": "Disallow all traffic", - "FromPort": 252, - "IpProtocol": "icmp", - "ToPort": 86 - } - ], - "SecurityGroupIngress": [ - { - "CidrIp": "0.0.0.0/0", - "Description": "Allow from anyone on port 80", - "FromPort": 80, - "IpProtocol": "tcp", - "ToPort": 80 - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" + "Port": 80, + "Protocol": "HTTP" + } + }, + "TG1F782B27A": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "Port": 80, + "Protocol": "HTTP", + "TargetGroupAttributes": [ + { + "Key": "stickiness.enabled", + "Value": "true" + }, + { + "Key": "stickiness.type", + "Value": "lb_cookie" + }, + { + "Key": "stickiness.lb_cookie.duration_seconds", + "Value": "3600" } + ], + "TargetType": "instance", + "VpcId": { + "Ref": "VPCB9E5F0B4" } - }, - "LB2Listener21DD466FB": { - "Type": "AWS::ElasticLoadBalancingV2::Listener", - "Properties": { - "DefaultActions": [ - { - "TargetGroupArn": { - "Ref": "TG2B005835E" - }, - "Type": "forward" - } - ], - "LoadBalancerArn": { - "Ref": "LB2D6E7799C" + } + }, + "LB2D6E7799C": { + "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Properties": { + "LoadBalancerAttributes": [ + { + "Key": "deletion_protection.enabled", + "Value": "false" + } + ], + "Scheme": "internet-facing", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "LB2SecurityGroup890F4405", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VPCPublicSubnet1SubnetB4246D30" }, - "Port": 80, - "Protocol": "HTTP" - } - }, - "TG2B005835E": { - "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", - "Properties": { - "Port": 80, - "Protocol": "HTTP", - "TargetGroupAttributes": [ - { - "Key": "stickiness.enabled", - "Value": "true" - }, - { - "Key": "stickiness.type", - "Value": "lb_cookie" - }, - { - "Key": "stickiness.lb_cookie.duration_seconds", - "Value": "3600" - } - ], - "TargetType": "instance", - "VpcId": { - "Ref": "VPCB9E5F0B4" + { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + ], + "Type": "application" + }, + "DependsOn": [ + "VPCPublicSubnet1DefaultRoute91CEF279", + "VPCPublicSubnet2DefaultRouteB7481BBA" + ] + }, + "LB2SecurityGroup890F4405": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Automatically created Security Group for ELB awscdkelbv2integLB21FE7870D", + "SecurityGroupEgress": [ + { + "CidrIp": "255.255.255.255/32", + "Description": "Disallow all traffic", + "FromPort": 252, + "IpProtocol": "icmp", + "ToPort": 86 } + ], + "SecurityGroupIngress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow from anyone on port 80", + "FromPort": 80, + "IpProtocol": "tcp", + "ToPort": 80 + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" } - }, - "LB3FEDE0043": { - "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", - "Properties": { - "LoadBalancerAttributes": [ - { - "Key": "deletion_protection.enabled", - "Value": "false" - } - ], - "Scheme": "internet-facing", - "SecurityGroups": [ - { - "Fn::GetAtt": [ - "LB3SecurityGroup042865F6", - "GroupId" - ] - } - ], - "Subnets": [ - { - "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + }, + "LB2Listener21DD466FB": { + "Type": "AWS::ElasticLoadBalancingV2::Listener", + "Properties": { + "DefaultActions": [ + { + "TargetGroupArn": { + "Ref": "TG2B005835E" }, - { - "Ref": "VPCPublicSubnet2Subnet74179F39" - } - ], - "Type": "application" - }, - "DependsOn": [ - "VPCPublicSubnet1DefaultRoute91CEF279", - "VPCPublicSubnet2DefaultRouteB7481BBA" - ] - }, - "LB3SecurityGroup042865F6": { - "Type": "AWS::EC2::SecurityGroup", - "Properties": { - "GroupDescription": "Automatically created Security Group for ELB awscdkelbv2integLB3D8963BBE", - "SecurityGroupEgress": [ - { - "CidrIp": "255.255.255.255/32", - "Description": "Disallow all traffic", - "FromPort": 252, - "IpProtocol": "icmp", - "ToPort": 86 - } - ], - "SecurityGroupIngress": [ - { - "CidrIp": "0.0.0.0/0", - "Description": "Allow from anyone on port 80", - "FromPort": 80, - "IpProtocol": "tcp", - "ToPort": 80 - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" + "Type": "forward" } - } - }, - "LB3Listener3B73BDE3E": { - "Type": "AWS::ElasticLoadBalancingV2::Listener", - "Properties": { - "DefaultActions": [ - { - "TargetGroupArn": { - "Ref": "TG3D0A4B3B3" - }, - "Type": "forward" - } - ], - "LoadBalancerArn": { - "Ref": "LB3FEDE0043" + ], + "LoadBalancerArn": { + "Ref": "LB2D6E7799C" + }, + "Port": 80, + "Protocol": "HTTP" + } + }, + "TG2B005835E": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "Port": 80, + "Protocol": "HTTP", + "TargetGroupAttributes": [ + { + "Key": "stickiness.enabled", + "Value": "true" }, - "Port": 80, - "Protocol": "HTTP" - } - }, - "TG3D0A4B3B3": { - "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", - "Properties": { - "Port": 80, - "Protocol": "HTTP", - "TargetGroupAttributes": [ - { - "Key": "stickiness.enabled", - "Value": "true" - }, - { - "Key": "stickiness.type", - "Value": "app_cookie" - }, - { - "Key": "stickiness.app_cookie.cookie_name", - "Value": "MyDeliciousCookie" - }, - { - "Key": "stickiness.app_cookie.duration_seconds", - "Value": "3600" - } - ], - "TargetType": "instance", - "VpcId": { - "Ref": "VPCB9E5F0B4" + { + "Key": "stickiness.type", + "Value": "app_cookie" + }, + { + "Key": "stickiness.app_cookie.cookie_name", + "Value": "MyDeliciousCookie" + }, + { + "Key": "stickiness.app_cookie.duration_seconds", + "Value": "3600" } + ], + "TargetType": "instance", + "VpcId": { + "Ref": "VPCB9E5F0B4" } } } - } \ No newline at end of file + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.ts index 8c9bcdf3be6e1..9ce66c2e374b3 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.ts @@ -10,6 +10,7 @@ const vpc = new ec2.Vpc(stack, 'VPC', { maxAzs: 2, }); +// Duration-based stickiness cookie const lb1 = new elbv2.ApplicationLoadBalancer(stack, 'LB1', { vpc, internetFacing: true, @@ -19,7 +20,6 @@ const listener1 = lb1.addListener('Listener1', { port: 80, }); -// Deprecated const tg1 = new elbv2.ApplicationTargetGroup(stack, 'TG1', { targetType: elbv2.TargetType.INSTANCE, port: 80, @@ -31,7 +31,7 @@ listener1.addTargetGroups('TG1', { targetGroups: [tg1], }); - +// Application-based stickiness cookie const lb2 = new elbv2.ApplicationLoadBalancer(stack, 'LB2', { vpc, internetFacing: true, @@ -44,7 +44,8 @@ const listener2 = lb2.addListener('Listener2', { const tg2 = new elbv2.ApplicationTargetGroup(stack, 'TG2', { targetType: elbv2.TargetType.INSTANCE, port: 80, - loadBalancerStickinessCookieDuration: cdk.Duration.hours(1), + stickinessCookieDuration: cdk.Duration.hours(1), + stickinessCookieName: 'MyDeliciousCookie', vpc, }); @@ -52,25 +53,4 @@ listener2.addTargetGroups('TG2', { targetGroups: [tg2], }); -const lb3 = new elbv2.ApplicationLoadBalancer(stack, 'LB3', { - vpc, - internetFacing: true, -}); - -const listener3 = lb3.addListener('Listener3', { - port: 80, -}); - -const tg3 = new elbv2.ApplicationTargetGroup(stack, 'TG3', { - targetType: elbv2.TargetType.INSTANCE, - port: 80, - appStickinessCookieDuration: cdk.Duration.hours(1), - appCookieName: 'MyDeliciousCookie', - vpc, -}); - -listener3.addTargetGroups('TG3', { - targetGroups: [tg3], -}); - app.synth(); From db848f71ad269f5175a6be9c74a4a0366f015ae9 Mon Sep 17 00:00:00 2001 From: robertd Date: Tue, 23 Feb 2021 12:39:56 -0700 Subject: [PATCH 03/15] update readme --- packages/@aws-cdk/aws-elasticloadbalancingv2/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md index 12f12f0fb489b..729b5e0d32277 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md @@ -250,20 +250,20 @@ By default, an Application Load Balancer routes each request independently to a Application Load Balancers support both duration-based cookies (`lb_cookie`) and application-based cookies (`app_cookie`). The key to managing sticky sessions is determining how long your load balancer should consistently route the user's request to the same target. Sticky sessions are enabled at the target group level. You can use a combination of duration-based stickiness, application-based stickiness, and no stickiness across all of your target groups. ```ts -// Target group with load balancer cookie duration +// Target group with duration-based cookie stickiness duration const tg1 = new elbv2.ApplicationTargetGroup(stack, 'TG1', { targetType: elbv2.TargetType.INSTANCE, port: 80, - loadBalancerStickinessCookieDuration: cdk.Duration.hours(1), + stickinessCookieDuration: cdk.Duration.minutes(5), vpc, }); -// Target group with application cookie duration +// Target group with application-based cookie stickiness duration const tg2 = new elbv2.ApplicationTargetGroup(stack, 'TG2', { targetType: elbv2.TargetType.INSTANCE, port: 80, - appStickinessCookieDuration: cdk.Duration.hours(1), - appCookieName: 'MyDeliciousCookie', + stickinessCookieDuration: cdk.Duration.minutes(5), + stickinessCookieName: 'MyDeliciousCookie', vpc, }); ``` From f323123bc3bd905d5e2071356f8830391b01c01b Mon Sep 17 00:00:00 2001 From: robertd Date: Tue, 23 Feb 2021 12:48:43 -0700 Subject: [PATCH 04/15] update readme --- packages/@aws-cdk/aws-elasticloadbalancingv2/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md index 729b5e0d32277..b69ea7ee9016f 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md @@ -250,7 +250,7 @@ By default, an Application Load Balancer routes each request independently to a Application Load Balancers support both duration-based cookies (`lb_cookie`) and application-based cookies (`app_cookie`). The key to managing sticky sessions is determining how long your load balancer should consistently route the user's request to the same target. Sticky sessions are enabled at the target group level. You can use a combination of duration-based stickiness, application-based stickiness, and no stickiness across all of your target groups. ```ts -// Target group with duration-based cookie stickiness duration +// Target group with duration-based stickiness const tg1 = new elbv2.ApplicationTargetGroup(stack, 'TG1', { targetType: elbv2.TargetType.INSTANCE, port: 80, @@ -258,7 +258,7 @@ const tg1 = new elbv2.ApplicationTargetGroup(stack, 'TG1', { vpc, }); -// Target group with application-based cookie stickiness duration +// Target group with application-based stickiness const tg2 = new elbv2.ApplicationTargetGroup(stack, 'TG2', { targetType: elbv2.TargetType.INSTANCE, port: 80, From 2e79f1e77cdd30f7f2cb3b82387ad6816894d924 Mon Sep 17 00:00:00 2001 From: robertd Date: Tue, 23 Feb 2021 13:00:02 -0700 Subject: [PATCH 05/15] update documentation --- .../lib/alb/application-listener.ts | 4 +-- .../lib/alb/application-target-group.ts | 26 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts index 59e86bafdafb4..a2073d8f0b24e 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts @@ -822,8 +822,8 @@ export interface AddApplicationTargetsProps extends AddRuleProps { * Names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, * and AWSALBTG; they're reserved for use by the load balancer. * - * Note: If you provide cookieName parameter application-based stickiness attributes (`app_cookie`) will be applied, - * otherwise it defaults to duration-based stickiness attributes (`lb_cookie`). + * Note: `stickinessCookieName` parameter depends on the presence of `stickinessCookieDuration` parameter. + * If `stickinessCookieDuration` is not set, `stickinessCookieName` will be omitted. * * @default No app cookie name * @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/sticky-sessions.html diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts index 3632bfca75238..ab23bed6efbd5 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts @@ -57,17 +57,6 @@ export interface ApplicationTargetGroupProps extends BaseTargetGroupProps { */ readonly stickinessCookieDuration?: Duration; - /** - * The targets to add to this target group. - * - * Can be `Instance`, `IPAddress`, or any self-registering load balancing - * target. If you use either `Instance` or `IPAddress` as targets, all - * target must be of the same type. - * - * @default - No targets. - */ - readonly targets?: IApplicationLoadBalancerTarget[]; - /** * The app cookie name. * @@ -76,13 +65,24 @@ export interface ApplicationTargetGroupProps extends BaseTargetGroupProps { * Names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, * and AWSALBTG; they're reserved for use by the load balancer. * - * Note: If you provide cookieName parameter application-based stickiness attributes (`app_cookie`) will be applied, - * otherwise it defaults to duration-based stickiness attributes (`lb_cookie`). + * Note: `stickinessCookieName` parameter depends on the presence of `stickinessCookieDuration` parameter. + * If `stickinessCookieDuration` is not set, `stickinessCookieName` will be omitted. * * @default No app cookie name * @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/sticky-sessions.html */ readonly stickinessCookieName?: string; + + /** + * The targets to add to this target group. + * + * Can be `Instance`, `IPAddress`, or any self-registering load balancing + * target. If you use either `Instance` or `IPAddress` as targets, all + * target must be of the same type. + * + * @default - No targets. + */ + readonly targets?: IApplicationLoadBalancerTarget[]; } /** From 4c9a91db4b8955c2f6d939fe1d60357d88e8165a Mon Sep 17 00:00:00 2001 From: robertd Date: Wed, 24 Feb 2021 07:41:43 -0700 Subject: [PATCH 06/15] move app cookie checks --- .../lib/alb/application-target-group.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts index ab23bed6efbd5..483a17b278bfb 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts @@ -127,14 +127,6 @@ export class ApplicationTargetGroup extends TargetGroupBase implements IApplicat if (props.slowStart !== undefined) { this.setAttribute('slow_start.duration_seconds', props.slowStart.toSeconds().toString()); } - if (props.stickinessCookieName !== undefined) { - if (props.stickinessCookieName.startsWith('AWSALB') || props.stickinessCookieName.startsWith('AWSALBAPP') || props.stickinessCookieName.startsWith('AWSALBTG')) { - throw new Error('App cookie names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, and AWSALBTG; they\'re reserved for use by the load balancer.'); - } - if (props.stickinessCookieName === '') { - throw new Error('App cookie name cannot be an empty string.'); - } - } if (props.stickinessCookieDuration) { this.enableCookieStickiness(props.stickinessCookieDuration, props.stickinessCookieName); } @@ -161,6 +153,14 @@ export class ApplicationTargetGroup extends TargetGroupBase implements IApplicat * @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/sticky-sessions.html */ public enableCookieStickiness(duration: Duration, cookieName?: string) { + if (cookieName !== undefined) { + if (cookieName.startsWith('AWSALB') || cookieName.startsWith('AWSALBAPP') || cookieName.startsWith('AWSALBTG')) { + throw new Error('App cookie names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, and AWSALBTG; they\'re reserved for use by the load balancer.'); + } + if (cookieName === '') { + throw new Error('App cookie name cannot be an empty string.'); + } + } this.setAttribute('stickiness.enabled', 'true'); if (cookieName) { this.setAttribute('stickiness.type', 'app_cookie'); From 7442bed433985f1db150fd86e2c17e865ba1e1c4 Mon Sep 17 00:00:00 2001 From: Robert Djurasaj Date: Wed, 24 Feb 2021 08:52:38 -0700 Subject: [PATCH 07/15] Update packages/@aws-cdk/aws-elasticloadbalancingv2/README.md Co-authored-by: Nick Lynch --- packages/@aws-cdk/aws-elasticloadbalancingv2/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md index b69ea7ee9016f..89baa6791ff2c 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md @@ -250,7 +250,7 @@ By default, an Application Load Balancer routes each request independently to a Application Load Balancers support both duration-based cookies (`lb_cookie`) and application-based cookies (`app_cookie`). The key to managing sticky sessions is determining how long your load balancer should consistently route the user's request to the same target. Sticky sessions are enabled at the target group level. You can use a combination of duration-based stickiness, application-based stickiness, and no stickiness across all of your target groups. ```ts -// Target group with duration-based stickiness +// Target group with duration-based stickiness with load-balancer generated cookie const tg1 = new elbv2.ApplicationTargetGroup(stack, 'TG1', { targetType: elbv2.TargetType.INSTANCE, port: 80, From f922c6b16680b9cd277e1589df5942ad147c6ec9 Mon Sep 17 00:00:00 2001 From: Robert Djurasaj Date: Wed, 24 Feb 2021 08:53:23 -0700 Subject: [PATCH 08/15] Update packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts Co-authored-by: Nick Lynch --- .../lib/alb/application-listener.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts index a2073d8f0b24e..e0a1855003d8c 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts @@ -815,9 +815,7 @@ export interface AddApplicationTargetsProps extends AddRuleProps { readonly stickinessCookieDuration?: Duration; /** - * The app cookie name. - * - * Indicates the name of the application-based stickiness cookie. + * The name of an application-based stickiness cookie. * * Names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, * and AWSALBTG; they're reserved for use by the load balancer. From ed8c0ca719803393f6e6301cc1077ea09e4d9df4 Mon Sep 17 00:00:00 2001 From: Robert Djurasaj Date: Wed, 24 Feb 2021 08:54:11 -0700 Subject: [PATCH 09/15] Update packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts Co-authored-by: Nick Lynch --- .../aws-elasticloadbalancingv2/lib/alb/application-listener.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts index e0a1855003d8c..1844314e1f560 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts @@ -823,7 +823,7 @@ export interface AddApplicationTargetsProps extends AddRuleProps { * Note: `stickinessCookieName` parameter depends on the presence of `stickinessCookieDuration` parameter. * If `stickinessCookieDuration` is not set, `stickinessCookieName` will be omitted. * - * @default No app cookie name + * @default - If `stickinessCookieDuration` is set, a load-balancer generated cookie is used. Otherwise, no stickiness is defined. * @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/sticky-sessions.html */ readonly stickinessCookieName?: string; From 0d1ea0562b765f04f8e0158cb24c695ab2cc8c9b Mon Sep 17 00:00:00 2001 From: Robert Djurasaj Date: Wed, 24 Feb 2021 08:54:36 -0700 Subject: [PATCH 10/15] Update packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts Co-authored-by: Nick Lynch --- .../lib/alb/application-target-group.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts index 483a17b278bfb..1f48aa2ac3549 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts @@ -147,7 +147,7 @@ export class ApplicationTargetGroup extends TargetGroupBase implements IApplicat /** * Enable sticky routing via a cookie to members of this target group. * - * Note: If you provide cookieName parameter application-based stickiness attributes (`app_cookie`) will be applied, + * Note: If the `cookieName` parameter is set, application-based stickiness will be applied, * otherwise it defaults to duration-based stickiness attributes (`lb_cookie`). * * @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/sticky-sessions.html From ca19300023b83890115e192bfa4d9881ab42b121 Mon Sep 17 00:00:00 2001 From: Robert Djurasaj Date: Wed, 24 Feb 2021 09:01:14 -0700 Subject: [PATCH 11/15] Update packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts Co-authored-by: Nick Lynch --- .../test/alb/target-group.test.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts index d7a16f3d53d09..5a0da7d1ee83c 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts @@ -163,13 +163,15 @@ describe('tests', () => { const vpc = new ec2.Vpc(stack, 'VPC', {}); // THEN - expect(() => { - new elbv2.ApplicationTargetGroup(stack, 'TargetGroup1', { - stickinessCookieDuration: cdk.Duration.minutes(5), - stickinessCookieName: 'AWSALBCookieName', - vpc, - }); - }).toThrow(/App cookie names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, and AWSALBTG; they're reserved for use by the load balancer./); + ['AWSALBCookieName', 'AWSALBstickinessCookieName', 'AWSALBTGCookieName'].forEach(badCookieName => { + expect(() => { + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup1', { + stickinessCookieDuration: cdk.Duration.minutes(5), + stickinessCookieName: badCookieName, + vpc, + }); + }).toThrow(errMessage); + }); expect(() => { new elbv2.ApplicationTargetGroup(stack, 'TargetGroup2', { From a73331045588debf8dad50b3fcd5bc3c6632df69 Mon Sep 17 00:00:00 2001 From: robertd Date: Wed, 24 Feb 2021 09:07:23 -0700 Subject: [PATCH 12/15] fix tests --- .../test/alb/target-group.test.ts | 23 ++++--------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts index 5a0da7d1ee83c..f1b71756e43db 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts @@ -156,38 +156,23 @@ describe('tests', () => { }); }); - test('Bad stickiness cookie names example', () => { + test('Bad stickiness cookie names', () => { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'Stack'); const vpc = new ec2.Vpc(stack, 'VPC', {}); + const errMessage = 'App cookie names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, and AWSALBTG; they\'re reserved for use by the load balancer'; // THEN - ['AWSALBCookieName', 'AWSALBstickinessCookieName', 'AWSALBTGCookieName'].forEach(badCookieName => { + ['AWSALBCookieName', 'AWSALBstickinessCookieName', 'AWSALBTGCookieName'].forEach((badCookieName, i) => { expect(() => { - new elbv2.ApplicationTargetGroup(stack, 'TargetGroup1', { + new elbv2.ApplicationTargetGroup(stack, `TargetGroup${i}`, { stickinessCookieDuration: cdk.Duration.minutes(5), stickinessCookieName: badCookieName, vpc, }); }).toThrow(errMessage); }); - - expect(() => { - new elbv2.ApplicationTargetGroup(stack, 'TargetGroup2', { - stickinessCookieDuration: cdk.Duration.minutes(5), - stickinessCookieName: 'AWSALBstickinessCookieName', - vpc, - }); - }).toThrow(/App cookie names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, and AWSALBTG; they're reserved for use by the load balancer./); - - expect(() => { - new elbv2.ApplicationTargetGroup(stack, 'TargetGroup3', { - stickinessCookieDuration: cdk.Duration.minutes(5), - stickinessCookieName: 'AWSALBTGCookieName', - vpc, - }); - }).toThrow(/App cookie names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, and AWSALBTG; they're reserved for use by the load balancer./); }); test('Empty stickiness cookie name', () => { From 459097fe2fd9968b505434c4bca97d7fb06c5636 Mon Sep 17 00:00:00 2001 From: robertd Date: Wed, 24 Feb 2021 09:36:48 -0700 Subject: [PATCH 13/15] consolidate alb integration tests --- .../test/integ.alb.expected.json | 32 + .../test/integ.alb.stickiness.expected.json | 569 ------------------ .../test/integ.alb.stickiness.ts | 56 -- .../test/integ.alb.ts | 3 + 4 files changed, 35 insertions(+), 625 deletions(-) delete mode 100644 packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.expected.json delete mode 100644 packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.ts diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.expected.json index 8fd29b717c9d5..c1dfdcb095bec 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.expected.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.expected.json @@ -438,6 +438,20 @@ "Properties": { "Port": 80, "Protocol": "HTTP", + "TargetGroupAttributes": [ + { + "Key": "stickiness.enabled", + "Value": "true" + }, + { + "Key": "stickiness.type", + "Value": "lb_cookie" + }, + { + "Key": "stickiness.lb_cookie.duration_seconds", + "Value": "300" + } + ], "Targets": [ { "Id": "10.0.128.4" @@ -454,6 +468,24 @@ "Properties": { "Port": 80, "Protocol": "HTTP", + "TargetGroupAttributes": [ + { + "Key": "stickiness.enabled", + "Value": "true" + }, + { + "Key": "stickiness.type", + "Value": "app_cookie" + }, + { + "Key": "stickiness.app_cookie.cookie_name", + "Value": "MyDeliciousCookie" + }, + { + "Key": "stickiness.app_cookie.duration_seconds", + "Value": "300" + } + ], "Targets": [ { "Id": "10.0.128.5" diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.expected.json deleted file mode 100644 index ef4694bca0e8e..0000000000000 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.expected.json +++ /dev/null @@ -1,569 +0,0 @@ -{ - "Resources": { - "VPCB9E5F0B4": { - "Type": "AWS::EC2::VPC", - "Properties": { - "CidrBlock": "10.0.0.0/16", - "EnableDnsHostnames": true, - "EnableDnsSupport": true, - "InstanceTenancy": "default", - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC" - } - ] - } - }, - "VPCPublicSubnet1SubnetB4246D30": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.0.0/18", - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "AvailabilityZone": "test-region-1a", - "MapPublicIpOnLaunch": true, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Public" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Public" - }, - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" - } - ] - } - }, - "VPCPublicSubnet1RouteTableFEE4B781": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" - } - ] - } - }, - "VPCPublicSubnet1RouteTableAssociation0B0896DC": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VPCPublicSubnet1RouteTableFEE4B781" - }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - } - } - }, - "VPCPublicSubnet1DefaultRoute91CEF279": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VPCPublicSubnet1RouteTableFEE4B781" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": { - "Ref": "VPCIGWB7E252D3" - } - }, - "DependsOn": [ - "VPCVPCGW99B986DC" - ] - }, - "VPCPublicSubnet1EIP6AD938E8": { - "Type": "AWS::EC2::EIP", - "Properties": { - "Domain": "vpc", - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" - } - ] - } - }, - "VPCPublicSubnet1NATGatewayE0556630": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "VPCPublicSubnet1EIP6AD938E8", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet1" - } - ] - } - }, - "VPCPublicSubnet2Subnet74179F39": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.64.0/18", - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "AvailabilityZone": "test-region-1b", - "MapPublicIpOnLaunch": true, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Public" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Public" - }, - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" - } - ] - } - }, - "VPCPublicSubnet2RouteTable6F1A15F1": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" - } - ] - } - }, - "VPCPublicSubnet2RouteTableAssociation5A808732": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" - }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - } - } - }, - "VPCPublicSubnet2DefaultRouteB7481BBA": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": { - "Ref": "VPCIGWB7E252D3" - } - }, - "DependsOn": [ - "VPCVPCGW99B986DC" - ] - }, - "VPCPublicSubnet2EIP4947BC00": { - "Type": "AWS::EC2::EIP", - "Properties": { - "Domain": "vpc", - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" - } - ] - } - }, - "VPCPublicSubnet2NATGateway3C070193": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "VPCPublicSubnet2EIP4947BC00", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PublicSubnet2" - } - ] - } - }, - "VPCPrivateSubnet1Subnet8BCA10E0": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.128.0/18", - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "AvailabilityZone": "test-region-1a", - "MapPublicIpOnLaunch": false, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Private" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Private" - }, - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet1" - } - ] - } - }, - "VPCPrivateSubnet1RouteTableBE8A6027": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet1" - } - ] - } - }, - "VPCPrivateSubnet1RouteTableAssociation347902D1": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" - }, - "SubnetId": { - "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" - } - } - }, - "VPCPrivateSubnet1DefaultRouteAE1D6490": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": "VPCPublicSubnet1NATGatewayE0556630" - } - } - }, - "VPCPrivateSubnet2SubnetCFCDAA7A": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "CidrBlock": "10.0.192.0/18", - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "AvailabilityZone": "test-region-1b", - "MapPublicIpOnLaunch": false, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Private" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Private" - }, - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet2" - } - ] - } - }, - "VPCPrivateSubnet2RouteTable0A19E10E": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC/PrivateSubnet2" - } - ] - } - }, - "VPCPrivateSubnet2RouteTableAssociation0C73D413": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" - }, - "SubnetId": { - "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" - } - } - }, - "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": "VPCPublicSubnet2NATGateway3C070193" - } - } - }, - "VPCIGWB7E252D3": { - "Type": "AWS::EC2::InternetGateway", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "aws-cdk-elbv2-integ/VPC" - } - ] - } - }, - "VPCVPCGW99B986DC": { - "Type": "AWS::EC2::VPCGatewayAttachment", - "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, - "InternetGatewayId": { - "Ref": "VPCIGWB7E252D3" - } - } - }, - "LB14381084D": { - "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", - "Properties": { - "LoadBalancerAttributes": [ - { - "Key": "deletion_protection.enabled", - "Value": "false" - } - ], - "Scheme": "internet-facing", - "SecurityGroups": [ - { - "Fn::GetAtt": [ - "LB1SecurityGroupBAD3FD3E", - "GroupId" - ] - } - ], - "Subnets": [ - { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, - { - "Ref": "VPCPublicSubnet2Subnet74179F39" - } - ], - "Type": "application" - }, - "DependsOn": [ - "VPCPublicSubnet1DefaultRoute91CEF279", - "VPCPublicSubnet2DefaultRouteB7481BBA" - ] - }, - "LB1SecurityGroupBAD3FD3E": { - "Type": "AWS::EC2::SecurityGroup", - "Properties": { - "GroupDescription": "Automatically created Security Group for ELB awscdkelbv2integLB1897DE5F5", - "SecurityGroupEgress": [ - { - "CidrIp": "255.255.255.255/32", - "Description": "Disallow all traffic", - "FromPort": 252, - "IpProtocol": "icmp", - "ToPort": 86 - } - ], - "SecurityGroupIngress": [ - { - "CidrIp": "0.0.0.0/0", - "Description": "Allow from anyone on port 80", - "FromPort": 80, - "IpProtocol": "tcp", - "ToPort": 80 - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "LB1Listener15311434D": { - "Type": "AWS::ElasticLoadBalancingV2::Listener", - "Properties": { - "DefaultActions": [ - { - "TargetGroupArn": { - "Ref": "TG1F782B27A" - }, - "Type": "forward" - } - ], - "LoadBalancerArn": { - "Ref": "LB14381084D" - }, - "Port": 80, - "Protocol": "HTTP" - } - }, - "TG1F782B27A": { - "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", - "Properties": { - "Port": 80, - "Protocol": "HTTP", - "TargetGroupAttributes": [ - { - "Key": "stickiness.enabled", - "Value": "true" - }, - { - "Key": "stickiness.type", - "Value": "lb_cookie" - }, - { - "Key": "stickiness.lb_cookie.duration_seconds", - "Value": "3600" - } - ], - "TargetType": "instance", - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "LB2D6E7799C": { - "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", - "Properties": { - "LoadBalancerAttributes": [ - { - "Key": "deletion_protection.enabled", - "Value": "false" - } - ], - "Scheme": "internet-facing", - "SecurityGroups": [ - { - "Fn::GetAtt": [ - "LB2SecurityGroup890F4405", - "GroupId" - ] - } - ], - "Subnets": [ - { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, - { - "Ref": "VPCPublicSubnet2Subnet74179F39" - } - ], - "Type": "application" - }, - "DependsOn": [ - "VPCPublicSubnet1DefaultRoute91CEF279", - "VPCPublicSubnet2DefaultRouteB7481BBA" - ] - }, - "LB2SecurityGroup890F4405": { - "Type": "AWS::EC2::SecurityGroup", - "Properties": { - "GroupDescription": "Automatically created Security Group for ELB awscdkelbv2integLB21FE7870D", - "SecurityGroupEgress": [ - { - "CidrIp": "255.255.255.255/32", - "Description": "Disallow all traffic", - "FromPort": 252, - "IpProtocol": "icmp", - "ToPort": 86 - } - ], - "SecurityGroupIngress": [ - { - "CidrIp": "0.0.0.0/0", - "Description": "Allow from anyone on port 80", - "FromPort": 80, - "IpProtocol": "tcp", - "ToPort": 80 - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "LB2Listener21DD466FB": { - "Type": "AWS::ElasticLoadBalancingV2::Listener", - "Properties": { - "DefaultActions": [ - { - "TargetGroupArn": { - "Ref": "TG2B005835E" - }, - "Type": "forward" - } - ], - "LoadBalancerArn": { - "Ref": "LB2D6E7799C" - }, - "Port": 80, - "Protocol": "HTTP" - } - }, - "TG2B005835E": { - "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", - "Properties": { - "Port": 80, - "Protocol": "HTTP", - "TargetGroupAttributes": [ - { - "Key": "stickiness.enabled", - "Value": "true" - }, - { - "Key": "stickiness.type", - "Value": "app_cookie" - }, - { - "Key": "stickiness.app_cookie.cookie_name", - "Value": "MyDeliciousCookie" - }, - { - "Key": "stickiness.app_cookie.duration_seconds", - "Value": "3600" - } - ], - "TargetType": "instance", - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.ts deleted file mode 100644 index 9ce66c2e374b3..0000000000000 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.stickiness.ts +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env node -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as cdk from '@aws-cdk/core'; -import * as elbv2 from '../lib'; - -const app = new cdk.App(); -const stack = new cdk.Stack(app, 'aws-cdk-elbv2-integ'); - -const vpc = new ec2.Vpc(stack, 'VPC', { - maxAzs: 2, -}); - -// Duration-based stickiness cookie -const lb1 = new elbv2.ApplicationLoadBalancer(stack, 'LB1', { - vpc, - internetFacing: true, -}); - -const listener1 = lb1.addListener('Listener1', { - port: 80, -}); - -const tg1 = new elbv2.ApplicationTargetGroup(stack, 'TG1', { - targetType: elbv2.TargetType.INSTANCE, - port: 80, - stickinessCookieDuration: cdk.Duration.hours(1), - vpc, -}); - -listener1.addTargetGroups('TG1', { - targetGroups: [tg1], -}); - -// Application-based stickiness cookie -const lb2 = new elbv2.ApplicationLoadBalancer(stack, 'LB2', { - vpc, - internetFacing: true, -}); - -const listener2 = lb2.addListener('Listener2', { - port: 80, -}); - -const tg2 = new elbv2.ApplicationTargetGroup(stack, 'TG2', { - targetType: elbv2.TargetType.INSTANCE, - port: 80, - stickinessCookieDuration: cdk.Duration.hours(1), - stickinessCookieName: 'MyDeliciousCookie', - vpc, -}); - -listener2.addTargetGroups('TG2', { - targetGroups: [tg2], -}); - -app.synth(); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.ts index 251c730c2fa42..df716e80e0f4f 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.ts @@ -22,6 +22,7 @@ const listener = lb.addListener('Listener', { const group1 = listener.addTargets('Target', { port: 80, targets: [new elbv2.IpTarget('10.0.128.4')], + stickinessCookieDuration: cdk.Duration.minutes(5), }); const group2 = listener.addTargets('ConditionalTarget', { @@ -29,6 +30,8 @@ const group2 = listener.addTargets('ConditionalTarget', { hostHeader: 'example.com', port: 80, targets: [new elbv2.IpTarget('10.0.128.5')], + stickinessCookieDuration: cdk.Duration.minutes(5), + stickinessCookieName: 'MyDeliciousCookie', }); group1.metricTargetResponseTime().createAlarm(stack, 'ResponseTimeHigh1', { From 8b40c6e1a745f7b31a99093813a10b763854913e Mon Sep 17 00:00:00 2001 From: robertd Date: Wed, 24 Feb 2021 09:56:14 -0700 Subject: [PATCH 14/15] check if token is defined --- .../lib/alb/application-target-group.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts index 1f48aa2ac3549..dd6c70727a8a9 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts @@ -1,6 +1,6 @@ import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; -import { Annotations, Duration } from '@aws-cdk/core'; +import { Annotations, Duration, Token } from '@aws-cdk/core'; import { IConstruct, Construct } from 'constructs'; import { ApplicationELBMetrics } from '../elasticloadbalancingv2-canned-metrics.generated'; import { @@ -154,7 +154,7 @@ export class ApplicationTargetGroup extends TargetGroupBase implements IApplicat */ public enableCookieStickiness(duration: Duration, cookieName?: string) { if (cookieName !== undefined) { - if (cookieName.startsWith('AWSALB') || cookieName.startsWith('AWSALBAPP') || cookieName.startsWith('AWSALBTG')) { + if (!Token.isUnresolved(cookieName) && (cookieName.startsWith('AWSALB') || cookieName.startsWith('AWSALBAPP') || cookieName.startsWith('AWSALBTG'))) { throw new Error('App cookie names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, and AWSALBTG; they\'re reserved for use by the load balancer.'); } if (cookieName === '') { From ab071164b7c16db010dbde382c1279e07e9cb395 Mon Sep 17 00:00:00 2001 From: robertd Date: Wed, 24 Feb 2021 10:30:12 -0700 Subject: [PATCH 15/15] fix docstring for stickinessCookieName --- .../lib/alb/application-target-group.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts index dd6c70727a8a9..4196f370cc173 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts @@ -58,9 +58,7 @@ export interface ApplicationTargetGroupProps extends BaseTargetGroupProps { readonly stickinessCookieDuration?: Duration; /** - * The app cookie name. - * - * Indicates the name of the application-based stickiness cookie. + * The name of an application-based stickiness cookie. * * Names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, * and AWSALBTG; they're reserved for use by the load balancer. @@ -68,7 +66,7 @@ export interface ApplicationTargetGroupProps extends BaseTargetGroupProps { * Note: `stickinessCookieName` parameter depends on the presence of `stickinessCookieDuration` parameter. * If `stickinessCookieDuration` is not set, `stickinessCookieName` will be omitted. * - * @default No app cookie name + * @default - If `stickinessCookieDuration` is set, a load-balancer generated cookie is used. Otherwise, no stickiness is defined. * @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/sticky-sessions.html */ readonly stickinessCookieName?: string;