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.
@@ -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": (0, stack_1.getStackScopedName)(serviceName),
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
- return __awaiter(this, void 0, void 0, function* () {
46
- if (undefined === cluster) {
47
- const defaultClusterName = `${domain_1.env}-main`;
48
- cluster = (yield aws.ecs.getCluster({ clusterName: defaultClusterName }, { async: true })).arn;
49
- }
50
- if (typeof cluster === "string") {
51
- if (!cachedClusterInstances[cluster]) {
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.arn;
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
- return __awaiter(this, void 0, void 0, function* () {
116
- 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;
117
- if (undefined === essential) {
118
- essential = true;
119
- }
120
- if (undefined === memoryReservation) {
121
- memoryReservation = 512;
122
- }
123
- if (undefined === cpuReservation) {
124
- cpuReservation = 256;
125
- }
126
- if (undefined === desiredCount) {
127
- desiredCount = 1;
128
- }
129
- if (undefined === securityGroups) {
130
- securityGroups = [];
131
- }
132
- if (undefined === version) {
133
- version = (0, stack_1.getStackId)();
134
- }
135
- if (undefined === extraPortMappings) {
136
- extraPortMappings = [];
137
- }
138
- if (undefined === extraALBMappings) {
139
- extraALBMappings = [];
140
- }
141
- if (undefined === dependsOn) {
142
- dependsOn = [];
143
- }
144
- if (undefined === mountPoints) {
145
- mountPoints = [];
146
- }
147
- if (undefined === secrets) {
148
- secrets = [];
149
- }
150
- const { role: executionRole, policies: executionPolicies } = getFargateExecutionRole(`${serviceName}-${version}-execution`, executionRolePolicies || {});
151
- dependsOn.push(...executionPolicies);
152
- const { role: taskRole, policies } = getFargateTaskRole(`${serviceName}-${version}-task`, taskRolePolicies || {});
153
- dependsOn.push(...policies);
154
- let dockerLabels = {};
155
- if (metrics && (metrics.port || dockerListeningPort)) {
156
- dockerLabels.ECS_PROMETHEUS_EXPORTER_PORT =
157
- "" + (metrics.port || dockerListeningPort);
158
- dockerLabels.ECS_PROMETHEUS_METRICS_PATH = metrics.path || "/metrics";
159
- if (metrics.jobName) {
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
- // this port should be the internal port used for administrative purposes
167
- let serviceDiscoveryPort = dockerListeningPort;
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
- // enable egress traffic from the task to the internet
204
- (0, accessTheInternet_1.makeSecurityGroupAccessTheInternetV2)(taskSecurityGroup, serviceName);
205
- // make the container fully accessible from the bastion of the environment
206
- (0, acceptBastion_1.makeSecurityGroupAccessibleFromBastion)(taskSecurityGroup, serviceName);
207
- const targetGroups = [];
208
- if (dontExpose) {
209
- const service = yield createInternalService({
210
- serviceName,
211
- cluster,
212
- desiredCount,
213
- ephemeralStorageInGB,
214
- executionRole,
215
- taskRole,
216
- assignPublicIp: !dontAssignPublicIp,
217
- serviceDiscoveryPort,
218
- forceNewDeployment,
219
- ignoreServiceDiscovery,
220
- securityGroups: [taskSecurityGroup.id, ...securityGroups],
221
- containerInfo: {
222
- name: serviceName,
223
- secrets: [],
224
- environment,
225
- essential,
226
- image: dockerImage,
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
- return {
244
- service,
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: extraALBMapping.dockerListeningPort,
257
- hostPort: extraALBMapping.dockerListeningPort,
182
+ containerPort: port,
183
+ hostPort: port,
184
+ protocol: "tcp",
258
185
  });
259
186
  }
260
- }
261
- const portMapping = {
262
- containerPort: dockerListeningPort,
263
- hostPort: dockerListeningPort,
264
- };
265
- // make the service accesible by the ALB
266
- (0, acceptAlb_1.makeSecurityGroupAccessibleFromSharedAlb)(taskSecurityGroup);
267
- const service = yield createInternalService({
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 { endpoint: `https://${hostname}/`, service, exposed };
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
- var _a, _b;
307
- return __awaiter(this, void 0, void 0, function* () {
308
- let { serviceName, cluster, securityGroups, ignoreServiceDiscovery, serviceDiscoveryPort, desiredCount, executionRole, taskRole, containerInfo, assignPublicIp, dependsOn, volumes, team, targetGroups, runtimePlatform, ephemeralStorageInGB, appAutoscaling, forceNewDeployment, } = config;
309
- if (!desiredCount && desiredCount !== 0)
310
- desiredCount = 1;
311
- assignPublicIp = !!assignPublicIp;
312
- let serviceRegistries;
313
- if (!ignoreServiceDiscovery) {
314
- const serviceDiscovery = new aws.servicediscovery.Service(serviceName, {
315
- name: serviceName,
316
- description: "service discovery for " + serviceName,
317
- dnsConfig: {
318
- dnsRecords: [
319
- { type: "A", ttl: 10 },
320
- { type: "SRV", ttl: 10 },
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
- const taskDefinition = new aws.ecs.TaskDefinition((0, stack_1.getStackScopedName)(serviceName) + "-taskdefinition", {
336
- executionRoleArn: executionRole === null || executionRole === void 0 ? void 0 : executionRole.arn,
337
- taskRoleArn: taskRole === null || taskRole === void 0 ? void 0 : taskRole.arn,
338
- tags: { ServiceName: serviceName, Team: team },
339
- containerDefinitions: pulumi.jsonStringify([
340
- Object.assign(Object.assign({}, containerInfo), { logConfiguration: (0, exports.getDefaultLogs)(serviceName, logGroup) }),
341
- ]),
342
- ephemeralStorage: !!ephemeralStorageInGB
343
- ? {
344
- sizeInGib: ephemeralStorageInGB,
345
- }
346
- : undefined,
347
- cpu: (_a = containerInfo.cpu) === null || _a === void 0 ? void 0 : _a.toString(),
348
- memory: (_b = containerInfo.memoryReservation) === null || _b === void 0 ? void 0 : _b.toString(),
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
- serviceRegistries,
363
- desiredCount,
364
- launchType: "FARGATE",
365
- enableEcsManagedTags: true,
366
- forceNewDeployment,
367
- waitForSteadyState: false,
368
- taskDefinition: taskDefinition.arn,
369
- loadBalancers: [
370
- ...targetGroups.map((tg) => ({
371
- targetGroupArn: tg.arn,
372
- containerName: serviceName,
373
- containerPort: tg.port,
374
- })),
375
- ],
376
- }, Object.assign(Object.assign({}, extraOpts), { dependsOn }));
377
- if (appAutoscaling) {
378
- setAutoscaling(service, serviceName, { appAutoscaling, desiredCount });
379
- }
380
- return service;
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: (_a = config.appAutoscaling.minCapacity) !== null && _a !== void 0 ? _a : config.desiredCount,
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: Object.assign({ context, args: {
12
+ build: {
13
+ context,
14
+ args: {
13
15
  DOCKER_BUILDKIT: "1",
14
- } }, options),
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
+ }>;