@aws/ml-container-creator 0.2.5 → 0.3.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.
- package/bin/cli.js +45 -4
- package/config/bootstrap-stack.json +14 -0
- package/infra/ci-harness/package-lock.json +22 -9
- package/package.json +7 -8
- package/servers/base-image-picker/index.js +3 -3
- package/servers/base-image-picker/manifest.json +4 -2
- package/servers/instance-sizer/index.js +564 -0
- package/servers/instance-sizer/lib/instance-ranker.js +270 -0
- package/servers/instance-sizer/lib/model-resolver.js +269 -0
- package/servers/instance-sizer/lib/vram-estimator.js +177 -0
- package/servers/instance-sizer/manifest.json +17 -0
- package/servers/instance-sizer/package.json +15 -0
- package/servers/{instance-recommender → lib}/catalogs/instances.json +136 -34
- package/servers/{base-image-picker → lib}/catalogs/model-servers.json +302 -254
- package/servers/lib/catalogs/model-sizes.json +131 -0
- package/servers/lib/catalogs/models.json +632 -0
- package/servers/{model-picker → lib}/catalogs/popular-diffusors.json +32 -10
- package/servers/{model-picker → lib}/catalogs/popular-transformers.json +59 -26
- package/servers/{base-image-picker → lib}/catalogs/python-slim.json +12 -12
- package/servers/lib/schemas/image-catalog.schema.json +6 -12
- package/servers/lib/schemas/instances.schema.json +29 -0
- package/servers/lib/schemas/model-catalog.schema.json +12 -10
- package/servers/lib/schemas/unified-model-catalog.schema.json +129 -0
- package/servers/model-picker/index.js +4 -4
- package/servers/model-picker/manifest.json +2 -3
- package/servers/region-picker/index.js +1 -1
- package/servers/region-picker/manifest.json +1 -1
- package/src/app.js +36 -0
- package/src/lib/architecture-sync.js +171 -0
- package/src/lib/arn-detection.js +22 -0
- package/src/lib/bootstrap-command-handler.js +120 -0
- package/src/lib/cli-handler.js +3 -3
- package/src/lib/config-manager.js +47 -1
- package/src/lib/configuration-manager.js +2 -2
- package/src/lib/cross-cutting-checker.js +460 -0
- package/src/lib/deployment-entry-schema.js +1 -2
- package/src/lib/dry-run-validator.js +78 -0
- package/src/lib/generation-validator.js +102 -0
- package/src/lib/mcp-validator-config.js +89 -0
- package/src/lib/payload-builder.js +153 -0
- package/src/lib/prompt-runner.js +866 -149
- package/src/lib/prompts.js +2 -2
- package/src/lib/registry-command-handler.js +236 -0
- package/src/lib/registry-loader.js +5 -5
- package/src/lib/schema-sync.js +203 -0
- package/src/lib/schema-validation-engine.js +195 -0
- package/src/lib/secret-classification.js +56 -0
- package/src/lib/secrets-command-handler.js +550 -0
- package/src/lib/service-model-parser.js +102 -0
- package/src/lib/validate-runner.js +216 -0
- package/src/lib/validation-report.js +140 -0
- package/src/lib/validators/base-validator.js +36 -0
- package/src/lib/validators/catalog-validator.js +177 -0
- package/src/lib/validators/enum-validator.js +120 -0
- package/src/lib/validators/required-field-validator.js +150 -0
- package/src/lib/validators/type-validator.js +313 -0
- package/src/prompt-adapter.js +3 -2
- package/templates/Dockerfile +1 -1
- package/templates/do/build +37 -5
- package/templates/do/config +15 -3
- package/templates/do/deploy +60 -5
- package/templates/do/logs +18 -3
- package/templates/do/run +15 -1
- package/templates/do/validate +61 -0
- package/servers/instance-recommender/LICENSE +0 -202
- package/servers/instance-recommender/index.js +0 -284
- package/servers/instance-recommender/manifest.json +0 -16
- package/servers/instance-recommender/package.json +0 -15
- /package/servers/{model-picker → lib}/catalogs/jumpstart-public.json +0 -0
- /package/servers/{region-picker → lib}/catalogs/regions.json +0 -0
- /package/servers/{base-image-picker → lib}/catalogs/triton-backends.json +0 -0
- /package/servers/{base-image-picker → lib}/catalogs/triton.json +0 -0
package/src/app.js
CHANGED
|
@@ -119,6 +119,23 @@ export async function run(projectName, options) {
|
|
|
119
119
|
let answers;
|
|
120
120
|
if (configManager.shouldSkipPrompts()) {
|
|
121
121
|
console.log('\n🚀 Skipping prompts - using configuration from other sources');
|
|
122
|
+
|
|
123
|
+
// Fail-fast if required parameters are missing
|
|
124
|
+
const missing = configManager.getMissingRequiredParameters();
|
|
125
|
+
if (missing.length > 0) {
|
|
126
|
+
console.error('\n❌ Cannot skip prompts — required parameters are missing:\n');
|
|
127
|
+
for (const param of missing) {
|
|
128
|
+
const matrix = configManager._getParameterMatrix()[param];
|
|
129
|
+
const cliFlag = matrix?.cliOption ? `--${matrix.cliOption}` : '';
|
|
130
|
+
const envVar = matrix?.envVar || '';
|
|
131
|
+
const hints = [cliFlag, envVar].filter(Boolean).join(' or ');
|
|
132
|
+
console.error(` • ${param}${hints ? ` (${hints})` : ''}`);
|
|
133
|
+
}
|
|
134
|
+
console.error('\n Provide these via CLI flags, environment variables, or a config file.');
|
|
135
|
+
console.error(' Run "ml-container-creator --help" for available options.\n');
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
|
|
122
139
|
answers = configManager.getFinalConfiguration();
|
|
123
140
|
|
|
124
141
|
// Infer modelSource from model name prefix if not set
|
|
@@ -188,6 +205,23 @@ export async function run(projectName, options) {
|
|
|
188
205
|
|
|
189
206
|
// --- Phase: Writing ---
|
|
190
207
|
const destDir = path.resolve(answers.destinationDir);
|
|
208
|
+
|
|
209
|
+
// Safety guard: refuse to generate into the generator's own directory
|
|
210
|
+
const destPkgPath = path.join(destDir, 'package.json');
|
|
211
|
+
if (fs.existsSync(destPkgPath)) {
|
|
212
|
+
try {
|
|
213
|
+
const destPkg = JSON.parse(fs.readFileSync(destPkgPath, 'utf8'));
|
|
214
|
+
if (destPkg.name === '@aws/ml-container-creator') {
|
|
215
|
+
console.log('\n❌ Refusing to generate into the generator\'s own directory.');
|
|
216
|
+
console.log(' This would overwrite the generator source files.');
|
|
217
|
+
console.log(' Use --project-dir or provide a project name instead.\n');
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
} catch {
|
|
221
|
+
// If we can't read/parse package.json, it's not the generator dir — proceed
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
191
225
|
fs.mkdirSync(destDir, { recursive: true });
|
|
192
226
|
|
|
193
227
|
await writeProject(TEMPLATE_DIR, destDir, answers, registryConfigManager, tritonBackends, configManager);
|
|
@@ -476,7 +510,9 @@ async function _ensureTemplateVariables(answers, registryConfigManager = null) {
|
|
|
476
510
|
chatTemplate: null,
|
|
477
511
|
chatTemplateSource: null,
|
|
478
512
|
hfToken: null,
|
|
513
|
+
hfTokenArn: null,
|
|
479
514
|
ngcApiKey: null,
|
|
515
|
+
ngcTokenArn: null,
|
|
480
516
|
envVars: {},
|
|
481
517
|
inferenceAmiVersion: null,
|
|
482
518
|
accelerator: null,
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Architecture Sync
|
|
6
|
+
*
|
|
7
|
+
* Fetches model registry source files from server GitHub repositories
|
|
8
|
+
* and extracts supported model_type values into the model-servers catalog.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Parse vLLM's model registry Python source to extract model_type keys.
|
|
15
|
+
*
|
|
16
|
+
* vLLM's registry maps architecture class names to (module, impl_class) tuples:
|
|
17
|
+
* "LlamaForCausalLM": ("llama", "LlamaForCausalLM"),
|
|
18
|
+
* "Qwen2ForCausalLM": ("qwen2", "Qwen2ForCausalLM"),
|
|
19
|
+
*
|
|
20
|
+
* The module name (first tuple element) corresponds to the model_type.
|
|
21
|
+
* Also matches older formats where model_type is used directly as dict key.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} source - Python source code content
|
|
24
|
+
* @returns {string[]} Sorted array of model_type strings
|
|
25
|
+
*/
|
|
26
|
+
export const parseVllmRegistry = (source) => {
|
|
27
|
+
const modelTypes = new Set();
|
|
28
|
+
const patterns = [
|
|
29
|
+
// Tuple value format: ("module_name", "ClassName") — extract module_name
|
|
30
|
+
/\("([a-z][a-z0-9_]*)"\s*,\s*"[A-Z]/g,
|
|
31
|
+
// Direct lowercase key format (older registries): "model_type": (
|
|
32
|
+
/"([a-z][a-z0-9_]*)":\s*\(/g,
|
|
33
|
+
// Direct lowercase key format: "model_type": ClassName
|
|
34
|
+
/"([a-z][a-z0-9_]*)":\s*[A-Z]/g,
|
|
35
|
+
// Direct lowercase key format: "model_type": [
|
|
36
|
+
/"([a-z][a-z0-9_]*)":\s*\[/g
|
|
37
|
+
];
|
|
38
|
+
for (const pattern of patterns) {
|
|
39
|
+
let match;
|
|
40
|
+
while ((match = pattern.exec(source)) !== null) {
|
|
41
|
+
modelTypes.add(match[1]);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return [...modelTypes].sort();
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Parse SGLang's model_registry.py to extract model_type keys.
|
|
49
|
+
*
|
|
50
|
+
* Matches patterns like:
|
|
51
|
+
* "llama": ModelClass,
|
|
52
|
+
* "qwen2": (ModulePath, ClassName),
|
|
53
|
+
*
|
|
54
|
+
* @param {string} source - Python source code content
|
|
55
|
+
* @returns {string[]} Sorted array of model_type strings
|
|
56
|
+
*/
|
|
57
|
+
export const parseSglangRegistry = (source) => {
|
|
58
|
+
const modelTypes = new Set();
|
|
59
|
+
const patterns = [
|
|
60
|
+
/"([a-z][a-z0-9_]*)":\s*\(/g,
|
|
61
|
+
/"([a-z][a-z0-9_]*)":\s*[A-Z]/g,
|
|
62
|
+
/"([a-z][a-z0-9_]*)":\s*\[/g
|
|
63
|
+
];
|
|
64
|
+
for (const pattern of patterns) {
|
|
65
|
+
let match;
|
|
66
|
+
while ((match = pattern.exec(source)) !== null) {
|
|
67
|
+
modelTypes.add(match[1]);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return [...modelTypes].sort();
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Parse TensorRT-LLM's models __init__.py to extract model_type keys.
|
|
75
|
+
*
|
|
76
|
+
* Matches patterns from MODEL_MAP or similar dict structures:
|
|
77
|
+
* "llama": LlamaForCausalLM,
|
|
78
|
+
* "gpt2": GPT2LMHeadModel,
|
|
79
|
+
*
|
|
80
|
+
* @param {string} source - Python source code content
|
|
81
|
+
* @returns {string[]} Sorted array of model_type strings
|
|
82
|
+
*/
|
|
83
|
+
export const parseTensorRTRegistry = (source) => {
|
|
84
|
+
const modelTypes = new Set();
|
|
85
|
+
const patterns = [
|
|
86
|
+
/"([a-z][a-z0-9_]*)":\s*[A-Z]/g,
|
|
87
|
+
/"([a-z][a-z0-9_]*)":\s*\(/g,
|
|
88
|
+
/'([a-z][a-z0-9_]*)':\s*[A-Z]/g,
|
|
89
|
+
/'([a-z][a-z0-9_]*)':\s*\(/g
|
|
90
|
+
];
|
|
91
|
+
for (const pattern of patterns) {
|
|
92
|
+
let match;
|
|
93
|
+
while ((match = pattern.exec(source)) !== null) {
|
|
94
|
+
modelTypes.add(match[1]);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return [...modelTypes].sort();
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Configuration mapping each server to its GitHub repository,
|
|
102
|
+
* registry file path, tag prefix, and parser function.
|
|
103
|
+
*/
|
|
104
|
+
export const SERVER_REGISTRY_SOURCES = {
|
|
105
|
+
vllm: {
|
|
106
|
+
repo: 'vllm-project/vllm',
|
|
107
|
+
file: 'vllm/model_executor/models/registry.py',
|
|
108
|
+
tagPrefix: 'v',
|
|
109
|
+
parser: parseVllmRegistry
|
|
110
|
+
},
|
|
111
|
+
sglang: {
|
|
112
|
+
repo: 'sgl-project/sglang',
|
|
113
|
+
file: 'python/sglang/srt/models/model_registry.py',
|
|
114
|
+
tagPrefix: 'v',
|
|
115
|
+
parser: parseSglangRegistry
|
|
116
|
+
},
|
|
117
|
+
'tensorrt-llm': {
|
|
118
|
+
repo: 'NVIDIA/TensorRT-LLM',
|
|
119
|
+
file: 'tensorrt_llm/models/__init__.py',
|
|
120
|
+
tagPrefix: 'v',
|
|
121
|
+
parser: parseTensorRTRegistry
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Sync supported model architectures from server GitHub repositories
|
|
127
|
+
* into the model-servers catalog.
|
|
128
|
+
*
|
|
129
|
+
* For each server entry in the catalog that has a matching source config,
|
|
130
|
+
* fetches the model registry file from GitHub at the version tag and
|
|
131
|
+
* parses it to extract supported model_type values.
|
|
132
|
+
*
|
|
133
|
+
* @param {string} catalogPath - Path to model-servers.json
|
|
134
|
+
* @returns {object} Summary with counts and failures
|
|
135
|
+
*/
|
|
136
|
+
export const syncArchitectures = async (catalogPath) => {
|
|
137
|
+
const catalog = JSON.parse(readFileSync(catalogPath, 'utf8'));
|
|
138
|
+
const summary = { servers: [], failures: [] };
|
|
139
|
+
|
|
140
|
+
for (const [server, entries] of Object.entries(catalog)) {
|
|
141
|
+
const source = SERVER_REGISTRY_SOURCES[server];
|
|
142
|
+
if (!source) continue;
|
|
143
|
+
|
|
144
|
+
for (const entry of entries) {
|
|
145
|
+
const version = entry.labels?.framework_version;
|
|
146
|
+
if (!version) continue;
|
|
147
|
+
|
|
148
|
+
const tag = `${source.tagPrefix}${version}`;
|
|
149
|
+
const url = `https://raw.githubusercontent.com/${source.repo}/${tag}/${source.file}`;
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const response = await fetch(url);
|
|
153
|
+
if (!response.ok) {
|
|
154
|
+
summary.failures.push({ server, version, reason: `HTTP ${response.status}` });
|
|
155
|
+
console.log(` ⚠️ ${server} ${version}: fetch failed (HTTP ${response.status})`);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const content = await response.text();
|
|
159
|
+
entry.supportedModelTypes = source.parser(content);
|
|
160
|
+
summary.servers.push({ server, version, count: entry.supportedModelTypes.length });
|
|
161
|
+
console.log(` ✓ ${server} ${version}: ${entry.supportedModelTypes.length} architectures`);
|
|
162
|
+
} catch (err) {
|
|
163
|
+
summary.failures.push({ server, version, reason: err.message });
|
|
164
|
+
console.log(` ⚠️ ${server} ${version}: fetch failed (${err.message})`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
writeFileSync(catalogPath, JSON.stringify(catalog, null, 4));
|
|
170
|
+
return summary;
|
|
171
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ARN Detection Utility
|
|
6
|
+
*
|
|
7
|
+
* Provides a pure function for distinguishing AWS Secrets Manager ARNs
|
|
8
|
+
* from plaintext values. Used by the prompt flow and CLI to determine
|
|
9
|
+
* whether user input should be treated as a secret reference or a
|
|
10
|
+
* literal token value.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const SECRETS_MANAGER_ARN_PREFIX = 'arn:aws:secretsmanager:';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Determines if a value is a Secrets Manager ARN.
|
|
17
|
+
* @param {*} value - The input value to check
|
|
18
|
+
* @returns {boolean} True if the value is a Secrets Manager ARN
|
|
19
|
+
*/
|
|
20
|
+
export function isSecretsManagerArn(value) {
|
|
21
|
+
return typeof value === 'string' && value.startsWith(SECRETS_MANAGER_ARN_PREFIX);
|
|
22
|
+
}
|
|
@@ -24,6 +24,8 @@ import { fileURLToPath } from 'node:url';
|
|
|
24
24
|
import BootstrapConfig from './bootstrap-config.js';
|
|
25
25
|
import AwsProfileParser from './aws-profile-parser.js';
|
|
26
26
|
import AssetManager from './asset-manager.js';
|
|
27
|
+
import McpCommandHandler from './mcp-command-handler.js';
|
|
28
|
+
import RegistryCommandHandler from './registry-command-handler.js';
|
|
27
29
|
import { runPrompts } from '../prompt-adapter.js';
|
|
28
30
|
|
|
29
31
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -45,6 +47,12 @@ export default class BootstrapCommandHandler {
|
|
|
45
47
|
* @param {object} options - Parsed CLI options
|
|
46
48
|
*/
|
|
47
49
|
async handle(args, options) {
|
|
50
|
+
// Handle legacy --sync-schemas flag for backward compatibility
|
|
51
|
+
if (options['sync-schemas']) {
|
|
52
|
+
await this._handleSyncSchemas();
|
|
53
|
+
if (args.length === 0) return;
|
|
54
|
+
}
|
|
55
|
+
|
|
48
56
|
if (args.length === 0) {
|
|
49
57
|
await this._handleInteractiveSetup(options);
|
|
50
58
|
return;
|
|
@@ -74,6 +82,9 @@ export default class BootstrapCommandHandler {
|
|
|
74
82
|
case 'update':
|
|
75
83
|
await this._handleUpdate(options);
|
|
76
84
|
break;
|
|
85
|
+
case 'sync-schemas':
|
|
86
|
+
await this._handleSyncSchemas();
|
|
87
|
+
break;
|
|
77
88
|
default:
|
|
78
89
|
console.log(`Unknown bootstrap subcommand: ${subcommand}`);
|
|
79
90
|
this._showHelp();
|
|
@@ -302,6 +313,9 @@ export default class BootstrapCommandHandler {
|
|
|
302
313
|
|
|
303
314
|
// Display summary
|
|
304
315
|
this._displaySummary(profileName, profileData);
|
|
316
|
+
|
|
317
|
+
// Step 6: Post-setup chain (mcp init → sync-architectures → sync-schemas)
|
|
318
|
+
await this._runPostSetupChain(options);
|
|
305
319
|
}
|
|
306
320
|
|
|
307
321
|
/**
|
|
@@ -927,6 +941,35 @@ export default class BootstrapCommandHandler {
|
|
|
927
941
|
console.log(`\n Done. ${toRemove.length} removed, ${after.length} remaining.`);
|
|
928
942
|
}
|
|
929
943
|
|
|
944
|
+
/**
|
|
945
|
+
* Handle sync-schemas subcommand: download service models and verify AWS CLI.
|
|
946
|
+
*/
|
|
947
|
+
async _handleSyncSchemas() {
|
|
948
|
+
console.log('\n📦 Schema Sync — Downloading AWS service models...\n');
|
|
949
|
+
|
|
950
|
+
// Verify AWS CLI is installed
|
|
951
|
+
try {
|
|
952
|
+
const version = execSync('aws --version', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
953
|
+
console.log(` AWS CLI: ${version}`);
|
|
954
|
+
} catch {
|
|
955
|
+
console.log(' ⚠️ AWS CLI not found.');
|
|
956
|
+
console.log(' Install: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html');
|
|
957
|
+
console.log(' Continuing without AWS CLI verification...\n');
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
// Dynamic import to avoid circular dependencies
|
|
961
|
+
const { syncSchemas } = await import('./schema-sync.js');
|
|
962
|
+
const result = await syncSchemas();
|
|
963
|
+
|
|
964
|
+
if (result.success) {
|
|
965
|
+
console.log('\n ✅ Schema sync complete.');
|
|
966
|
+
} else {
|
|
967
|
+
console.log('\n ⚠️ Schema sync completed with errors (some services may be unavailable).');
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
console.log(` Manifest written: lastSynced = ${result.manifest.lastSynced}\n`);
|
|
971
|
+
}
|
|
972
|
+
|
|
930
973
|
/**
|
|
931
974
|
* Re-deploy bootstrap infrastructure using the active profile.
|
|
932
975
|
* No prompts — reads all config from the existing profile and re-applies
|
|
@@ -1016,6 +1059,74 @@ export default class BootstrapCommandHandler {
|
|
|
1016
1059
|
// Save updated profile
|
|
1017
1060
|
this.config.setProfile(name, profileConfig);
|
|
1018
1061
|
console.log(`\n✅ Update complete for profile "${name}"`);
|
|
1062
|
+
|
|
1063
|
+
// Re-run post-setup chain after updating AWS resources
|
|
1064
|
+
await this._runPostSetupChain(options);
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* Run the post-setup chain: mcp init → registry sync-architectures → sync-schemas.
|
|
1069
|
+
* Each step is independent — failures are collected and reported at the end.
|
|
1070
|
+
*
|
|
1071
|
+
* @param {object} options - Parsed CLI options (checks skipPostSetup)
|
|
1072
|
+
*/
|
|
1073
|
+
async _runPostSetupChain(options = {}) {
|
|
1074
|
+
if (options['skip-post-setup']) {
|
|
1075
|
+
console.log('\n⏭️ Skipping post-setup chain (--skip-post-setup)');
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
console.log('\n🔗 Running post-setup configuration...\n');
|
|
1080
|
+
|
|
1081
|
+
const failures = [];
|
|
1082
|
+
|
|
1083
|
+
// 1. MCP init — register bundled MCP servers
|
|
1084
|
+
console.log('📡 Registering MCP servers...');
|
|
1085
|
+
try {
|
|
1086
|
+
const generatorAdapter = {
|
|
1087
|
+
destinationPath(...segments) {
|
|
1088
|
+
return path.resolve(process.cwd(), ...segments);
|
|
1089
|
+
}
|
|
1090
|
+
};
|
|
1091
|
+
const mcpHandler = new McpCommandHandler(generatorAdapter);
|
|
1092
|
+
await mcpHandler.handle(['init'], {});
|
|
1093
|
+
} catch (error) {
|
|
1094
|
+
failures.push({ step: 'mcp init', error: error.message });
|
|
1095
|
+
console.log(` ⚠️ mcp init failed: ${error.message}`);
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
// 2. Registry sync-architectures — populate supportedModelTypes
|
|
1099
|
+
console.log('\n📋 Syncing model architecture registry...');
|
|
1100
|
+
try {
|
|
1101
|
+
const registryHandler = new RegistryCommandHandler();
|
|
1102
|
+
await registryHandler.handle(['sync-architectures'], {});
|
|
1103
|
+
} catch (error) {
|
|
1104
|
+
failures.push({ step: 'registry sync-architectures', error: error.message });
|
|
1105
|
+
console.log(` ⚠️ registry sync-architectures failed: ${error.message}`);
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
// 3. Schema sync — download AWS service models
|
|
1109
|
+
console.log('\n📐 Syncing service schemas...');
|
|
1110
|
+
try {
|
|
1111
|
+
await this._handleSyncSchemas();
|
|
1112
|
+
} catch (error) {
|
|
1113
|
+
failures.push({ step: 'sync-schemas', error: error.message });
|
|
1114
|
+
console.log(` ⚠️ sync-schemas failed: ${error.message}`);
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
// Report results
|
|
1118
|
+
if (failures.length === 0) {
|
|
1119
|
+
console.log('\n✅ Bootstrap complete — all systems operational');
|
|
1120
|
+
} else {
|
|
1121
|
+
console.log(`\n⚠️ Bootstrap complete with ${failures.length} warning${failures.length === 1 ? '' : 's'}:`);
|
|
1122
|
+
for (const { step, error } of failures) {
|
|
1123
|
+
console.log(` • ${step}: ${error}`);
|
|
1124
|
+
}
|
|
1125
|
+
console.log('\n These steps can be re-run individually:');
|
|
1126
|
+
console.log(' ml-container-creator mcp init');
|
|
1127
|
+
console.log(' ml-container-creator registry sync-architectures');
|
|
1128
|
+
console.log(' ml-container-creator bootstrap sync-schemas');
|
|
1129
|
+
}
|
|
1019
1130
|
}
|
|
1020
1131
|
|
|
1021
1132
|
/**
|
|
@@ -1204,12 +1315,20 @@ export default class BootstrapCommandHandler {
|
|
|
1204
1315
|
Effect: 'Allow',
|
|
1205
1316
|
Action: [
|
|
1206
1317
|
's3:GetObject',
|
|
1318
|
+
's3:PutObject',
|
|
1319
|
+
's3:AbortMultipartUpload',
|
|
1207
1320
|
's3:ListBucket'
|
|
1208
1321
|
],
|
|
1209
1322
|
Resource: [
|
|
1210
1323
|
'arn:aws:s3:::ml-container-creator-*',
|
|
1211
1324
|
'arn:aws:s3:::ml-container-creator-*/*'
|
|
1212
1325
|
]
|
|
1326
|
+
},
|
|
1327
|
+
{
|
|
1328
|
+
Sid: 'SNSPublish',
|
|
1329
|
+
Effect: 'Allow',
|
|
1330
|
+
Action: 'sns:Publish',
|
|
1331
|
+
Resource: 'arn:aws:sns:*:*:ml-container-creator-*'
|
|
1213
1332
|
}
|
|
1214
1333
|
]
|
|
1215
1334
|
};
|
|
@@ -1611,6 +1730,7 @@ SETUP OPTIONS:
|
|
|
1611
1730
|
--skip-s3 Skip S3 bucket creation
|
|
1612
1731
|
--ci Provision CI testing infrastructure
|
|
1613
1732
|
--skip-ci Skip CI infrastructure provisioning
|
|
1733
|
+
--skip-post-setup Skip post-setup chain (mcp init, sync-architectures, sync-schemas)
|
|
1614
1734
|
|
|
1615
1735
|
STATUS OPTIONS:
|
|
1616
1736
|
--verify Check each active resource against AWS APIs for drift detection
|
package/src/lib/cli-handler.js
CHANGED
|
@@ -280,9 +280,9 @@ TRANSFORMER MODEL EXAMPLES:
|
|
|
280
280
|
|
|
281
281
|
REGISTRY CONTRIBUTION:
|
|
282
282
|
To contribute to the catalogs:
|
|
283
|
-
- Framework Catalog: servers/
|
|
284
|
-
- Model Catalog: servers/
|
|
285
|
-
- Instance Catalog: servers/
|
|
283
|
+
- Framework Catalog: servers/lib/catalogs/model-servers.json
|
|
284
|
+
- Model Catalog: servers/lib/catalogs/popular-transformers.json
|
|
285
|
+
- Instance Catalog: servers/lib/catalogs/instances.json
|
|
286
286
|
|
|
287
287
|
See docs/REGISTRY_CONTRIBUTION_GUIDE.md for detailed contribution guidelines.
|
|
288
288
|
|
|
@@ -29,7 +29,7 @@ import ParameterSchemaValidator from './parameter-schema-validator.js';
|
|
|
29
29
|
|
|
30
30
|
const __configMgrFilename = fileURLToPath(import.meta.url);
|
|
31
31
|
const __configMgrDir = dirname(__configMgrFilename);
|
|
32
|
-
const tritonBackendsCatalogPath = resolve(__configMgrDir, '../../servers/
|
|
32
|
+
const tritonBackendsCatalogPath = resolve(__configMgrDir, '../../servers/lib/catalogs/triton-backends.json');
|
|
33
33
|
|
|
34
34
|
function loadTritonBackendsFromCatalog() {
|
|
35
35
|
try {
|
|
@@ -300,6 +300,15 @@ export default class ConfigManager {
|
|
|
300
300
|
finalConfig.hfToken = this._resolveHfToken(finalConfig.hfToken);
|
|
301
301
|
}
|
|
302
302
|
|
|
303
|
+
// Mutual exclusion: ARN takes precedence over plaintext when both are set
|
|
304
|
+
// (CLI validation should prevent this, but enforce at config level too)
|
|
305
|
+
if (finalConfig.hfTokenArn) {
|
|
306
|
+
finalConfig.hfToken = null;
|
|
307
|
+
}
|
|
308
|
+
if (finalConfig.ngcTokenArn) {
|
|
309
|
+
finalConfig.ngcApiKey = null;
|
|
310
|
+
}
|
|
311
|
+
|
|
303
312
|
// Map awsRoleArn to roleArn for templates
|
|
304
313
|
if (finalConfig.awsRoleArn) {
|
|
305
314
|
finalConfig.roleArn = finalConfig.awsRoleArn;
|
|
@@ -643,6 +652,28 @@ export default class ConfigManager {
|
|
|
643
652
|
default: null,
|
|
644
653
|
valueSpace: 'bounded'
|
|
645
654
|
},
|
|
655
|
+
hfTokenArn: {
|
|
656
|
+
cliOption: 'hf-token-arn',
|
|
657
|
+
envVar: null,
|
|
658
|
+
configFile: true,
|
|
659
|
+
packageJson: false,
|
|
660
|
+
mcp: false,
|
|
661
|
+
promptable: false,
|
|
662
|
+
required: false,
|
|
663
|
+
default: null,
|
|
664
|
+
valueSpace: 'bounded'
|
|
665
|
+
},
|
|
666
|
+
ngcTokenArn: {
|
|
667
|
+
cliOption: 'ngc-token-arn',
|
|
668
|
+
envVar: null,
|
|
669
|
+
configFile: true,
|
|
670
|
+
packageJson: false,
|
|
671
|
+
mcp: false,
|
|
672
|
+
promptable: false,
|
|
673
|
+
required: false,
|
|
674
|
+
default: null,
|
|
675
|
+
valueSpace: 'bounded'
|
|
676
|
+
},
|
|
646
677
|
deploymentTarget: {
|
|
647
678
|
cliOption: 'deployment-target',
|
|
648
679
|
envVar: 'ML_DEPLOYMENT_TARGET',
|
|
@@ -1675,6 +1706,18 @@ export default class ConfigManager {
|
|
|
1675
1706
|
}
|
|
1676
1707
|
}
|
|
1677
1708
|
|
|
1709
|
+
// Validate mutual exclusion: plaintext token and ARN cannot both be set
|
|
1710
|
+
if (this.config.hfToken && this.config.hfTokenArn) {
|
|
1711
|
+
errors.push('Cannot specify both --hf-token and --hf-token-arn. Use one or the other.');
|
|
1712
|
+
}
|
|
1713
|
+
if (this.config.ngcTokenArn) {
|
|
1714
|
+
// Check ngcToken from CLI options (Commander converts --ngc-token to ngcToken)
|
|
1715
|
+
const ngcTokenFromCli = this.options['ngc-token'];
|
|
1716
|
+
if (ngcTokenFromCli) {
|
|
1717
|
+
errors.push('Cannot specify both --ngc-token and --ngc-token-arn. Use one or the other.');
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1678
1721
|
// Validate AWS Role ARN format if provided
|
|
1679
1722
|
if (this.config.awsRoleArn) {
|
|
1680
1723
|
try {
|
|
@@ -1927,6 +1970,9 @@ export default class ConfigManager {
|
|
|
1927
1970
|
// For required parameters: fill auto-generatable values
|
|
1928
1971
|
if (this.config[param] === undefined || this.config[param] === null) {
|
|
1929
1972
|
if (param === 'instanceType') {
|
|
1973
|
+
// If instance-sizer is configured and model is known, defer to sizer
|
|
1974
|
+
// The sizer query happens in PromptRunner after model is selected
|
|
1975
|
+
// For now, set a heuristic default that may be overridden by the sizer
|
|
1930
1976
|
const arch = architecture || 'http';
|
|
1931
1977
|
this.config[param] = arch === 'http' ? 'ml.m5.large' : 'ml.g5.xlarge';
|
|
1932
1978
|
} else if (param === 'modelFormat') {
|
|
@@ -619,8 +619,8 @@ export default class ConfigurationManager {
|
|
|
619
619
|
*/
|
|
620
620
|
_generateSubmissionInstructions(registryType, config, configEntry) {
|
|
621
621
|
const registryFile = registryType === 'framework'
|
|
622
|
-
? 'servers/
|
|
623
|
-
: 'servers/
|
|
622
|
+
? 'servers/lib/catalogs/model-servers.json'
|
|
623
|
+
: 'servers/lib/catalogs/popular-transformers.json';
|
|
624
624
|
|
|
625
625
|
const registryName = registryType === 'framework'
|
|
626
626
|
? 'Framework_Catalog'
|