Skip to content

Commit

Permalink
feat(aws-codedeploy): add auto rollback configuration to server Deplo…
Browse files Browse the repository at this point in the history
…yment Group. (#925)
  • Loading branch information
skinny85 authored Oct 18, 2018
1 parent 36f29b6 commit 7ee91cf
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 0 deletions.
6 changes: 6 additions & 0 deletions packages/@aws-cdk/aws-codedeploy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ const deploymentGroup = new codedeploy.ServerDeploymentGroup(this, 'CodeDeployDe
// whether to ignore failure to fetch the status of alarms from CloudWatch
// default: false
ignorePollAlarmsFailure: false,
// auto-rollback configuration
autoRollback: {
failedDeployment: true, // default: true
stoppedDeployment: true, // default: false
deploymentInAlarm: true, // default: true if you provided any alarms, false otherwise
},
});
```

Expand Down
67 changes: 67 additions & 0 deletions packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,33 @@ export class InstanceTagSet {
}
}

/**
* The configuration for automatically rolling back deployments in a given Deployment Group.
*/
export interface AutoRollbackConfig {
/**
* Whether to automatically roll back a deployment that fails.
*
* @default true
*/
failedDeployment?: boolean;

/**
* Whether to automatically roll back a deployment that was manually stopped.
*
* @default false
*/
stoppedDeployment?: boolean;

/**
* Whether to automatically roll back a deployment during which one of the configured
* CloudWatch alarms for this Deployment Group went off.
*
* @default true if you've provided any Alarms with the `alarms` property, false otherwise
*/
deploymentInAlarm?: boolean;
}

/**
* Construction properties for {@link ServerDeploymentGroup}.
*/
Expand Down Expand Up @@ -224,6 +251,11 @@ export interface ServerDeploymentGroupProps {
* @default false
*/
ignorePollAlarmsFailure?: boolean;

/**
* The auto-rollback configuration for this Deployment Group.
*/
autoRollback?: AutoRollbackConfig;
}

/**
Expand Down Expand Up @@ -281,6 +313,7 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupRef {
ec2TagSet: this.ec2TagSet(props.ec2InstanceTags),
onPremisesTagSet: this.onPremiseTagSet(props.onPremiseInstanceTags),
alarmConfiguration: new cdk.Token(() => this.renderAlarmConfiguration(props.ignorePollAlarmsFailure)),
autoRollbackConfiguration: new cdk.Token(() => this.renderAutoRollbackConfiguration(props.autoRollback)),
});

this.deploymentGroupName = resource.deploymentGroupName;
Expand Down Expand Up @@ -455,6 +488,40 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupRef {
ignorePollAlarmFailure,
};
}

private renderAutoRollbackConfiguration(autoRollbackConfig: AutoRollbackConfig = {}):
cloudformation.DeploymentGroupResource.AutoRollbackConfigurationProperty | undefined {
const events = new Array<string>();

// we roll back failed deployments by default
if (autoRollbackConfig.failedDeployment !== false) {
events.push('DEPLOYMENT_FAILURE');
}

// we _do not_ roll back stopped deployments by default
if (autoRollbackConfig.stoppedDeployment === true) {
events.push('DEPLOYMENT_STOP_ON_REQUEST');
}

// we _do not_ roll back alarm-triggering deployments by default
// unless the Deployment Group has at least one alarm
if (autoRollbackConfig.deploymentInAlarm !== false) {
if (this.alarms.length > 0) {
events.push('DEPLOYMENT_STOP_ON_ALARM');
} else if (autoRollbackConfig.deploymentInAlarm === true) {
throw new Error(
"The auto-rollback setting 'deploymentInAlarm' does not have any effect unless you associate " +
"at least one CloudWatch alarm with the Deployment Group");
}
}

return events.length > 0
? {
enabled: true,
events,
}
: undefined;
}
}

function deploymentGroupName2Arn(applicationName: string, deploymentGroupName: string): string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ new codedeploy.ServerDeploymentGroup(stack, 'CodeDeployGroup', {
evaluationPeriods: 1,
}),
],
autoRollback: {
failedDeployment: false,
deploymentInAlarm: false,
},
});

app.run();
64 changes: 64 additions & 0 deletions packages/@aws-cdk/aws-codedeploy/test/test.deployment-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,5 +296,69 @@ export = {

test.done();
},

'only automatically rolls back failed deployments by default'(test: Test) {
const stack = new cdk.Stack();

new codedeploy.ServerDeploymentGroup(stack, 'DeploymentGroup');

expect(stack).to(haveResource('AWS::CodeDeploy::DeploymentGroup', {
"AutoRollbackConfiguration": {
"Enabled": true,
"Events": [
"DEPLOYMENT_FAILURE",
],
},
}));

test.done();
},

'rolls back alarmed deployments if at least one alarm has been added'(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', {
autoRollback: {
failedDeployment: false,
},
});
deploymentGroup.addAlarm(alarm);

expect(stack).to(haveResource('AWS::CodeDeploy::DeploymentGroup', {
"AutoRollbackConfiguration": {
"Enabled": true,
"Events": [
"DEPLOYMENT_STOP_ON_ALARM",
],
},
}));

test.done();
},

'setting to roll back on alarms without providing any results in an exception'(test: Test) {
const stack = new cdk.Stack();

new codedeploy.ServerDeploymentGroup(stack, 'DeploymentGroup', {
autoRollback: {
deploymentInAlarm: true,
},
});

test.throws(() => {
stack.toCloudFormation();
}, /deploymentInAlarm/);

test.done();
},
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@
"Arn"
]
},
"AutoRollbackConfiguration": {
"Enabled": true,
"Events": [
"DEPLOYMENT_FAILURE"
]
},
"DeploymentConfigName": {
"Ref": "CustomDeployConfig52EEBC13"
},
Expand Down

0 comments on commit 7ee91cf

Please sign in to comment.