Skip to content

Commit de488df

Browse files
authored
fix(aws-elasticloadbalancingv2): target group metrics (#1226)
TargetGroup metrics used to use ${TargetGroup.LoadBalancerArns} to find the load balancer's full name, but that introduces a deployment-time ordering dependency on the creation of the Listener object. Instead, use the Listener ARN to get the load balancer name. We now have an ordering requirement in the CDK code but that can be detected early and solved by the user. Fixes #1213.
1 parent 542bee4 commit de488df

File tree

8 files changed

+228
-53
lines changed

8 files changed

+228
-53
lines changed

packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-elbv2.expected.json

+3-27
Original file line numberDiff line numberDiff line change
@@ -495,15 +495,7 @@
495495
"Fn::Split": [
496496
"/",
497497
{
498-
"Fn::Select": [
499-
0,
500-
{
501-
"Fn::GetAtt": [
502-
"LBListenerTargetGroupF04FCF6D",
503-
"LoadBalancerArns"
504-
]
505-
}
506-
]
498+
"Ref": "LBListener49E825B4"
507499
}
508500
]
509501
}
@@ -517,15 +509,7 @@
517509
"Fn::Split": [
518510
"/",
519511
{
520-
"Fn::Select": [
521-
0,
522-
{
523-
"Fn::GetAtt": [
524-
"LBListenerTargetGroupF04FCF6D",
525-
"LoadBalancerArns"
526-
]
527-
}
528-
]
512+
"Ref": "LBListener49E825B4"
529513
}
530514
]
531515
}
@@ -539,15 +523,7 @@
539523
"Fn::Split": [
540524
"/",
541525
{
542-
"Fn::Select": [
543-
0,
544-
{
545-
"Fn::GetAtt": [
546-
"LBListenerTargetGroupF04FCF6D",
547-
"LoadBalancerArns"
548-
]
549-
}
550-
]
526+
"Ref": "LBListener49E825B4"
551527
}
552528
]
553529
}

packages/@aws-cdk/aws-autoscaling/test/test.scaling.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,7 @@ export = {
9494
const arnParts = {
9595
"Fn::Split": [
9696
"/",
97-
{ "Fn::Select": [
98-
0,
99-
{ "Fn::GetAtt": [ "ALBListenerTargetsGroup01D7716A", "LoadBalancerArns" ] }
100-
]}
97+
{ Ref: "ALBListener3B99FF85" }
10198
]};
10299

103100
expect(stack).to(haveResource('AWS::AutoScaling::ScalingPolicy', {

packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import cloudwatch = require('@aws-cdk/aws-cloudwatch');
22
import ec2 = require('@aws-cdk/aws-ec2');
33
import cdk = require('@aws-cdk/cdk');
4-
import { BaseTargetGroup, BaseTargetGroupProps, ITargetGroup, LoadBalancerTargetProps, TargetGroupRefProps } from '../shared/base-target-group';
4+
import { BaseTargetGroup, BaseTargetGroupProps, ITargetGroup, loadBalancerNameFromListenerArn,
5+
LoadBalancerTargetProps, TargetGroupRefProps } from '../shared/base-target-group';
56
import { ApplicationProtocol } from '../shared/enums';
67
import { BaseImportedTargetGroup } from '../shared/imported';
78
import { determineProtocolAndPort, LazyDependable } from '../shared/util';
@@ -149,6 +150,16 @@ export class ApplicationTargetGroup extends BaseTargetGroup {
149150
this.loadBalancerAssociationDependencies.push(dependable || listener);
150151
}
151152

153+
/**
154+
* Full name of first load balancer
155+
*/
156+
public get firstLoadBalancerFullName(): string {
157+
if (this.listeners.length === 0) {
158+
throw new Error('The TargetGroup needs to be attached to a LoadBalancer before you can call this method');
159+
}
160+
return loadBalancerNameFromListenerArn(this.listeners[0].listenerArn);
161+
}
162+
152163
/**
153164
* Return the given named metric for this Application Load Balancer Target Group
154165
*

packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-target-group.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import cdk = require('@aws-cdk/cdk');
2-
import { BaseTargetGroup, BaseTargetGroupProps, ITargetGroup, LoadBalancerTargetProps, TargetGroupRefProps } from '../shared/base-target-group';
2+
import { BaseTargetGroup, BaseTargetGroupProps, ITargetGroup, loadBalancerNameFromListenerArn,
3+
LoadBalancerTargetProps, TargetGroupRefProps } from '../shared/base-target-group';
34
import { Protocol } from '../shared/enums';
45
import { BaseImportedTargetGroup } from '../shared/imported';
56
import { LazyDependable } from '../shared/util';
@@ -42,12 +43,16 @@ export class NetworkTargetGroup extends BaseTargetGroup {
4243
return new ImportedNetworkTargetGroup(parent, id, props);
4344
}
4445

46+
private readonly listeners: INetworkListener[];
47+
4548
constructor(parent: cdk.Construct, id: string, props: NetworkTargetGroupProps) {
4649
super(parent, id, props, {
4750
protocol: Protocol.Tcp,
4851
port: props.port,
4952
});
5053

54+
this.listeners = [];
55+
5156
if (props.proxyProtocolV2) {
5257
this.setAttribute('proxy_protocol_v2.enabled', 'true');
5358
}
@@ -72,6 +77,17 @@ export class NetworkTargetGroup extends BaseTargetGroup {
7277
*/
7378
public registerListener(listener: INetworkListener) {
7479
this.loadBalancerAssociationDependencies.push(listener);
80+
this.listeners.push(listener);
81+
}
82+
83+
/**
84+
* Full name of first load balancer
85+
*/
86+
public get firstLoadBalancerFullName(): string {
87+
if (this.listeners.length === 0) {
88+
throw new Error('The TargetGroup needs to be attached to a LoadBalancer before you can call this method');
89+
}
90+
return loadBalancerNameFromListenerArn(this.listeners[0].listenerArn);
7591
}
7692
}
7793

packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts

+17-6
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ export abstract class BaseTargetGroup extends cdk.Construct implements ITargetGr
160160
*
161161
* @example app/my-load-balancer/123456789
162162
*/
163-
public readonly firstLoadBalancerFullName: string;
163+
public abstract readonly firstLoadBalancerFullName: string;
164164

165165
/**
166166
* Health check for the members of this target group
@@ -240,11 +240,6 @@ export abstract class BaseTargetGroup extends cdk.Construct implements ITargetGr
240240
this.loadBalancerArns = this.resource.targetGroupLoadBalancerArns.toString();
241241
this.targetGroupName = this.resource.targetGroupName;
242242
this.defaultPort = `${additionalProps.port}`;
243-
244-
const firstLoadBalancerArn = new cdk.FnSelect(0, this.targetGroupLoadBalancerArns);
245-
// arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-internal-load-balancer/50dc6c495c0c9188
246-
const arnParts = new cdk.FnSplit('/', firstLoadBalancerArn);
247-
this.firstLoadBalancerFullName = `${new cdk.FnSelect(1, arnParts)}/${new cdk.FnSelect(2, arnParts)}/${new cdk.FnSelect(3, arnParts)}`;
248243
}
249244

250245
/**
@@ -365,3 +360,19 @@ export interface LoadBalancerTargetProps {
365360
*/
366361
targetJson?: any;
367362
}
363+
364+
/**
365+
* Extract the full load balancer name (used for metrics) from the listener ARN:
366+
*
367+
* Turns
368+
*
369+
* arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/app/my-load-balancer/50dc6c495c0c9188/f2f7dc8efc522ab2
370+
*
371+
* Into
372+
*
373+
* app/my-load-balancer/50dc6c495c0c9188
374+
*/
375+
export function loadBalancerNameFromListenerArn(listenerArn: string) {
376+
const arnParts = new cdk.FnSplit('/', listenerArn);
377+
return `${new cdk.FnSelect(1, arnParts)}/${new cdk.FnSelect(2, arnParts)}/${new cdk.FnSelect(3, arnParts)}`;
378+
}

packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,12 @@ export = {
389389
// GIVEN
390390
const stack = new cdk.Stack();
391391
const vpc = new ec2.VpcNetwork(stack, 'VPC');
392+
const lb = new elbv2.ApplicationLoadBalancer(stack, 'LB', { vpc });
392393
const group = new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { vpc, port: 80 });
394+
lb.addListener('SomeListener', {
395+
port: 80,
396+
defaultTargetGroups: [group]
397+
});
393398

394399
// WHEN
395400
const metrics = [];
@@ -404,16 +409,17 @@ export = {
404409

405410
for (const metric of metrics) {
406411
test.equal('AWS/ApplicationELB', metric.namespace);
407-
const firstArn = { "Fn::Select": [0, { "Fn::GetAtt": ["TargetGroup3D7CD9B8", "LoadBalancerArns"] }] };
412+
const loadBalancerArn = { Ref: "LBSomeListenerCA01F1A0" };
413+
408414
test.deepEqual(cdk.resolve(metric.dimensions), {
409415
TargetGroup: { 'Fn::GetAtt': [ 'TargetGroup3D7CD9B8', 'TargetGroupFullName' ] },
410416
LoadBalancer: { 'Fn::Join':
411417
[ '',
412-
[ { 'Fn::Select': [ 1, { 'Fn::Split': [ '/', firstArn ] } ] },
418+
[ { 'Fn::Select': [ 1, { 'Fn::Split': [ '/', loadBalancerArn ] } ] },
413419
'/',
414-
{ 'Fn::Select': [ 2, { 'Fn::Split': [ '/', firstArn ] } ] },
420+
{ 'Fn::Select': [ 2, { 'Fn::Split': [ '/', loadBalancerArn ] } ] },
415421
'/',
416-
{ 'Fn::Select': [ 3, { 'Fn::Split': [ '/', firstArn ] } ] }
422+
{ 'Fn::Select': [ 3, { 'Fn::Split': [ '/', loadBalancerArn ] } ] }
417423
]
418424
]
419425
}

0 commit comments

Comments
 (0)