|
1 |
| -import { Match, Template } from '../../../assertions'; |
| 1 | +import { Annotations, Match, Template } from '../../../assertions'; |
2 | 2 | import { AutoScalingGroup } from '../../../aws-autoscaling';
|
3 | 3 | import { Certificate, CertificateValidation } from '../../../aws-certificatemanager';
|
4 | 4 | import * as ec2 from '../../../aws-ec2';
|
5 | 5 | import { MachineImage } from '../../../aws-ec2';
|
6 | 6 | import * as ecs from '../../../aws-ecs';
|
7 | 7 | import { AsgCapacityProvider } from '../../../aws-ecs';
|
8 |
| -import { ApplicationLoadBalancer, ApplicationProtocol, NetworkLoadBalancer, SslPolicy } from '../../../aws-elasticloadbalancingv2'; |
| 8 | +import { ApplicationLoadBalancer, ApplicationProtocol, ListenerAction, NetworkLoadBalancer, SslPolicy } from '../../../aws-elasticloadbalancingv2'; |
9 | 9 | import * as iam from '../../../aws-iam';
|
10 | 10 | import * as route53 from '../../../aws-route53';
|
11 | 11 | import * as cloudmap from '../../../aws-servicediscovery';
|
@@ -1111,6 +1111,150 @@ describe('ApplicationLoadBalancedFargateService', () => {
|
1111 | 1111 | });
|
1112 | 1112 | });
|
1113 | 1113 |
|
| 1114 | + test('creates a separate redirect listener when listenerPort is not 80', () => { |
| 1115 | + // GIVEN |
| 1116 | + const stack = new cdk.Stack(); |
| 1117 | + const vpc = new ec2.Vpc(stack, 'VPC'); |
| 1118 | + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); |
| 1119 | + const zone = new route53.PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); |
| 1120 | + |
| 1121 | + // WHEN |
| 1122 | + const service = new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { |
| 1123 | + cluster, |
| 1124 | + taskImageOptions: { |
| 1125 | + image: ecs.ContainerImage.fromRegistry('test'), |
| 1126 | + }, |
| 1127 | + domainName: 'api.example.com', |
| 1128 | + domainZone: zone, |
| 1129 | + protocol: ApplicationProtocol.HTTPS, |
| 1130 | + redirectHTTP: true, |
| 1131 | + listenerPort: 8443, |
| 1132 | + }); |
| 1133 | + |
| 1134 | + // THEN |
| 1135 | + // Verify that we have two listeners - one for HTTPS and one for HTTP redirect |
| 1136 | + Template.fromStack(stack).resourceCountIs('AWS::ElasticLoadBalancingV2::Listener', 2); |
| 1137 | + |
| 1138 | + // Verify the HTTPS listener is on port 8443 |
| 1139 | + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { |
| 1140 | + Port: 8443, |
| 1141 | + Protocol: 'HTTPS', |
| 1142 | + }); |
| 1143 | + |
| 1144 | + // Verify the HTTP redirect listener is on port 80 |
| 1145 | + Template.fromStack(stack).hasResourceProperties('AWS::ElasticLoadBalancingV2::Listener', { |
| 1146 | + Port: 80, |
| 1147 | + Protocol: 'HTTP', |
| 1148 | + DefaultActions: [ |
| 1149 | + Match.objectLike({ |
| 1150 | + Type: 'redirect', |
| 1151 | + RedirectConfig: { |
| 1152 | + Protocol: 'HTTPS', |
| 1153 | + Port: '8443', |
| 1154 | + StatusCode: 'HTTP_301', |
| 1155 | + }, |
| 1156 | + }), |
| 1157 | + ], |
| 1158 | + }); |
| 1159 | + |
| 1160 | + // Verify the dependency between listeners |
| 1161 | + expect(service.redirectListener?.node.dependencies[0]).toBe(service.listener); |
| 1162 | + }); |
| 1163 | + |
| 1164 | + test('throws error when trying to use redirectHTTP with listener on port 80', () => { |
| 1165 | + // GIVEN |
| 1166 | + const app = new cdk.App(); |
| 1167 | + const stack = new cdk.Stack(app); |
| 1168 | + const vpc = new ec2.Vpc(stack, 'VPC'); |
| 1169 | + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); |
| 1170 | + const zone = new route53.PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); |
| 1171 | + |
| 1172 | + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { |
| 1173 | + cluster, |
| 1174 | + taskImageOptions: { |
| 1175 | + image: ecs.ContainerImage.fromRegistry('test'), |
| 1176 | + }, |
| 1177 | + domainName: 'api.example.com', |
| 1178 | + domainZone: zone, |
| 1179 | + protocol: ApplicationProtocol.HTTPS, |
| 1180 | + redirectHTTP: true, |
| 1181 | + listenerPort: 80, |
| 1182 | + }); |
| 1183 | + |
| 1184 | + // THEN |
| 1185 | + expect(() => { |
| 1186 | + app.synth(); |
| 1187 | + }).toThrow('Validation failed with the following errors:\n [Default/Service/LB] Cannot automatically configure redirectHTTP: A listener already exists on port 80.'); |
| 1188 | + }); |
| 1189 | + |
| 1190 | + test('adds validation for existing port 80 listeners not owned by the construct', () => { |
| 1191 | + // GIVEN |
| 1192 | + const app = new cdk.App(); |
| 1193 | + const stack = new cdk.Stack(app); |
| 1194 | + const vpc = new ec2.Vpc(stack, 'VPC'); |
| 1195 | + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); |
| 1196 | + const zone = new route53.PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); |
| 1197 | + |
| 1198 | + // Create a load balancer with an existing port 80 listener |
| 1199 | + const lb = new ApplicationLoadBalancer(stack, 'ALB', { vpc, internetFacing: true }); |
| 1200 | + lb.addListener('ExistingPort80Listener', { |
| 1201 | + port: 80, |
| 1202 | + protocol: ApplicationProtocol.HTTP, |
| 1203 | + defaultAction: ListenerAction.redirect({ port: '1000' }), |
| 1204 | + }); |
| 1205 | + |
| 1206 | + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { |
| 1207 | + cluster, |
| 1208 | + taskImageOptions: { |
| 1209 | + image: ecs.ContainerImage.fromRegistry('test'), |
| 1210 | + }, |
| 1211 | + domainName: 'api.example.com', |
| 1212 | + domainZone: zone, |
| 1213 | + protocol: ApplicationProtocol.HTTPS, |
| 1214 | + redirectHTTP: true, |
| 1215 | + loadBalancer: lb, |
| 1216 | + }); |
| 1217 | + // THEN |
| 1218 | + expect(() => { |
| 1219 | + app.synth(); |
| 1220 | + }).toThrow('Validation failed with the following errors:\n [Default/ALB] Cannot automatically configure redirectHTTP: A listener already exists on port 80.'); |
| 1221 | + }); |
| 1222 | + |
| 1223 | + test('adds warning for imported load balancers', () => { |
| 1224 | + // GIVEN |
| 1225 | + const stack = new cdk.Stack(); |
| 1226 | + const vpc = new ec2.Vpc(stack, 'VPC'); |
| 1227 | + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); |
| 1228 | + const zone = new route53.PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); |
| 1229 | + |
| 1230 | + // Create an imported load balancer |
| 1231 | + const importedLb = ApplicationLoadBalancer.fromApplicationLoadBalancerAttributes(stack, 'ImportedALB', { |
| 1232 | + loadBalancerArn: 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188', |
| 1233 | + securityGroupId: 'sg-123456789', |
| 1234 | + loadBalancerDnsName: 'my-load-balancer-1234567890.us-west-2.elb.amazonaws.com', |
| 1235 | + loadBalancerCanonicalHostedZoneId: 'some-hosted-zone', |
| 1236 | + vpc, |
| 1237 | + }); |
| 1238 | + |
| 1239 | + // WHEN |
| 1240 | + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { |
| 1241 | + cluster, |
| 1242 | + taskImageOptions: { |
| 1243 | + image: ecs.ContainerImage.fromRegistry('test'), |
| 1244 | + }, |
| 1245 | + domainName: 'api.example.com', |
| 1246 | + domainZone: zone, |
| 1247 | + protocol: ApplicationProtocol.HTTPS, |
| 1248 | + redirectHTTP: true, |
| 1249 | + loadBalancer: importedLb, |
| 1250 | + }); |
| 1251 | + |
| 1252 | + // THEN |
| 1253 | + // Verify that a warning is added |
| 1254 | + const annotations = Annotations.fromStack(stack); |
| 1255 | + annotations.hasWarning('/Default/Service', 'Cannot automatically configure port 80 HTTP redirect with redirectHTTP: The construct cannot reliably determine if a port 80 listener already exists. Please configure the redirect manually on the port 80 listener.'); |
| 1256 | + }); |
| 1257 | + |
1114 | 1258 | test('errors when setting HTTPS protocol but not domain name', () => {
|
1115 | 1259 | // GIVEN
|
1116 | 1260 | const stack = new cdk.Stack();
|
|
0 commit comments