Skip to content

Commit 0b28886

Browse files
authored
feat(aws-codedeploy): Add the auto-scaling groups property to ServerDeploymentGroup. (#739)
1 parent e6b67ad commit 0b28886

File tree

5 files changed

+153
-5
lines changed

5 files changed

+153
-5
lines changed

packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,8 @@ export class AutoScalingGroup extends cdk.Construct implements elb.ILoadBalancer
249249
* Add command to the startup script of fleet instances.
250250
* The command must be in the scripting language supported by the fleet's OS (i.e. Linux/Windows).
251251
*/
252-
public addUserData(script: string) {
253-
this.userDataLines.push(script);
252+
public addUserData(...scriptLines: string[]) {
253+
scriptLines.forEach(scriptLine => this.userDataLines.push(scriptLine));
254254
}
255255

256256
public autoScalingGroupName() {

packages/@aws-cdk/aws-codedeploy/README.md

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ To create a new CodeDeploy Deployment Group that deploys to EC2/on-premise insta
2828
const deploymentGroup = new codedeploy.ServerDeploymentGroup(this, 'CodeDeployDeploymentGroup', {
2929
application,
3030
deploymentGroupName: 'MyDeploymentGroup',
31+
autoScalingGroups: [asg1, asg2],
32+
// adds User Data that installs the CodeDeploy agent on your auto-scaling groups hosts
33+
// default: true
34+
installAgent: true,
3135
});
3236
```
3337

packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts

+94-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import autoscaling = require("@aws-cdk/aws-autoscaling");
2+
import ec2 = require("@aws-cdk/aws-ec2");
3+
import s3 = require("@aws-cdk/aws-s3");
14
import cdk = require("@aws-cdk/cdk");
25
import iam = require("../../aws-iam/lib/role");
36
import { ServerApplication, ServerApplicationRef } from "./application";
@@ -56,9 +59,11 @@ export abstract class ServerDeploymentGroupRef extends cdk.Construct {
5659
}
5760

5861
public abstract readonly application: ServerApplicationRef;
62+
public abstract readonly role?: iam.Role;
5963
public abstract readonly deploymentGroupName: string;
6064
public abstract readonly deploymentGroupArn: string;
6165
public readonly deploymentConfig: IServerDeploymentConfig;
66+
public abstract readonly autoScalingGroups?: autoscaling.AutoScalingGroup[];
6267

6368
constructor(parent: cdk.Construct, id: string, deploymentConfig?: IServerDeploymentConfig) {
6469
super(parent, id);
@@ -71,14 +76,17 @@ export abstract class ServerDeploymentGroupRef extends cdk.Construct {
7176
deploymentGroupName: new cdk.Output(this, 'DeploymentGroupName', {
7277
value: this.deploymentGroupName
7378
}).makeImportValue().toString(),
79+
deploymentConfig: this.deploymentConfig,
7480
};
7581
}
7682
}
7783

7884
class ImportedServerDeploymentGroupRef extends ServerDeploymentGroupRef {
7985
public readonly application: ServerApplicationRef;
86+
public readonly role?: iam.Role = undefined;
8087
public readonly deploymentGroupName: string;
8188
public readonly deploymentGroupArn: string;
89+
public readonly autoScalingGroups?: autoscaling.AutoScalingGroup[] = undefined;
8290

8391
constructor(parent: cdk.Construct, id: string, props: ServerDeploymentGroupRefProps) {
8492
super(parent, id, props.deploymentConfig);
@@ -119,19 +127,39 @@ export interface ServerDeploymentGroupProps {
119127
* @default ServerDeploymentConfig#OneAtATime
120128
*/
121129
deploymentConfig?: IServerDeploymentConfig;
130+
131+
/**
132+
* The auto-scaling groups belonging to this Deployment Group.
133+
*
134+
* @default []
135+
*/
136+
autoScalingGroups?: autoscaling.AutoScalingGroup[];
137+
138+
/**
139+
* If you've provided any auto-scaling groups with the {@link #autoScalingGroups} property,
140+
* you can set this property to add User Data that installs the CodeDeploy agent on the instances.
141+
*
142+
* @default true
143+
* @see https://docs.aws.amazon.com/codedeploy/latest/userguide/codedeploy-agent-operations-install.html
144+
*/
145+
installAgent?: boolean;
122146
}
123147

124148
/**
125149
* A CodeDeploy Deployment Group that deploys to EC2/on-premise instances.
126150
*/
127151
export class ServerDeploymentGroup extends ServerDeploymentGroupRef {
128152
public readonly application: ServerApplicationRef;
129-
public readonly role: iam.Role;
153+
public readonly role?: iam.Role;
130154
public readonly deploymentGroupArn: string;
131155
public readonly deploymentGroupName: string;
132156

157+
private readonly _autoScalingGroups: autoscaling.AutoScalingGroup[];
158+
private readonly installAgent: boolean;
159+
private readonly codeDeployBucket: s3.BucketRef;
160+
133161
constructor(parent: cdk.Construct, id: string, props: ServerDeploymentGroupProps = {}) {
134-
super(parent, id, props && props.deploymentConfig);
162+
super(parent, id, props.deploymentConfig);
135163

136164
this.application = props.application || new ServerApplication(this, 'Application');
137165

@@ -140,18 +168,82 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupRef {
140168
managedPolicyArns: ['arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole'],
141169
});
142170

171+
this._autoScalingGroups = props.autoScalingGroups || [];
172+
this.installAgent = props.installAgent === undefined ? true : props.installAgent;
173+
const region = (new cdk.AwsRegion()).toString();
174+
this.codeDeployBucket = s3.BucketRef.import(this, 'CodeDeployBucket', {
175+
bucketName: `aws-codedeploy-${region}`,
176+
});
177+
for (const asg of this._autoScalingGroups) {
178+
this.addCodeDeployAgentInstallUserData(asg);
179+
}
180+
143181
const resource = new cloudformation.DeploymentGroupResource(this, 'Resource', {
144182
applicationName: this.application.applicationName,
145183
deploymentGroupName: props.deploymentGroupName,
146184
serviceRoleArn: this.role.roleArn,
147185
deploymentConfigName: props.deploymentConfig &&
148186
props.deploymentConfig.deploymentConfigName,
187+
autoScalingGroups: new cdk.Token(() =>
188+
this._autoScalingGroups.length === 0
189+
? undefined
190+
: this._autoScalingGroups.map(asg => asg.autoScalingGroupName())),
149191
});
150192

151193
this.deploymentGroupName = resource.deploymentGroupName;
152194
this.deploymentGroupArn = deploymentGroupName2Arn(this.application.applicationName,
153195
this.deploymentGroupName);
154196
}
197+
198+
public addAutoScalingGroup(asg: autoscaling.AutoScalingGroup): void {
199+
this._autoScalingGroups.push(asg);
200+
this.addCodeDeployAgentInstallUserData(asg);
201+
}
202+
203+
public get autoScalingGroups(): autoscaling.AutoScalingGroup[] | undefined {
204+
return this._autoScalingGroups.slice();
205+
}
206+
207+
private addCodeDeployAgentInstallUserData(asg: autoscaling.AutoScalingGroup): void {
208+
if (!this.installAgent) {
209+
return;
210+
}
211+
212+
this.codeDeployBucket.grantRead(asg.role, 'latest/*');
213+
214+
const region = (new cdk.AwsRegion()).toString();
215+
switch (asg.osType) {
216+
case ec2.OperatingSystemType.Linux:
217+
asg.addUserData(
218+
'PKG_CMD=`which yum 2>/dev/null`',
219+
'if [ -z "$PKG_CMD" ]; then',
220+
'PKG_CMD=apt-get',
221+
'else',
222+
'PKG=CMD=yum',
223+
'fi',
224+
'$PKG_CMD update -y',
225+
'$PKG_CMD install -y ruby2.0',
226+
'if [ $? -ne 0 ]; then',
227+
'$PKG_CMD install -y ruby',
228+
'fi',
229+
'$PKG_CMD install -y awscli',
230+
'TMP_DIR=`mktemp -d`',
231+
'cd $TMP_DIR',
232+
`aws s3 cp s3://aws-codedeploy-${region}/latest/install . --region ${region}`,
233+
'chmod +x ./install',
234+
'./install auto',
235+
'rm -fr $TMP_DIR',
236+
);
237+
break;
238+
case ec2.OperatingSystemType.Windows:
239+
asg.addUserData(
240+
'Set-Variable -Name TEMPDIR -Value (New-TemporaryFile).DirectoryName',
241+
`aws s3 cp s3://aws-codedeploy-${region}/latest/codedeploy-agent.msi $TEMPDIR\\codedeploy-agent.msi`,
242+
'$TEMPDIR\\codedeploy-agent.msi /quiet /l c:\\temp\\host-agent-install-log.txt',
243+
);
244+
break;
245+
}
246+
}
155247
}
156248

157249
function deploymentGroupName2Arn(applicationName: string, deploymentGroupName: string): string {

packages/@aws-cdk/aws-codedeploy/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,15 @@
5353
"license": "Apache-2.0",
5454
"devDependencies": {
5555
"@aws-cdk/assert": "^0.9.2",
56+
"@aws-cdk/aws-ec2": "^0.9.2",
5657
"cdk-build-tools": "^0.9.2",
5758
"cfn2ts": "^0.9.2",
5859
"pkglint": "^0.9.2"
5960
},
6061
"dependencies": {
62+
"@aws-cdk/aws-autoscaling": "^0.9.2",
6163
"@aws-cdk/aws-codepipeline-api": "^0.9.2",
64+
"@aws-cdk/aws-s3": "^0.9.2",
6265
"@aws-cdk/cdk": "^0.9.2"
6366
},
6467
"homepage": "https://github.com/awslabs/aws-cdk"

packages/@aws-cdk/aws-codedeploy/test/test.deployment-group.ts

+50-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { expect, haveResource } from '@aws-cdk/assert';
2+
import autoscaling = require('@aws-cdk/aws-autoscaling');
3+
import ec2 = require('@aws-cdk/aws-ec2');
24
import cdk = require('@aws-cdk/cdk');
35
import { Test } from 'nodeunit';
46
import codedeploy = require('../lib');
@@ -38,6 +40,53 @@ export = {
3840
test.notEqual(deploymentGroup, undefined);
3941

4042
test.done();
41-
}
43+
},
44+
45+
"created with ASGs contains the ASG names"(test: Test) {
46+
const stack = new cdk.Stack();
47+
48+
const asg = new autoscaling.AutoScalingGroup(stack, 'ASG', {
49+
instanceType: new ec2.InstanceTypePair(ec2.InstanceClass.Standard3, ec2.InstanceSize.Small),
50+
machineImage: new ec2.AmazonLinuxImage(),
51+
vpc: new ec2.VpcNetwork(stack, 'VPC'),
52+
});
53+
54+
new codedeploy.ServerDeploymentGroup(stack, 'DeploymentGroup', {
55+
autoScalingGroups: [asg],
56+
});
57+
58+
expect(stack).to(haveResource('AWS::CodeDeploy::DeploymentGroup', {
59+
"AutoScalingGroups": [
60+
{
61+
"Ref": "ASG46ED3070",
62+
},
63+
]
64+
}));
65+
66+
test.done();
67+
},
68+
69+
"created without ASGs but adding them later contains the ASG names"(test: Test) {
70+
const stack = new cdk.Stack();
71+
72+
const asg = new autoscaling.AutoScalingGroup(stack, 'ASG', {
73+
instanceType: new ec2.InstanceTypePair(ec2.InstanceClass.Standard3, ec2.InstanceSize.Small),
74+
machineImage: new ec2.AmazonLinuxImage(),
75+
vpc: new ec2.VpcNetwork(stack, 'VPC'),
76+
});
77+
78+
const deploymentGroup = new codedeploy.ServerDeploymentGroup(stack, 'DeploymentGroup');
79+
deploymentGroup.addAutoScalingGroup(asg);
80+
81+
expect(stack).to(haveResource('AWS::CodeDeploy::DeploymentGroup', {
82+
"AutoScalingGroups": [
83+
{
84+
"Ref": "ASG46ED3070",
85+
},
86+
]
87+
}));
88+
89+
test.done();
90+
},
4291
},
4392
};

0 commit comments

Comments
 (0)