@stacksjs/ts-cloud 0.1.7 → 0.1.9
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/dist/aws/s3.d.ts +1 -1
- package/dist/bin/cli.js +223 -222
- package/dist/index.js +132 -132
- package/package.json +18 -16
- package/src/aws/acm.ts +768 -0
- package/src/aws/application-autoscaling.ts +845 -0
- package/src/aws/bedrock.ts +4074 -0
- package/src/aws/client.ts +891 -0
- package/src/aws/cloudformation.ts +896 -0
- package/src/aws/cloudfront.ts +1531 -0
- package/src/aws/cloudwatch-logs.ts +154 -0
- package/src/aws/comprehend.ts +839 -0
- package/src/aws/connect.ts +1056 -0
- package/src/aws/deploy-imap.ts +384 -0
- package/src/aws/dynamodb.ts +340 -0
- package/src/aws/ec2.ts +1385 -0
- package/src/aws/ecr.ts +621 -0
- package/src/aws/ecs.ts +615 -0
- package/src/aws/elasticache.ts +301 -0
- package/src/aws/elbv2.ts +942 -0
- package/src/aws/email.ts +928 -0
- package/src/aws/eventbridge.ts +248 -0
- package/src/aws/iam.ts +1689 -0
- package/src/aws/imap-server.ts +2100 -0
- package/src/aws/index.ts +213 -0
- package/src/aws/kendra.ts +1097 -0
- package/src/aws/lambda.ts +786 -0
- package/src/aws/opensearch.ts +158 -0
- package/src/aws/personalize.ts +977 -0
- package/src/aws/polly.ts +559 -0
- package/src/aws/rds.ts +888 -0
- package/src/aws/rekognition.ts +846 -0
- package/src/aws/route53-domains.ts +359 -0
- package/src/aws/route53.ts +1046 -0
- package/src/aws/s3.ts +2334 -0
- package/src/aws/scheduler.ts +571 -0
- package/src/aws/secrets-manager.ts +769 -0
- package/src/aws/ses.ts +1081 -0
- package/src/aws/setup-phone.ts +104 -0
- package/src/aws/setup-sms.ts +580 -0
- package/src/aws/sms.ts +1735 -0
- package/src/aws/smtp-server.ts +531 -0
- package/src/aws/sns.ts +758 -0
- package/src/aws/sqs.ts +382 -0
- package/src/aws/ssm.ts +807 -0
- package/src/aws/sts.ts +92 -0
- package/src/aws/support.ts +391 -0
- package/src/aws/test-imap.ts +86 -0
- package/src/aws/textract.ts +780 -0
- package/src/aws/transcribe.ts +108 -0
- package/src/aws/translate.ts +641 -0
- package/src/aws/voice.ts +1379 -0
- package/src/config.ts +35 -0
- package/src/deploy/index.ts +7 -0
- package/src/deploy/static-site-external-dns.ts +945 -0
- package/src/deploy/static-site.ts +1175 -0
- package/src/dns/cloudflare.ts +548 -0
- package/src/dns/godaddy.ts +412 -0
- package/src/dns/index.ts +205 -0
- package/src/dns/porkbun.ts +362 -0
- package/src/dns/route53-adapter.ts +414 -0
- package/src/dns/types.ts +119 -0
- package/src/dns/validator.ts +369 -0
- package/src/generators/index.ts +5 -0
- package/src/generators/infrastructure.ts +1660 -0
- package/src/index.ts +163 -0
- package/src/push/apns.ts +452 -0
- package/src/push/fcm.ts +506 -0
- package/src/push/index.ts +58 -0
- package/src/security/pre-deploy-scanner.ts +655 -0
- package/src/ssl/acme-client.ts +478 -0
- package/src/ssl/index.ts +7 -0
- package/src/ssl/letsencrypt.ts +747 -0
- package/src/types.ts +2 -0
- package/src/utils/cli.ts +398 -0
- package/src/validation/index.ts +5 -0
- package/src/validation/template.ts +405 -0
package/src/aws/ecs.ts
ADDED
|
@@ -0,0 +1,615 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS ECS Operations
|
|
3
|
+
* Direct API calls without AWS CLI dependency
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { AWSClient } from './client'
|
|
7
|
+
|
|
8
|
+
export interface Service {
|
|
9
|
+
serviceArn?: string
|
|
10
|
+
serviceName?: string
|
|
11
|
+
clusterArn?: string
|
|
12
|
+
status?: string
|
|
13
|
+
desiredCount?: number
|
|
14
|
+
runningCount?: number
|
|
15
|
+
pendingCount?: number
|
|
16
|
+
launchType?: string
|
|
17
|
+
taskDefinition?: string
|
|
18
|
+
deployments?: Deployment[]
|
|
19
|
+
events?: ServiceEvent[]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface Deployment {
|
|
23
|
+
id?: string
|
|
24
|
+
status?: string
|
|
25
|
+
taskDefinition?: string
|
|
26
|
+
desiredCount?: number
|
|
27
|
+
runningCount?: number
|
|
28
|
+
pendingCount?: number
|
|
29
|
+
createdAt?: string
|
|
30
|
+
updatedAt?: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ServiceEvent {
|
|
34
|
+
id?: string
|
|
35
|
+
createdAt?: string
|
|
36
|
+
message?: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface DescribeServicesOptions {
|
|
40
|
+
cluster: string
|
|
41
|
+
services: string[]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface Task {
|
|
45
|
+
taskArn?: string
|
|
46
|
+
taskDefinitionArn?: string
|
|
47
|
+
clusterArn?: string
|
|
48
|
+
lastStatus?: string
|
|
49
|
+
desiredStatus?: string
|
|
50
|
+
containers?: Container[]
|
|
51
|
+
createdAt?: string
|
|
52
|
+
startedAt?: string
|
|
53
|
+
stoppedAt?: string
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface Container {
|
|
57
|
+
containerArn?: string
|
|
58
|
+
name?: string
|
|
59
|
+
lastStatus?: string
|
|
60
|
+
exitCode?: number
|
|
61
|
+
reason?: string
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* ECS service management using direct API calls
|
|
66
|
+
*/
|
|
67
|
+
export class ECSClient {
|
|
68
|
+
private client: AWSClient
|
|
69
|
+
private region: string
|
|
70
|
+
|
|
71
|
+
constructor(region: string = 'us-east-1', profile?: string) {
|
|
72
|
+
this.region = region
|
|
73
|
+
this.client = new AWSClient()
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Describe ECS services
|
|
78
|
+
*/
|
|
79
|
+
async describeServices(options: DescribeServicesOptions): Promise<{ services?: Service[], failures?: any[] }> {
|
|
80
|
+
const params: Record<string, any> = {
|
|
81
|
+
cluster: options.cluster,
|
|
82
|
+
services: options.services,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const result = await this.client.request({
|
|
86
|
+
service: 'ecs',
|
|
87
|
+
region: this.region,
|
|
88
|
+
method: 'POST',
|
|
89
|
+
path: '/',
|
|
90
|
+
headers: {
|
|
91
|
+
'X-Amz-Target': 'AmazonEC2ContainerServiceV20141113.DescribeServices',
|
|
92
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
93
|
+
},
|
|
94
|
+
body: JSON.stringify(params),
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
return result
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* List ECS services in a cluster
|
|
102
|
+
*/
|
|
103
|
+
async listServices(cluster: string): Promise<{ serviceArns?: string[] }> {
|
|
104
|
+
const params: Record<string, any> = {
|
|
105
|
+
cluster,
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const result = await this.client.request({
|
|
109
|
+
service: 'ecs',
|
|
110
|
+
region: this.region,
|
|
111
|
+
method: 'POST',
|
|
112
|
+
path: '/',
|
|
113
|
+
headers: {
|
|
114
|
+
'X-Amz-Target': 'AmazonEC2ContainerServiceV20141113.ListServices',
|
|
115
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
116
|
+
},
|
|
117
|
+
body: JSON.stringify(params),
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
return result
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* List tasks in a cluster
|
|
125
|
+
*/
|
|
126
|
+
async listTasks(cluster: string, serviceName?: string): Promise<{ taskArns?: string[] }> {
|
|
127
|
+
const params: Record<string, any> = {
|
|
128
|
+
cluster,
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (serviceName) {
|
|
132
|
+
params.serviceName = serviceName
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const result = await this.client.request({
|
|
136
|
+
service: 'ecs',
|
|
137
|
+
region: this.region,
|
|
138
|
+
method: 'POST',
|
|
139
|
+
path: '/',
|
|
140
|
+
headers: {
|
|
141
|
+
'X-Amz-Target': 'AmazonEC2ContainerServiceV20141113.ListTasks',
|
|
142
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
143
|
+
},
|
|
144
|
+
body: JSON.stringify(params),
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
return result
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Describe ECS tasks
|
|
152
|
+
*/
|
|
153
|
+
async describeTasks(cluster: string, tasks: string[]): Promise<{ tasks?: Task[], failures?: any[] }> {
|
|
154
|
+
const params: Record<string, any> = {
|
|
155
|
+
cluster,
|
|
156
|
+
tasks,
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const result = await this.client.request({
|
|
160
|
+
service: 'ecs',
|
|
161
|
+
region: this.region,
|
|
162
|
+
method: 'POST',
|
|
163
|
+
path: '/',
|
|
164
|
+
headers: {
|
|
165
|
+
'X-Amz-Target': 'AmazonEC2ContainerServiceV20141113.DescribeTasks',
|
|
166
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
167
|
+
},
|
|
168
|
+
body: JSON.stringify(params),
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
return result
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Update ECS service (e.g., force new deployment)
|
|
176
|
+
*/
|
|
177
|
+
async updateService(options: {
|
|
178
|
+
cluster: string
|
|
179
|
+
service: string
|
|
180
|
+
forceNewDeployment?: boolean
|
|
181
|
+
desiredCount?: number
|
|
182
|
+
taskDefinition?: string
|
|
183
|
+
}): Promise<{ service?: Service }> {
|
|
184
|
+
const params: Record<string, any> = {
|
|
185
|
+
cluster: options.cluster,
|
|
186
|
+
service: options.service,
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (options.forceNewDeployment !== undefined) {
|
|
190
|
+
params.forceNewDeployment = options.forceNewDeployment
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (options.desiredCount !== undefined) {
|
|
194
|
+
params.desiredCount = options.desiredCount
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (options.taskDefinition) {
|
|
198
|
+
params.taskDefinition = options.taskDefinition
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const result = await this.client.request({
|
|
202
|
+
service: 'ecs',
|
|
203
|
+
region: this.region,
|
|
204
|
+
method: 'POST',
|
|
205
|
+
path: '/',
|
|
206
|
+
headers: {
|
|
207
|
+
'X-Amz-Target': 'AmazonEC2ContainerServiceV20141113.UpdateService',
|
|
208
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
209
|
+
},
|
|
210
|
+
body: JSON.stringify(params),
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
return result
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Create a new ECS service
|
|
218
|
+
*/
|
|
219
|
+
async createService(options: {
|
|
220
|
+
cluster: string
|
|
221
|
+
serviceName: string
|
|
222
|
+
taskDefinition: string
|
|
223
|
+
desiredCount: number
|
|
224
|
+
launchType?: 'EC2' | 'FARGATE' | 'EXTERNAL'
|
|
225
|
+
networkConfiguration?: {
|
|
226
|
+
awsvpcConfiguration: {
|
|
227
|
+
subnets: string[]
|
|
228
|
+
securityGroups?: string[]
|
|
229
|
+
assignPublicIp?: 'ENABLED' | 'DISABLED'
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
loadBalancers?: Array<{
|
|
233
|
+
targetGroupArn: string
|
|
234
|
+
containerName: string
|
|
235
|
+
containerPort: number
|
|
236
|
+
}>
|
|
237
|
+
healthCheckGracePeriodSeconds?: number
|
|
238
|
+
deploymentConfiguration?: {
|
|
239
|
+
minimumHealthyPercent?: number
|
|
240
|
+
maximumPercent?: number
|
|
241
|
+
}
|
|
242
|
+
}): Promise<{ service?: Service }> {
|
|
243
|
+
const params: Record<string, any> = {
|
|
244
|
+
cluster: options.cluster,
|
|
245
|
+
serviceName: options.serviceName,
|
|
246
|
+
taskDefinition: options.taskDefinition,
|
|
247
|
+
desiredCount: options.desiredCount,
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (options.launchType) {
|
|
251
|
+
params.launchType = options.launchType
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (options.networkConfiguration) {
|
|
255
|
+
params.networkConfiguration = options.networkConfiguration
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (options.loadBalancers) {
|
|
259
|
+
params.loadBalancers = options.loadBalancers
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (options.healthCheckGracePeriodSeconds !== undefined) {
|
|
263
|
+
params.healthCheckGracePeriodSeconds = options.healthCheckGracePeriodSeconds
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (options.deploymentConfiguration) {
|
|
267
|
+
params.deploymentConfiguration = options.deploymentConfiguration
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const result = await this.client.request({
|
|
271
|
+
service: 'ecs',
|
|
272
|
+
region: this.region,
|
|
273
|
+
method: 'POST',
|
|
274
|
+
path: '/',
|
|
275
|
+
headers: {
|
|
276
|
+
'X-Amz-Target': 'AmazonEC2ContainerServiceV20141113.CreateService',
|
|
277
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
278
|
+
},
|
|
279
|
+
body: JSON.stringify(params),
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
return result
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Delete an ECS service
|
|
287
|
+
*/
|
|
288
|
+
async deleteService(options: {
|
|
289
|
+
cluster: string
|
|
290
|
+
service: string
|
|
291
|
+
force?: boolean
|
|
292
|
+
}): Promise<{ service?: Service }> {
|
|
293
|
+
const params: Record<string, any> = {
|
|
294
|
+
cluster: options.cluster,
|
|
295
|
+
service: options.service,
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (options.force !== undefined) {
|
|
299
|
+
params.force = options.force
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const result = await this.client.request({
|
|
303
|
+
service: 'ecs',
|
|
304
|
+
region: this.region,
|
|
305
|
+
method: 'POST',
|
|
306
|
+
path: '/',
|
|
307
|
+
headers: {
|
|
308
|
+
'X-Amz-Target': 'AmazonEC2ContainerServiceV20141113.DeleteService',
|
|
309
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
310
|
+
},
|
|
311
|
+
body: JSON.stringify(params),
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
return result
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* List ECS clusters
|
|
319
|
+
*/
|
|
320
|
+
async listClusters(): Promise<{ clusterArns?: string[] }> {
|
|
321
|
+
const result = await this.client.request({
|
|
322
|
+
service: 'ecs',
|
|
323
|
+
region: this.region,
|
|
324
|
+
method: 'POST',
|
|
325
|
+
path: '/',
|
|
326
|
+
headers: {
|
|
327
|
+
'X-Amz-Target': 'AmazonEC2ContainerServiceV20141113.ListClusters',
|
|
328
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
329
|
+
},
|
|
330
|
+
body: JSON.stringify({}),
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
return result
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Describe ECS clusters
|
|
338
|
+
*/
|
|
339
|
+
async describeClusters(clusters: string[]): Promise<{ clusters?: any[], failures?: any[] }> {
|
|
340
|
+
const params = {
|
|
341
|
+
clusters,
|
|
342
|
+
include: ['ATTACHMENTS', 'CONFIGURATIONS', 'SETTINGS', 'STATISTICS', 'TAGS'],
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const result = await this.client.request({
|
|
346
|
+
service: 'ecs',
|
|
347
|
+
region: this.region,
|
|
348
|
+
method: 'POST',
|
|
349
|
+
path: '/',
|
|
350
|
+
headers: {
|
|
351
|
+
'X-Amz-Target': 'AmazonEC2ContainerServiceV20141113.DescribeClusters',
|
|
352
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
353
|
+
},
|
|
354
|
+
body: JSON.stringify(params),
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
return result
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Stop a running task
|
|
362
|
+
*/
|
|
363
|
+
async stopTask(options: {
|
|
364
|
+
cluster: string
|
|
365
|
+
task: string
|
|
366
|
+
reason?: string
|
|
367
|
+
}): Promise<{ task?: Task }> {
|
|
368
|
+
const params: Record<string, any> = {
|
|
369
|
+
cluster: options.cluster,
|
|
370
|
+
task: options.task,
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (options.reason) {
|
|
374
|
+
params.reason = options.reason
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const result = await this.client.request({
|
|
378
|
+
service: 'ecs',
|
|
379
|
+
region: this.region,
|
|
380
|
+
method: 'POST',
|
|
381
|
+
path: '/',
|
|
382
|
+
headers: {
|
|
383
|
+
'X-Amz-Target': 'AmazonEC2ContainerServiceV20141113.StopTask',
|
|
384
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
385
|
+
},
|
|
386
|
+
body: JSON.stringify(params),
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
return result
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Run a one-off task
|
|
394
|
+
*/
|
|
395
|
+
async runTask(options: {
|
|
396
|
+
cluster: string
|
|
397
|
+
taskDefinition: string
|
|
398
|
+
count?: number
|
|
399
|
+
launchType?: 'EC2' | 'FARGATE' | 'EXTERNAL'
|
|
400
|
+
networkConfiguration?: {
|
|
401
|
+
awsvpcConfiguration: {
|
|
402
|
+
subnets: string[]
|
|
403
|
+
securityGroups?: string[]
|
|
404
|
+
assignPublicIp?: 'ENABLED' | 'DISABLED'
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
overrides?: {
|
|
408
|
+
containerOverrides?: Array<{
|
|
409
|
+
name: string
|
|
410
|
+
command?: string[]
|
|
411
|
+
environment?: Array<{ name: string, value: string }>
|
|
412
|
+
}>
|
|
413
|
+
}
|
|
414
|
+
}): Promise<{ tasks?: Task[], failures?: any[] }> {
|
|
415
|
+
const params: Record<string, any> = {
|
|
416
|
+
cluster: options.cluster,
|
|
417
|
+
taskDefinition: options.taskDefinition,
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (options.count !== undefined) {
|
|
421
|
+
params.count = options.count
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (options.launchType) {
|
|
425
|
+
params.launchType = options.launchType
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (options.networkConfiguration) {
|
|
429
|
+
params.networkConfiguration = options.networkConfiguration
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (options.overrides) {
|
|
433
|
+
params.overrides = options.overrides
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const result = await this.client.request({
|
|
437
|
+
service: 'ecs',
|
|
438
|
+
region: this.region,
|
|
439
|
+
method: 'POST',
|
|
440
|
+
path: '/',
|
|
441
|
+
headers: {
|
|
442
|
+
'X-Amz-Target': 'AmazonEC2ContainerServiceV20141113.RunTask',
|
|
443
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
444
|
+
},
|
|
445
|
+
body: JSON.stringify(params),
|
|
446
|
+
})
|
|
447
|
+
|
|
448
|
+
return result
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Register a new task definition
|
|
453
|
+
*/
|
|
454
|
+
async registerTaskDefinition(options: {
|
|
455
|
+
family: string
|
|
456
|
+
containerDefinitions: Array<{
|
|
457
|
+
name: string
|
|
458
|
+
image: string
|
|
459
|
+
memory?: number
|
|
460
|
+
cpu?: number
|
|
461
|
+
essential?: boolean
|
|
462
|
+
portMappings?: Array<{
|
|
463
|
+
containerPort: number
|
|
464
|
+
hostPort?: number
|
|
465
|
+
protocol?: 'tcp' | 'udp'
|
|
466
|
+
}>
|
|
467
|
+
environment?: Array<{ name: string, value: string }>
|
|
468
|
+
secrets?: Array<{ name: string, valueFrom: string }>
|
|
469
|
+
logConfiguration?: {
|
|
470
|
+
logDriver: string
|
|
471
|
+
options?: Record<string, string>
|
|
472
|
+
}
|
|
473
|
+
}>
|
|
474
|
+
cpu?: string
|
|
475
|
+
memory?: string
|
|
476
|
+
networkMode?: 'bridge' | 'host' | 'awsvpc' | 'none'
|
|
477
|
+
requiresCompatibilities?: Array<'EC2' | 'FARGATE' | 'EXTERNAL'>
|
|
478
|
+
executionRoleArn?: string
|
|
479
|
+
taskRoleArn?: string
|
|
480
|
+
}): Promise<{ taskDefinition?: any }> {
|
|
481
|
+
const result = await this.client.request({
|
|
482
|
+
service: 'ecs',
|
|
483
|
+
region: this.region,
|
|
484
|
+
method: 'POST',
|
|
485
|
+
path: '/',
|
|
486
|
+
headers: {
|
|
487
|
+
'X-Amz-Target': 'AmazonEC2ContainerServiceV20141113.RegisterTaskDefinition',
|
|
488
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
489
|
+
},
|
|
490
|
+
body: JSON.stringify(options),
|
|
491
|
+
})
|
|
492
|
+
|
|
493
|
+
return result
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Deregister a task definition
|
|
498
|
+
*/
|
|
499
|
+
async deregisterTaskDefinition(taskDefinition: string): Promise<{ taskDefinition?: any }> {
|
|
500
|
+
const result = await this.client.request({
|
|
501
|
+
service: 'ecs',
|
|
502
|
+
region: this.region,
|
|
503
|
+
method: 'POST',
|
|
504
|
+
path: '/',
|
|
505
|
+
headers: {
|
|
506
|
+
'X-Amz-Target': 'AmazonEC2ContainerServiceV20141113.DeregisterTaskDefinition',
|
|
507
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
508
|
+
},
|
|
509
|
+
body: JSON.stringify({ taskDefinition }),
|
|
510
|
+
})
|
|
511
|
+
|
|
512
|
+
return result
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Describe task definitions
|
|
517
|
+
*/
|
|
518
|
+
async describeTaskDefinition(taskDefinition: string): Promise<{ taskDefinition?: any, tags?: any[] }> {
|
|
519
|
+
const result = await this.client.request({
|
|
520
|
+
service: 'ecs',
|
|
521
|
+
region: this.region,
|
|
522
|
+
method: 'POST',
|
|
523
|
+
path: '/',
|
|
524
|
+
headers: {
|
|
525
|
+
'X-Amz-Target': 'AmazonEC2ContainerServiceV20141113.DescribeTaskDefinition',
|
|
526
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
527
|
+
},
|
|
528
|
+
body: JSON.stringify({ taskDefinition, include: ['TAGS'] }),
|
|
529
|
+
})
|
|
530
|
+
|
|
531
|
+
return result
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* List task definition families
|
|
536
|
+
*/
|
|
537
|
+
async listTaskDefinitionFamilies(options?: {
|
|
538
|
+
familyPrefix?: string
|
|
539
|
+
status?: 'ACTIVE' | 'INACTIVE' | 'ALL'
|
|
540
|
+
}): Promise<{ families?: string[] }> {
|
|
541
|
+
const params: Record<string, any> = {}
|
|
542
|
+
|
|
543
|
+
if (options?.familyPrefix) {
|
|
544
|
+
params.familyPrefix = options.familyPrefix
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
if (options?.status) {
|
|
548
|
+
params.status = options.status
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
const result = await this.client.request({
|
|
552
|
+
service: 'ecs',
|
|
553
|
+
region: this.region,
|
|
554
|
+
method: 'POST',
|
|
555
|
+
path: '/',
|
|
556
|
+
headers: {
|
|
557
|
+
'X-Amz-Target': 'AmazonEC2ContainerServiceV20141113.ListTaskDefinitionFamilies',
|
|
558
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
559
|
+
},
|
|
560
|
+
body: JSON.stringify(params),
|
|
561
|
+
})
|
|
562
|
+
|
|
563
|
+
return result
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Wait for service to become stable
|
|
568
|
+
*/
|
|
569
|
+
async waitForServiceStable(cluster: string, service: string, maxAttempts = 40, delayMs = 15000): Promise<boolean> {
|
|
570
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
571
|
+
const result = await this.describeServices({
|
|
572
|
+
cluster,
|
|
573
|
+
services: [service],
|
|
574
|
+
})
|
|
575
|
+
|
|
576
|
+
const svc = result.services?.[0]
|
|
577
|
+
if (svc) {
|
|
578
|
+
// Check if all deployments are completed
|
|
579
|
+
const primaryDeployment = svc.deployments?.find((d: Deployment) => d.status === 'PRIMARY')
|
|
580
|
+
if (primaryDeployment &&
|
|
581
|
+
primaryDeployment.runningCount === primaryDeployment.desiredCount &&
|
|
582
|
+
svc.deployments?.length === 1) {
|
|
583
|
+
return true
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Wait before next check
|
|
588
|
+
await new Promise(resolve => setTimeout(resolve, delayMs))
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
return false
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Helper: Force new deployment
|
|
596
|
+
*/
|
|
597
|
+
async forceNewDeployment(cluster: string, service: string): Promise<{ service?: Service }> {
|
|
598
|
+
return this.updateService({
|
|
599
|
+
cluster,
|
|
600
|
+
service,
|
|
601
|
+
forceNewDeployment: true,
|
|
602
|
+
})
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Helper: Scale service
|
|
607
|
+
*/
|
|
608
|
+
async scaleService(cluster: string, service: string, desiredCount: number): Promise<{ service?: Service }> {
|
|
609
|
+
return this.updateService({
|
|
610
|
+
cluster,
|
|
611
|
+
service,
|
|
612
|
+
desiredCount,
|
|
613
|
+
})
|
|
614
|
+
}
|
|
615
|
+
}
|