@aws/ml-container-creator 0.2.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 (143) hide show
  1. package/LICENSE +202 -0
  2. package/LICENSE-THIRD-PARTY +68620 -0
  3. package/NOTICE +2 -0
  4. package/README.md +106 -0
  5. package/bin/cli.js +365 -0
  6. package/config/defaults.json +32 -0
  7. package/config/presets/transformers-djl.json +26 -0
  8. package/config/presets/transformers-gpu.json +24 -0
  9. package/config/presets/transformers-lmi.json +27 -0
  10. package/package.json +129 -0
  11. package/servers/README.md +419 -0
  12. package/servers/base-image-picker/catalogs/model-servers.json +1191 -0
  13. package/servers/base-image-picker/catalogs/python-slim.json +38 -0
  14. package/servers/base-image-picker/catalogs/triton-backends.json +51 -0
  15. package/servers/base-image-picker/catalogs/triton.json +38 -0
  16. package/servers/base-image-picker/index.js +495 -0
  17. package/servers/base-image-picker/manifest.json +17 -0
  18. package/servers/base-image-picker/package.json +15 -0
  19. package/servers/hyperpod-cluster-picker/LICENSE +202 -0
  20. package/servers/hyperpod-cluster-picker/index.js +424 -0
  21. package/servers/hyperpod-cluster-picker/manifest.json +14 -0
  22. package/servers/hyperpod-cluster-picker/package.json +17 -0
  23. package/servers/instance-recommender/LICENSE +202 -0
  24. package/servers/instance-recommender/catalogs/instances.json +852 -0
  25. package/servers/instance-recommender/index.js +284 -0
  26. package/servers/instance-recommender/manifest.json +16 -0
  27. package/servers/instance-recommender/package.json +15 -0
  28. package/servers/lib/LICENSE +202 -0
  29. package/servers/lib/bedrock-client.js +160 -0
  30. package/servers/lib/custom-validators.js +46 -0
  31. package/servers/lib/dynamic-resolver.js +36 -0
  32. package/servers/lib/package.json +11 -0
  33. package/servers/lib/schemas/image-catalog.schema.json +185 -0
  34. package/servers/lib/schemas/instances.schema.json +124 -0
  35. package/servers/lib/schemas/manifest.schema.json +64 -0
  36. package/servers/lib/schemas/model-catalog.schema.json +91 -0
  37. package/servers/lib/schemas/regions.schema.json +26 -0
  38. package/servers/lib/schemas/triton-backends.schema.json +51 -0
  39. package/servers/model-picker/catalogs/jumpstart-public.json +66 -0
  40. package/servers/model-picker/catalogs/popular-diffusors.json +88 -0
  41. package/servers/model-picker/catalogs/popular-transformers.json +226 -0
  42. package/servers/model-picker/index.js +1693 -0
  43. package/servers/model-picker/manifest.json +18 -0
  44. package/servers/model-picker/package.json +20 -0
  45. package/servers/region-picker/LICENSE +202 -0
  46. package/servers/region-picker/catalogs/regions.json +263 -0
  47. package/servers/region-picker/index.js +230 -0
  48. package/servers/region-picker/manifest.json +16 -0
  49. package/servers/region-picker/package.json +15 -0
  50. package/src/app.js +1007 -0
  51. package/src/copy-tpl.js +77 -0
  52. package/src/lib/accelerator-validator.js +39 -0
  53. package/src/lib/asset-manager.js +385 -0
  54. package/src/lib/aws-profile-parser.js +181 -0
  55. package/src/lib/bootstrap-command-handler.js +1647 -0
  56. package/src/lib/bootstrap-config.js +238 -0
  57. package/src/lib/ci-register-helpers.js +124 -0
  58. package/src/lib/ci-report-helpers.js +158 -0
  59. package/src/lib/ci-stage-helpers.js +268 -0
  60. package/src/lib/cli-handler.js +529 -0
  61. package/src/lib/comment-generator.js +544 -0
  62. package/src/lib/community-reports-validator.js +91 -0
  63. package/src/lib/config-manager.js +2106 -0
  64. package/src/lib/configuration-exporter.js +204 -0
  65. package/src/lib/configuration-manager.js +695 -0
  66. package/src/lib/configuration-matcher.js +221 -0
  67. package/src/lib/cpu-validator.js +36 -0
  68. package/src/lib/cuda-validator.js +57 -0
  69. package/src/lib/deployment-config-resolver.js +103 -0
  70. package/src/lib/deployment-entry-schema.js +125 -0
  71. package/src/lib/deployment-registry.js +598 -0
  72. package/src/lib/docker-introspection-validator.js +51 -0
  73. package/src/lib/engine-prefix-resolver.js +60 -0
  74. package/src/lib/huggingface-client.js +172 -0
  75. package/src/lib/key-value-parser.js +37 -0
  76. package/src/lib/known-flags-validator.js +200 -0
  77. package/src/lib/manifest-cli.js +280 -0
  78. package/src/lib/mcp-client.js +303 -0
  79. package/src/lib/mcp-command-handler.js +532 -0
  80. package/src/lib/neuron-validator.js +80 -0
  81. package/src/lib/parameter-schema-validator.js +284 -0
  82. package/src/lib/prompt-runner.js +1349 -0
  83. package/src/lib/prompts.js +1138 -0
  84. package/src/lib/registry-command-handler.js +519 -0
  85. package/src/lib/registry-loader.js +198 -0
  86. package/src/lib/rocm-validator.js +80 -0
  87. package/src/lib/schema-validator.js +157 -0
  88. package/src/lib/sensitive-redactor.js +59 -0
  89. package/src/lib/template-engine.js +156 -0
  90. package/src/lib/template-manager.js +341 -0
  91. package/src/lib/validation-engine.js +314 -0
  92. package/src/prompt-adapter.js +63 -0
  93. package/templates/Dockerfile +300 -0
  94. package/templates/IAM_PERMISSIONS.md +84 -0
  95. package/templates/MIGRATION.md +488 -0
  96. package/templates/PROJECT_README.md +439 -0
  97. package/templates/TEMPLATE_SYSTEM.md +243 -0
  98. package/templates/buildspec.yml +64 -0
  99. package/templates/code/chat_template.jinja +1 -0
  100. package/templates/code/flask/gunicorn_config.py +35 -0
  101. package/templates/code/flask/wsgi.py +10 -0
  102. package/templates/code/model_handler.py +387 -0
  103. package/templates/code/serve +300 -0
  104. package/templates/code/serve.py +175 -0
  105. package/templates/code/serving.properties +105 -0
  106. package/templates/code/start_server.py +39 -0
  107. package/templates/code/start_server.sh +39 -0
  108. package/templates/diffusors/Dockerfile +72 -0
  109. package/templates/diffusors/patch_image_api.py +35 -0
  110. package/templates/diffusors/serve +115 -0
  111. package/templates/diffusors/start_server.sh +114 -0
  112. package/templates/do/.gitkeep +1 -0
  113. package/templates/do/README.md +541 -0
  114. package/templates/do/build +83 -0
  115. package/templates/do/ci +681 -0
  116. package/templates/do/clean +811 -0
  117. package/templates/do/config +260 -0
  118. package/templates/do/deploy +1560 -0
  119. package/templates/do/export +306 -0
  120. package/templates/do/logs +319 -0
  121. package/templates/do/manifest +12 -0
  122. package/templates/do/push +119 -0
  123. package/templates/do/register +580 -0
  124. package/templates/do/run +113 -0
  125. package/templates/do/submit +417 -0
  126. package/templates/do/test +1147 -0
  127. package/templates/hyperpod/configmap.yaml +24 -0
  128. package/templates/hyperpod/deployment.yaml +71 -0
  129. package/templates/hyperpod/pvc.yaml +42 -0
  130. package/templates/hyperpod/service.yaml +17 -0
  131. package/templates/nginx-diffusors.conf +74 -0
  132. package/templates/nginx-predictors.conf +47 -0
  133. package/templates/nginx-tensorrt.conf +74 -0
  134. package/templates/requirements.txt +61 -0
  135. package/templates/sample_model/test_inference.py +123 -0
  136. package/templates/sample_model/train_abalone.py +252 -0
  137. package/templates/test/test_endpoint.sh +79 -0
  138. package/templates/test/test_local_image.sh +80 -0
  139. package/templates/test/test_model_handler.py +180 -0
  140. package/templates/triton/Dockerfile +128 -0
  141. package/templates/triton/config.pbtxt +163 -0
  142. package/templates/triton/model.py +130 -0
  143. package/templates/triton/requirements.txt +11 -0
@@ -0,0 +1,417 @@
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
+ echo "🚀 Submitting CodeBuild job for ${PROJECT_NAME}"
14
+ echo " Deployment config: ${DEPLOYMENT_CONFIG}"
15
+ echo " Region: ${AWS_REGION}"
16
+ echo " Compute type: ${CODEBUILD_COMPUTE_TYPE}"
17
+ echo " ECR repository: ${ECR_REPOSITORY_NAME}"
18
+
19
+ # Validate AWS credentials
20
+ echo "🔍 Validating AWS credentials..."
21
+ if ! aws sts get-caller-identity &> /dev/null; then
22
+ echo "❌ AWS credentials not configured"
23
+ echo " Run: aws configure"
24
+ echo " Or set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables"
25
+ exit 4
26
+ fi
27
+
28
+ # Get AWS account ID
29
+ AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
30
+ if [ -z "$AWS_ACCOUNT_ID" ]; then
31
+ echo "❌ Failed to get AWS account ID"
32
+ exit 4
33
+ fi
34
+
35
+ echo "✅ AWS credentials validated (Account: ${AWS_ACCOUNT_ID})"
36
+
37
+ # Create ECR repository if it doesn't exist
38
+ echo "📦 Checking ECR repository..."
39
+ if ! aws ecr describe-repositories --repository-names "${ECR_REPOSITORY_NAME}" --region "${AWS_REGION}" >/dev/null 2>&1; then
40
+ echo "📦 Creating shared ECR repository: ${ECR_REPOSITORY_NAME}"
41
+ aws ecr create-repository --repository-name "${ECR_REPOSITORY_NAME}" --region "${AWS_REGION}"
42
+ echo "✅ ECR repository created successfully"
43
+ echo "ℹ️ This repository will be shared by all ML container projects"
44
+ else
45
+ echo "✅ ECR repository already exists: ${ECR_REPOSITORY_NAME}"
46
+ fi
47
+
48
+ # Create CodeBuild service role if it doesn't exist
49
+ ROLE_NAME="${CODEBUILD_PROJECT_NAME}-service-role"
50
+ echo "🔐 Checking CodeBuild service role..."
51
+ if ! aws iam get-role --role-name "${ROLE_NAME}" >/dev/null 2>&1; then
52
+ echo "🔐 Creating CodeBuild service role: ${ROLE_NAME}"
53
+
54
+ # Create trust policy
55
+ cat > /tmp/codebuild-trust-policy.json << EOF
56
+ {
57
+ "Version": "2012-10-17",
58
+ "Statement": [
59
+ {
60
+ "Effect": "Allow",
61
+ "Principal": {
62
+ "Service": "codebuild.amazonaws.com"
63
+ },
64
+ "Action": "sts:AssumeRole"
65
+ }
66
+ ]
67
+ }
68
+ EOF
69
+
70
+ # Create the role
71
+ aws iam create-role \
72
+ --role-name "${ROLE_NAME}" \
73
+ --assume-role-policy-document file:///tmp/codebuild-trust-policy.json \
74
+ --description "Service role for CodeBuild project ${CODEBUILD_PROJECT_NAME}"
75
+
76
+ # Create and attach policy
77
+ cat > /tmp/codebuild-policy.json << EOF
78
+ {
79
+ "Version": "2012-10-17",
80
+ "Statement": [
81
+ {
82
+ "Effect": "Allow",
83
+ "Action": [
84
+ "logs:CreateLogGroup",
85
+ "logs:CreateLogStream",
86
+ "logs:PutLogEvents"
87
+ ],
88
+ "Resource": "arn:aws:logs:${AWS_REGION}:${AWS_ACCOUNT_ID}:log-group:/aws/codebuild/${CODEBUILD_PROJECT_NAME}*"
89
+ },
90
+ {
91
+ "Effect": "Allow",
92
+ "Action": [
93
+ "ecr:BatchCheckLayerAvailability",
94
+ "ecr:GetDownloadUrlForLayer",
95
+ "ecr:BatchGetImage",
96
+ "ecr:GetAuthorizationToken",
97
+ "ecr:PutImage",
98
+ "ecr:InitiateLayerUpload",
99
+ "ecr:UploadLayerPart",
100
+ "ecr:CompleteLayerUpload"
101
+ ],
102
+ "Resource": "*"
103
+ },
104
+ {
105
+ "Effect": "Allow",
106
+ "Action": [
107
+ "s3:GetObject",
108
+ "s3:GetObjectVersion"
109
+ ],
110
+ "Resource": [
111
+ "arn:aws:s3:::codebuild-source-${AWS_ACCOUNT_ID}-${AWS_REGION}/*"
112
+ ]
113
+ },
114
+ {
115
+ "Effect": "Allow",
116
+ "Action": [
117
+ "s3:ListBucket"
118
+ ],
119
+ "Resource": [
120
+ "arn:aws:s3:::codebuild-source-${AWS_ACCOUNT_ID}-${AWS_REGION}"
121
+ ]
122
+ }
123
+ ]
124
+ }
125
+ EOF
126
+
127
+ aws iam put-role-policy \
128
+ --role-name "${ROLE_NAME}" \
129
+ --policy-name CodeBuildServicePolicy \
130
+ --policy-document file:///tmp/codebuild-policy.json
131
+
132
+ # Clean up temporary files
133
+ rm -f /tmp/codebuild-trust-policy.json /tmp/codebuild-policy.json
134
+
135
+ echo "✅ CodeBuild service role created successfully"
136
+
137
+ # Record IAM role in manifest (non-blocking)
138
+ ROLE_ARN="arn:aws:iam::${AWS_ACCOUNT_ID}:role/${ROLE_NAME}"
139
+ ./do/manifest add \
140
+ --type iam-role \
141
+ --id "${ROLE_ARN}" \
142
+ --project "${PROJECT_NAME}" \
143
+ --meta "{\"roleName\":\"${ROLE_NAME}\",\"region\":\"${AWS_REGION}\"}" \
144
+ 2>/dev/null || true
145
+
146
+ # Wait for role to propagate
147
+ echo "⏳ Waiting for IAM role to propagate..."
148
+ sleep 10
149
+ else
150
+ echo "✅ CodeBuild service role already exists"
151
+ fi
152
+
153
+ # Create CodeBuild project if it doesn't exist
154
+ echo "🏗️ Checking CodeBuild project..."
155
+ PROJECT_EXISTS=$(aws codebuild batch-get-projects --names "${CODEBUILD_PROJECT_NAME}" --region "${AWS_REGION}" --query 'projects[0].name' --output text 2>/dev/null)
156
+ if [ "$PROJECT_EXISTS" = "None" ] || [ -z "$PROJECT_EXISTS" ] || [ "$PROJECT_EXISTS" = "null" ]; then
157
+ echo "🏗️ Creating CodeBuild project: ${CODEBUILD_PROJECT_NAME}"
158
+
159
+ # Create project configuration as JSON
160
+ cat > /tmp/codebuild-project.json << EOF
161
+ {
162
+ "name": "${CODEBUILD_PROJECT_NAME}",
163
+ "description": "Build project for ${PROJECT_NAME} ML container (${CODEBUILD_COMPUTE_TYPE})",
164
+ "source": {
165
+ "type": "NO_SOURCE",
166
+ "buildspec": "version: 0.2\n\nenv:\n variables:\n AWS_DEFAULT_REGION: ${AWS_REGION}\n AWS_ACCOUNT_ID: \"\"\n ECR_REPOSITORY_NAME: \"${ECR_REPOSITORY_NAME}\"\n PROJECT_NAME: \"${PROJECT_NAME}\"\n IMAGE_TAG: \"latest\"\n\nphases:\n pre_build:\n commands:\n - echo Logging in to Amazon ECR...\n - AWS_ACCOUNT_ID=\$(aws sts get-caller-identity --query Account --output text)\n - aws ecr get-login-password --region \$AWS_DEFAULT_REGION | docker login --username AWS --password-stdin \$AWS_ACCOUNT_ID.dkr.ecr.\$AWS_DEFAULT_REGION.amazonaws.com\n - echo Authenticating with AWS Deep Learning Container ECR...\n - aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 763104351884.dkr.ecr.us-east-1.amazonaws.com\n - REPOSITORY_URI=\$AWS_ACCOUNT_ID.dkr.ecr.\$AWS_DEFAULT_REGION.amazonaws.com/\$ECR_REPOSITORY_NAME\n - IMAGE_TAG=\${CODEBUILD_RESOLVED_SOURCE_VERSION:-latest}\n - PROJECT_TAG=\"\$PROJECT_NAME-\$(date +%Y%m%d-%H%M%S)\"\n - echo Repository URI is \$REPOSITORY_URI\n - echo Project tag is \$PROJECT_TAG\n - echo Image tag is \$IMAGE_TAG\n on-failure: ABORT\n build:\n commands:\n - echo Build started on \`date\`\n - echo Building the Docker image for project \$PROJECT_NAME...\n - docker build -t \$REPOSITORY_URI:\$PROJECT_TAG .\n - docker tag \$REPOSITORY_URI:\$PROJECT_TAG \$REPOSITORY_URI:\$PROJECT_NAME-latest\n - docker tag \$REPOSITORY_URI:\$PROJECT_TAG \$REPOSITORY_URI:latest\n - echo Build completed on \`date\`\n on-failure: ABORT\n post_build:\n commands:\n - echo Post-build started on \`date\`\n - echo Pushing the Docker images for project \$PROJECT_NAME...\n - docker push \$REPOSITORY_URI:\$PROJECT_TAG || (echo \"Failed to push project tag \$PROJECT_TAG\" && exit 1)\n - docker push \$REPOSITORY_URI:\$PROJECT_NAME-latest || (echo \"Failed to push project latest tag\" && exit 1)\n - docker push \$REPOSITORY_URI:latest || (echo \"Failed to push latest tag\" && exit 1)\n - echo Successfully pushed images to ECR repository \$ECR_REPOSITORY_NAME\n - echo \"Available tags:\"\n - echo \" - \$PROJECT_TAG (timestamped build)\"\n - echo \" - \$PROJECT_NAME-latest (project latest)\"\n - echo \" - latest (global latest)\"\n - echo Writing image definitions file...\n - printf '[{\"name\":\"%s\",\"imageUri\":\"%s\"}]' \$PROJECT_NAME \$REPOSITORY_URI:\$PROJECT_TAG > imagedefinitions.json\n - echo Post-build completed on \`date\`\n\nartifacts:\n files:\n - imagedefinitions.json\n name: ${PROJECT_NAME}-artifacts"
167
+ },
168
+ "artifacts": {
169
+ "type": "NO_ARTIFACTS"
170
+ },
171
+ "environment": {
172
+ "type": "LINUX_CONTAINER",
173
+ "image": "aws/codebuild/amazonlinux2-x86_64-standard:3.0",
174
+ "computeType": "${CODEBUILD_COMPUTE_TYPE}",
175
+ "privilegedMode": true
176
+ },
177
+ "serviceRole": "arn:aws:iam::${AWS_ACCOUNT_ID}:role/${ROLE_NAME}"
178
+ }
179
+ EOF
180
+
181
+ # Create project using JSON input
182
+ aws codebuild create-project \
183
+ --region "${AWS_REGION}" \
184
+ --cli-input-json file:///tmp/codebuild-project.json > /tmp/codebuild-create-output.json 2>&1
185
+
186
+ CREATE_EXIT_CODE=$?
187
+
188
+ if [ $CREATE_EXIT_CODE -eq 0 ]; then
189
+ echo "✅ CodeBuild project created successfully"
190
+ if [ -f /tmp/codebuild-create-output.json ]; then
191
+ PROJECT_ARN=$(cat /tmp/codebuild-create-output.json | jq -r '.project.arn // "N/A"' 2>/dev/null || echo "N/A")
192
+ echo " Project ARN: $PROJECT_ARN"
193
+ fi
194
+
195
+ # Wait for project to be available
196
+ echo "⏳ Waiting for CodeBuild project to be available..."
197
+ sleep 5
198
+
199
+ # Verify project was created
200
+ VERIFY_PROJECT=$(aws codebuild batch-get-projects --names "${CODEBUILD_PROJECT_NAME}" --region "${AWS_REGION}" --query 'projects[0].name' --output text 2>/dev/null)
201
+ if [ "$VERIFY_PROJECT" = "None" ] || [ -z "$VERIFY_PROJECT" ] || [ "$VERIFY_PROJECT" = "null" ]; then
202
+ echo "❌ Project creation verification failed"
203
+ echo " Create output:"
204
+ cat /tmp/codebuild-create-output.json 2>/dev/null || echo " No output file"
205
+ rm -f /tmp/codebuild-create-output.json /tmp/codebuild-project.json
206
+ exit 1
207
+ else
208
+ echo "✅ Project creation verified: $VERIFY_PROJECT"
209
+ fi
210
+
211
+ # Record CodeBuild project in manifest (non-blocking)
212
+ if [ "$PROJECT_ARN" != "N/A" ] && [ -n "$PROJECT_ARN" ]; then
213
+ ./do/manifest add \
214
+ --type codebuild-project \
215
+ --id "${PROJECT_ARN}" \
216
+ --project "${PROJECT_NAME}" \
217
+ --meta "{\"projectName\":\"${CODEBUILD_PROJECT_NAME}\",\"region\":\"${AWS_REGION}\"}" \
218
+ 2>/dev/null || true
219
+ fi
220
+ else
221
+ echo "❌ Failed to create CodeBuild project: ${CODEBUILD_PROJECT_NAME} (exit code: $CREATE_EXIT_CODE)"
222
+ echo " Error output:"
223
+ cat /tmp/codebuild-create-output.json 2>/dev/null || echo " No error output available"
224
+ echo ""
225
+ echo " Please check:"
226
+ echo " 1. IAM permissions for CodeBuild operations"
227
+ echo " 2. Service role ARN: arn:aws:iam::${AWS_ACCOUNT_ID}:role/${ROLE_NAME}"
228
+ echo " 3. AWS region: ${AWS_REGION}"
229
+ echo " 4. Project name format: ${CODEBUILD_PROJECT_NAME}"
230
+ echo " 5. Network connectivity to AWS services"
231
+ rm -f /tmp/codebuild-create-output.json /tmp/codebuild-project.json
232
+ exit 1
233
+ fi
234
+
235
+ # Clean up output files
236
+ rm -f /tmp/codebuild-create-output.json /tmp/codebuild-project.json
237
+ else
238
+ echo "✅ CodeBuild project already exists: $PROJECT_EXISTS"
239
+ fi
240
+
241
+ # Upload source code to S3
242
+ echo "📁 Uploading source code from current directory..."
243
+
244
+ # Create a temporary zip file with the current directory contents
245
+ TEMP_ZIP="/tmp/${PROJECT_NAME}-source.zip"
246
+ echo "📦 Creating source archive..."
247
+
248
+ # Create zip file excluding unnecessary files
249
+ zip -r "$TEMP_ZIP" . \
250
+ -x "*.git*" \
251
+ -x "*node_modules*" \
252
+ -x "*.DS_Store*" \
253
+ -x "*__pycache__*" \
254
+ -x "*.pyc" \
255
+ -x "*/.pytest_cache/*" \
256
+ -x "*/test/*" \
257
+ -x "*/tests/*" \
258
+ >/dev/null 2>&1
259
+
260
+ if [ ! -f "$TEMP_ZIP" ]; then
261
+ echo "❌ Failed to create source archive"
262
+ exit 1
263
+ fi
264
+
265
+ echo "✅ Source archive created: $(du -h "$TEMP_ZIP" | cut -f1)"
266
+
267
+ # Upload source to S3 for CodeBuild
268
+ S3_BUCKET="codebuild-source-${AWS_ACCOUNT_ID}-${AWS_REGION}"
269
+ S3_KEY="${PROJECT_NAME}/source-$(date +%Y%m%d-%H%M%S).zip"
270
+
271
+ # Create S3 bucket if it doesn't exist
272
+ if ! aws s3api head-bucket --bucket "$S3_BUCKET" --region "${AWS_REGION}" >/dev/null 2>&1; then
273
+ echo "📦 Creating S3 bucket for CodeBuild source: $S3_BUCKET"
274
+ if [ "${AWS_REGION}" = "us-east-1" ]; then
275
+ aws s3api create-bucket --bucket "$S3_BUCKET" --region "${AWS_REGION}"
276
+ else
277
+ aws s3api create-bucket --bucket "$S3_BUCKET" --region "${AWS_REGION}" --create-bucket-configuration LocationConstraint="${AWS_REGION}"
278
+ fi
279
+ fi
280
+
281
+ # Upload source to S3
282
+ echo "📤 Uploading source to S3..."
283
+ aws s3 cp "$TEMP_ZIP" "s3://$S3_BUCKET/$S3_KEY" --region "${AWS_REGION}"
284
+
285
+ # Record S3 object in manifest (non-blocking)
286
+ ./do/manifest add \
287
+ --type s3-object \
288
+ --id "s3://${S3_BUCKET}/${S3_KEY}" \
289
+ --project "${PROJECT_NAME}" \
290
+ --meta "{\"bucket\":\"${S3_BUCKET}\",\"key\":\"${S3_KEY}\",\"region\":\"${AWS_REGION}\"}" \
291
+ 2>/dev/null || true
292
+
293
+ # Clean up local zip file
294
+ rm -f "$TEMP_ZIP"
295
+
296
+ # Start CodeBuild job
297
+ echo "🚀 Starting CodeBuild job..."
298
+ echo " Project: ${CODEBUILD_PROJECT_NAME}"
299
+ echo " S3 source: s3://$S3_BUCKET/$S3_KEY"
300
+
301
+ # Double-check project exists before starting build
302
+ FINAL_CHECK=$(aws codebuild batch-get-projects --names "${CODEBUILD_PROJECT_NAME}" --region "${AWS_REGION}" --query 'projects[0].name' --output text 2>/dev/null)
303
+ if [ "$FINAL_CHECK" = "None" ] || [ -z "$FINAL_CHECK" ] || [ "$FINAL_CHECK" = "null" ]; then
304
+ echo "❌ CodeBuild project not found before starting build: ${CODEBUILD_PROJECT_NAME}"
305
+ echo " Available projects in region ${AWS_REGION}:"
306
+ aws codebuild list-projects --region "${AWS_REGION}" --query 'projects' --output table 2>/dev/null || echo " Could not list projects"
307
+ exit 1
308
+ fi
309
+
310
+ # Start build
311
+ aws codebuild start-build \
312
+ --project-name "${CODEBUILD_PROJECT_NAME}" \
313
+ --source-type-override S3 \
314
+ --source-location-override "$S3_BUCKET/$S3_KEY" \
315
+ --region "${AWS_REGION}" \
316
+ --query 'build.id' \
317
+ --output text > /tmp/build-id.txt 2>&1
318
+
319
+ START_EXIT_CODE=$?
320
+ BUILD_ID=""
321
+
322
+ if [ $START_EXIT_CODE -eq 0 ]; then
323
+ BUILD_ID=$(cat /tmp/build-id.txt)
324
+ rm -f /tmp/build-id.txt
325
+ else
326
+ echo "❌ Failed to start build (exit code: $START_EXIT_CODE)"
327
+ echo " Error output:"
328
+ cat /tmp/build-id.txt 2>/dev/null || echo " No error output available"
329
+ rm -f /tmp/build-id.txt
330
+ exit 1
331
+ fi
332
+
333
+ # Check if BUILD_ID is valid
334
+ if [ -z "$BUILD_ID" ] || [ "$BUILD_ID" = "None" ] || [ "$BUILD_ID" = "null" ]; then
335
+ echo "❌ Failed to start CodeBuild job"
336
+ echo " Debugging information:"
337
+ echo " Project name: ${CODEBUILD_PROJECT_NAME}"
338
+ echo " Region: ${AWS_REGION}"
339
+ echo " Account ID: ${AWS_ACCOUNT_ID}"
340
+ echo " S3 Source: s3://$S3_BUCKET/$S3_KEY"
341
+ exit 1
342
+ fi
343
+
344
+ echo "✅ Build started with ID: $BUILD_ID"
345
+ echo "📊 Monitor build at: https://${AWS_REGION}.console.aws.amazon.com/codesuite/codebuild/projects/${CODEBUILD_PROJECT_NAME}/build/$BUILD_ID"
346
+ echo ""
347
+ echo "⏳ Monitoring build progress..."
348
+
349
+ # Monitor build status
350
+ PREVIOUS_STATUS=""
351
+ while true; do
352
+ BUILD_INFO=$(aws codebuild batch-get-builds \
353
+ --ids "$BUILD_ID" \
354
+ --region "${AWS_REGION}" \
355
+ --query 'builds[0].[buildStatus,currentPhase]' \
356
+ --output text)
357
+
358
+ # Parse status
359
+ BUILD_STATUS=$(echo "$BUILD_INFO" | awk '{print $1}')
360
+ CURRENT_PHASE=$(echo "$BUILD_INFO" | awk '{print $2}')
361
+
362
+ # Only print status changes
363
+ CURRENT_STATUS="$BUILD_STATUS:$CURRENT_PHASE"
364
+ if [ "$CURRENT_STATUS" != "$PREVIOUS_STATUS" ]; then
365
+ echo "📋 Build status: $BUILD_STATUS | Phase: $CURRENT_PHASE"
366
+ PREVIOUS_STATUS="$CURRENT_STATUS"
367
+ fi
368
+
369
+ # Check for completion
370
+ if [[ "$BUILD_STATUS" == "SUCCEEDED"* ]]; then
371
+ echo ""
372
+ echo "✅ Build completed successfully!"
373
+ echo "🐳 Docker image available at:"
374
+ echo " ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPOSITORY_NAME}:${PROJECT_NAME}-latest"
375
+ echo " ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPOSITORY_NAME}:latest"
376
+ echo ""
377
+ echo "Next steps:"
378
+ echo " • Deploy to SageMaker: ./do/deploy"
379
+ echo " • Or use the ECR image URI in your own deployment process"
380
+ exit 0
381
+ elif [[ "$BUILD_STATUS" == "FAILED"* ]] || [[ "$BUILD_STATUS" == "FAULT"* ]] || [[ "$BUILD_STATUS" == "STOPPED"* ]] || [[ "$BUILD_STATUS" == "TIMED_OUT"* ]]; then
382
+ echo ""
383
+ echo "❌ Build failed with status: $BUILD_STATUS"
384
+ echo ""
385
+ echo "📋 Fetching build logs..."
386
+
387
+ # Try to get build logs
388
+ LOG_GROUP="/aws/codebuild/${CODEBUILD_PROJECT_NAME}"
389
+ LOG_STREAM=$(aws logs describe-log-streams \
390
+ --log-group-name "$LOG_GROUP" \
391
+ --order-by LastEventTime \
392
+ --descending \
393
+ --max-items 1 \
394
+ --region "${AWS_REGION}" \
395
+ --query 'logStreams[0].logStreamName' \
396
+ --output text 2>/dev/null || echo "")
397
+
398
+ if [ -n "$LOG_STREAM" ] && [ "$LOG_STREAM" != "None" ]; then
399
+ echo "Recent build logs:"
400
+ echo "=================="
401
+ aws logs get-log-events \
402
+ --log-group-name "$LOG_GROUP" \
403
+ --log-stream-name "$LOG_STREAM" \
404
+ --region "${AWS_REGION}" \
405
+ --query 'events[-20:].message' \
406
+ --output text 2>/dev/null || echo "Could not retrieve logs"
407
+ else
408
+ echo "Could not retrieve build logs. Check the CodeBuild console for details."
409
+ fi
410
+
411
+ echo ""
412
+ echo "🔍 For detailed logs, visit: https://${AWS_REGION}.console.aws.amazon.com/codesuite/codebuild/projects/${CODEBUILD_PROJECT_NAME}/build/$BUILD_ID"
413
+ exit 1
414
+ fi
415
+
416
+ sleep 30
417
+ done