Skip to content

Commit

Permalink
feat(aws-codedeploy): add support for setting CloudWatch alarms on a …
Browse files Browse the repository at this point in the history
…server Deployment Group.
  • Loading branch information
skinny85 committed Oct 13, 2018
1 parent 106d03a commit b0cdfd3
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 37 deletions.
6 changes: 6 additions & 0 deletions packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ export class Alarm extends Construct {
*/
public readonly alarmArn: string;

/**
* Name of this alarm.
*/
public readonly alarmName: string;

/**
* The metric object this alarm was based on
*/
Expand Down Expand Up @@ -163,6 +168,7 @@ export class Alarm extends Construct {
});

this.alarmArn = alarm.alarmArn;
this.alarmName = alarm.alarmName;
this.metric = props.metric;
this.annotation = {
// tslint:disable-next-line:max-line-length
Expand Down
7 changes: 7 additions & 0 deletions packages/@aws-cdk/aws-codedeploy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ const deploymentGroup = new codedeploy.ServerDeploymentGroup(this, 'CodeDeployDe
stoppedDeployment: true, // default: true,
deploymentInAlarm: true, // default: true,
},
// CloudWatch alarms
alarms: [
new cloudwatch.Alarm(/* ... */),
],
// whether to ignore failure to fetch the status of alarms from CloudWatch
// default: false
ignorePollAlarmsFailure: false,
});
```

Expand Down
38 changes: 37 additions & 1 deletion packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import autoscaling = require("@aws-cdk/aws-autoscaling");
import cloudwatch = require("@aws-cdk/aws-cloudwatch");
import codedeploylb = require("@aws-cdk/aws-codedeploy-api");
import ec2 = require("@aws-cdk/aws-ec2");
import iam = require('@aws-cdk/aws-iam');
Expand Down Expand Up @@ -216,7 +217,7 @@ export interface ServerDeploymentGroupProps {
*/
loadBalancer?: codedeploylb.ILoadBalancer;

/*
/**
* All EC2 instances matching the given set of tags when a deployment occurs will be added to this Deployment Group.
*
* @default no additional EC2 instances will be added to the Deployment Group
Expand All @@ -230,7 +231,26 @@ export interface ServerDeploymentGroupProps {
*/
onPremiseInstanceTags?: InstanceTagSet;

/**
* Auto-rollback configuration.
*
* @default roll back on all events
*/
autoRollback?: IAutoRollbackConfig;

/**
* The CloudWatch alarms associated with this Deployment Group.
*
* @default []
*/
alarms?: cloudwatch.Alarm[];

/**
* Whether to continue a deployment even if fetching the alarm status from CloudWatch failed.
*
* @default false
*/
ignorePollAlarmsFailure?: boolean;
}

/**
Expand All @@ -245,6 +265,7 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupRef {
private readonly _autoScalingGroups: autoscaling.AutoScalingGroup[];
private readonly installAgent: boolean;
private readonly codeDeployBucket: s3.BucketRef;
private readonly alarms: cloudwatch.Alarm[];

constructor(parent: cdk.Construct, id: string, props: ServerDeploymentGroupProps = {}) {
super(parent, id, props.deploymentConfig);
Expand All @@ -266,6 +287,8 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupRef {
this.addCodeDeployAgentInstallUserData(asg);
}

this.alarms = props.alarms || [];

const resource = new cloudformation.DeploymentGroupResource(this, 'Resource', {
applicationName: this.application.applicationName,
deploymentGroupName: props.deploymentGroupName,
Expand All @@ -285,6 +308,15 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupRef {
ec2TagSet: this.ec2TagSet(props.ec2InstanceTags),
onPremisesTagSet: this.onPremiseTagSet(props.onPremiseInstanceTags),
autoRollbackConfiguration: this.autoRollbackConfig(props.autoRollback || {}),
alarmConfiguration: new cdk.Token(() =>
this.alarms.length === 0
? undefined
: {
alarms: this.alarms.map(a => ({ name: a.alarmName })),
enabled: true,
ignorePollAlarmsFailure: props.ignorePollAlarmsFailure,
},
),
});

this.deploymentGroupName = resource.deploymentGroupName;
Expand All @@ -297,6 +329,10 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupRef {
this.addCodeDeployAgentInstallUserData(asg);
}

public addAlarm(alarm: cloudwatch.Alarm): void {
this.alarms.push(alarm);
}

public get autoScalingGroups(): autoscaling.AutoScalingGroup[] | undefined {
return this._autoScalingGroups.slice();
}
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-codedeploy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"@aws-cdk/aws-autoscaling": "^0.12.0",
"@aws-cdk/aws-codedeploy-api": "^0.12.0",
"@aws-cdk/aws-codepipeline-api": "^0.12.0",
"@aws-cdk/aws-cloudwatch": "^0.12.0",
"@aws-cdk/aws-iam": "^0.12.0",
"@aws-cdk/aws-s3": "^0.12.0",
"@aws-cdk/cdk": "^0.12.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@
}
}
},
"VPCPublicSubnet1DefaultRoute91CEF279": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "VPCPublicSubnet1RouteTableFEE4B781"
},
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "VPCIGWB7E252D3"
}
}
},
"VPCPublicSubnet1EIP6AD938E8": {
"Type": "AWS::EC2::EIP",
"Properties": {
Expand All @@ -83,18 +95,6 @@
]
}
},
"VPCPublicSubnet1DefaultRoute91CEF279": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "VPCPublicSubnet1RouteTableFEE4B781"
},
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "VPCIGWB7E252D3"
}
}
},
"VPCPublicSubnet2Subnet74179F39": {
"Type": "AWS::EC2::Subnet",
"Properties": {
Expand Down Expand Up @@ -137,6 +137,18 @@
}
}
},
"VPCPublicSubnet2DefaultRouteB7481BBA": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "VPCPublicSubnet2RouteTable6F1A15F1"
},
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "VPCIGWB7E252D3"
}
}
},
"VPCPublicSubnet2EIP4947BC00": {
"Type": "AWS::EC2::EIP",
"Properties": {
Expand All @@ -163,18 +175,6 @@
]
}
},
"VPCPublicSubnet2DefaultRouteB7481BBA": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "VPCPublicSubnet2RouteTable6F1A15F1"
},
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "VPCIGWB7E252D3"
}
}
},
"VPCPublicSubnet3Subnet631C5E25": {
"Type": "AWS::EC2::Subnet",
"Properties": {
Expand Down Expand Up @@ -217,6 +217,18 @@
}
}
},
"VPCPublicSubnet3DefaultRouteA0D29D46": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "VPCPublicSubnet3RouteTable98AE0E14"
},
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "VPCIGWB7E252D3"
}
}
},
"VPCPublicSubnet3EIPAD4BC883": {
"Type": "AWS::EC2::EIP",
"Properties": {
Expand All @@ -243,18 +255,6 @@
]
}
},
"VPCPublicSubnet3DefaultRouteA0D29D46": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "VPCPublicSubnet3RouteTable98AE0E14"
},
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "VPCIGWB7E252D3"
}
}
},
"VPCPrivateSubnet1Subnet8BCA10E0": {
"Type": "AWS::EC2::Subnet",
"Properties": {
Expand Down Expand Up @@ -712,6 +712,18 @@
]
}
},
"Alarm1F9009D71": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"ComparisonOperator": "GreaterThanOrEqualToThreshold",
"EvaluationPeriods": 1,
"MetricName": "Errors",
"Namespace": "my.namespace",
"Period": 300,
"Threshold": 1,
"Statistic": "Average"
}
},
"CodeDeployGroupApplication13EFBDA6": {
"Type": "AWS::CodeDeploy::Application",
"Properties": {
Expand Down Expand Up @@ -750,6 +762,16 @@
"Arn"
]
},
"AlarmConfiguration": {
"Alarms": [
{
"Name": {
"Ref": "Alarm1F9009D71"
}
}
],
"Enabled": true
},
"AutoScalingGroups": [
{
"Ref": "ASG46ED3070"
Expand Down
11 changes: 11 additions & 0 deletions packages/@aws-cdk/aws-codedeploy/test/integ.deployment-group.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import autoscaling = require('@aws-cdk/aws-autoscaling');
import cloudwatch = require('@aws-cdk/aws-cloudwatch');
import ec2 = require('@aws-cdk/aws-ec2');
import lb = require('@aws-cdk/aws-elasticloadbalancing');
import cdk = require('@aws-cdk/cdk');
Expand Down Expand Up @@ -30,6 +31,16 @@ new codedeploy.ServerDeploymentGroup(stack, 'CodeDeployGroup', {
stoppedDeployment: false,
deploymentInAlarm: false,
},
alarms: [
new cloudwatch.Alarm(stack, 'Alarm1', {
metric: new cloudwatch.Metric({
metricName: 'Errors',
namespace: 'my.namespace',
}),
threshold: 1,
evaluationPeriods: 1,
}),
],
});

app.run();
32 changes: 32 additions & 0 deletions packages/@aws-cdk/aws-codedeploy/test/test.deployment-group.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { expect, haveResource } from '@aws-cdk/assert';
import autoscaling = require('@aws-cdk/aws-autoscaling');
import cloudwatch = require('@aws-cdk/aws-cloudwatch');
import ec2 = require('@aws-cdk/aws-ec2');
import lbv2 = require('@aws-cdk/aws-elasticloadbalancingv2');
import cdk = require('@aws-cdk/cdk');
Expand Down Expand Up @@ -264,5 +265,36 @@ export = {

test.done();
},

'can have alarms added to it after being created'(test: Test) {
const stack = new cdk.Stack();

const alarm = new cloudwatch.Alarm(stack, 'Alarm1', {
metric: new cloudwatch.Metric({
metricName: 'Errors',
namespace: 'my.namespace',
}),
threshold: 1,
evaluationPeriods: 1,
});

const deploymentGroup = new codedeploy.ServerDeploymentGroup(stack, 'DeploymentGroup');
deploymentGroup.addAlarm(alarm);

expect(stack).to(haveResource('AWS::CodeDeploy::DeploymentGroup', {
"AlarmConfiguration": {
"Alarms": [
{
"Name": {
"Ref": "Alarm1F9009D71",
},
},
],
"Enabled": true,
},
}));

test.done();
},
},
};

0 comments on commit b0cdfd3

Please sign in to comment.