Skip to content

Commit

Permalink
feat(ec2): add vpn metrics
Browse files Browse the repository at this point in the history
Add VPN metrics (TunnelState, TunnelDataIn, TunnelDataOut) across all tunnels
and per connection by adding a new augmentation.

Adapt AugmentationGenerator to convert resource name to Kebab case module
name and to support name overrides for class, interface and module when these
cannot be directly derived from the CloudFormation resource name: no base
class or resource name not really Pascal case (e.g. VPNConnection).
  • Loading branch information
jogold committed Mar 9, 2019
1 parent 85a1840 commit 429b101
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 8 deletions.
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-ec2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -341,3 +341,5 @@ vpc.addVpnConnection('Dynamic', {
```

Routes will be propagated on the route tables associated with the private subnets.

VPN connections expose metric across all tunnels and per connection.
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-ec2/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ export * from './vpn';

// AWS::EC2 CloudFormation Resources:
export * from './ec2.generated';

import './ec2-augmentations.generated';
39 changes: 39 additions & 0 deletions packages/@aws-cdk/aws-ec2/lib/vpn.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import cloudwatch = require('@aws-cdk/aws-cloudwatch');
import cdk = require('@aws-cdk/cdk');
import net = require('net');
import { CfnCustomerGateway, CfnVPNConnection, CfnVPNConnectionRoute } from './ec2.generated';
Expand Down Expand Up @@ -98,6 +99,44 @@ export enum VpnConnectionType {
}

export class VpnConnection extends cdk.Construct implements IVpnConnection {
/**
* Return the given named metric for all VPN connections.
*/
public static metricAll(metricName: string, props?: cloudwatch.MetricCustomization): cloudwatch.Metric {
return new cloudwatch.Metric({
namespace: 'AWS/VPN',
metricName,
...props
});
}

/**
* Metric for the tunnel state of all VPN connections.
*
* @default average over 5 minutes
*/
public static metricAllTunnelState(props?: cloudwatch.MetricCustomization): cloudwatch.Metric {
return this.metricAll('TunnelSate', { statistic: 'avg', ...props });
}

/**
* Metric for the tunnel data in of all VPN connections.
*
* @default sum over 5 minutes
*/
public static metricAllTunnelDataIn(props?: cloudwatch.MetricCustomization): cloudwatch.Metric {
return this.metricAll('TunnelDataIn', { statistic: 'sum', ...props });
}

/**
* Metric for the tunnel data out of all VPN connections.
*
* @default sum over 5 minutes
*/
public static metricAllTunnelDataOut(props?: cloudwatch.MetricCustomization): cloudwatch.Metric {
return this.metricAll('TunnelDataOut', { statistic: 'sum', ...props });
}

public readonly vpnId: string;
public readonly customerGatewayId: string;
public readonly customerGatewayIp: string;
Expand Down
4 changes: 3 additions & 1 deletion packages/@aws-cdk/aws-ec2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,13 @@
},
"dependencies": {
"@aws-cdk/aws-iam": "^0.25.2",
"@aws-cdk/aws-cloudwatch": "^0.25.2",
"@aws-cdk/cdk": "^0.25.2",
"@aws-cdk/cx-api": "^0.25.2"
},
"homepage": "https://github.com/awslabs/aws-cdk",
"peerDependencies": {
"@aws-cdk/aws-cloudwatch": "^0.25.2",
"@aws-cdk/cdk": "^0.25.2",
"@aws-cdk/cx-api": "^0.25.2"
},
Expand All @@ -78,4 +80,4 @@
"resource-attribute:@aws-cdk/aws-ec2.ISecurityGroup.securityGroupVpcId"
]
}
}
}
41 changes: 40 additions & 1 deletion packages/@aws-cdk/aws-ec2/test/test.vpn.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect, haveResource, } from '@aws-cdk/assert';
import { Stack } from '@aws-cdk/cdk';
import { Test } from 'nodeunit';
import { VpcNetwork } from '../lib';
import { VpcNetwork, VpnConnection } from '../lib';

export = {
'can add a vpn connection to a vpc with a vpn gateway'(test: Test) {
Expand Down Expand Up @@ -258,6 +258,45 @@ export = {
}
}), /`tunnelInsideCidr`.+size/);

test.done();
},

'can use metricTunnelState on a vpn connection'(test: Test) {
// GIVEN
const stack = new Stack();

const vpc = new VpcNetwork(stack, 'VpcNetwork', {
vpnGateway: true
});

const vpn = vpc.addVpnConnection('Vpn', {
ip: '192.0.2.1'
});

// THEN
test.deepEqual(stack.node.resolve(vpn.metricTunnelState()), {
dimensions: { VpnId: { Ref: 'VpcNetworkVpnA476C58D' } },
namespace: 'AWS/VPN',
metricName: 'TunnelState',
periodSec: 300,
statistic: 'Average'
});

test.done();
},

'can use metricAllTunnelDataOut'(test: Test) {
// GIVEN
const stack = new Stack();

// THEN
test.deepEqual(stack.node.resolve(VpnConnection.metricAllTunnelDataOut()), {
namespace: 'AWS/VPN',
metricName: 'TunnelDataOut',
periodSec: 300,
statistic: 'Sum'
});

test.done();
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"overrides": {
"interface": "IVpnConnection",
"class": "VpnConnection",
"module": "vpn"
},
"metrics": {
"namespace": "AWS/VPN",
"dimensions": { "VpnId": "this.vpnId" },
"metrics": [
{
"name": "TunnelState",
"documentation": "The state of the tunnel. 0 indicates DOWN and 1 indicates UP."
},
{
"name": "TunnelDataIn",
"documentation": "The bytes received through the VPN tunnel.",
"type": "count"
},
{
"name": "TunnelDataOut",
"documentation": "The bytes sent through the VPN tunnel.",
"type": "count"
}
]
}
}
24 changes: 23 additions & 1 deletion packages/@aws-cdk/cfnspec/lib/schema/augmentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,28 @@ export interface ResourceAugmentation {
* Metric augmentations for this resource type
*/
metrics?: ResourceMetricAugmentations;

/**
* Overrides for this resource augmentation
*/
overrides?: ResourceOverrides;
}

export interface ResourceOverrides {
/**
* The name of the resource class
*/
class?: string;

/**
* The name of the resource interface
*/
interface?: string;

/**
* The name of the module
*/
module?: string;
}

export interface ResourceMetricAugmentations {
Expand Down Expand Up @@ -57,4 +79,4 @@ export enum MetricType {
* property. The most useful aggregate of this type of metric is "Max".
*/
Gauge = 'gauge'
}
}
11 changes: 6 additions & 5 deletions tools/cfn2ts/lib/augmentation-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class AugmentationGenerator {

if (aug.metrics) {
this.code.line('import cloudwatch = require("@aws-cdk/aws-cloudwatch");');
this.emitMetricAugmentations(resourceTypeName, aug.metrics);
this.emitMetricAugmentations(resourceTypeName, aug.metrics, aug.overrides);
hadAugmentations = true;
}
}
Expand All @@ -39,14 +39,15 @@ export class AugmentationGenerator {
return await this.code.save(dir);
}

private emitMetricAugmentations(resourceTypeName: string, metrics: schema.ResourceMetricAugmentations) {
private emitMetricAugmentations(resourceTypeName: string, metrics: schema.ResourceMetricAugmentations, overrides?: schema.ResourceOverrides) {
const cfnName = SpecName.parse(resourceTypeName);
const resourceName = genspec.CodeName.forCfnResource(cfnName, this.affix);
const l2ClassName = resourceName.className.replace(/^Cfn/, '');
const kebabL2ClassName = l2ClassName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();

const baseClassName = l2ClassName + 'Base';
const interfaceName = 'I' + l2ClassName;
const baseClassModule = `./${l2ClassName.toLowerCase()}-base`;
const baseClassName = (overrides && overrides.class) || l2ClassName + 'Base';
const interfaceName = (overrides && overrides.interface) || 'I' + l2ClassName;
const baseClassModule = `./${(overrides && overrides.module) || `${kebabL2ClassName}-base`}`;

this.code.line(`import { ${baseClassName} } from "${baseClassModule}";`);

Expand Down

0 comments on commit 429b101

Please sign in to comment.