Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(aws-elasticloadbalancingv2): target group metrics #1226

Merged
merged 2 commits into from
Nov 21, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import cloudwatch = require('@aws-cdk/aws-cloudwatch');
import ec2 = require('@aws-cdk/aws-ec2');
import cdk = require('@aws-cdk/cdk');
import { BaseTargetGroup, BaseTargetGroupProps, ITargetGroup, LoadBalancerTargetProps, TargetGroupRefProps } from '../shared/base-target-group';
import { BaseTargetGroup, BaseTargetGroupProps, ITargetGroup, loadBalancerNameFromListenerArn,
LoadBalancerTargetProps, TargetGroupRefProps } from '../shared/base-target-group';
import { ApplicationProtocol } from '../shared/enums';
import { BaseImportedTargetGroup } from '../shared/imported';
import { determineProtocolAndPort, LazyDependable } from '../shared/util';
Expand Down Expand Up @@ -149,6 +150,16 @@ export class ApplicationTargetGroup extends BaseTargetGroup {
this.loadBalancerAssociationDependencies.push(dependable || listener);
}

/**
* Full name of first load balancer
*/
public get firstLoadBalancerFullName(): string {
if (this.listeners.length === 0) {
throw new Error('The TargetGroup needs to be attached to a LoadBalancer before you can call this method');
}
return loadBalancerNameFromListenerArn(this.listeners[0].listenerArn);
}

/**
* Return the given named metric for this Application Load Balancer Target Group
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import cdk = require('@aws-cdk/cdk');
import { BaseTargetGroup, BaseTargetGroupProps, ITargetGroup, LoadBalancerTargetProps, TargetGroupRefProps } from '../shared/base-target-group';
import { BaseTargetGroup, BaseTargetGroupProps, ITargetGroup, loadBalancerNameFromListenerArn,
LoadBalancerTargetProps, TargetGroupRefProps } from '../shared/base-target-group';
import { Protocol } from '../shared/enums';
import { BaseImportedTargetGroup } from '../shared/imported';
import { LazyDependable } from '../shared/util';
Expand Down Expand Up @@ -42,12 +43,16 @@ export class NetworkTargetGroup extends BaseTargetGroup {
return new ImportedNetworkTargetGroup(parent, id, props);
}

private readonly listeners: INetworkListener[];

constructor(parent: cdk.Construct, id: string, props: NetworkTargetGroupProps) {
super(parent, id, props, {
protocol: Protocol.Tcp,
port: props.port,
});

this.listeners = [];

if (props.proxyProtocolV2) {
this.setAttribute('proxy_protocol_v2.enabled', 'true');
}
Expand All @@ -72,6 +77,17 @@ export class NetworkTargetGroup extends BaseTargetGroup {
*/
public registerListener(listener: INetworkListener) {
this.loadBalancerAssociationDependencies.push(listener);
this.listeners.push(listener);
}

/**
* Full name of first load balancer
*/
public get firstLoadBalancerFullName(): string {
if (this.listeners.length === 0) {
throw new Error('The TargetGroup needs to be attached to a LoadBalancer before you can call this method');
}
return loadBalancerNameFromListenerArn(this.listeners[0].listenerArn);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ export abstract class BaseTargetGroup extends cdk.Construct implements ITargetGr
*
* @example app/my-load-balancer/123456789
*/
public readonly firstLoadBalancerFullName: string;
public abstract readonly firstLoadBalancerFullName: string;

/**
* Health check for the members of this target group
Expand Down Expand Up @@ -240,11 +240,6 @@ export abstract class BaseTargetGroup extends cdk.Construct implements ITargetGr
this.loadBalancerArns = this.resource.targetGroupLoadBalancerArns.toString();
this.targetGroupName = this.resource.targetGroupName;
this.defaultPort = `${additionalProps.port}`;

const firstLoadBalancerArn = new cdk.FnSelect(0, this.targetGroupLoadBalancerArns);
// arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-internal-load-balancer/50dc6c495c0c9188
const arnParts = new cdk.FnSplit('/', firstLoadBalancerArn);
this.firstLoadBalancerFullName = `${new cdk.FnSelect(1, arnParts)}/${new cdk.FnSelect(2, arnParts)}/${new cdk.FnSelect(3, arnParts)}`;
}

/**
Expand Down Expand Up @@ -365,3 +360,9 @@ export interface LoadBalancerTargetProps {
*/
targetJson?: any;
}

export function loadBalancerNameFromListenerArn(listenerArn: string) {
// arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/app/my-load-balancer/50dc6c495c0c9188/f2f7dc8efc522ab2
Copy link
Contributor

Choose a reason for hiding this comment

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

Would prefer this to be part of the function JSDoc as an example, and I think it'd be nice to have the corresponding output, too (aka what part are we extracting in fact).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fair

const arnParts = new cdk.FnSplit('/', listenerArn);
return `${new cdk.FnSelect(1, arnParts)}/${new cdk.FnSelect(2, arnParts)}/${new cdk.FnSelect(3, arnParts)}`;
}
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,12 @@ export = {
// GIVEN
const stack = new cdk.Stack();
const vpc = new ec2.VpcNetwork(stack, 'VPC');
const lb = new elbv2.ApplicationLoadBalancer(stack, 'LB', { vpc });
const group = new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { vpc, port: 80 });
lb.addListener('SomeListener', {
port: 80,
defaultTargetGroups: [group]
});

// WHEN
const metrics = [];
Expand All @@ -404,16 +409,17 @@ export = {

for (const metric of metrics) {
test.equal('AWS/ApplicationELB', metric.namespace);
const firstArn = { "Fn::Select": [0, { "Fn::GetAtt": ["TargetGroup3D7CD9B8", "LoadBalancerArns"] }] };
const loadBalancerArn = { Ref: "LBSomeListenerCA01F1A0" };

test.deepEqual(cdk.resolve(metric.dimensions), {
TargetGroup: { 'Fn::GetAtt': [ 'TargetGroup3D7CD9B8', 'TargetGroupFullName' ] },
LoadBalancer: { 'Fn::Join':
[ '',
[ { 'Fn::Select': [ 1, { 'Fn::Split': [ '/', firstArn ] } ] },
[ { 'Fn::Select': [ 1, { 'Fn::Split': [ '/', loadBalancerArn ] } ] },
'/',
{ 'Fn::Select': [ 2, { 'Fn::Split': [ '/', firstArn ] } ] },
{ 'Fn::Select': [ 2, { 'Fn::Split': [ '/', loadBalancerArn ] } ] },
'/',
{ 'Fn::Select': [ 3, { 'Fn::Split': [ '/', firstArn ] } ] }
{ 'Fn::Select': [ 3, { 'Fn::Split': [ '/', loadBalancerArn ] } ] }
]
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,6 @@
},
"VPCPublicSubnet1DefaultRoute91CEF279": {
"Type": "AWS::EC2::Route",
"DependsOn": [
"VPCVPCGW99B986DC"
],
"Properties": {
"RouteTableId": {
"Ref": "VPCPublicSubnet1RouteTableFEE4B781"
Expand All @@ -78,7 +75,10 @@
"GatewayId": {
"Ref": "VPCIGWB7E252D3"
}
}
},
"DependsOn": [
"VPCVPCGW99B986DC"
]
},
"VPCPublicSubnet1EIP6AD938E8": {
"Type": "AWS::EC2::EIP",
Expand Down Expand Up @@ -158,9 +158,6 @@
},
"VPCPublicSubnet2DefaultRouteB7481BBA": {
"Type": "AWS::EC2::Route",
"DependsOn": [
"VPCVPCGW99B986DC"
],
"Properties": {
"RouteTableId": {
"Ref": "VPCPublicSubnet2RouteTable6F1A15F1"
Expand All @@ -169,7 +166,10 @@
"GatewayId": {
"Ref": "VPCIGWB7E252D3"
}
}
},
"DependsOn": [
"VPCVPCGW99B986DC"
]
},
"VPCPublicSubnet2EIP4947BC00": {
"Type": "AWS::EC2::EIP",
Expand Down Expand Up @@ -471,6 +471,154 @@
},
"Priority": 10
}
},
"ResponseTimeHigh1D16E109F": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"ComparisonOperator": "GreaterThanOrEqualToThreshold",
"EvaluationPeriods": 2,
"MetricName": "TargetResponseTime",
"Namespace": "AWS/ApplicationELB",
"Period": 300,
"Threshold": 5,
"Dimensions": [
{
"Name": "TargetGroup",
"Value": {
"Fn::GetAtt": [
"LBListenerTargetGroupF04FCF6D",
"TargetGroupFullName"
]
}
},
{
"Name": "LoadBalancer",
"Value": {
"Fn::Join": [
"",
[
{
"Fn::Select": [
1,
{
"Fn::Split": [
"/",
{
"Ref": "LBListener49E825B4"
}
]
}
]
},
"/",
{
"Fn::Select": [
2,
{
"Fn::Split": [
"/",
{
"Ref": "LBListener49E825B4"
}
]
}
]
},
"/",
{
"Fn::Select": [
3,
{
"Fn::Split": [
"/",
{
"Ref": "LBListener49E825B4"
}
]
}
]
}
]
]
}
}
],
"Statistic": "Average"
}
},
"ResponseTimeHigh2FFCF1FE1": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"ComparisonOperator": "GreaterThanOrEqualToThreshold",
"EvaluationPeriods": 2,
"MetricName": "TargetResponseTime",
"Namespace": "AWS/ApplicationELB",
"Period": 300,
"Threshold": 5,
"Dimensions": [
{
"Name": "TargetGroup",
"Value": {
"Fn::GetAtt": [
"LBListenerConditionalTargetGroupA75CCCD9",
"TargetGroupFullName"
]
}
},
{
"Name": "LoadBalancer",
"Value": {
"Fn::Join": [
"",
[
{
"Fn::Select": [
1,
{
"Fn::Split": [
"/",
{
"Ref": "LBListener49E825B4"
}
]
}
]
},
"/",
{
"Fn::Select": [
2,
{
"Fn::Split": [
"/",
{
"Ref": "LBListener49E825B4"
}
]
}
]
},
"/",
{
"Fn::Select": [
3,
{
"Fn::Split": [
"/",
{
"Ref": "LBListener49E825B4"
}
]
}
]
}
]
]
}
}
],
"Statistic": "Average"
}
}
}
}
14 changes: 12 additions & 2 deletions packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,26 @@ const listener = lb.addListener('Listener', {
port: 80,
});

listener.addTargets('Target', {
const group1 = listener.addTargets('Target', {
port: 80,
targets: [new elbv2.IpTarget('10.0.1.1')]
});

listener.addTargets('ConditionalTarget', {
const group2 = listener.addTargets('ConditionalTarget', {
priority: 10,
hostHeader: 'example.com',
port: 80,
targets: [new elbv2.IpTarget('10.0.1.2')]
});

group1.metricTargetResponseTime().newAlarm(stack, 'ResponseTimeHigh1', {
threshold: 5,
evaluationPeriods: 2,
});

group2.metricTargetResponseTime().newAlarm(stack, 'ResponseTimeHigh2', {
threshold: 5,
evaluationPeriods: 2,
});

app.run();