/
run-ecs-ec2-task.ts
102 lines (89 loc) · 3.06 KB
/
run-ecs-ec2-task.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
import ec2 = require('@aws-cdk/aws-ec2');
import ecs = require('@aws-cdk/aws-ecs');
import { CommonEcsRunTaskProps, EcsRunTaskBase } from './run-ecs-task-base';
/**
* Properties to run an ECS task on EC2 in StepFunctionsan ECS
*/
export interface RunEcsEc2TaskProps extends CommonEcsRunTaskProps {
/**
* In what subnets to place the task's ENIs
*
* (Only applicable in case the TaskDefinition is configured for AwsVpc networking)
*
* @default Private subnets
*/
readonly subnets?: ec2.SubnetSelection;
/**
* Existing security group to use for the task's ENIs
*
* (Only applicable in case the TaskDefinition is configured for AwsVpc networking)
*
* @default A new security group is created
*/
readonly securityGroup?: ec2.ISecurityGroup;
/**
* Placement constraints
*
* @default No constraints
*/
readonly placementConstraints?: ecs.PlacementConstraint[];
/**
* Placement strategies
*
* @default No strategies
*/
readonly placementStrategies?: ecs.PlacementStrategy[];
}
/**
* Run an ECS/EC2 Task in a StepFunctions workflow
*/
export class RunEcsEc2Task extends EcsRunTaskBase {
constructor(props: RunEcsEc2TaskProps) {
if (!props.taskDefinition.isEc2Compatible) {
throw new Error('Supplied TaskDefinition is not configured for compatibility with EC2');
}
if (!props.cluster.hasEc2Capacity) {
throw new Error('Cluster for this service needs Ec2 capacity. Call addXxxCapacity() on the cluster.');
}
if (!props.taskDefinition.defaultContainer) {
throw new Error('A TaskDefinition must have at least one essential container');
}
super({
...props,
parameters: {
LaunchType: 'EC2',
PlacementConstraints: noEmpty(flatten((props.placementConstraints || []).map(c => c.toJson().map(uppercaseKeys)))),
PlacementStrategy: noEmpty(flatten((props.placementStrategies || []).map(c => c.toJson().map(uppercaseKeys)))),
}
});
if (props.taskDefinition.networkMode === ecs.NetworkMode.AWS_VPC) {
this.configureAwsVpcNetworking(props.cluster.vpc, undefined, props.subnets, props.securityGroup);
} else {
// Either None, Bridge or Host networking. Copy SecurityGroup from ASG.
validateNoNetworkingProps(props);
this.connections.addSecurityGroup(...props.cluster.connections.securityGroups);
}
}
}
/**
* Validate combinations of networking arguments
*/
function validateNoNetworkingProps(props: RunEcsEc2TaskProps) {
if (props.subnets !== undefined || props.securityGroup !== undefined) {
throw new Error('vpcPlacement and securityGroup can only be used in AwsVpc networking mode');
}
}
function uppercaseKeys(obj: {[key: string]: any}): {[key: string]: any} {
const ret: {[key: string]: any} = {};
for (const key of Object.keys(obj)) {
ret[key.slice(0, 1).toUpperCase() + key.slice(1)] = obj[key];
}
return ret;
}
function flatten<A>(xs: A[][]): A[] {
return Array.prototype.concat([], ...xs);
}
function noEmpty<A>(xs: A[]): A[] | undefined {
if (xs.length === 0) { return undefined; }
return xs;
}