-
Notifications
You must be signed in to change notification settings - Fork 3.9k
/
deploy-action.ts
116 lines (105 loc) · 4.03 KB
/
deploy-action.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import * as codepipeline from '@aws-cdk/aws-codepipeline';
import * as ecs from '@aws-cdk/aws-ecs';
import * as iam from '@aws-cdk/aws-iam';
import { Construct } from '@aws-cdk/core';
import { Action } from '../action';
import { deployArtifactBounds } from '../common';
/**
* Construction properties of {@link EcsDeployAction}.
*/
export interface EcsDeployActionProps extends codepipeline.CommonAwsActionProps {
/**
* The input artifact that contains the JSON image definitions file to use for deployments.
* The JSON file is a list of objects,
* each with 2 keys: `name` is the name of the container in the Task Definition,
* and `imageUri` is the Docker image URI you want to update your service with.
* If you use this property, it's assumed the file is called 'imagedefinitions.json'.
* If your build uses a different file, leave this property empty,
* and use the `imageFile` property instead.
*
* @default - one of this property, or `imageFile`, is required
* @see https://docs.aws.amazon.com/codepipeline/latest/userguide/pipelines-create.html#pipelines-create-image-definitions
*/
readonly input?: codepipeline.Artifact;
/**
* The name of the JSON image definitions file to use for deployments.
* The JSON file is a list of objects,
* each with 2 keys: `name` is the name of the container in the Task Definition,
* and `imageUri` is the Docker image URI you want to update your service with.
* Use this property if you want to use a different name for this file than the default 'imagedefinitions.json'.
* If you use this property, you don't need to specify the `input` property.
*
* @default - one of this property, or `input`, is required
* @see https://docs.aws.amazon.com/codepipeline/latest/userguide/pipelines-create.html#pipelines-create-image-definitions
*/
readonly imageFile?: codepipeline.ArtifactPath;
/**
* The ECS Service to deploy.
*/
readonly service: ecs.BaseService;
}
/**
* CodePipeline Action to deploy an ECS Service.
*/
export class EcsDeployAction extends Action {
private readonly props: EcsDeployActionProps;
constructor(props: EcsDeployActionProps) {
super({
...props,
category: codepipeline.ActionCategory.DEPLOY,
provider: 'ECS',
artifactBounds: deployArtifactBounds(),
inputs: [determineInputArtifact(props)],
resource: props.service
});
this.props = props;
}
protected bound(_scope: Construct, _stage: codepipeline.IStage, options: codepipeline.ActionBindOptions):
codepipeline.ActionConfig {
// permissions based on CodePipeline documentation:
// https://docs.aws.amazon.com/codepipeline/latest/userguide/how-to-custom-role.html#how-to-update-role-new-services
options.role.addToPolicy(new iam.PolicyStatement({
actions: [
'ecs:DescribeServices',
'ecs:DescribeTaskDefinition',
'ecs:DescribeTasks',
'ecs:ListTasks',
'ecs:RegisterTaskDefinition',
'ecs:UpdateService',
],
resources: ['*']
}));
options.role.addToPolicy(new iam.PolicyStatement({
actions: ['iam:PassRole'],
resources: ['*'],
conditions: {
StringEqualsIfExists: {
'iam:PassedToService': [
'ec2.amazonaws.com',
'ecs-tasks.amazonaws.com',
],
}
}
}));
options.bucket.grantRead(options.role);
return {
configuration: {
ClusterName: this.props.service.cluster.clusterName,
ServiceName: this.props.service.serviceName,
FileName: this.props.imageFile && this.props.imageFile.fileName,
},
};
}
}
function determineInputArtifact(props: EcsDeployActionProps): codepipeline.Artifact {
if (props.imageFile && props.input) {
throw new Error("Exactly one of 'input' or 'imageFile' can be provided in the ECS deploy Action");
}
if (props.imageFile) {
return props.imageFile.artifact;
}
if (props.input) {
return props.input;
}
throw new Error("Specifying one of 'input' or 'imageFile' is required for the ECS deploy Action");
}