@aws/ml-container-creator 0.9.0 → 0.10.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.
Files changed (48) hide show
  1. package/bin/cli.js +31 -137
  2. package/config/parameter-schema-v2.json +2065 -0
  3. package/package.json +6 -3
  4. package/servers/lib/catalogs/jumpstart-public.json +101 -16
  5. package/servers/lib/catalogs/models.json +182 -26
  6. package/src/app.js +6 -389
  7. package/src/lib/bootstrap-command-handler.js +75 -1078
  8. package/src/lib/bootstrap-profile-manager.js +634 -0
  9. package/src/lib/bootstrap-provisioners.js +421 -0
  10. package/src/lib/config-loader.js +405 -0
  11. package/src/lib/config-manager.js +59 -1668
  12. package/src/lib/config-mcp-client.js +118 -0
  13. package/src/lib/config-validator.js +634 -0
  14. package/src/lib/cuda-resolver.js +140 -0
  15. package/src/lib/e2e-catalog-validator.js +251 -3
  16. package/src/lib/e2e-ci-recorder.js +103 -0
  17. package/src/lib/generated/cli-options.js +471 -0
  18. package/src/lib/generated/parameter-matrix.js +671 -0
  19. package/src/lib/generated/validation-rules.js +202 -0
  20. package/src/lib/marketplace-flow.js +276 -0
  21. package/src/lib/mcp-query-runner.js +768 -0
  22. package/src/lib/parameter-schema-validator.js +62 -18
  23. package/src/lib/prompt-runner.js +41 -1504
  24. package/src/lib/prompts/feature-prompts.js +172 -0
  25. package/src/lib/prompts/index.js +48 -0
  26. package/src/lib/prompts/infrastructure-prompts.js +690 -0
  27. package/src/lib/prompts/model-prompts.js +552 -0
  28. package/src/lib/prompts/project-prompts.js +70 -0
  29. package/src/lib/prompts.js +2 -1446
  30. package/src/lib/registry-command-handler.js +135 -3
  31. package/src/lib/secrets-prompt-runner.js +251 -0
  32. package/src/lib/template-variable-resolver.js +398 -0
  33. package/templates/code/serve +5 -134
  34. package/templates/code/serve.d/lmi.ejs +19 -0
  35. package/templates/code/serve.d/sglang.ejs +47 -0
  36. package/templates/code/serve.d/tensorrt-llm.ejs +53 -0
  37. package/templates/code/serve.d/vllm.ejs +48 -0
  38. package/templates/do/clean +1 -1387
  39. package/templates/do/clean.d/async-inference.ejs +508 -0
  40. package/templates/do/clean.d/batch-transform.ejs +512 -0
  41. package/templates/do/clean.d/hyperpod-eks.ejs +481 -0
  42. package/templates/do/clean.d/managed-inference.ejs +1043 -0
  43. package/templates/do/deploy +1 -1766
  44. package/templates/do/deploy.d/async-inference.ejs +501 -0
  45. package/templates/do/deploy.d/batch-transform.ejs +529 -0
  46. package/templates/do/deploy.d/hyperpod-eks.ejs +339 -0
  47. package/templates/do/deploy.d/managed-inference.ejs +726 -0
  48. package/config/parameter-schema.json +0 -88
@@ -0,0 +1,512 @@
1
+ #!/bin/bash
2
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ set -e
6
+ set -u
7
+ set -o pipefail
8
+
9
+ # Source configuration
10
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
+ source "${SCRIPT_DIR}/config"
12
+
13
+ # Parse arguments
14
+ CLEANUP_TARGET=""
15
+ CLEANUP_ARG=""
16
+ FORCE_CLEAN=false
17
+
18
+ for arg in "$@"; do
19
+ case "$arg" in
20
+ --force) FORCE_CLEAN=true ;;
21
+ -*) ;; # ignore other flags
22
+ *)
23
+ if [ -z "${CLEANUP_TARGET}" ]; then
24
+ CLEANUP_TARGET="$arg"
25
+ elif [ -z "${CLEANUP_ARG}" ]; then
26
+ CLEANUP_ARG="$arg"
27
+ fi
28
+ ;;
29
+ esac
30
+ done
31
+
32
+ # Function to display usage
33
+ show_usage() {
34
+ echo "Usage: ./do/clean [local|ecr|batch|codebuild|all]"
35
+ echo ""
36
+ echo "Cleanup targets:"
37
+ echo " local - Remove local Docker images"
38
+ echo " ecr - Remove images from Amazon ECR"
39
+ echo " batch - Stop running transform job and delete SageMaker model"
40
+ echo " codebuild - Delete CodeBuild project, IAM role, and S3 source artifacts"
41
+ echo " all - Perform all cleanup operations"
42
+ echo ""
43
+ echo "Examples:"
44
+ echo " ./do/clean local # Remove local Docker images only"
45
+ echo " ./do/clean batch # Stop transform job and delete model"
46
+ echo " ./do/clean codebuild # Delete CodeBuild project and rebuild fresh"
47
+ echo " ./do/clean all # Clean up everything"
48
+ }
49
+
50
+ # Function to confirm action (skipped when --force is set)
51
+ confirm_action() {
52
+ local message="$1"
53
+ if [ "${FORCE_CLEAN}" = true ]; then
54
+ return 0
55
+ fi
56
+ echo ""
57
+ echo "⚠️ ${message}"
58
+ read -p " Are you sure? (yes/no): " -r
59
+ echo ""
60
+ if [[ ! $REPLY =~ ^[Yy][Ee][Ss]$ ]]; then
61
+ echo "❌ Operation cancelled"
62
+ return 1
63
+ fi
64
+ return 0
65
+ }
66
+
67
+ # Function to clean local Docker images
68
+ clean_local() {
69
+ echo "🧹 Cleaning local Docker images"
70
+ echo " Project: ${PROJECT_NAME}"
71
+
72
+ LOCAL_PATTERN="^${PROJECT_NAME}:"
73
+ ECR_PATTERN="\.dkr\.ecr\..*\.amazonaws\.com/${ECR_REPOSITORY_NAME}:${PROJECT_NAME}-"
74
+
75
+ if ! docker images --format "{{.Repository}}:{{.Tag}}" | grep -qE "${LOCAL_PATTERN}|${ECR_PATTERN}"; then
76
+ echo "ℹ️ No local images found for ${PROJECT_NAME}"
77
+ return 0
78
+ fi
79
+
80
+ echo ""
81
+ echo "Images to be removed:"
82
+ docker images --format "{{.Repository}}:{{.Tag}}" | grep -E "${LOCAL_PATTERN}|${ECR_PATTERN}" | while read -r image; do
83
+ echo " ${image}"
84
+ done
85
+
86
+ if ! confirm_action "This will remove all local Docker images for ${PROJECT_NAME}"; then
87
+ return 1
88
+ fi
89
+
90
+ echo "🗑️ Removing local images..."
91
+ docker images --format "{{.Repository}}:{{.Tag}}" | grep -E "${LOCAL_PATTERN}|${ECR_PATTERN}" | while read -r image; do
92
+ echo " Removing: ${image}"
93
+ docker rmi "${image}" || echo " ⚠️ Failed to remove ${image}"
94
+ done
95
+
96
+ echo "✅ Local images cleaned"
97
+ }
98
+
99
+ # Function to clean ECR images
100
+ clean_ecr() {
101
+ echo "🧹 Cleaning ECR images"
102
+ echo " Repository: ${ECR_REPOSITORY_NAME}"
103
+ echo " Region: ${AWS_REGION}"
104
+
105
+ if ! aws sts get-caller-identity &> /dev/null; then
106
+ echo "❌ AWS credentials not configured"
107
+ echo " Run: aws configure"
108
+ exit 4
109
+ fi
110
+
111
+ AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
112
+
113
+ if ! aws ecr describe-repositories \
114
+ --repository-names "${ECR_REPOSITORY_NAME}" \
115
+ --region "${AWS_REGION}" &> /dev/null; then
116
+ echo "ℹ️ ECR repository ${ECR_REPOSITORY_NAME} does not exist"
117
+ return 0
118
+ fi
119
+
120
+ echo ""
121
+ echo "Checking for images in repository..."
122
+
123
+ if ! IMAGE_IDS=$(aws ecr list-images \
124
+ --repository-name "${ECR_REPOSITORY_NAME}" \
125
+ --region "${AWS_REGION}" \
126
+ --query "imageIds[?starts_with(imageTag, '${PROJECT_NAME}-')].[imageTag]" \
127
+ --output text 2>&1); then
128
+ echo "ℹ️ No images found for project: ${PROJECT_NAME}"
129
+ return 0
130
+ fi
131
+
132
+ if [ -z "${IMAGE_IDS}" ] || [ "${IMAGE_IDS}" = "None" ]; then
133
+ echo "ℹ️ No images found for project: ${PROJECT_NAME}"
134
+ return 0
135
+ fi
136
+
137
+ echo "Images for project ${PROJECT_NAME}:"
138
+ echo "${IMAGE_IDS}" | while read -r tag; do
139
+ if [ -n "${tag}" ] && [ "${tag}" != "None" ]; then
140
+ echo " - ${tag}"
141
+ fi
142
+ done
143
+
144
+ if ! confirm_action "This will remove all images from ECR repository ${ECR_REPOSITORY_NAME}"; then
145
+ return 1
146
+ fi
147
+
148
+ echo "🗑️ Removing ECR images..."
149
+
150
+ IMAGE_IDS_JSON=$(aws ecr list-images \
151
+ --repository-name "${ECR_REPOSITORY_NAME}" \
152
+ --region "${AWS_REGION}" \
153
+ --query "imageIds[?starts_with(imageTag, '${PROJECT_NAME}-')]" \
154
+ --output json)
155
+
156
+ if [ "${IMAGE_IDS_JSON}" != "[]" ] && [ -n "${IMAGE_IDS_JSON}" ]; then
157
+ if aws ecr batch-delete-image \
158
+ --repository-name "${ECR_REPOSITORY_NAME}" \
159
+ --region "${AWS_REGION}" \
160
+ --image-ids "${IMAGE_IDS_JSON}" &> /dev/null; then
161
+ echo "✅ ECR images removed for project: ${PROJECT_NAME}"
162
+ else
163
+ echo "❌ Failed to remove some ECR images"
164
+ return 1
165
+ fi
166
+ else
167
+ echo "ℹ️ No images to remove for project: ${PROJECT_NAME}"
168
+ fi
169
+ }
170
+
171
+ # Function to clean SageMaker managed inference batch resources
172
+ clean_batch() {
173
+ echo "🧹 Cleaning SageMaker managed inference batch resources"
174
+ echo " Project: ${PROJECT_NAME}"
175
+ echo " Region: ${AWS_REGION}"
176
+
177
+ if ! aws sts get-caller-identity &> /dev/null; then
178
+ echo "❌ AWS credentials not configured"
179
+ echo " Run: aws configure"
180
+ exit 4
181
+ fi
182
+
183
+ local TJ_NAME="${TRANSFORM_JOB_NAME:-}"
184
+ local SM_MODEL_NAME="${SAGEMAKER_MODEL_NAME:-}"
185
+
186
+ if [ -z "${TJ_NAME}" ] && [ -z "${SM_MODEL_NAME}" ]; then
187
+ echo "❌ No transform job or model name found"
188
+ echo " Run ./do/deploy first, or set TRANSFORM_JOB_NAME in do/config"
189
+ return 1
190
+ fi
191
+
192
+ echo ""
193
+ echo "Checking for SageMaker resources..."
194
+
195
+ local JOB_EXISTS=false
196
+ local JOB_STATUS=""
197
+ if [ -n "${TJ_NAME}" ]; then
198
+ JOB_STATUS=$(aws sagemaker describe-transform-job \
199
+ --transform-job-name "${TJ_NAME}" \
200
+ --region "${AWS_REGION}" \
201
+ --query 'TransformJobStatus' \
202
+ --output text 2>/dev/null || echo "")
203
+ if [ -n "${JOB_STATUS}" ]; then
204
+ JOB_EXISTS=true
205
+ echo " ✓ Transform job: ${TJ_NAME} (${JOB_STATUS})"
206
+ else
207
+ echo "ℹ️ Transform job not found: ${TJ_NAME}"
208
+ fi
209
+ fi
210
+
211
+ local MODEL_EXISTS=false
212
+ if [ -n "${SM_MODEL_NAME}" ]; then
213
+ if aws sagemaker describe-model \
214
+ --model-name "${SM_MODEL_NAME}" \
215
+ --region "${AWS_REGION}" &> /dev/null; then
216
+ MODEL_EXISTS=true
217
+ echo " ✓ SageMaker model: ${SM_MODEL_NAME}"
218
+ else
219
+ echo "ℹ️ SageMaker model not found: ${SM_MODEL_NAME}"
220
+ fi
221
+ fi
222
+
223
+ if [ "${JOB_EXISTS}" = false ] && [ "${MODEL_EXISTS}" = false ]; then
224
+ echo "ℹ️ No batch transform resources found to clean"
225
+ return 0
226
+ fi
227
+
228
+ if ! confirm_action "This will stop the transform job (if running) and delete the SageMaker model"; then
229
+ return 1
230
+ fi
231
+
232
+ # Stop transform job if in progress
233
+ if [ "${JOB_EXISTS}" = true ] && [ "${JOB_STATUS}" = "InProgress" ]; then
234
+ echo "🗑️ Stopping transform job: ${TJ_NAME}"
235
+ if aws sagemaker stop-transform-job \
236
+ --transform-job-name "${TJ_NAME}" \
237
+ --region "${AWS_REGION}" &> /dev/null; then
238
+ echo "⏳ Waiting for transform job to stop..."
239
+ aws sagemaker wait transform-job-completed-or-stopped \
240
+ --transform-job-name "${TJ_NAME}" \
241
+ --region "${AWS_REGION}" 2>/dev/null || sleep 15
242
+ echo "✅ Transform job stopped"
243
+
244
+ AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
245
+ ./do/manifest delete --id "arn:aws:sagemaker:${AWS_REGION}:${AWS_ACCOUNT_ID}:transform-job/${TJ_NAME}" 2>/dev/null || true
246
+ else
247
+ echo "❌ Failed to stop transform job"
248
+ fi
249
+ fi
250
+
251
+ # Delete SageMaker model
252
+ if [ "${MODEL_EXISTS}" = true ]; then
253
+ echo "🗑️ Deleting SageMaker model: ${SM_MODEL_NAME}"
254
+ if aws sagemaker delete-model \
255
+ --model-name "${SM_MODEL_NAME}" \
256
+ --region "${AWS_REGION}" &> /dev/null; then
257
+ echo "✅ SageMaker model deleted"
258
+ else
259
+ echo "❌ Failed to delete SageMaker model"
260
+ fi
261
+ fi
262
+
263
+ # Remove saved names from config
264
+ if grep -q "^export TRANSFORM_JOB_NAME=" "${SCRIPT_DIR}/config" 2>/dev/null; then
265
+ sed -i.bak '/^# Last deployed resources/d;/^export TRANSFORM_JOB_NAME=/d;/^export SAGEMAKER_MODEL_NAME=/d' "${SCRIPT_DIR}/config"
266
+ rm -f "${SCRIPT_DIR}/config.bak"
267
+ fi
268
+
269
+ echo "✅ SageMaker managed inference batch resources cleaned"
270
+ }
271
+
272
+ # Function to clean CodeBuild project and related resources
273
+ clean_codebuild() {
274
+ echo "🧹 Cleaning CodeBuild resources"
275
+ echo " Project: ${CODEBUILD_PROJECT_NAME:-not set}"
276
+ echo " Region: ${AWS_REGION}"
277
+
278
+ if [ -z "${CODEBUILD_PROJECT_NAME:-}" ]; then
279
+ echo "ℹ️ No CodeBuild project name configured (build target may not be codebuild)"
280
+ return 0
281
+ fi
282
+
283
+ if ! aws sts get-caller-identity &> /dev/null; then
284
+ echo "❌ AWS credentials not configured"
285
+ echo " Run: aws configure"
286
+ exit 4
287
+ fi
288
+
289
+ AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
290
+
291
+ PROJECT_CHECK=$(aws codebuild batch-get-projects \
292
+ --names "${CODEBUILD_PROJECT_NAME}" \
293
+ --region "${AWS_REGION}" \
294
+ --query 'projects[0].name' \
295
+ --output text 2>/dev/null)
296
+
297
+ if [ "$PROJECT_CHECK" = "None" ] || [ -z "$PROJECT_CHECK" ] || [ "$PROJECT_CHECK" = "null" ]; then
298
+ echo "ℹ️ CodeBuild project not found: ${CODEBUILD_PROJECT_NAME}"
299
+ return 0
300
+ fi
301
+
302
+ echo ""
303
+ echo "Resources to be removed:"
304
+ echo " • CodeBuild project: ${CODEBUILD_PROJECT_NAME}"
305
+
306
+ ROLE_NAME="${CODEBUILD_PROJECT_NAME}-service-role"
307
+ ROLE_EXISTS=false
308
+ if aws iam get-role --role-name "${ROLE_NAME}" &> /dev/null; then
309
+ ROLE_EXISTS=true
310
+ echo " • IAM service role: ${ROLE_NAME}"
311
+ fi
312
+
313
+ S3_BUCKET="codebuild-source-${AWS_ACCOUNT_ID}-${AWS_REGION}"
314
+ S3_PREFIX="${PROJECT_NAME}/"
315
+ S3_EXISTS=false
316
+ if aws s3api head-bucket --bucket "$S3_BUCKET" --region "${AWS_REGION}" &> /dev/null; then
317
+ S3_COUNT=$(aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX" --region "${AWS_REGION}" 2>/dev/null | wc -l | tr -d ' ')
318
+ if [ "$S3_COUNT" -gt 0 ]; then
319
+ S3_EXISTS=true
320
+ echo " • S3 source artifacts: s3://$S3_BUCKET/$S3_PREFIX ($S3_COUNT objects)"
321
+ fi
322
+ fi
323
+
324
+ if ! confirm_action "This will delete the CodeBuild project and associated resources"; then
325
+ return 1
326
+ fi
327
+
328
+ echo "🗑️ Deleting CodeBuild project: ${CODEBUILD_PROJECT_NAME}"
329
+ if aws codebuild delete-project \
330
+ --name "${CODEBUILD_PROJECT_NAME}" \
331
+ --region "${AWS_REGION}" &> /dev/null; then
332
+ echo "✅ CodeBuild project deleted"
333
+
334
+ ./do/manifest delete --id "arn:aws:codebuild:${AWS_REGION}:${AWS_ACCOUNT_ID}:project/${CODEBUILD_PROJECT_NAME}" 2>/dev/null || true
335
+ else
336
+ echo "❌ Failed to delete CodeBuild project"
337
+ fi
338
+
339
+ if [ "$ROLE_EXISTS" = true ]; then
340
+ echo "🗑️ Deleting IAM service role: ${ROLE_NAME}"
341
+ POLICIES=$(aws iam list-role-policies --role-name "${ROLE_NAME}" --query 'PolicyNames' --output text 2>/dev/null || echo "")
342
+ for policy in $POLICIES; do
343
+ aws iam delete-role-policy --role-name "${ROLE_NAME}" --policy-name "$policy" 2>/dev/null || true
344
+ done
345
+ if aws iam delete-role --role-name "${ROLE_NAME}" &> /dev/null; then
346
+ echo "✅ IAM service role deleted"
347
+
348
+ ./do/manifest delete --id "arn:aws:iam::${AWS_ACCOUNT_ID}:role/${ROLE_NAME}" 2>/dev/null || true
349
+ else
350
+ echo "❌ Failed to delete IAM service role"
351
+ fi
352
+ fi
353
+
354
+ if [ "$S3_EXISTS" = true ]; then
355
+ echo "🗑️ Deleting S3 source artifacts: s3://$S3_BUCKET/$S3_PREFIX"
356
+ if aws s3 rm "s3://$S3_BUCKET/$S3_PREFIX" --recursive --region "${AWS_REGION}" &> /dev/null; then
357
+ echo "✅ S3 source artifacts deleted"
358
+ else
359
+ echo "❌ Failed to delete S3 source artifacts"
360
+ fi
361
+ fi
362
+
363
+ echo "✅ CodeBuild resources cleaned"
364
+ }
365
+
366
+ # Main script logic
367
+ echo "🧹 Cleanup script for ${PROJECT_NAME}"
368
+ echo ""
369
+
370
+ if [ -z "${CLEANUP_TARGET}" ]; then
371
+ CLEANUP_TARGET="batch"
372
+ fi
373
+
374
+ case "${CLEANUP_TARGET}" in
375
+ local)
376
+ clean_local
377
+ ;;
378
+ ecr)
379
+ clean_ecr
380
+ ;;
381
+ batch)
382
+ clean_batch
383
+ ;;
384
+ codebuild)
385
+ clean_codebuild
386
+ ;;
387
+ <% if (typeof includeBenchmark !== 'undefined' && includeBenchmark) { %>
388
+ benchmark)
389
+ echo "🧹 Cleaning benchmark resources..."
390
+ WORKLOAD_CONFIG_NAME="${PROJECT_NAME}-benchmark-config"
391
+
392
+ if aws sagemaker describe-ai-workload-config \
393
+ --ai-workload-config-name "$WORKLOAD_CONFIG_NAME" \
394
+ --region "$AWS_REGION" 2>/dev/null; then
395
+ aws sagemaker delete-ai-workload-config \
396
+ --ai-workload-config-name "$WORKLOAD_CONFIG_NAME" \
397
+ --region "$AWS_REGION"
398
+ echo " ✓ Deleted workload config: $WORKLOAD_CONFIG_NAME"
399
+ fi
400
+
401
+ aws sagemaker list-ai-benchmark-jobs \
402
+ --name-contains "${PROJECT_NAME}-benchmark-" \
403
+ --region "$AWS_REGION" \
404
+ --query 'AIBenchmarkJobs[?AIBenchmarkJobStatus!=`InProgress`].AIBenchmarkJobName' \
405
+ --output text | tr '\t' '\n' | while read -r job; do
406
+ [ -z "$job" ] && continue
407
+ aws sagemaker delete-ai-benchmark-job \
408
+ --ai-benchmark-job-name "$job" \
409
+ --region "$AWS_REGION"
410
+ echo " ✓ Deleted benchmark job: $job"
411
+ done
412
+
413
+ if [ -d "${SCRIPT_DIR}/../benchmarks" ]; then
414
+ read -p "Delete local benchmark results? (Y/n) " CONFIRM_DELETE
415
+ CONFIRM_DELETE="${CONFIRM_DELETE:-Y}"
416
+ if [[ "${CONFIRM_DELETE}" =~ ^[Yy]$ ]]; then
417
+ rm -rf "${SCRIPT_DIR}/../benchmarks"
418
+ echo " ✓ Deleted local benchmarks/ directory"
419
+ else
420
+ echo " ⏭ Skipped local benchmarks/ deletion"
421
+ fi
422
+ fi
423
+
424
+ echo "✅ Benchmark cleanup complete"
425
+ ;;
426
+ <% } %>
427
+ all)
428
+ echo "🧹 Performing complete cleanup"
429
+ echo ""
430
+
431
+ CLEANED_ITEMS=()
432
+
433
+ if clean_local; then
434
+ CLEANED_ITEMS+=("Local Docker images")
435
+ fi
436
+
437
+ echo ""
438
+
439
+ if clean_ecr; then
440
+ CLEANED_ITEMS+=("ECR images")
441
+ fi
442
+
443
+ echo ""
444
+
445
+ # Clean SageMaker managed inference batch resources
446
+ if clean_batch; then
447
+ CLEANED_ITEMS+=("SageMaker managed inference batch resources")
448
+ fi
449
+
450
+ echo ""
451
+
452
+ if clean_codebuild; then
453
+ CLEANED_ITEMS+=("CodeBuild resources")
454
+ fi
455
+
456
+ <% if (typeof includeBenchmark !== 'undefined' && includeBenchmark) { %>
457
+ echo ""
458
+
459
+ WORKLOAD_CONFIG_NAME="${PROJECT_NAME}-benchmark-config"
460
+
461
+ if aws sagemaker describe-ai-workload-config \
462
+ --ai-workload-config-name "$WORKLOAD_CONFIG_NAME" \
463
+ --region "$AWS_REGION" 2>/dev/null; then
464
+ aws sagemaker delete-ai-workload-config \
465
+ --ai-workload-config-name "$WORKLOAD_CONFIG_NAME" \
466
+ --region "$AWS_REGION"
467
+ echo " ✓ Deleted workload config: $WORKLOAD_CONFIG_NAME"
468
+ fi
469
+
470
+ aws sagemaker list-ai-benchmark-jobs \
471
+ --name-contains "${PROJECT_NAME}-benchmark-" \
472
+ --region "$AWS_REGION" \
473
+ --query 'AIBenchmarkJobs[?AIBenchmarkJobStatus!=`InProgress`].AIBenchmarkJobName' \
474
+ --output text | tr '\t' '\n' | while read -r job; do
475
+ [ -z "$job" ] && continue
476
+ aws sagemaker delete-ai-benchmark-job \
477
+ --ai-benchmark-job-name "$job" \
478
+ --region "$AWS_REGION"
479
+ echo " ✓ Deleted benchmark job: $job"
480
+ done
481
+
482
+ if [ -d "${SCRIPT_DIR}/../benchmarks" ]; then
483
+ read -p "Delete local benchmark results? (Y/n) " CONFIRM_DELETE
484
+ CONFIRM_DELETE="${CONFIRM_DELETE:-Y}"
485
+ if [[ "${CONFIRM_DELETE}" =~ ^[Yy]$ ]]; then
486
+ rm -rf "${SCRIPT_DIR}/../benchmarks"
487
+ echo " ✓ Deleted local benchmarks/ directory"
488
+ else
489
+ echo " ⏭ Skipped local benchmarks/ deletion"
490
+ fi
491
+ fi
492
+
493
+ CLEANED_ITEMS+=("Benchmark resources")
494
+ <% } %>
495
+ echo ""
496
+ echo "✅ Cleanup complete!"
497
+ echo ""
498
+ echo "Summary of cleaned resources:"
499
+ for item in "${CLEANED_ITEMS[@]}"; do
500
+ echo " ✓ ${item}"
501
+ done
502
+ ;;
503
+ *)
504
+ echo "❌ Unknown cleanup target: ${CLEANUP_TARGET}"
505
+ echo ""
506
+ show_usage
507
+ exit 1
508
+ ;;
509
+ esac
510
+
511
+ echo ""
512
+ echo "Cleanup finished!"