dcl-ops-lib 8.3.3 → 9.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/acceptBastion.js +3 -12
- package/acceptDb.js +6 -15
- package/accessTheInternet.js +23 -34
- package/alb.js +7 -16
- package/buildStatic.js +1 -2
- package/cloudflare.js +47 -57
- package/createFargateTask.d.ts +3 -2
- package/createFargateTask.js +233 -252
- package/createImageFromContext.js +6 -2
- package/createSQSTriggeredFargateTask.d.ts +63 -0
- package/createSQSTriggeredFargateTask.js +110 -0
- package/createScheduledFargateTask.d.ts +75 -0
- package/createScheduledFargateTask.js +108 -0
- package/exposePublicService.js +74 -85
- package/fargateHelpers.d.ts +220 -0
- package/fargateHelpers.js +178 -0
- package/getAmi.js +14 -25
- package/getImageRegistryAndCredentials.js +3 -12
- package/index.d.ts +32 -0
- package/index.js +52 -0
- package/lambda.js +124 -132
- package/package.json +13 -9
- package/prometheus.js +6 -15
- package/scheduledTaskBase.d.ts +142 -0
- package/scheduledTaskBase.js +146 -0
- package/slack.d.ts +4 -0
- package/slack.js +21 -0
- package/utils.js +1 -1
- package/values.js +12 -23
- package/vpc.js +7 -18
package/createFargateTask.js
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.createInternalService = exports.createFargateTask = exports.getFargateTaskRole = exports.getFargateExecutionRole = exports.getClusterInstance = exports.getDefaultLogs = void 0;
|
|
13
4
|
const aws = require("@pulumi/aws");
|
|
@@ -22,11 +13,12 @@ const supra_1 = require("./supra");
|
|
|
22
13
|
const stack_1 = require("./stack");
|
|
23
14
|
const prometheus_1 = require("./prometheus");
|
|
24
15
|
const accessTheInternet_1 = require("./accessTheInternet");
|
|
16
|
+
const fargateHelpers_1 = require("./fargateHelpers");
|
|
25
17
|
const getDefaultLogs = (serviceName, logGroup) => {
|
|
26
18
|
return {
|
|
27
19
|
logDriver: "awslogs",
|
|
28
20
|
options: {
|
|
29
|
-
"awslogs-group":
|
|
21
|
+
"awslogs-group": logGroup.name,
|
|
30
22
|
"awslogs-region": "us-east-1",
|
|
31
23
|
"awslogs-stream-prefix": serviceName,
|
|
32
24
|
},
|
|
@@ -41,20 +33,18 @@ const extraOpts = {
|
|
|
41
33
|
},
|
|
42
34
|
};
|
|
43
35
|
const cachedClusterInstances = {};
|
|
44
|
-
function getClusterInstance(cluster) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
cachedClusterInstances[cluster] = (yield aws.ecs.getCluster({ clusterName: cluster }, { async: true })).arn;
|
|
53
|
-
}
|
|
54
|
-
return cachedClusterInstances[cluster];
|
|
36
|
+
async function getClusterInstance(cluster) {
|
|
37
|
+
if (undefined === cluster) {
|
|
38
|
+
const defaultClusterName = `${domain_1.env}-main`;
|
|
39
|
+
cluster = (await aws.ecs.getCluster({ clusterName: defaultClusterName }, { async: true })).arn;
|
|
40
|
+
}
|
|
41
|
+
if (typeof cluster === "string") {
|
|
42
|
+
if (!cachedClusterInstances[cluster]) {
|
|
43
|
+
cachedClusterInstances[cluster] = (await aws.ecs.getCluster({ clusterName: cluster }, { async: true })).arn;
|
|
55
44
|
}
|
|
56
|
-
return cluster
|
|
57
|
-
}
|
|
45
|
+
return cachedClusterInstances[cluster];
|
|
46
|
+
}
|
|
47
|
+
return cluster.arn;
|
|
58
48
|
}
|
|
59
49
|
exports.getClusterInstance = getClusterInstance;
|
|
60
50
|
function getFargateExecutionRole(name, policyArnNamedMap) {
|
|
@@ -111,182 +101,123 @@ exports.getFargateTaskRole = getFargateTaskRole;
|
|
|
111
101
|
* @param options.policyArnNamedMap key-value named map of policies to attach to the default execution role for this task
|
|
112
102
|
* @param options.appAutoscaling Configuration for autoscaling
|
|
113
103
|
*/
|
|
114
|
-
function createFargateTask(serviceName, dockerImage, dockerListeningPort, environment, hostname, options) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
dockerLabels.ECS_PROMETHEUS_JOB_NAME = metrics.jobName;
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
dockerLabels.ECS_PROMETHEUS_JOB_NAME = serviceName;
|
|
164
|
-
}
|
|
104
|
+
async function createFargateTask(serviceName, dockerImage, dockerListeningPort, environment, hostname, options) {
|
|
105
|
+
let { healthCheck, healthCheckContainer, essential, dontExpose, securityGroups, cluster, memoryReservation, command, version, ephemeralStorageInGB, desiredCount, cpuReservation, extraPortMappings, extraALBMappings, executionRolePolicies, taskRolePolicies, ignoreServiceDiscovery, secrets, metrics, forceNewDeployment, dontAssignPublicIp, dependsOn, volumes, deregistrationDelay, mountPoints, repositoryCredentials, team, appAutoscaling, } = options;
|
|
106
|
+
if (undefined === essential) {
|
|
107
|
+
essential = true;
|
|
108
|
+
}
|
|
109
|
+
if (undefined === memoryReservation) {
|
|
110
|
+
memoryReservation = fargateHelpers_1.DEFAULT_MEMORY;
|
|
111
|
+
}
|
|
112
|
+
if (undefined === cpuReservation) {
|
|
113
|
+
cpuReservation = fargateHelpers_1.DEFAULT_CPU;
|
|
114
|
+
}
|
|
115
|
+
if (undefined === desiredCount) {
|
|
116
|
+
desiredCount = fargateHelpers_1.DEFAULT_DESIRED_COUNT;
|
|
117
|
+
}
|
|
118
|
+
if (undefined === securityGroups) {
|
|
119
|
+
securityGroups = [];
|
|
120
|
+
}
|
|
121
|
+
if (undefined === version) {
|
|
122
|
+
version = (0, stack_1.getStackId)();
|
|
123
|
+
}
|
|
124
|
+
if (undefined === extraPortMappings) {
|
|
125
|
+
extraPortMappings = [];
|
|
126
|
+
}
|
|
127
|
+
if (undefined === extraALBMappings) {
|
|
128
|
+
extraALBMappings = [];
|
|
129
|
+
}
|
|
130
|
+
if (undefined === dependsOn) {
|
|
131
|
+
dependsOn = [];
|
|
132
|
+
}
|
|
133
|
+
if (undefined === mountPoints) {
|
|
134
|
+
mountPoints = [];
|
|
135
|
+
}
|
|
136
|
+
if (undefined === secrets) {
|
|
137
|
+
secrets = [];
|
|
138
|
+
}
|
|
139
|
+
const { role: executionRole, policies: executionPolicies } = getFargateExecutionRole(`${serviceName}-${version}-execution`, executionRolePolicies || {});
|
|
140
|
+
dependsOn.push(...executionPolicies);
|
|
141
|
+
const { role: taskRole, policies } = getFargateTaskRole(`${serviceName}-${version}-task`, taskRolePolicies || {});
|
|
142
|
+
dependsOn.push(...policies);
|
|
143
|
+
let dockerLabels = {};
|
|
144
|
+
if (metrics && (metrics.port || dockerListeningPort)) {
|
|
145
|
+
dockerLabels.ECS_PROMETHEUS_EXPORTER_PORT =
|
|
146
|
+
"" + (metrics.port || dockerListeningPort);
|
|
147
|
+
dockerLabels.ECS_PROMETHEUS_METRICS_PATH = metrics.path || "/metrics";
|
|
148
|
+
if (metrics.jobName) {
|
|
149
|
+
dockerLabels.ECS_PROMETHEUS_JOB_NAME = metrics.jobName;
|
|
165
150
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const vpc = yield (0, vpc_1.getVpc)();
|
|
169
|
-
const taskSecurityGroup = new aws.ec2.SecurityGroup(`${serviceName}-${version}`, {
|
|
170
|
-
vpcId: vpc.id,
|
|
171
|
-
tags: { ServiceName: serviceName, Team: team },
|
|
172
|
-
});
|
|
173
|
-
if (dockerLabels.ECS_PROMETHEUS_EXPORTER_PORT) {
|
|
174
|
-
let fromPort = 0;
|
|
175
|
-
let toPort = 0;
|
|
176
|
-
new Set(dockerLabels.ECS_PROMETHEUS_EXPORTER_PORT.split(/;/g).map(($) => parseInt($))).forEach((port) => {
|
|
177
|
-
if (fromPort == 0 || fromPort > port)
|
|
178
|
-
fromPort = port;
|
|
179
|
-
if (toPort == 0 || toPort < port)
|
|
180
|
-
toPort = port;
|
|
181
|
-
// create a security group to enable metrics access by cwagent from inside the VPC
|
|
182
|
-
new aws.ec2.SecurityGroupRule(`metrics-${port}`, {
|
|
183
|
-
type: "ingress",
|
|
184
|
-
fromPort: port,
|
|
185
|
-
toPort: port,
|
|
186
|
-
protocol: "tcp",
|
|
187
|
-
cidrBlocks: [vpc.cidrBlock],
|
|
188
|
-
securityGroupId: taskSecurityGroup.id,
|
|
189
|
-
});
|
|
190
|
-
if (!extraPortMappings.find(($) => $.hostPort != metrics.port) &&
|
|
191
|
-
(port != dockerListeningPort || dontExpose)) {
|
|
192
|
-
extraPortMappings.push({
|
|
193
|
-
containerPort: port,
|
|
194
|
-
hostPort: port,
|
|
195
|
-
protocol: "tcp",
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
serviceDiscoveryPort = port;
|
|
199
|
-
});
|
|
200
|
-
// enable prometheus to access fromPort-toPort
|
|
201
|
-
(0, prometheus_1.makeSecurityGroupAccessibleByPrometheus)(taskSecurityGroup, fromPort, toPort, serviceName);
|
|
151
|
+
else {
|
|
152
|
+
dockerLabels.ECS_PROMETHEUS_JOB_NAME = serviceName;
|
|
202
153
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
command,
|
|
228
|
-
healthCheck: healthCheckContainer,
|
|
229
|
-
memoryReservation,
|
|
230
|
-
cpu: cpuReservation,
|
|
231
|
-
portMappings: extraPortMappings,
|
|
232
|
-
dockerLabels,
|
|
233
|
-
mountPoints,
|
|
234
|
-
repositoryCredentials,
|
|
235
|
-
},
|
|
236
|
-
dependsOn,
|
|
237
|
-
volumes,
|
|
238
|
-
team,
|
|
239
|
-
targetGroups,
|
|
240
|
-
runtimePlatform: options.runtimePlatform,
|
|
241
|
-
appAutoscaling,
|
|
154
|
+
}
|
|
155
|
+
// this port should be the internal port used for administrative purposes
|
|
156
|
+
let serviceDiscoveryPort = dockerListeningPort;
|
|
157
|
+
const vpc = await (0, vpc_1.getVpc)();
|
|
158
|
+
const taskSecurityGroup = new aws.ec2.SecurityGroup(`${serviceName}-${version}`, {
|
|
159
|
+
vpcId: vpc.id,
|
|
160
|
+
tags: (0, fargateHelpers_1.createResourceTags)(serviceName, team),
|
|
161
|
+
});
|
|
162
|
+
if (dockerLabels.ECS_PROMETHEUS_EXPORTER_PORT) {
|
|
163
|
+
let fromPort = 0;
|
|
164
|
+
let toPort = 0;
|
|
165
|
+
new Set(dockerLabels.ECS_PROMETHEUS_EXPORTER_PORT.split(/;/g).map(($) => parseInt($))).forEach((port) => {
|
|
166
|
+
if (fromPort == 0 || fromPort > port)
|
|
167
|
+
fromPort = port;
|
|
168
|
+
if (toPort == 0 || toPort < port)
|
|
169
|
+
toPort = port;
|
|
170
|
+
// create a security group to enable metrics access by cwagent from inside the VPC
|
|
171
|
+
new aws.ec2.SecurityGroupRule(`metrics-${port}`, {
|
|
172
|
+
type: "ingress",
|
|
173
|
+
fromPort: port,
|
|
174
|
+
toPort: port,
|
|
175
|
+
protocol: "tcp",
|
|
176
|
+
cidrBlocks: [vpc.cidrBlock],
|
|
177
|
+
securityGroupId: taskSecurityGroup.id,
|
|
242
178
|
});
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
endpoint: "not exposed",
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
const exposed = yield (0, exposePublicService_1.exposePublicService)(`${serviceName}-${version}`, hostname, dockerListeningPort, healthCheck, vpc.id, options.extraExposedServiceOptions, deregistrationDelay);
|
|
249
|
-
targetGroups.push(exposed.targetGroup);
|
|
250
|
-
for (let extraALBMapping of extraALBMappings) {
|
|
251
|
-
const exposedExtra = yield (0, exposePublicService_1.exposePublicService)(`${serviceName}-${extraALBMapping.dockerListeningPort}-${version}`, extraALBMapping.domain, extraALBMapping.dockerListeningPort, extraALBMapping.healthCheck, vpc.id, extraALBMapping.extraExposedServiceOptions);
|
|
252
|
-
targetGroups.push(exposedExtra.targetGroup);
|
|
253
|
-
// we have to do this check because the port might have been added to the array before if it's included in ECS_PROMETHEUS_EXPORTER_PORT
|
|
254
|
-
if (!extraPortMappings.find((port) => port.hostPort === extraALBMapping.dockerListeningPort)) {
|
|
179
|
+
if (!extraPortMappings.find(($) => $.hostPort != metrics.port) &&
|
|
180
|
+
(port != dockerListeningPort || dontExpose)) {
|
|
255
181
|
extraPortMappings.push({
|
|
256
|
-
containerPort:
|
|
257
|
-
hostPort:
|
|
182
|
+
containerPort: port,
|
|
183
|
+
hostPort: port,
|
|
184
|
+
protocol: "tcp",
|
|
258
185
|
});
|
|
259
186
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
187
|
+
serviceDiscoveryPort = port;
|
|
188
|
+
});
|
|
189
|
+
// enable prometheus to access fromPort-toPort
|
|
190
|
+
(0, prometheus_1.makeSecurityGroupAccessibleByPrometheus)(taskSecurityGroup, fromPort, toPort, serviceName);
|
|
191
|
+
}
|
|
192
|
+
// enable egress traffic from the task to the internet
|
|
193
|
+
(0, accessTheInternet_1.makeSecurityGroupAccessTheInternetV2)(taskSecurityGroup, serviceName);
|
|
194
|
+
// make the container fully accessible from the bastion of the environment
|
|
195
|
+
(0, acceptBastion_1.makeSecurityGroupAccessibleFromBastion)(taskSecurityGroup, serviceName);
|
|
196
|
+
const targetGroups = [];
|
|
197
|
+
if (dontExpose) {
|
|
198
|
+
const service = await createInternalService({
|
|
268
199
|
serviceName,
|
|
269
200
|
cluster,
|
|
270
201
|
desiredCount,
|
|
271
202
|
ephemeralStorageInGB,
|
|
272
203
|
executionRole,
|
|
273
204
|
taskRole,
|
|
274
|
-
forceNewDeployment,
|
|
275
205
|
assignPublicIp: !dontAssignPublicIp,
|
|
206
|
+
serviceDiscoveryPort,
|
|
207
|
+
forceNewDeployment,
|
|
276
208
|
ignoreServiceDiscovery,
|
|
277
209
|
securityGroups: [taskSecurityGroup.id, ...securityGroups],
|
|
278
|
-
serviceDiscoveryPort,
|
|
279
210
|
containerInfo: {
|
|
280
211
|
name: serviceName,
|
|
281
|
-
secrets,
|
|
212
|
+
secrets: [],
|
|
282
213
|
environment,
|
|
283
|
-
portMappings: [...extraPortMappings, portMapping],
|
|
284
214
|
essential,
|
|
285
215
|
image: dockerImage,
|
|
286
216
|
command,
|
|
287
217
|
healthCheck: healthCheckContainer,
|
|
288
218
|
memoryReservation,
|
|
289
219
|
cpu: cpuReservation,
|
|
220
|
+
portMappings: extraPortMappings,
|
|
290
221
|
dockerLabels,
|
|
291
222
|
mountPoints,
|
|
292
223
|
repositoryCredentials,
|
|
@@ -298,98 +229,148 @@ function createFargateTask(serviceName, dockerImage, dockerListeningPort, enviro
|
|
|
298
229
|
runtimePlatform: options.runtimePlatform,
|
|
299
230
|
appAutoscaling,
|
|
300
231
|
});
|
|
301
|
-
return {
|
|
232
|
+
return {
|
|
233
|
+
service,
|
|
234
|
+
endpoint: "not exposed",
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
const exposed = await (0, exposePublicService_1.exposePublicService)(`${serviceName}-${version}`, hostname, dockerListeningPort, healthCheck, vpc.id, options.extraExposedServiceOptions, deregistrationDelay);
|
|
238
|
+
targetGroups.push(exposed.targetGroup);
|
|
239
|
+
for (let extraALBMapping of extraALBMappings) {
|
|
240
|
+
const exposedExtra = await (0, exposePublicService_1.exposePublicService)(`${serviceName}-${extraALBMapping.dockerListeningPort}-${version}`, extraALBMapping.domain, extraALBMapping.dockerListeningPort, extraALBMapping.healthCheck, vpc.id, extraALBMapping.extraExposedServiceOptions);
|
|
241
|
+
targetGroups.push(exposedExtra.targetGroup);
|
|
242
|
+
// we have to do this check because the port might have been added to the array before if it's included in ECS_PROMETHEUS_EXPORTER_PORT
|
|
243
|
+
if (!extraPortMappings.find((port) => port.hostPort === extraALBMapping.dockerListeningPort)) {
|
|
244
|
+
extraPortMappings.push({
|
|
245
|
+
containerPort: extraALBMapping.dockerListeningPort,
|
|
246
|
+
hostPort: extraALBMapping.dockerListeningPort,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const portMapping = {
|
|
251
|
+
containerPort: dockerListeningPort,
|
|
252
|
+
hostPort: dockerListeningPort,
|
|
253
|
+
};
|
|
254
|
+
// make the service accesible by the ALB
|
|
255
|
+
(0, acceptAlb_1.makeSecurityGroupAccessibleFromSharedAlb)(taskSecurityGroup);
|
|
256
|
+
const service = await createInternalService({
|
|
257
|
+
serviceName,
|
|
258
|
+
cluster,
|
|
259
|
+
desiredCount,
|
|
260
|
+
ephemeralStorageInGB,
|
|
261
|
+
executionRole,
|
|
262
|
+
taskRole,
|
|
263
|
+
forceNewDeployment,
|
|
264
|
+
assignPublicIp: !dontAssignPublicIp,
|
|
265
|
+
ignoreServiceDiscovery,
|
|
266
|
+
securityGroups: [taskSecurityGroup.id, ...securityGroups],
|
|
267
|
+
serviceDiscoveryPort,
|
|
268
|
+
containerInfo: {
|
|
269
|
+
name: serviceName,
|
|
270
|
+
secrets,
|
|
271
|
+
environment,
|
|
272
|
+
portMappings: [...extraPortMappings, portMapping],
|
|
273
|
+
essential,
|
|
274
|
+
image: dockerImage,
|
|
275
|
+
command,
|
|
276
|
+
healthCheck: healthCheckContainer,
|
|
277
|
+
memoryReservation,
|
|
278
|
+
cpu: cpuReservation,
|
|
279
|
+
dockerLabels,
|
|
280
|
+
mountPoints,
|
|
281
|
+
repositoryCredentials,
|
|
282
|
+
},
|
|
283
|
+
dependsOn,
|
|
284
|
+
volumes,
|
|
285
|
+
team,
|
|
286
|
+
targetGroups,
|
|
287
|
+
runtimePlatform: options.runtimePlatform,
|
|
288
|
+
appAutoscaling,
|
|
302
289
|
});
|
|
290
|
+
return { endpoint: `https://${hostname}/`, service, exposed };
|
|
303
291
|
}
|
|
304
292
|
exports.createFargateTask = createFargateTask;
|
|
305
|
-
function createInternalService(config) {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
namespaceId: (0, supra_1.getInternalServiceDiscoveryNamespaceId)(),
|
|
323
|
-
},
|
|
324
|
-
});
|
|
325
|
-
serviceRegistries = {
|
|
326
|
-
port: serviceDiscoveryPort,
|
|
327
|
-
registryArn: serviceDiscovery.arn,
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
const logGroup = new aws.cloudwatch.LogGroup((0, stack_1.getStackScopedName)(serviceName), {
|
|
331
|
-
name: (0, stack_1.getStackScopedName)(serviceName),
|
|
332
|
-
retentionInDays: 60,
|
|
333
|
-
tags: { ServiceName: serviceName, Team: team },
|
|
293
|
+
async function createInternalService(config) {
|
|
294
|
+
let { serviceName, cluster, securityGroups, ignoreServiceDiscovery, serviceDiscoveryPort, desiredCount, executionRole, taskRole, containerInfo, assignPublicIp, dependsOn, volumes, team, targetGroups, runtimePlatform, ephemeralStorageInGB, appAutoscaling, forceNewDeployment, } = config;
|
|
295
|
+
if (!desiredCount && desiredCount !== 0)
|
|
296
|
+
desiredCount = 1;
|
|
297
|
+
assignPublicIp = !!assignPublicIp;
|
|
298
|
+
let serviceRegistries;
|
|
299
|
+
if (!ignoreServiceDiscovery) {
|
|
300
|
+
const serviceDiscovery = new aws.servicediscovery.Service(serviceName, {
|
|
301
|
+
name: serviceName,
|
|
302
|
+
description: "service discovery for " + serviceName,
|
|
303
|
+
dnsConfig: {
|
|
304
|
+
dnsRecords: [
|
|
305
|
+
{ type: "A", ttl: 10 },
|
|
306
|
+
{ type: "SRV", ttl: 10 },
|
|
307
|
+
],
|
|
308
|
+
namespaceId: (0, supra_1.getInternalServiceDiscoveryNamespaceId)(),
|
|
309
|
+
},
|
|
334
310
|
});
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
runtimePlatform: runtimePlatform,
|
|
350
|
-
requiresCompatibilities: ["FARGATE"],
|
|
351
|
-
networkMode: "awsvpc",
|
|
352
|
-
volumes: volumes,
|
|
353
|
-
family: (0, stack_1.getStackScopedName)(serviceName),
|
|
354
|
-
}, { dependsOn: [logGroup] });
|
|
355
|
-
const service = new aws.ecs.Service((0, stack_1.getStackScopedName)(serviceName), {
|
|
356
|
-
cluster: yield getClusterInstance(cluster),
|
|
357
|
-
tags: { ServiceName: serviceName, StackId: (0, stack_1.getStackId)(), Team: team },
|
|
358
|
-
networkConfiguration: {
|
|
359
|
-
subnets: yield (0, network_1.getPrivateSubnetIds)(),
|
|
360
|
-
securityGroups: securityGroups,
|
|
311
|
+
serviceRegistries = {
|
|
312
|
+
port: serviceDiscoveryPort,
|
|
313
|
+
registryArn: serviceDiscovery.arn,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
const logGroup = (0, fargateHelpers_1.createLogGroup)(serviceName, team);
|
|
317
|
+
const taskDefinition = (0, fargateHelpers_1.createFargateTaskDefinition)({
|
|
318
|
+
name: serviceName,
|
|
319
|
+
executionRoleArn: executionRole?.arn,
|
|
320
|
+
taskRoleArn: taskRole?.arn,
|
|
321
|
+
containerDefinitions: pulumi.jsonStringify([
|
|
322
|
+
{
|
|
323
|
+
...containerInfo,
|
|
324
|
+
logConfiguration: (0, exports.getDefaultLogs)(serviceName, logGroup),
|
|
361
325
|
},
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
326
|
+
]),
|
|
327
|
+
team,
|
|
328
|
+
cpu: containerInfo.cpu ?? fargateHelpers_1.DEFAULT_CPU,
|
|
329
|
+
memory: containerInfo.memoryReservation ?? fargateHelpers_1.DEFAULT_MEMORY,
|
|
330
|
+
ephemeralStorageInGB,
|
|
331
|
+
runtimePlatform,
|
|
332
|
+
volumes,
|
|
333
|
+
dependsOn: [logGroup],
|
|
334
|
+
});
|
|
335
|
+
const service = new aws.ecs.Service((0, stack_1.getStackScopedName)(serviceName), {
|
|
336
|
+
cluster: await getClusterInstance(cluster),
|
|
337
|
+
tags: (0, fargateHelpers_1.createResourceTags)(serviceName, team, { StackId: (0, stack_1.getStackId)() }),
|
|
338
|
+
networkConfiguration: {
|
|
339
|
+
subnets: await (0, network_1.getPrivateSubnetIds)(),
|
|
340
|
+
securityGroups: securityGroups,
|
|
341
|
+
},
|
|
342
|
+
serviceRegistries,
|
|
343
|
+
desiredCount,
|
|
344
|
+
launchType: "FARGATE",
|
|
345
|
+
enableEcsManagedTags: true,
|
|
346
|
+
forceNewDeployment,
|
|
347
|
+
waitForSteadyState: false,
|
|
348
|
+
taskDefinition: taskDefinition.arn,
|
|
349
|
+
loadBalancers: [
|
|
350
|
+
...targetGroups.map((tg) => ({
|
|
351
|
+
targetGroupArn: tg.arn,
|
|
352
|
+
containerName: serviceName,
|
|
353
|
+
containerPort: tg.port,
|
|
354
|
+
})),
|
|
355
|
+
],
|
|
356
|
+
}, {
|
|
357
|
+
...extraOpts,
|
|
358
|
+
dependsOn,
|
|
381
359
|
});
|
|
360
|
+
if (appAutoscaling) {
|
|
361
|
+
setAutoscaling(service, serviceName, { appAutoscaling, desiredCount });
|
|
362
|
+
}
|
|
363
|
+
return service;
|
|
382
364
|
}
|
|
383
365
|
exports.createInternalService = createInternalService;
|
|
384
366
|
function setAutoscaling(service, serviceName, config) {
|
|
385
|
-
var _a;
|
|
386
367
|
if ((!config.appAutoscaling.policy && !config.appAutoscaling.scheduleAction) ||
|
|
387
368
|
(config.appAutoscaling.policy && config.appAutoscaling.scheduleAction)) {
|
|
388
369
|
throw new Error("Invalid autoscaling configuration. You must provide either a policy OR a scheduleAction.");
|
|
389
370
|
}
|
|
390
371
|
const ecsTarget = new aws.appautoscaling.Target(`ecs-target-${(0, stack_1.getStackScopedName)(serviceName)}`, {
|
|
391
372
|
maxCapacity: config.appAutoscaling.maxCapacity,
|
|
392
|
-
minCapacity:
|
|
373
|
+
minCapacity: config.appAutoscaling.minCapacity ?? config.desiredCount,
|
|
393
374
|
resourceId: service.id.apply((id) => {
|
|
394
375
|
return id.split(":").pop();
|
|
395
376
|
}),
|
|
@@ -9,9 +9,13 @@ function createImageFromContext(name, context, options, imageOpts) {
|
|
|
9
9
|
const registry = (0, getImageRegistryAndCredentials_1.getImageRegistryAndCredentials)(ecr);
|
|
10
10
|
const image = new docker.Image(`${name}-image`, {
|
|
11
11
|
imageName: ecr.repositoryUrl,
|
|
12
|
-
build:
|
|
12
|
+
build: {
|
|
13
|
+
context,
|
|
14
|
+
args: {
|
|
13
15
|
DOCKER_BUILDKIT: "1",
|
|
14
|
-
}
|
|
16
|
+
},
|
|
17
|
+
...options,
|
|
18
|
+
},
|
|
15
19
|
registry: registry,
|
|
16
20
|
}, imageOpts);
|
|
17
21
|
return {
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as pulumi from "@pulumi/pulumi";
|
|
2
|
+
import { BaseFargateTaskOptions } from "./scheduledTaskBase";
|
|
3
|
+
/**
|
|
4
|
+
* SQS trigger configuration for the task
|
|
5
|
+
*/
|
|
6
|
+
export type SqsTriggerConfig = {
|
|
7
|
+
/**
|
|
8
|
+
* ARN of the SQS queue to trigger from
|
|
9
|
+
*/
|
|
10
|
+
queueArn: pulumi.Input<string>;
|
|
11
|
+
/**
|
|
12
|
+
* Number of messages per batch (default: 1)
|
|
13
|
+
* Each batch triggers one task invocation
|
|
14
|
+
*/
|
|
15
|
+
batchSize?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Maximum batching window in seconds (default: 0)
|
|
18
|
+
* How long to wait to accumulate messages before triggering
|
|
19
|
+
*/
|
|
20
|
+
maximumBatchingWindowSeconds?: number;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Options for creating an SQS-triggered Fargate task
|
|
24
|
+
*/
|
|
25
|
+
export type SQSTriggeredFargateTaskOptions = BaseFargateTaskOptions & {
|
|
26
|
+
/**
|
|
27
|
+
* SQS queue trigger configuration - required
|
|
28
|
+
*/
|
|
29
|
+
sqsTrigger: SqsTriggerConfig;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Creates a Fargate task that is triggered by messages in an SQS queue.
|
|
33
|
+
* Uses EventBridge Pipes to connect the SQS queue to ECS task execution.
|
|
34
|
+
*
|
|
35
|
+
* @param taskName A name for this task. For example, "order-processor"
|
|
36
|
+
* @param dockerImage The docker image to run
|
|
37
|
+
* @param options Configuration options for the SQS-triggered task
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* await createSQSTriggeredFargateTask("order-processor", "myapp/processor:latest", {
|
|
42
|
+
* sqsTrigger: {
|
|
43
|
+
* queueArn: ordersQueue.arn,
|
|
44
|
+
* batchSize: 10,
|
|
45
|
+
* maximumBatchingWindowSeconds: 30,
|
|
46
|
+
* },
|
|
47
|
+
* cpu: 512,
|
|
48
|
+
* memory: 1024,
|
|
49
|
+
* environment: [{ name: "DB_HOST", value: dbHost }],
|
|
50
|
+
* slackChannel: "#order-processing-alerts",
|
|
51
|
+
* team: "platform",
|
|
52
|
+
* });
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function createSQSTriggeredFargateTask(taskName: string, dockerImage: string | Promise<string> | pulumi.OutputInstance<string>, options: SQSTriggeredFargateTaskOptions): Promise<{
|
|
56
|
+
taskDefinition: import("@pulumi/aws/ecs/taskDefinition").TaskDefinition;
|
|
57
|
+
taskSecurityGroup: import("@pulumi/aws/ec2/securityGroup").SecurityGroup;
|
|
58
|
+
logGroup: import("@pulumi/aws/cloudwatch/logGroup").LogGroup;
|
|
59
|
+
executionRole: import("@pulumi/aws/iam/role").Role;
|
|
60
|
+
taskRole: import("@pulumi/aws/iam/role").Role;
|
|
61
|
+
eventBridgeRole: import("@pulumi/aws/iam/role").Role;
|
|
62
|
+
pipe: import("@pulumi/aws/pipes/pipe").Pipe;
|
|
63
|
+
}>;
|