@stacksjs/ts-cloud 0.1.3 → 0.1.5
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/README.md +98 -13
- package/dist/aws/acm.d.ts +129 -0
- package/dist/aws/application-autoscaling.d.ts +282 -0
- package/dist/aws/bedrock.d.ts +2292 -0
- package/dist/aws/client.d.ts +79 -0
- package/dist/aws/cloudformation.d.ts +105 -0
- package/dist/aws/cloudfront.d.ts +265 -0
- package/dist/aws/cloudwatch-logs.d.ts +48 -0
- package/dist/aws/comprehend.d.ts +505 -0
- package/dist/aws/connect.d.ts +377 -0
- package/dist/aws/deploy-imap.d.ts +14 -0
- package/dist/aws/dynamodb.d.ts +176 -0
- package/dist/aws/ec2.d.ts +272 -0
- package/dist/aws/ecr.d.ts +149 -0
- package/dist/aws/ecs.d.ts +162 -0
- package/dist/aws/elasticache.d.ts +71 -0
- package/dist/aws/elbv2.d.ts +248 -0
- package/dist/aws/email.d.ts +175 -0
- package/dist/aws/eventbridge.d.ts +142 -0
- package/dist/aws/iam.d.ts +638 -0
- package/dist/aws/imap-server.d.ts +119 -0
- package/{src/aws/index.ts → dist/aws/index.d.ts} +62 -83
- package/{src/aws/kendra.ts → dist/aws/kendra.d.ts} +71 -386
- package/dist/aws/lambda.d.ts +232 -0
- package/dist/aws/opensearch.d.ts +87 -0
- package/dist/aws/personalize.d.ts +516 -0
- package/dist/aws/polly.d.ts +214 -0
- package/dist/aws/rds.d.ts +240 -0
- package/dist/aws/rekognition.d.ts +543 -0
- package/dist/aws/route53-domains.d.ts +113 -0
- package/dist/aws/route53.d.ts +215 -0
- package/dist/aws/s3.d.ts +212 -0
- package/dist/aws/scheduler.d.ts +140 -0
- package/dist/aws/secrets-manager.d.ts +170 -0
- package/dist/aws/ses.d.ts +288 -0
- package/dist/aws/setup-phone.d.ts +0 -0
- package/dist/aws/setup-sms.d.ts +115 -0
- package/dist/aws/sms.d.ts +304 -0
- package/dist/aws/smtp-server.d.ts +61 -0
- package/dist/aws/sns.d.ts +117 -0
- package/dist/aws/sqs.d.ts +65 -0
- package/dist/aws/ssm.d.ts +179 -0
- package/dist/aws/sts.d.ts +15 -0
- package/dist/aws/support.d.ts +104 -0
- package/dist/aws/test-imap.d.ts +0 -0
- package/dist/aws/textract.d.ts +403 -0
- package/dist/aws/transcribe.d.ts +60 -0
- package/dist/aws/translate.d.ts +358 -0
- package/dist/aws/voice.d.ts +219 -0
- package/dist/bin/cli.js +1724 -0
- package/dist/config.d.ts +7 -0
- package/dist/deploy/index.d.ts +2 -0
- package/dist/deploy/static-site-external-dns.d.ts +51 -0
- package/dist/deploy/static-site.d.ts +71 -0
- package/dist/dns/cloudflare.d.ts +52 -0
- package/dist/dns/godaddy.d.ts +38 -0
- package/dist/dns/index.d.ts +45 -0
- package/dist/dns/porkbun.d.ts +18 -0
- package/dist/dns/route53-adapter.d.ts +38 -0
- package/{src/dns/types.ts → dist/dns/types.d.ts} +26 -63
- package/dist/dns/validator.d.ts +78 -0
- package/dist/generators/index.d.ts +1 -0
- package/dist/generators/infrastructure.d.ts +30 -0
- package/{src/index.ts → dist/index.d.ts} +70 -93
- package/dist/index.js +7881 -0
- package/dist/push/apns.d.ts +60 -0
- package/dist/push/fcm.d.ts +117 -0
- package/dist/push/index.d.ts +14 -0
- package/dist/security/pre-deploy-scanner.d.ts +69 -0
- package/dist/ssl/acme-client.d.ts +67 -0
- package/dist/ssl/index.d.ts +2 -0
- package/dist/ssl/letsencrypt.d.ts +48 -0
- package/dist/types.d.ts +1 -0
- package/dist/utils/cli.d.ts +123 -0
- package/dist/validation/index.d.ts +1 -0
- package/dist/validation/template.d.ts +23 -0
- package/package.json +8 -8
- package/bin/cli.ts +0 -133
- package/bin/commands/analytics.ts +0 -328
- package/bin/commands/api.ts +0 -379
- package/bin/commands/assets.ts +0 -221
- package/bin/commands/audit.ts +0 -501
- package/bin/commands/backup.ts +0 -682
- package/bin/commands/cache.ts +0 -294
- package/bin/commands/cdn.ts +0 -281
- package/bin/commands/config.ts +0 -202
- package/bin/commands/container.ts +0 -105
- package/bin/commands/cost.ts +0 -208
- package/bin/commands/database.ts +0 -401
- package/bin/commands/deploy.ts +0 -674
- package/bin/commands/domain.ts +0 -397
- package/bin/commands/email.ts +0 -423
- package/bin/commands/environment.ts +0 -285
- package/bin/commands/events.ts +0 -424
- package/bin/commands/firewall.ts +0 -145
- package/bin/commands/function.ts +0 -116
- package/bin/commands/generate.ts +0 -280
- package/bin/commands/git.ts +0 -139
- package/bin/commands/iam.ts +0 -464
- package/bin/commands/index.ts +0 -48
- package/bin/commands/init.ts +0 -120
- package/bin/commands/logs.ts +0 -148
- package/bin/commands/network.ts +0 -579
- package/bin/commands/notify.ts +0 -489
- package/bin/commands/queue.ts +0 -407
- package/bin/commands/scheduler.ts +0 -370
- package/bin/commands/secrets.ts +0 -54
- package/bin/commands/server.ts +0 -629
- package/bin/commands/shared.ts +0 -97
- package/bin/commands/ssl.ts +0 -138
- package/bin/commands/stack.ts +0 -325
- package/bin/commands/status.ts +0 -385
- package/bin/commands/storage.ts +0 -450
- package/bin/commands/team.ts +0 -96
- package/bin/commands/tunnel.ts +0 -489
- package/bin/commands/utils.ts +0 -202
- package/build.ts +0 -15
- package/cloud +0 -2
- package/src/aws/acm.ts +0 -768
- package/src/aws/application-autoscaling.ts +0 -845
- package/src/aws/bedrock.ts +0 -4074
- package/src/aws/client.ts +0 -878
- package/src/aws/cloudformation.ts +0 -896
- package/src/aws/cloudfront.ts +0 -1531
- package/src/aws/cloudwatch-logs.ts +0 -154
- package/src/aws/comprehend.ts +0 -839
- package/src/aws/connect.ts +0 -1056
- package/src/aws/deploy-imap.ts +0 -384
- package/src/aws/dynamodb.ts +0 -340
- package/src/aws/ec2.ts +0 -1385
- package/src/aws/ecr.ts +0 -621
- package/src/aws/ecs.ts +0 -615
- package/src/aws/elasticache.ts +0 -301
- package/src/aws/elbv2.ts +0 -942
- package/src/aws/email.ts +0 -928
- package/src/aws/eventbridge.ts +0 -248
- package/src/aws/iam.ts +0 -1689
- package/src/aws/imap-server.ts +0 -2100
- package/src/aws/lambda.ts +0 -786
- package/src/aws/opensearch.ts +0 -158
- package/src/aws/personalize.ts +0 -977
- package/src/aws/polly.ts +0 -559
- package/src/aws/rds.ts +0 -888
- package/src/aws/rekognition.ts +0 -846
- package/src/aws/route53-domains.ts +0 -359
- package/src/aws/route53.ts +0 -1046
- package/src/aws/s3.ts +0 -2318
- package/src/aws/scheduler.ts +0 -571
- package/src/aws/secrets-manager.ts +0 -769
- package/src/aws/ses.ts +0 -1081
- package/src/aws/setup-phone.ts +0 -104
- package/src/aws/setup-sms.ts +0 -580
- package/src/aws/sms.ts +0 -1735
- package/src/aws/smtp-server.ts +0 -531
- package/src/aws/sns.ts +0 -758
- package/src/aws/sqs.ts +0 -382
- package/src/aws/ssm.ts +0 -807
- package/src/aws/sts.ts +0 -92
- package/src/aws/support.ts +0 -391
- package/src/aws/test-imap.ts +0 -86
- package/src/aws/textract.ts +0 -780
- package/src/aws/transcribe.ts +0 -108
- package/src/aws/translate.ts +0 -641
- package/src/aws/voice.ts +0 -1379
- package/src/config.ts +0 -35
- package/src/deploy/index.ts +0 -7
- package/src/deploy/static-site-external-dns.ts +0 -906
- package/src/deploy/static-site.ts +0 -1125
- package/src/dns/godaddy.ts +0 -412
- package/src/dns/index.ts +0 -183
- package/src/dns/porkbun.ts +0 -362
- package/src/dns/route53-adapter.ts +0 -414
- package/src/dns/validator.ts +0 -369
- package/src/generators/index.ts +0 -5
- package/src/generators/infrastructure.ts +0 -1660
- package/src/push/apns.ts +0 -452
- package/src/push/fcm.ts +0 -506
- package/src/push/index.ts +0 -58
- package/src/ssl/acme-client.ts +0 -478
- package/src/ssl/index.ts +0 -7
- package/src/ssl/letsencrypt.ts +0 -747
- package/src/types.ts +0 -2
- package/src/utils/cli.ts +0 -398
- package/src/validation/index.ts +0 -5
- package/src/validation/template.ts +0 -405
- package/test/index.test.ts +0 -128
- package/tsconfig.json +0 -18
package/bin/commands/status.ts
DELETED
|
@@ -1,385 +0,0 @@
|
|
|
1
|
-
import type { CLI } from '@stacksjs/clapp'
|
|
2
|
-
import type { Distribution } from '../../src/aws/cloudfront'
|
|
3
|
-
import type { CertificateDetail } from '../../src/aws/acm'
|
|
4
|
-
import * as cli from '../../src/utils/cli'
|
|
5
|
-
import { loadValidatedConfig } from './shared'
|
|
6
|
-
|
|
7
|
-
export function registerStatusCommands(app: CLI): void {
|
|
8
|
-
app
|
|
9
|
-
.command('status', 'Show overall infrastructure health dashboard')
|
|
10
|
-
.option('--region <region>', 'AWS region')
|
|
11
|
-
.action(async (options: { region?: string }) => {
|
|
12
|
-
cli.header('Infrastructure Status Dashboard')
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
const config = await loadValidatedConfig()
|
|
16
|
-
const region = options.region || config.project.region || 'us-east-1'
|
|
17
|
-
|
|
18
|
-
cli.info(`Region: ${region}`)
|
|
19
|
-
cli.info(`Project: ${config.project.name || 'Unknown'}`)
|
|
20
|
-
cli.info('')
|
|
21
|
-
|
|
22
|
-
const checks: { name: string; status: string; details: string }[] = []
|
|
23
|
-
|
|
24
|
-
// Check EC2 Instances
|
|
25
|
-
const ec2Spinner = new cli.Spinner('Checking EC2 instances...')
|
|
26
|
-
ec2Spinner.start()
|
|
27
|
-
try {
|
|
28
|
-
const { EC2Client } = await import('../../src/aws/ec2')
|
|
29
|
-
const ec2 = new EC2Client(region)
|
|
30
|
-
const instances = await ec2.describeInstances({
|
|
31
|
-
Filters: [{ Name: 'instance-state-name', Values: ['running', 'pending', 'stopping', 'stopped'] }],
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
let running = 0
|
|
35
|
-
let stopped = 0
|
|
36
|
-
let total = 0
|
|
37
|
-
|
|
38
|
-
for (const reservation of instances.Reservations || []) {
|
|
39
|
-
for (const instance of reservation.Instances || []) {
|
|
40
|
-
total++
|
|
41
|
-
if (instance.State?.Name === 'running') running++
|
|
42
|
-
else if (instance.State?.Name === 'stopped') stopped++
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
ec2Spinner.succeed('EC2 instances checked')
|
|
47
|
-
checks.push({
|
|
48
|
-
name: 'EC2 Instances',
|
|
49
|
-
status: running > 0 ? 'OK' : (total > 0 ? 'WARN' : 'INFO'),
|
|
50
|
-
details: `${running} running, ${stopped} stopped, ${total} total`,
|
|
51
|
-
})
|
|
52
|
-
}
|
|
53
|
-
catch (error: any) {
|
|
54
|
-
ec2Spinner.fail('EC2 check failed')
|
|
55
|
-
checks.push({ name: 'EC2 Instances', status: 'ERROR', details: error.message })
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Check RDS Instances
|
|
59
|
-
const rdsSpinner = new cli.Spinner('Checking RDS instances...')
|
|
60
|
-
rdsSpinner.start()
|
|
61
|
-
try {
|
|
62
|
-
const { RDSClient } = await import('../../src/aws/rds')
|
|
63
|
-
const rds = new RDSClient(region)
|
|
64
|
-
const result = await rds.describeDBInstances()
|
|
65
|
-
const instances = result.DBInstances || []
|
|
66
|
-
|
|
67
|
-
const available = instances.filter(i => i.DBInstanceStatus === 'available').length
|
|
68
|
-
|
|
69
|
-
rdsSpinner.succeed('RDS instances checked')
|
|
70
|
-
checks.push({
|
|
71
|
-
name: 'RDS Databases',
|
|
72
|
-
status: instances.length > 0 && available === instances.length ? 'OK' : (instances.length > 0 ? 'WARN' : 'INFO'),
|
|
73
|
-
details: `${available} available, ${instances.length} total`,
|
|
74
|
-
})
|
|
75
|
-
}
|
|
76
|
-
catch (error: any) {
|
|
77
|
-
rdsSpinner.fail('RDS check failed')
|
|
78
|
-
checks.push({ name: 'RDS Databases', status: 'ERROR', details: error.message })
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Check Lambda Functions
|
|
82
|
-
const lambdaSpinner = new cli.Spinner('Checking Lambda functions...')
|
|
83
|
-
lambdaSpinner.start()
|
|
84
|
-
try {
|
|
85
|
-
const { LambdaClient } = await import('../../src/aws/lambda')
|
|
86
|
-
const lambda = new LambdaClient(region)
|
|
87
|
-
const result = await lambda.listFunctions()
|
|
88
|
-
const functions = result.Functions || []
|
|
89
|
-
|
|
90
|
-
lambdaSpinner.succeed('Lambda functions checked')
|
|
91
|
-
checks.push({
|
|
92
|
-
name: 'Lambda Functions',
|
|
93
|
-
status: 'OK',
|
|
94
|
-
details: `${functions.length} function(s)`,
|
|
95
|
-
})
|
|
96
|
-
}
|
|
97
|
-
catch (error: any) {
|
|
98
|
-
lambdaSpinner.fail('Lambda check failed')
|
|
99
|
-
checks.push({ name: 'Lambda Functions', status: 'ERROR', details: error.message })
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Check S3 Buckets
|
|
103
|
-
const s3Spinner = new cli.Spinner('Checking S3 buckets...')
|
|
104
|
-
s3Spinner.start()
|
|
105
|
-
try {
|
|
106
|
-
const { S3Client } = await import('../../src/aws/s3')
|
|
107
|
-
const s3 = new S3Client(region)
|
|
108
|
-
const result = await s3.listBuckets()
|
|
109
|
-
const buckets = result.Buckets || []
|
|
110
|
-
|
|
111
|
-
s3Spinner.succeed('S3 buckets checked')
|
|
112
|
-
checks.push({
|
|
113
|
-
name: 'S3 Buckets',
|
|
114
|
-
status: 'OK',
|
|
115
|
-
details: `${buckets.length} bucket(s)`,
|
|
116
|
-
})
|
|
117
|
-
}
|
|
118
|
-
catch (error: any) {
|
|
119
|
-
s3Spinner.fail('S3 check failed')
|
|
120
|
-
checks.push({ name: 'S3 Buckets', status: 'ERROR', details: error.message })
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Check CloudFront Distributions
|
|
124
|
-
const cfSpinner = new cli.Spinner('Checking CloudFront distributions...')
|
|
125
|
-
cfSpinner.start()
|
|
126
|
-
try {
|
|
127
|
-
const { CloudFrontClient } = await import('../../src/aws/cloudfront')
|
|
128
|
-
const cloudfront = new CloudFrontClient()
|
|
129
|
-
const distributions = await cloudfront.listDistributions()
|
|
130
|
-
|
|
131
|
-
const deployed = distributions.filter((d: Distribution) => d.Status === 'Deployed').length
|
|
132
|
-
|
|
133
|
-
cfSpinner.succeed('CloudFront checked')
|
|
134
|
-
checks.push({
|
|
135
|
-
name: 'CloudFront',
|
|
136
|
-
status: distributions.length > 0 && deployed === distributions.length ? 'OK' : (distributions.length > 0 ? 'WARN' : 'INFO'),
|
|
137
|
-
details: `${deployed} deployed, ${distributions.length} total`,
|
|
138
|
-
})
|
|
139
|
-
}
|
|
140
|
-
catch (error: any) {
|
|
141
|
-
cfSpinner.fail('CloudFront check failed')
|
|
142
|
-
checks.push({ name: 'CloudFront', status: 'ERROR', details: error.message })
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Check SQS Queues
|
|
146
|
-
const sqsSpinner = new cli.Spinner('Checking SQS queues...')
|
|
147
|
-
sqsSpinner.start()
|
|
148
|
-
try {
|
|
149
|
-
const { SQSClient } = await import('../../src/aws/sqs')
|
|
150
|
-
const sqs = new SQSClient(region)
|
|
151
|
-
const result = await sqs.listQueues()
|
|
152
|
-
const queues = result.QueueUrls || []
|
|
153
|
-
|
|
154
|
-
sqsSpinner.succeed('SQS queues checked')
|
|
155
|
-
checks.push({
|
|
156
|
-
name: 'SQS Queues',
|
|
157
|
-
status: 'OK',
|
|
158
|
-
details: `${queues.length} queue(s)`,
|
|
159
|
-
})
|
|
160
|
-
}
|
|
161
|
-
catch (error: any) {
|
|
162
|
-
sqsSpinner.fail('SQS check failed')
|
|
163
|
-
checks.push({ name: 'SQS Queues', status: 'ERROR', details: error.message })
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Check CloudFormation Stacks
|
|
167
|
-
const cfnSpinner = new cli.Spinner('Checking CloudFormation stacks...')
|
|
168
|
-
cfnSpinner.start()
|
|
169
|
-
try {
|
|
170
|
-
const { CloudFormationClient } = await import('../../src/aws/cloudformation')
|
|
171
|
-
const cfn = new CloudFormationClient(region)
|
|
172
|
-
const result = await cfn.listStacks([
|
|
173
|
-
'CREATE_COMPLETE',
|
|
174
|
-
'UPDATE_COMPLETE',
|
|
175
|
-
'CREATE_IN_PROGRESS',
|
|
176
|
-
'UPDATE_IN_PROGRESS',
|
|
177
|
-
'ROLLBACK_COMPLETE',
|
|
178
|
-
'UPDATE_ROLLBACK_COMPLETE',
|
|
179
|
-
])
|
|
180
|
-
const stacks = result.StackSummaries || []
|
|
181
|
-
|
|
182
|
-
const healthy = stacks.filter(s =>
|
|
183
|
-
s.StackStatus === 'CREATE_COMPLETE' || s.StackStatus === 'UPDATE_COMPLETE',
|
|
184
|
-
).length
|
|
185
|
-
|
|
186
|
-
const inProgress = stacks.filter(s =>
|
|
187
|
-
s.StackStatus?.includes('IN_PROGRESS'),
|
|
188
|
-
).length
|
|
189
|
-
|
|
190
|
-
const failed = stacks.filter(s =>
|
|
191
|
-
s.StackStatus?.includes('ROLLBACK'),
|
|
192
|
-
).length
|
|
193
|
-
|
|
194
|
-
cfnSpinner.succeed('CloudFormation checked')
|
|
195
|
-
checks.push({
|
|
196
|
-
name: 'CloudFormation',
|
|
197
|
-
status: failed > 0 ? 'WARN' : (inProgress > 0 ? 'INFO' : 'OK'),
|
|
198
|
-
details: `${healthy} healthy, ${inProgress} in progress, ${failed} rolled back`,
|
|
199
|
-
})
|
|
200
|
-
}
|
|
201
|
-
catch (error: any) {
|
|
202
|
-
cfnSpinner.fail('CloudFormation check failed')
|
|
203
|
-
checks.push({ name: 'CloudFormation', status: 'ERROR', details: error.message })
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Check ACM Certificates
|
|
207
|
-
const acmSpinner = new cli.Spinner('Checking SSL certificates...')
|
|
208
|
-
acmSpinner.start()
|
|
209
|
-
try {
|
|
210
|
-
const { ACMClient } = await import('../../src/aws/acm')
|
|
211
|
-
const acm = new ACMClient('us-east-1')
|
|
212
|
-
const result = await acm.listCertificates()
|
|
213
|
-
const certSummaries = result.CertificateSummaryList || []
|
|
214
|
-
|
|
215
|
-
// Get full details for each certificate to access Status and NotAfter
|
|
216
|
-
const certs: CertificateDetail[] = await Promise.all(
|
|
217
|
-
certSummaries.map(c => acm.describeCertificate({ CertificateArn: c.CertificateArn })),
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
const issued = certs.filter(c => c.Status === 'ISSUED').length
|
|
221
|
-
const pending = certs.filter(c => c.Status === 'PENDING_VALIDATION').length
|
|
222
|
-
const expiringSoon = certs.filter((c) => {
|
|
223
|
-
if (c.NotAfter) {
|
|
224
|
-
const daysUntilExpiry = (new Date(c.NotAfter).getTime() - Date.now()) / (1000 * 60 * 60 * 24)
|
|
225
|
-
return daysUntilExpiry < 30
|
|
226
|
-
}
|
|
227
|
-
return false
|
|
228
|
-
}).length
|
|
229
|
-
|
|
230
|
-
acmSpinner.succeed('SSL certificates checked')
|
|
231
|
-
checks.push({
|
|
232
|
-
name: 'SSL Certificates',
|
|
233
|
-
status: expiringSoon > 0 ? 'WARN' : (pending > 0 ? 'INFO' : 'OK'),
|
|
234
|
-
details: `${issued} issued, ${pending} pending${expiringSoon > 0 ? `, ${expiringSoon} expiring soon` : ''}`,
|
|
235
|
-
})
|
|
236
|
-
}
|
|
237
|
-
catch (error: any) {
|
|
238
|
-
acmSpinner.fail('ACM check failed')
|
|
239
|
-
checks.push({ name: 'SSL Certificates', status: 'ERROR', details: error.message })
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Display summary
|
|
243
|
-
cli.info('\n' + '='.repeat(60))
|
|
244
|
-
cli.info('HEALTH SUMMARY')
|
|
245
|
-
cli.info('='.repeat(60) + '\n')
|
|
246
|
-
|
|
247
|
-
for (const check of checks) {
|
|
248
|
-
let icon = ''
|
|
249
|
-
if (check.status === 'OK') {
|
|
250
|
-
icon = `${cli.colors.green}[OK]${cli.colors.reset}`
|
|
251
|
-
}
|
|
252
|
-
else if (check.status === 'WARN') {
|
|
253
|
-
icon = `${cli.colors.yellow}[WARN]${cli.colors.reset}`
|
|
254
|
-
}
|
|
255
|
-
else if (check.status === 'ERROR') {
|
|
256
|
-
icon = `${cli.colors.red}[ERROR]${cli.colors.reset}`
|
|
257
|
-
}
|
|
258
|
-
else {
|
|
259
|
-
icon = `${cli.colors.blue}[INFO]${cli.colors.reset}`
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
console.log(`${icon} ${check.name.padEnd(20)} ${check.details}`)
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Overall status
|
|
266
|
-
const hasErrors = checks.some(c => c.status === 'ERROR')
|
|
267
|
-
const hasWarnings = checks.some(c => c.status === 'WARN')
|
|
268
|
-
|
|
269
|
-
cli.info('')
|
|
270
|
-
if (hasErrors) {
|
|
271
|
-
cli.error('Some services have errors. Check the details above.')
|
|
272
|
-
}
|
|
273
|
-
else if (hasWarnings) {
|
|
274
|
-
cli.warn('Some services need attention. Check the warnings above.')
|
|
275
|
-
}
|
|
276
|
-
else {
|
|
277
|
-
cli.success('All services are healthy!')
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
catch (error: any) {
|
|
281
|
-
cli.error(`Failed to get status: ${error.message}`)
|
|
282
|
-
process.exit(1)
|
|
283
|
-
}
|
|
284
|
-
})
|
|
285
|
-
|
|
286
|
-
app
|
|
287
|
-
.command('status:costs', 'Show current month cost summary')
|
|
288
|
-
.option('--region <region>', 'AWS region')
|
|
289
|
-
.action(async (options: { region?: string }) => {
|
|
290
|
-
cli.header('Cost Summary')
|
|
291
|
-
|
|
292
|
-
try {
|
|
293
|
-
cli.info('Fetching cost data from AWS Cost Explorer...')
|
|
294
|
-
cli.info('')
|
|
295
|
-
|
|
296
|
-
// Get current month dates
|
|
297
|
-
const now = new Date()
|
|
298
|
-
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1)
|
|
299
|
-
const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0)
|
|
300
|
-
|
|
301
|
-
cli.info(`Period: ${startOfMonth.toISOString().split('T')[0]} to ${endOfMonth.toISOString().split('T')[0]}`)
|
|
302
|
-
cli.info('')
|
|
303
|
-
|
|
304
|
-
// Note: Cost Explorer API requires special permissions
|
|
305
|
-
cli.info('Note: Cost data requires AWS Cost Explorer API access.')
|
|
306
|
-
cli.info('Run `cloud cost` for detailed cost analysis.')
|
|
307
|
-
}
|
|
308
|
-
catch (error: any) {
|
|
309
|
-
cli.error(`Failed to get cost summary: ${error.message}`)
|
|
310
|
-
process.exit(1)
|
|
311
|
-
}
|
|
312
|
-
})
|
|
313
|
-
|
|
314
|
-
app
|
|
315
|
-
.command('status:alarms', 'Show CloudWatch alarm status')
|
|
316
|
-
.option('--region <region>', 'AWS region')
|
|
317
|
-
.action(async (options: { region?: string }) => {
|
|
318
|
-
cli.header('CloudWatch Alarms')
|
|
319
|
-
|
|
320
|
-
try {
|
|
321
|
-
const config = await loadValidatedConfig()
|
|
322
|
-
const region = options.region || config.project.region || 'us-east-1'
|
|
323
|
-
|
|
324
|
-
const { AWSClient } = await import('../../src/aws/client')
|
|
325
|
-
|
|
326
|
-
class CloudWatchClient {
|
|
327
|
-
private client: InstanceType<typeof AWSClient>
|
|
328
|
-
private region: string
|
|
329
|
-
|
|
330
|
-
constructor(region: string) {
|
|
331
|
-
this.region = region
|
|
332
|
-
this.client = new AWSClient()
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
async describeAlarms() {
|
|
336
|
-
return this.client.request({
|
|
337
|
-
service: 'monitoring',
|
|
338
|
-
region: this.region,
|
|
339
|
-
method: 'POST',
|
|
340
|
-
path: '/',
|
|
341
|
-
headers: {
|
|
342
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
343
|
-
},
|
|
344
|
-
body: 'Action=DescribeAlarms&Version=2010-08-01',
|
|
345
|
-
})
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
const cloudwatch = new CloudWatchClient(region)
|
|
350
|
-
|
|
351
|
-
const spinner = new cli.Spinner('Fetching alarms...')
|
|
352
|
-
spinner.start()
|
|
353
|
-
|
|
354
|
-
const result = await cloudwatch.describeAlarms()
|
|
355
|
-
const alarms = result.MetricAlarms || []
|
|
356
|
-
|
|
357
|
-
spinner.succeed(`Found ${alarms.length} alarm(s)`)
|
|
358
|
-
|
|
359
|
-
if (alarms.length === 0) {
|
|
360
|
-
cli.info('No CloudWatch alarms configured')
|
|
361
|
-
return
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
const alarming = alarms.filter((a: any) => a.StateValue === 'ALARM')
|
|
365
|
-
const ok = alarms.filter((a: any) => a.StateValue === 'OK')
|
|
366
|
-
const insufficient = alarms.filter((a: any) => a.StateValue === 'INSUFFICIENT_DATA')
|
|
367
|
-
|
|
368
|
-
cli.info('')
|
|
369
|
-
cli.info(`Alarming: ${alarming.length}`)
|
|
370
|
-
cli.info(`OK: ${ok.length}`)
|
|
371
|
-
cli.info(`Insufficient Data: ${insufficient.length}`)
|
|
372
|
-
|
|
373
|
-
if (alarming.length > 0) {
|
|
374
|
-
cli.info('\nAlarms in ALARM state:')
|
|
375
|
-
for (const alarm of alarming) {
|
|
376
|
-
cli.error(` - ${alarm.AlarmName}: ${alarm.AlarmDescription || 'No description'}`)
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
catch (error: any) {
|
|
381
|
-
cli.error(`Failed to get alarms: ${error.message}`)
|
|
382
|
-
process.exit(1)
|
|
383
|
-
}
|
|
384
|
-
})
|
|
385
|
-
}
|