Skip to content

Commit 6319c25

Browse files
clareliguoriarewa
authored andcommitted
feat(codedeploy): CodeDeploy deployment config constructs for Lambda and ECS (aws#22159)
CloudFormation now supports Lambda and ECS in the `AWS::CodeDeploy::DeploymentConfig` resource type. This PR adds L2 constructs specific to ECS and Lambda for that resource type. ---- ### All Submissions: * [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### New Features * [x] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [x] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)? *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 38816b2 commit 6319c25

34 files changed

+1753
-216
lines changed

Diff for: packages/@aws-cdk/aws-codedeploy/README.md

+126-37
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ AWS CodeDeploy is a deployment service that automates application deployments to
1515
Amazon EC2 instances, on-premises instances, serverless Lambda functions, or
1616
Amazon ECS services.
1717

18-
The CDK currently supports Amazon EC2, on-premise and AWS Lambda applications.
18+
The CDK currently supports Amazon EC2, on-premise, AWS Lambda, and Amazon ECS applications.
1919

2020
## EC2/on-premise Applications
2121

@@ -143,7 +143,7 @@ const deploymentGroup = new codedeploy.ServerDeploymentGroup(this, 'DeploymentGr
143143
});
144144
```
145145

146-
## Deployment Configurations
146+
## EC2/on-premise Deployment Configurations
147147

148148
You can also pass a Deployment Configuration when creating the Deployment Group:
149149

@@ -226,41 +226,6 @@ In order to deploy a new version of this function:
226226
2. Re-deploy the stack (this will trigger a deployment).
227227
3. Monitor the CodeDeploy deployment as traffic shifts between the versions.
228228

229-
230-
### Create a custom Deployment Config
231-
232-
CodeDeploy for Lambda comes with built-in configurations for traffic shifting.
233-
If you want to specify your own strategy,
234-
you can do so with the CustomLambdaDeploymentConfig construct,
235-
letting you specify precisely how fast a new function version is deployed.
236-
237-
```ts
238-
const config = new codedeploy.CustomLambdaDeploymentConfig(this, 'CustomConfig', {
239-
type: codedeploy.CustomLambdaDeploymentConfigType.CANARY,
240-
interval: Duration.minutes(1),
241-
percentage: 5,
242-
});
243-
244-
declare const application: codedeploy.LambdaApplication;
245-
declare const alias: lambda.Alias;
246-
const deploymentGroup = new codedeploy.LambdaDeploymentGroup(this, 'BlueGreenDeployment', {
247-
application,
248-
alias,
249-
deploymentConfig: config,
250-
});
251-
```
252-
253-
You can specify a custom name for your deployment config, but if you do you will not be able to update the interval/percentage through CDK.
254-
255-
```ts
256-
const config = new codedeploy.CustomLambdaDeploymentConfig(this, 'CustomConfig', {
257-
type: codedeploy.CustomLambdaDeploymentConfigType.CANARY,
258-
interval: Duration.minutes(1),
259-
percentage: 5,
260-
deploymentConfigName: 'MyDeploymentConfig',
261-
});
262-
```
263-
264229
### Rollbacks and Alarms
265230

266231
CodeDeploy will roll back if the deployment fails. You can optionally trigger a rollback when one or more alarms are in a failed state:
@@ -327,3 +292,127 @@ const deploymentGroup = codedeploy.LambdaDeploymentGroup.fromLambdaDeploymentGro
327292
deploymentGroupName: 'MyExistingDeploymentGroup',
328293
});
329294
```
295+
296+
## Lambda Deployment Configurations
297+
298+
CodeDeploy for Lambda comes with predefined configurations for traffic shifting.
299+
The predefined configurations are available as LambdaDeploymentConfig constants.
300+
301+
```ts
302+
const config = codedeploy.LambdaDeploymentConfig.CANARY_10PERCENT_30MINUTES;
303+
304+
declare const application: codedeploy.LambdaApplication;
305+
declare const alias: lambda.Alias;
306+
const deploymentGroup = new codedeploy.LambdaDeploymentGroup(this, 'BlueGreenDeployment', {
307+
application,
308+
alias,
309+
deploymentConfig: config,
310+
});
311+
```
312+
313+
If you want to specify your own strategy,
314+
you can do so with the LambdaDeploymentConfig construct,
315+
letting you specify precisely how fast a new function version is deployed.
316+
317+
```ts
318+
const config = new codedeploy.LambdaDeploymentConfig(this, 'CustomConfig', {
319+
trafficRoutingConfig: new codedeploy.TimeBasedCanaryTrafficRoutingConfig({
320+
interval: cdk.Duration.minutes(15),
321+
percentage: 5,
322+
}),
323+
});
324+
325+
declare const application: codedeploy.LambdaApplication;
326+
declare const alias: lambda.Alias;
327+
const deploymentGroup = new codedeploy.LambdaDeploymentGroup(this, 'BlueGreenDeployment', {
328+
application,
329+
alias,
330+
deploymentConfig: config,
331+
});
332+
```
333+
334+
You can specify a custom name for your deployment config, but if you do you will not be able to update the interval/percentage through CDK.
335+
336+
```ts
337+
const config = new codedeploy.LambdaDeploymentConfig(this, 'CustomConfig', {
338+
trafficRoutingConfig: new codedeploy.TimeBasedCanaryTrafficRoutingConfig({
339+
interval: cdk.Duration.minutes(15),
340+
percentage: 5,
341+
}),
342+
deploymentConfigName: 'MyDeploymentConfig',
343+
});
344+
```
345+
346+
To import an already existing Deployment Config:
347+
348+
```ts
349+
const deploymentConfig = codedeploy.LambdaDeploymentConfig.fromLambdaDeploymentConfigName(
350+
this,
351+
'ExistingDeploymentConfiguration',
352+
'MyExistingDeploymentConfiguration',
353+
);
354+
```
355+
356+
## ECS Applications
357+
358+
To create a new CodeDeploy Application that deploys an ECS service:
359+
360+
```ts
361+
const application = new codedeploy.EcsApplication(this, 'CodeDeployApplication', {
362+
applicationName: 'MyApplication', // optional property
363+
});
364+
```
365+
366+
To import an already existing Application:
367+
368+
```ts
369+
const application = codedeploy.EcsApplication.fromEcsApplicationName(
370+
this,
371+
'ExistingCodeDeployApplication',
372+
'MyExistingApplication',
373+
);
374+
```
375+
376+
## ECS Deployment Configurations
377+
378+
CodeDeploy for ECS comes with predefined configurations for traffic shifting.
379+
The predefined configurations are available as LambdaDeploymentConfig constants.
380+
381+
```ts
382+
const config = codedeploy.EcsDeploymentConfig.CANARY_10PERCENT_5MINUTES;
383+
```
384+
385+
If you want to specify your own strategy,
386+
you can do so with the EcsDeploymentConfig construct,
387+
letting you specify precisely how fast an ECS service is deployed.
388+
389+
```ts
390+
new codedeploy.EcsDeploymentConfig(this, 'CustomConfig', {
391+
trafficRoutingConfig: new codedeploy.TimeBasedCanaryTrafficRoutingConfig({
392+
interval: cdk.Duration.minutes(15),
393+
percentage: 5,
394+
}),
395+
});
396+
```
397+
398+
You can specify a custom name for your deployment config, but if you do you will not be able to update the interval/percentage through CDK.
399+
400+
```ts
401+
const config = new codedeploy.EcsDeploymentConfig(this, 'CustomConfig', {
402+
trafficRoutingConfig: new codedeploy.TimeBasedCanaryTrafficRoutingConfig({
403+
interval: cdk.Duration.minutes(15),
404+
percentage: 5,
405+
}),
406+
deploymentConfigName: 'MyDeploymentConfig',
407+
});
408+
```
409+
410+
Or import an existing one:
411+
412+
```ts
413+
const deploymentConfig = codedeploy.EcsDeploymentConfig.fromEcsDeploymentConfigName(
414+
this,
415+
'ExistingDeploymentConfiguration',
416+
'MyExistingDeploymentConfiguration',
417+
);
418+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
import { ArnFormat, Resource, Stack } from '@aws-cdk/core';
2+
import { Construct } from 'constructs';
3+
import { CfnDeploymentConfig } from './codedeploy.generated';
4+
import { MinimumHealthyHosts } from './host-health-config';
5+
import { TrafficRouting } from './traffic-routing-config';
6+
import { arnForDeploymentConfig, validateName } from './utils';
7+
8+
/**
9+
* The base class for ServerDeploymentConfig, EcsDeploymentConfig,
10+
* and LambdaDeploymentConfig deployment configurations.
11+
*/
12+
export interface IBaseDeploymentConfig {
13+
/**
14+
* The physical, human-readable name of the Deployment Configuration.
15+
* @attribute
16+
*/
17+
readonly deploymentConfigName: string;
18+
19+
/**
20+
* The ARN of the Deployment Configuration.
21+
* @attribute
22+
*/
23+
readonly deploymentConfigArn: string;
24+
}
25+
26+
/**
27+
* Construction properties of {@link BaseDeploymentConfig}.
28+
*/
29+
export interface BaseDeploymentConfigOptions {
30+
/**
31+
* The physical, human-readable name of the Deployment Configuration.
32+
* @default - automatically generated name
33+
*/
34+
readonly deploymentConfigName?: string;
35+
}
36+
37+
/**
38+
* The compute platform of a deployment configuration
39+
*/
40+
export enum ComputePlatform {
41+
/**
42+
* The deployment will target EC2 instances or on-premise servers
43+
*/
44+
SERVER = 'Server',
45+
46+
/**
47+
* The deployment will target a Lambda function
48+
*/
49+
LAMBDA = 'Lambda',
50+
51+
/**
52+
* The deployment will target an ECS server
53+
*/
54+
ECS = 'ECS'
55+
}
56+
57+
/**
58+
* Complete base deployment config properties that are required to be supplied by the implementation
59+
* of the BaseDeploymentConfig class.
60+
*/
61+
export interface BaseDeploymentConfigProps extends BaseDeploymentConfigOptions {
62+
/**
63+
* The destination compute platform for the deployment.
64+
*
65+
* @default ComputePlatform.Server
66+
*/
67+
readonly computePlatform?: ComputePlatform;
68+
69+
/**
70+
* The configuration that specifies how traffic is shifted during a deployment.
71+
* Only applicable to ECS and Lambda deployments, and must not be specified for Server deployments.
72+
* @default None
73+
*/
74+
readonly trafficRouting?: TrafficRouting;
75+
76+
/**
77+
* Minimum number of healthy hosts.
78+
* @default None
79+
*/
80+
readonly minimumHealthyHosts?: MinimumHealthyHosts;
81+
}
82+
83+
/**
84+
* The base class for ServerDeploymentConfig, EcsDeploymentConfig,
85+
* and LambdaDeploymentConfig deployment configurations.
86+
*
87+
* @resource AWS::CodeDeploy::DeploymentConfig
88+
*/
89+
export abstract class BaseDeploymentConfig extends Resource implements IBaseDeploymentConfig {
90+
/**
91+
* Import a custom Deployment Configuration for a Deployment Group defined outside the CDK.
92+
*
93+
* @param scope the parent Construct for this new Construct
94+
* @param id the logical ID of this new Construct
95+
* @param deploymentConfigName the name of the referenced custom Deployment Configuration
96+
* @returns a Construct representing a reference to an existing custom Deployment Configuration
97+
*/
98+
protected static fromDeploymentConfigName(scope: Construct, id: string, deploymentConfigName: string): IBaseDeploymentConfig {
99+
ignore(id);
100+
const arn = Stack.of(scope).formatArn({
101+
service: 'codedeploy',
102+
resource: 'deploymentconfig',
103+
resourceName: deploymentConfigName,
104+
arnFormat: ArnFormat.COLON_RESOURCE_NAME,
105+
});
106+
return {
107+
deploymentConfigName: deploymentConfigName,
108+
deploymentConfigArn: arn,
109+
};
110+
}
111+
112+
/**
113+
* This method should be used only for static references to predefined deployment configurations,
114+
* like EcsDeploymentConfig.ALL_AT_ONCE
115+
* @param name the name of the referenced custom Deployment Configuration
116+
* @returns a reference to an existing custom Deployment Configuration
117+
*/
118+
protected static deploymentConfig(name: string): IBaseDeploymentConfig {
119+
return {
120+
deploymentConfigName: name,
121+
deploymentConfigArn: arnForDeploymentConfig(name),
122+
};
123+
}
124+
125+
/**
126+
* The name of the deployment config
127+
* @attribute
128+
*/
129+
public readonly deploymentConfigName: string;
130+
131+
/**
132+
* The arn of the deployment config
133+
* @attribute
134+
*/
135+
public readonly deploymentConfigArn: string;
136+
137+
public constructor(scope: Construct, id: string, props?: BaseDeploymentConfigProps) {
138+
super(scope, id, {
139+
physicalName: props?.deploymentConfigName,
140+
});
141+
142+
// Traffic routing is not applicable to Server-based deployment configs
143+
if (props?.trafficRouting && (props?.computePlatform === undefined || props?.computePlatform === ComputePlatform.SERVER)) {
144+
throw new Error('Traffic routing config must not be specified for a Server-base deployment configuration');
145+
}
146+
147+
// Minimum healthy hosts is only applicable to Server-based deployment configs
148+
if (props?.minimumHealthyHosts && props?.computePlatform && props?.computePlatform !== ComputePlatform.SERVER) {
149+
throw new Error('Minimum healthy hosts config must only be specified for a Server-base deployment configuration');
150+
}
151+
152+
const resource = new CfnDeploymentConfig(this, 'Resource', {
153+
deploymentConfigName: this.physicalName,
154+
computePlatform: props?.computePlatform,
155+
trafficRoutingConfig: props?.trafficRouting?.bind(this),
156+
minimumHealthyHosts: props?.minimumHealthyHosts?._json,
157+
});
158+
159+
this.deploymentConfigName = this.getResourceNameAttribute(resource.ref);
160+
this.deploymentConfigArn = this.getResourceArnAttribute(arnForDeploymentConfig(resource.ref), {
161+
service: 'codedeploy',
162+
resource: 'deploymentconfig',
163+
resourceName: this.physicalName,
164+
arnFormat: ArnFormat.COLON_RESOURCE_NAME,
165+
});
166+
167+
this.node.addValidation({ validate: () => validateName('Deployment config', this.physicalName) });
168+
}
169+
}
170+
171+
function ignore(_x: any) { return; }

0 commit comments

Comments
 (0)