@aifabrix/builder 2.44.5 → 2.45.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/.cursor/rules/cli-layout.mdc +8 -4
- package/.cursor/rules/project-rules.mdc +1 -1
- package/README.md +15 -23
- package/integration/hubspot-test/README.md +2 -0
- package/integration/hubspot-test/test.js +5 -3
- package/jest.projects.js +104 -2
- package/lib/api/controller-health.api.js +49 -0
- package/lib/api/dimension-values.api.js +82 -0
- package/lib/api/dimensions.api.js +114 -0
- package/lib/api/external-systems.api.js +1 -0
- package/lib/api/integration-clients.api.js +168 -0
- package/lib/api/types/dimension-values.types.js +28 -0
- package/lib/api/types/dimensions.types.js +31 -0
- package/lib/api/types/integration-clients.types.js +45 -0
- package/lib/api/validation-runner.js +46 -25
- package/lib/app/deploy-config.js +11 -1
- package/lib/app/deploy-status-display.js +3 -3
- package/lib/app/deploy.js +36 -14
- package/lib/app/display.js +15 -11
- package/lib/app/helpers.js +3 -3
- package/lib/app/index.js +3 -3
- package/lib/app/push.js +46 -23
- package/lib/app/register.js +7 -6
- package/lib/app/restart-display.js +126 -0
- package/lib/app/rotate-secret.js +7 -6
- package/lib/app/run-container-start.js +12 -6
- package/lib/app/run-env-compose.js +30 -1
- package/lib/app/run-helpers.js +58 -19
- package/lib/app/run-reload-sync.js +148 -0
- package/lib/app/run-resolve-image.js +51 -1
- package/lib/app/run.js +148 -74
- package/lib/app/show-display.js +7 -0
- package/lib/app/show.js +87 -5
- package/lib/build/index.js +83 -49
- package/lib/cli/doctor-check.js +117 -0
- package/lib/cli/index.js +8 -2
- package/lib/cli/infra-guided.js +460 -0
- package/lib/cli/installation-log-command.js +73 -0
- package/lib/cli/setup-app.js +31 -3
- package/lib/cli/setup-auth.js +98 -27
- package/lib/cli/setup-dev-path-commands.js +50 -3
- package/lib/cli/setup-infra-up-dataplane-action.js +111 -0
- package/lib/cli/setup-infra-up-platform-action.js +131 -0
- package/lib/cli/setup-infra.js +132 -118
- package/lib/cli/setup-integration-client.js +182 -0
- package/lib/cli/setup-parameters.js +21 -2
- package/lib/cli/setup-platform.js +102 -0
- package/lib/cli/setup-secrets.js +18 -6
- package/lib/cli/setup-utility-resolve.js +132 -0
- package/lib/cli/setup-utility.js +143 -84
- package/lib/commands/app-logs.js +81 -33
- package/lib/commands/auth-config.js +116 -18
- package/lib/commands/datasource-capability-dimension-cli.js +128 -0
- package/lib/commands/datasource-capability-output.js +29 -0
- package/lib/commands/datasource-capability-relate-cli.js +140 -0
- package/lib/commands/datasource-capability.js +411 -0
- package/lib/commands/datasource-unified-test-cli.options.js +1 -1
- package/lib/commands/datasource.js +53 -13
- package/lib/commands/dev-down.js +3 -3
- package/lib/commands/dev-infra-gate.js +32 -0
- package/lib/commands/dev-init.js +13 -7
- package/lib/commands/dimension-value.js +179 -0
- package/lib/commands/dimension.js +330 -0
- package/lib/commands/integration-client.js +430 -0
- package/lib/commands/login-device.js +65 -30
- package/lib/commands/login.js +21 -10
- package/lib/commands/parameters-validate.js +78 -13
- package/lib/commands/repair-datasource-auto-rbac.js +166 -0
- package/lib/commands/repair-datasource-keys.js +10 -5
- package/lib/commands/repair-datasource.js +19 -7
- package/lib/commands/repair-env-template.js +4 -1
- package/lib/commands/repair-openapi-sync.js +172 -0
- package/lib/commands/repair-persist.js +102 -0
- package/lib/commands/repair-rbac-extract.js +27 -0
- package/lib/commands/repair-rbac-migrate.js +186 -0
- package/lib/commands/repair-rbac.js +214 -31
- package/lib/commands/repair-system-alignment.js +246 -0
- package/lib/commands/repair-system-permissions.js +168 -0
- package/lib/commands/repair.js +120 -338
- package/lib/commands/secure.js +1 -1
- package/lib/commands/setup-modes.js +468 -0
- package/lib/commands/setup-prompts.js +421 -0
- package/lib/commands/setup.js +254 -0
- package/lib/commands/teardown.js +277 -0
- package/lib/commands/up-common.js +113 -19
- package/lib/commands/up-dataplane.js +44 -19
- package/lib/commands/up-miso.js +18 -18
- package/lib/commands/upload.js +111 -23
- package/lib/commands/wizard-core-helpers.js +14 -11
- package/lib/commands/wizard-core.js +6 -5
- package/lib/commands/wizard-dataplane.js +2 -2
- package/lib/commands/wizard-entity-selection.js +4 -3
- package/lib/commands/wizard-headless.js +2 -1
- package/lib/commands/wizard.js +2 -1
- package/lib/constants/infra-compose-service-names.js +40 -0
- package/lib/core/audit-logger.js +1 -34
- package/lib/core/config-admin-email.js +56 -0
- package/lib/core/config-normalize.js +60 -0
- package/lib/core/config-registered-controller-urls.js +54 -0
- package/lib/core/config.js +33 -50
- package/lib/core/env-reader.js +16 -3
- package/lib/core/secrets-admin-env.js +101 -0
- package/lib/core/secrets-ensure-infra.js +34 -1
- package/lib/core/secrets-ensure.js +88 -66
- package/lib/core/secrets-env-content.js +428 -0
- package/lib/core/secrets-env-declarative-expand.js +170 -0
- package/lib/core/secrets-env-write.js +29 -1
- package/lib/core/secrets-load.js +252 -0
- package/lib/core/secrets-names.js +32 -0
- package/lib/core/secrets.js +17 -757
- package/lib/datasource/capability/basic-exposure.js +76 -0
- package/lib/datasource/capability/capability-diff-slice.js +41 -0
- package/lib/datasource/capability/capability-key.js +34 -0
- package/lib/datasource/capability/capability-resolve.js +172 -0
- package/lib/datasource/capability/capability-storage-keys.js +22 -0
- package/lib/datasource/capability/copy-operations.js +348 -0
- package/lib/datasource/capability/copy-test-payload.js +139 -0
- package/lib/datasource/capability/create-operations.js +235 -0
- package/lib/datasource/capability/dimension-operations.js +151 -0
- package/lib/datasource/capability/dimension-validate.js +219 -0
- package/lib/datasource/capability/json-pointer.js +31 -0
- package/lib/datasource/capability/reference-rewrite.js +51 -0
- package/lib/datasource/capability/relate-operations.js +325 -0
- package/lib/datasource/capability/relate-validate.js +219 -0
- package/lib/datasource/capability/remove-operations.js +275 -0
- package/lib/datasource/capability/run-capability-copy.js +152 -0
- package/lib/datasource/capability/run-capability-diff.js +135 -0
- package/lib/datasource/capability/run-capability-dimension.js +291 -0
- package/lib/datasource/capability/run-capability-edit.js +377 -0
- package/lib/datasource/capability/run-capability-relate.js +193 -0
- package/lib/datasource/capability/run-capability-remove.js +105 -0
- package/lib/datasource/capability/templates/minimal-fetch.json +18 -0
- package/lib/datasource/capability/validate-capability-slice.js +35 -0
- package/lib/datasource/list.js +136 -23
- package/lib/datasource/log-viewer.js +2 -4
- package/lib/datasource/unified-validation-run.js +51 -16
- package/lib/datasource/validate.js +53 -1
- package/lib/deployment/deploy-poll-ui.js +60 -0
- package/lib/deployment/deployer-status.js +29 -3
- package/lib/deployment/deployer.js +48 -30
- package/lib/deployment/environment.js +7 -2
- package/lib/deployment/poll-interval.js +72 -0
- package/lib/deployment/push.js +11 -9
- package/lib/external-system/deploy.js +9 -2
- package/lib/external-system/download.js +61 -32
- package/lib/external-system/sync-deploy-manifest.js +33 -0
- package/lib/infrastructure/index.js +49 -19
- package/lib/infrastructure/orphan-infra-docker-teardown.js +177 -0
- package/lib/internal/node-fs.js +2 -0
- package/lib/parameters/infra-kv-discovery.js +29 -4
- package/lib/parameters/infra-parameter-catalog.js +6 -3
- package/lib/parameters/infra-parameter-validate.js +67 -19
- package/lib/resolvers/datasource-resolver.js +53 -0
- package/lib/resolvers/dimension-file.js +52 -0
- package/lib/resolvers/manifest-resolver.js +133 -0
- package/lib/schema/application-schema.json +4 -0
- package/lib/schema/external-datasource.schema.json +183 -53
- package/lib/schema/external-system.schema.json +23 -10
- package/lib/schema/infra.parameter.yaml +26 -1
- package/lib/schema/wizard-config.schema.json +1 -1
- package/lib/utils/aifabrix-config-dir-walk.js +40 -0
- package/lib/utils/aifabrix-runtime-config-dir.js +26 -3
- package/lib/utils/app-config-resolver.js +24 -1
- package/lib/utils/app-run-containers.js +2 -2
- package/lib/utils/applications-config-defaults.js +206 -0
- package/lib/utils/auth-config-validator.js +2 -12
- package/lib/utils/bash-secret-env.js +59 -0
- package/lib/utils/cli-secrets-error-format.js +78 -0
- package/lib/utils/cli-test-layout-chalk.js +31 -9
- package/lib/utils/cli-utils.js +4 -36
- package/lib/utils/compose-generate-docker-compose.js +111 -6
- package/lib/utils/compose-generator.js +17 -8
- package/lib/utils/controller-url.js +50 -7
- package/lib/utils/datasource-test-run-display.js +8 -0
- package/lib/utils/dev-hosts-helper.js +3 -2
- package/lib/utils/dev-init-ssh-merge.js +2 -1
- package/lib/utils/docker-build.js +17 -9
- package/lib/utils/docker-reload-mount.js +127 -0
- package/lib/utils/env-copy.js +99 -14
- package/lib/utils/env-template.js +5 -1
- package/lib/utils/external-readme.js +71 -2
- package/lib/utils/external-system-local-test-tty.js +3 -2
- package/lib/utils/external-system-readiness-core.js +45 -12
- package/lib/utils/external-system-readiness-deploy-display.js +3 -3
- package/lib/utils/external-system-readiness-display-internals.js +33 -3
- package/lib/utils/external-system-readiness-display.js +10 -1
- package/lib/utils/file-upload.js +40 -3
- package/lib/utils/health-check-db-init.js +107 -0
- package/lib/utils/health-check-public-warn.js +69 -0
- package/lib/utils/health-check-url.js +28 -10
- package/lib/utils/health-check.js +139 -107
- package/lib/utils/help-builder.js +5 -1
- package/lib/utils/image-name.js +34 -7
- package/lib/utils/infra-optional-service-flags.js +69 -0
- package/lib/utils/installation-log-core.js +282 -0
- package/lib/utils/installation-log-record.js +237 -0
- package/lib/utils/installation-log.js +123 -0
- package/lib/utils/integration-file-backup.js +74 -0
- package/lib/utils/log-redaction.js +105 -0
- package/lib/utils/manifest-location.js +164 -0
- package/lib/utils/manifest-source-emit.js +162 -0
- package/lib/utils/mutagen-install.js +30 -3
- package/lib/utils/paths.js +308 -76
- package/lib/utils/postgres-wipe.js +212 -0
- package/lib/utils/register-aifabrix-shell-env.js +15 -0
- package/lib/utils/remote-dev-auth.js +21 -5
- package/lib/utils/remote-docker-env.js +9 -1
- package/lib/utils/remote-secrets-loader.js +49 -4
- package/lib/utils/resolve-docker-image-ref.js +9 -3
- package/lib/utils/run-cli-flags.js +29 -0
- package/lib/utils/secrets-ancestor-paths.js +47 -0
- package/lib/utils/secrets-canonical.js +10 -3
- package/lib/utils/secrets-helpers.js +17 -10
- package/lib/utils/secrets-kv-refs.js +42 -0
- package/lib/utils/secrets-kv-scope.js +19 -2
- package/lib/utils/secrets-materialize-local.js +134 -0
- package/lib/utils/secrets-path.js +26 -13
- package/lib/utils/secrets-utils.js +20 -10
- package/lib/utils/system-builder-root.js +42 -0
- package/lib/utils/url-declarative-public-base.js +80 -12
- package/lib/utils/url-declarative-resolve-build-urls.js +238 -0
- package/lib/utils/url-declarative-resolve-build.js +24 -388
- package/lib/utils/url-declarative-resolve-expand-token.js +189 -0
- package/lib/utils/url-declarative-resolve-load-doc.js +12 -3
- package/lib/utils/url-declarative-resolve-surface-state.js +102 -0
- package/lib/utils/url-declarative-resolve.js +47 -7
- package/lib/utils/url-declarative-runtime-base-path.js +52 -0
- package/lib/utils/url-declarative-vdir-inactive-env.js +2 -1
- package/lib/utils/urls-local-registry-scan.js +103 -0
- package/lib/utils/urls-local-registry.js +158 -76
- package/lib/utils/validation-poll-ui.js +81 -0
- package/lib/utils/validation-run-poll.js +29 -5
- package/lib/utils/with-muted-logger.js +53 -0
- package/package.json +3 -1
- package/templates/applications/dataplane/application.yaml +5 -1
- package/templates/applications/dataplane/rbac.yaml +10 -10
- package/templates/applications/keycloak/env.template +8 -6
- package/templates/applications/miso-controller/application.yaml +9 -0
- package/templates/applications/miso-controller/env.template +27 -29
- package/templates/applications/miso-controller/rbac.yaml +9 -9
- package/templates/external-system/README.md.hbs +83 -123
- package/.npmrc.token +0 -1
- package/.nyc_output/55e9d034-ddab-4579-a706-e02a91d75c91.json +0 -1
- package/.nyc_output/processinfo/55e9d034-ddab-4579-a706-e02a91d75c91.json +0 -1
- package/.nyc_output/processinfo/index.json +0 -1
- package/lib/api/service-users.api.js +0 -150
- package/lib/api/types/service-users.types.js +0 -65
- package/lib/cli/setup-service-user.js +0 -187
- package/lib/commands/service-user.js +0 -429
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `aifabrix teardown` — full teardown of local infra and CLI state.
|
|
3
|
+
*
|
|
4
|
+
* Performs:
|
|
5
|
+
* 1. `down-infra -v` (stop infra + apps, remove all Docker volumes).
|
|
6
|
+
* 2. Remove every entry inside `~/.aifabrix/` (or the equivalent
|
|
7
|
+
* `getAifabrixSystemDir()`-resolved directory) except `config.yaml`.
|
|
8
|
+
* This includes `secrets.local.yaml`, `admin-secrets.env`,
|
|
9
|
+
* auth/token files, and any `infra-dev*` directories.
|
|
10
|
+
*
|
|
11
|
+
* Confirmation is required by default; pass `--yes` / `-y` to skip.
|
|
12
|
+
*
|
|
13
|
+
* @fileoverview aifabrix teardown handler
|
|
14
|
+
* @author AI Fabrix Team
|
|
15
|
+
* @version 2.0.0
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
'use strict';
|
|
19
|
+
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
const inquirer = require('inquirer');
|
|
23
|
+
const chalk = require('chalk');
|
|
24
|
+
const ora = require('ora');
|
|
25
|
+
|
|
26
|
+
const config = require('../core/config');
|
|
27
|
+
const installationLog = require('../utils/installation-log');
|
|
28
|
+
const infra = require('../infrastructure');
|
|
29
|
+
const pathsUtil = require('../utils/paths');
|
|
30
|
+
const logger = require('../utils/logger');
|
|
31
|
+
const { withMutedLogger } = require('../utils/with-muted-logger');
|
|
32
|
+
const {
|
|
33
|
+
formatSuccessLine,
|
|
34
|
+
formatSuccessParagraph,
|
|
35
|
+
formatProgress,
|
|
36
|
+
successGlyph
|
|
37
|
+
} = require('../utils/cli-test-layout-chalk');
|
|
38
|
+
|
|
39
|
+
/** File name kept by teardown (lowercase exact match). */
|
|
40
|
+
const PRESERVE_FILE = 'config.yaml';
|
|
41
|
+
/** Directory preserved by teardown (holds developer TLS client certs). */
|
|
42
|
+
const PRESERVE_CERTS_DIR = 'certs';
|
|
43
|
+
|
|
44
|
+
const PRESERVE_ENTRY_NAMES = new Set([PRESERVE_FILE, PRESERVE_CERTS_DIR]);
|
|
45
|
+
|
|
46
|
+
const SEPARATOR = '────────────────────────────────────────';
|
|
47
|
+
|
|
48
|
+
function title(text) {
|
|
49
|
+
return chalk.bold(text);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function shouldUseSpinner() {
|
|
53
|
+
return Boolean(process && process.stdout && process.stdout.isTTY);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function startSpinner(text) {
|
|
57
|
+
if (!shouldUseSpinner()) {
|
|
58
|
+
logger.log(formatProgress(text));
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
return ora({ text, spinner: 'dots' }).start();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function stopSpinnerSuccess(spinner, text) {
|
|
65
|
+
if (!spinner) {
|
|
66
|
+
logger.log(formatSuccessLine(text));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
spinner.succeed(text);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Ask the user to confirm teardown unless `assumeYes` is true.
|
|
74
|
+
* @async
|
|
75
|
+
* @param {boolean} assumeYes
|
|
76
|
+
* @returns {Promise<boolean>}
|
|
77
|
+
*/
|
|
78
|
+
async function confirmTeardown(assumeYes) {
|
|
79
|
+
if (assumeYes) return true;
|
|
80
|
+
const { ok } = await inquirer.prompt([
|
|
81
|
+
{
|
|
82
|
+
type: 'confirm',
|
|
83
|
+
name: 'ok',
|
|
84
|
+
message:
|
|
85
|
+
'This will stop all infra + apps, DELETE every Docker volume, and remove every file in ~/.aifabrix/ except config.yaml and certs/. Continue?',
|
|
86
|
+
default: false
|
|
87
|
+
}
|
|
88
|
+
]);
|
|
89
|
+
return ok === true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Remove every entry in the AI Fabrix system directory except `config.yaml`.
|
|
94
|
+
* Each removal is logged. Errors per entry are caught and logged so the
|
|
95
|
+
* teardown surfaces partial-success information instead of bailing on the
|
|
96
|
+
* first ENOENT/EBUSY.
|
|
97
|
+
*
|
|
98
|
+
* @returns {{ removed: string[], failed: string[] }}
|
|
99
|
+
*/
|
|
100
|
+
function cleanAifabrixSystemDir() {
|
|
101
|
+
const dir = pathsUtil.getAifabrixSystemDir();
|
|
102
|
+
const removed = [];
|
|
103
|
+
const failed = [];
|
|
104
|
+
if (!fs.existsSync(dir)) {
|
|
105
|
+
return { removed, failed };
|
|
106
|
+
}
|
|
107
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
108
|
+
for (const entry of entries) {
|
|
109
|
+
if (PRESERVE_ENTRY_NAMES.has(entry.name)) continue;
|
|
110
|
+
const target = path.join(dir, entry.name);
|
|
111
|
+
try {
|
|
112
|
+
fs.rmSync(target, { recursive: true, force: true });
|
|
113
|
+
removed.push(target);
|
|
114
|
+
} catch (err) {
|
|
115
|
+
failed.push(target);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return { removed, failed };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Stop infra with `down-infra -v` semantics. Tolerates already-down state.
|
|
123
|
+
* @async
|
|
124
|
+
* @returns {Promise<void>}
|
|
125
|
+
*/
|
|
126
|
+
async function stopInfraQuietly() {
|
|
127
|
+
try {
|
|
128
|
+
const spin = startSpinner('Stopping infrastructure (down-infra -v)...');
|
|
129
|
+
await withMutedLogger(async() => {
|
|
130
|
+
await infra.stopInfraWithVolumes();
|
|
131
|
+
});
|
|
132
|
+
stopSpinnerSuccess(spin, 'Infrastructure stopped and volumes removed');
|
|
133
|
+
} catch (err) {
|
|
134
|
+
logger.log(
|
|
135
|
+
chalk.yellow(
|
|
136
|
+
`Infrastructure already down or could not be stopped cleanly: ${err.message}`
|
|
137
|
+
)
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function logFooterStart(label) {
|
|
143
|
+
logger.log('');
|
|
144
|
+
logger.log(SEPARATOR);
|
|
145
|
+
logger.log(title(label));
|
|
146
|
+
logger.log(SEPARATOR);
|
|
147
|
+
logger.log('');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function logFooterEnd() {
|
|
151
|
+
logger.log(SEPARATOR);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function logSection(label, value) {
|
|
155
|
+
logger.log(title(label));
|
|
156
|
+
logger.log(` ${value}`);
|
|
157
|
+
logger.log('');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function buildDeveloperLabel() {
|
|
161
|
+
const developerId = await config.getDeveloperId();
|
|
162
|
+
const idNum = typeof developerId === 'string' ? parseInt(developerId, 10) : developerId;
|
|
163
|
+
if (!Number.isFinite(idNum)) return 'unknown';
|
|
164
|
+
return `dev${String(idNum).padStart(2, '0')} (id: ${idNum})`;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function logTeardownHeader() {
|
|
168
|
+
logger.log('');
|
|
169
|
+
logger.log(title('AI Fabrix Shutdown'));
|
|
170
|
+
logger.log(SEPARATOR);
|
|
171
|
+
logger.log('');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function logTeardownFooter({ devStr, removedCount, failedCount }) {
|
|
175
|
+
logFooterStart('Stopped');
|
|
176
|
+
logSection('Developer', devStr);
|
|
177
|
+
logSection(
|
|
178
|
+
'Cleaned',
|
|
179
|
+
`${successGlyph()} Removed ${removedCount} item(s) (${PRESERVE_FILE} and ${PRESERVE_CERTS_DIR}/ preserved)`
|
|
180
|
+
);
|
|
181
|
+
logger.log(chalk.yellow('⚠ Volumes removed: all local data deleted'));
|
|
182
|
+
logger.log('');
|
|
183
|
+
if (failedCount > 0) {
|
|
184
|
+
logger.log(chalk.yellow(`⚠ Could not remove ${failedCount} item(s)`));
|
|
185
|
+
logger.log('');
|
|
186
|
+
}
|
|
187
|
+
logFooterEnd();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function cleanFilesWithSpinner() {
|
|
191
|
+
const cleanSpin = startSpinner('Removing installation files...');
|
|
192
|
+
const result = cleanAifabrixSystemDir();
|
|
193
|
+
stopSpinnerSuccess(cleanSpin, `Removed ${result.removed.length} installation item(s)`);
|
|
194
|
+
return result;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function appendTeardownAbortedLog(options) {
|
|
198
|
+
const t = new Date();
|
|
199
|
+
try {
|
|
200
|
+
await installationLog.appendInstallationRecord({
|
|
201
|
+
command: 'teardown',
|
|
202
|
+
outcome: 'aborted',
|
|
203
|
+
startedAt: t,
|
|
204
|
+
completedAt: t,
|
|
205
|
+
options
|
|
206
|
+
});
|
|
207
|
+
} catch {
|
|
208
|
+
// ignore
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function appendTeardownSuccessLog(options, startedAt) {
|
|
213
|
+
let cfg = {};
|
|
214
|
+
try {
|
|
215
|
+
cfg = await config.getConfig();
|
|
216
|
+
} catch {
|
|
217
|
+
cfg = {};
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
220
|
+
await installationLog.appendInstallationRecord({
|
|
221
|
+
command: 'teardown',
|
|
222
|
+
outcome: 'success',
|
|
223
|
+
startedAt,
|
|
224
|
+
completedAt: new Date(),
|
|
225
|
+
options,
|
|
226
|
+
infra: { cfg, options: {} },
|
|
227
|
+
cleanup: { volumesRemoved: true, configPreserved: true },
|
|
228
|
+
configExtra: {
|
|
229
|
+
controllerUrl: await installationLog.resolveControllerUrlForLog(),
|
|
230
|
+
adminEmail: await installationLog.resolveAdminEmailPresence()
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
} catch {
|
|
234
|
+
// ignore
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Run the teardown.
|
|
240
|
+
*
|
|
241
|
+
* @async
|
|
242
|
+
* @function handleTeardown
|
|
243
|
+
* @param {Object} [options] - Commander options
|
|
244
|
+
* @param {boolean} [options.yes] - Skip the confirmation prompt
|
|
245
|
+
* @returns {Promise<void>}
|
|
246
|
+
*/
|
|
247
|
+
async function handleTeardown(options = {}) {
|
|
248
|
+
const assumeYes = options.yes === true || options.assumeYes === true;
|
|
249
|
+
logTeardownHeader();
|
|
250
|
+
|
|
251
|
+
const ok = await confirmTeardown(assumeYes);
|
|
252
|
+
if (!ok) {
|
|
253
|
+
await appendTeardownAbortedLog(options);
|
|
254
|
+
logger.log(chalk.yellow('Aborted by user.'));
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const startedAt = new Date();
|
|
259
|
+
try {
|
|
260
|
+
await stopInfraQuietly();
|
|
261
|
+
const { removed, failed } = cleanFilesWithSpinner();
|
|
262
|
+
const devStr = await buildDeveloperLabel();
|
|
263
|
+
logTeardownFooter({ devStr, removedCount: removed.length, failedCount: failed.length });
|
|
264
|
+
|
|
265
|
+
logger.log(formatSuccessParagraph('aifabrix teardown complete.'));
|
|
266
|
+
} finally {
|
|
267
|
+
await appendTeardownSuccessLog(options, startedAt);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
module.exports = {
|
|
272
|
+
handleTeardown,
|
|
273
|
+
cleanAifabrixSystemDir,
|
|
274
|
+
stopInfraQuietly,
|
|
275
|
+
PRESERVE_FILE,
|
|
276
|
+
PRESERVE_CERTS_DIR
|
|
277
|
+
};
|
|
@@ -20,6 +20,24 @@ const { loadConfigFile, writeConfigFile } = require('../utils/config-format');
|
|
|
20
20
|
const { isYamlPath } = require('../utils/config-format');
|
|
21
21
|
const { copyTemplateFiles } = require('../validation/template');
|
|
22
22
|
const { ensureReadmeForAppPath, ensureReadmeForApp } = require('../app/readme');
|
|
23
|
+
const { refreshUrlsLocalRegistryFromBuilder } = require('../utils/urls-local-registry');
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {string[]} entries
|
|
27
|
+
* @returns {string[]}
|
|
28
|
+
*/
|
|
29
|
+
function uniqueResolvedRoots(entries) {
|
|
30
|
+
const seen = new Set();
|
|
31
|
+
const out = [];
|
|
32
|
+
for (const e of entries) {
|
|
33
|
+
const r = path.resolve(e);
|
|
34
|
+
if (!seen.has(r)) {
|
|
35
|
+
seen.add(r);
|
|
36
|
+
out.push(r);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
23
41
|
|
|
24
42
|
/**
|
|
25
43
|
* Copy template to a target path if application config is missing there.
|
|
@@ -98,8 +116,9 @@ function patchEnvOutputPathInFile(configPath) {
|
|
|
98
116
|
function validateEnvOutputPathFolderOrNull(appName) {
|
|
99
117
|
if (!appName || typeof appName !== 'string') return;
|
|
100
118
|
const pathsToPatch = [pathsUtil.getBuilderPath(appName)];
|
|
119
|
+
const envBuilderRoot = process.env.AIFABRIX_BUILDER_DIR && String(process.env.AIFABRIX_BUILDER_DIR).trim();
|
|
101
120
|
const cwdBuilderPath = path.join(process.cwd(), 'builder', appName);
|
|
102
|
-
if (path.resolve(cwdBuilderPath) !== path.resolve(pathsToPatch[0])) {
|
|
121
|
+
if (envBuilderRoot && path.resolve(cwdBuilderPath) !== path.resolve(pathsToPatch[0])) {
|
|
103
122
|
pathsToPatch.push(cwdBuilderPath);
|
|
104
123
|
}
|
|
105
124
|
for (const appPath of pathsToPatch) {
|
|
@@ -176,49 +195,88 @@ function patchEnvOutputPathForDeployOnly(appName) {
|
|
|
176
195
|
*
|
|
177
196
|
* @returns {Promise<void>}
|
|
178
197
|
*/
|
|
179
|
-
async function applyUpPlatformForceConfig() {
|
|
198
|
+
async function applyUpPlatformForceConfig(opts = {}) {
|
|
199
|
+
const silent = Boolean(opts.silent);
|
|
180
200
|
const deviceCleared = await config.clearAllDeviceTokens();
|
|
181
201
|
const clientCleared = await config.clearAllClientTokens();
|
|
182
202
|
await config.setCurrentEnvironment('dev');
|
|
183
203
|
const defaultControllerUrl = await getDefaultControllerUrl();
|
|
184
204
|
await config.setControllerUrl(defaultControllerUrl);
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
205
|
+
|
|
206
|
+
const summary = { deviceCleared, clientCleared, defaultControllerUrl, environment: 'dev' };
|
|
207
|
+
if (!silent) {
|
|
208
|
+
logger.log(
|
|
209
|
+
chalk.blue(
|
|
210
|
+
`--force: cleared ${deviceCleared} device token(s) and ${clientCleared} client token(s); ` +
|
|
211
|
+
`environment set to dev; default controller set to ${defaultControllerUrl} (run aifabrix login after platform is up)`
|
|
212
|
+
)
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
return summary;
|
|
191
216
|
}
|
|
192
217
|
|
|
193
218
|
/**
|
|
194
|
-
*
|
|
195
|
-
*
|
|
219
|
+
* True when resolved path is the root itself or a subdirectory of an allowed builder root.
|
|
220
|
+
* @param {string} resolvedAppPath
|
|
221
|
+
* @param {string[]} allowedRoots - Absolute resolved directory roots
|
|
222
|
+
* @returns {boolean}
|
|
223
|
+
*/
|
|
224
|
+
function isUnderAllowedBuilderRoot(resolvedAppPath, allowedRoots) {
|
|
225
|
+
for (const root of allowedRoots) {
|
|
226
|
+
const r = path.resolve(root);
|
|
227
|
+
if (resolvedAppPath === r || resolvedAppPath.startsWith(r + path.sep)) {
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Removes builder app directories for the given app names. Only removes paths under an allowed
|
|
236
|
+
* builder root (project `builder/` or `~/.aifabrix/builder/`) to prevent path traversal.
|
|
237
|
+
* Uses {@link pathsUtil.getBuilderPath} for each app (system apps may resolve under the config dir).
|
|
196
238
|
*
|
|
197
239
|
* @param {string[]} appNames - Application names (e.g. ['keycloak', 'miso-controller', 'dataplane'])
|
|
198
240
|
* @returns {Promise<void>}
|
|
199
|
-
* @throws {Error} If any path is outside builder
|
|
241
|
+
* @throws {Error} If any path is outside allowed builder roots (path traversal attempt)
|
|
200
242
|
*/
|
|
201
|
-
async function cleanBuilderAppDirs(appNames) {
|
|
243
|
+
async function cleanBuilderAppDirs(appNames, opts = {}) {
|
|
244
|
+
const silent = Boolean(opts.silent);
|
|
202
245
|
if (!Array.isArray(appNames) || appNames.length === 0) return;
|
|
203
|
-
const
|
|
246
|
+
const allowedRoots = uniqueResolvedRoots([
|
|
247
|
+
path.join(process.cwd(), 'builder'),
|
|
248
|
+
pathsUtil.getBuilderRoot(),
|
|
249
|
+
pathsUtil.getSystemBuilderRoot()
|
|
250
|
+
]);
|
|
251
|
+
const cleaned = [];
|
|
204
252
|
for (const appName of appNames) {
|
|
205
253
|
if (!appName || typeof appName !== 'string') continue;
|
|
206
254
|
const appPath = path.resolve(pathsUtil.getBuilderPath(appName));
|
|
207
|
-
if (!
|
|
208
|
-
throw new Error(
|
|
255
|
+
if (!isUnderAllowedBuilderRoot(appPath, allowedRoots)) {
|
|
256
|
+
throw new Error(
|
|
257
|
+
`Path ${appPath} is outside allowed builder roots (${allowedRoots.join(', ')}); refusing to clean`
|
|
258
|
+
);
|
|
209
259
|
}
|
|
210
260
|
if (fs.existsSync(appPath)) {
|
|
211
261
|
fs.rmSync(appPath, { recursive: true });
|
|
212
|
-
|
|
262
|
+
cleaned.push(appName);
|
|
263
|
+
if (!silent) {
|
|
264
|
+
logger.log(chalk.blue(`Cleaned builder/${appName}`));
|
|
265
|
+
}
|
|
213
266
|
}
|
|
214
267
|
}
|
|
268
|
+
return cleaned;
|
|
215
269
|
}
|
|
216
270
|
|
|
217
271
|
/**
|
|
218
272
|
* Ensures builder app directory exists from template if application config is missing.
|
|
219
273
|
* If builder/<appName>/application config does not exist, copies from templates/applications/<appName>.
|
|
220
274
|
* Uses AIFABRIX_BUILDER_DIR when set (e.g. by up-miso/up-dataplane from config aifabrix-env-config).
|
|
221
|
-
* When
|
|
275
|
+
* When `process.env.AIFABRIX_BUILDER_DIR` is set and the primary app path differs from
|
|
276
|
+
* `cwd/builder/<appName>`, also copies into `cwd/builder/<appName>` so the repo tree is not empty
|
|
277
|
+
* while using a custom builder root. Skips that extra copy for platform apps (`keycloak`,
|
|
278
|
+
* `miso-controller`, `dataplane`) so they materialize only under the system builder root, and when
|
|
279
|
+
* no custom dir is in use.
|
|
222
280
|
*
|
|
223
281
|
* @async
|
|
224
282
|
* @function ensureAppFromTemplate
|
|
@@ -241,8 +299,13 @@ async function ensureAppFromTemplate(appName) {
|
|
|
241
299
|
logger.log(formatSuccessLine(`Copied template for ${appName}`));
|
|
242
300
|
}
|
|
243
301
|
|
|
302
|
+
const envBuilderRoot = process.env.AIFABRIX_BUILDER_DIR && String(process.env.AIFABRIX_BUILDER_DIR).trim();
|
|
244
303
|
const cwdBuilderPath = path.join(process.cwd(), 'builder', appName);
|
|
245
|
-
if (
|
|
304
|
+
if (
|
|
305
|
+
envBuilderRoot &&
|
|
306
|
+
path.resolve(cwdBuilderPath) !== path.resolve(appPath) &&
|
|
307
|
+
!pathsUtil.isSystemBuilderAppName(appName)
|
|
308
|
+
) {
|
|
246
309
|
const cwdCopied = await ensureTemplateAtPath(appName, cwdBuilderPath);
|
|
247
310
|
if (cwdCopied) {
|
|
248
311
|
logger.log(chalk.blue(`Creating builder/${appName} in project (from template)...`));
|
|
@@ -254,11 +317,42 @@ async function ensureAppFromTemplate(appName) {
|
|
|
254
317
|
return primaryCopied;
|
|
255
318
|
}
|
|
256
319
|
|
|
320
|
+
/**
|
|
321
|
+
* Merge builder/packages `application.yaml` into `~/.aifabrix/urls.local.yaml`.
|
|
322
|
+
* Same scan as the end of {@link prepareUrlsLocalRegistryForUpPlatform}; call after platform app
|
|
323
|
+
* templates exist (e.g. `up-miso`, `up-dataplane`) so declarative `url://` and tooling see ports/patterns.
|
|
324
|
+
*/
|
|
325
|
+
function refreshUrlsLocalRegistryForCurrentProject() {
|
|
326
|
+
try {
|
|
327
|
+
refreshUrlsLocalRegistryFromBuilder(pathsUtil.getProjectRoot());
|
|
328
|
+
} catch (error) {
|
|
329
|
+
logger.warn(chalk.yellow(`⚠ Could not refresh URLs registry: ${error.message}`));
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* For `aifabrix up-platform` only: materialize all three platform apps from templates if missing
|
|
335
|
+
* (paths follow cwd / material `builder/` only — no `AIFABRIX_BUILDER_DIR` override), then refresh
|
|
336
|
+
* `~/.aifabrix/urls.local.yaml` so declarative `url://` expansion (e.g. cross-references between
|
|
337
|
+
* miso-controller, dataplane, keycloak) sees every app's port and pattern before Keycloak or Miso
|
|
338
|
+
* resolve their `.env` files.
|
|
339
|
+
*
|
|
340
|
+
* @returns {Promise<void>}
|
|
341
|
+
*/
|
|
342
|
+
async function prepareUrlsLocalRegistryForUpPlatform() {
|
|
343
|
+
await ensureAppFromTemplate('keycloak');
|
|
344
|
+
await ensureAppFromTemplate('miso-controller');
|
|
345
|
+
await ensureAppFromTemplate('dataplane');
|
|
346
|
+
refreshUrlsLocalRegistryForCurrentProject();
|
|
347
|
+
}
|
|
348
|
+
|
|
257
349
|
module.exports = {
|
|
258
350
|
applyUpPlatformForceConfig,
|
|
259
351
|
cleanBuilderAppDirs,
|
|
260
352
|
ensureAppFromTemplate,
|
|
261
353
|
patchEnvOutputPathForDeployOnly,
|
|
262
354
|
validateEnvOutputPathFolderOrNull,
|
|
263
|
-
getEnvOutputPathFolder
|
|
355
|
+
getEnvOutputPathFolder,
|
|
356
|
+
prepareUrlsLocalRegistryForUpPlatform,
|
|
357
|
+
refreshUrlsLocalRegistryForCurrentProject
|
|
264
358
|
};
|
|
@@ -2,17 +2,16 @@ const { formatSuccessLine, formatSuccessParagraph } = require('../utils/cli-test
|
|
|
2
2
|
/**
|
|
3
3
|
* AI Fabrix Builder - Up Dataplane Command
|
|
4
4
|
*
|
|
5
|
-
* Always local deployment:
|
|
6
|
-
* deployment manifest to Miso Controller, then runs
|
|
7
|
-
* (same as aifabrix deploy dataplane --local). If app is already
|
|
8
|
-
*
|
|
5
|
+
* Always local deployment: requires dev infra (same gate as up-miso), then registers or
|
|
6
|
+
* rotates dataplane in dev, sends deployment manifest to Miso Controller, then runs dataplane
|
|
7
|
+
* locally (same as aifabrix deploy dataplane --local). If app is already registered, uses
|
|
8
|
+
* rotate-secret; otherwise registers.
|
|
9
9
|
*
|
|
10
10
|
* @fileoverview up-dataplane command implementation
|
|
11
11
|
* @author AI Fabrix Team
|
|
12
12
|
* @version 2.0.0
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
const path = require('path');
|
|
16
15
|
const readline = require('readline');
|
|
17
16
|
const chalk = require('chalk');
|
|
18
17
|
const pathsUtil = require('../utils/paths');
|
|
@@ -29,7 +28,8 @@ const { checkApplicationExists } = require('../utils/app-existence');
|
|
|
29
28
|
const { checkHealthEndpoint } = require('../utils/health-check');
|
|
30
29
|
const { validateControllerUrl } = require('../utils/auth-config-validator');
|
|
31
30
|
const app = require('../app');
|
|
32
|
-
const {
|
|
31
|
+
const { assertDevInfraUp } = require('./dev-infra-gate');
|
|
32
|
+
const { ensureAppFromTemplate, validateEnvOutputPathFolderOrNull, refreshUrlsLocalRegistryForCurrentProject } = require('./up-common');
|
|
33
33
|
|
|
34
34
|
const CONTROLLER_HEALTH_PATH = '/health';
|
|
35
35
|
|
|
@@ -130,7 +130,14 @@ async function registerOrRotateDataplane(options, controllerUrl, environmentKey,
|
|
|
130
130
|
*/
|
|
131
131
|
async function deployDataplaneToController(options) {
|
|
132
132
|
const imageOverride = options.image || buildDataplaneImageRef(options);
|
|
133
|
-
const deployOpts = {
|
|
133
|
+
const deployOpts = {
|
|
134
|
+
imageOverride,
|
|
135
|
+
image: imageOverride,
|
|
136
|
+
registryMode: options.registryMode,
|
|
137
|
+
// Guided up-platform already shows a top-level spinner for the dataplane step.
|
|
138
|
+
// Avoid nested deploy polling spinners/logs.
|
|
139
|
+
silentPoll: options.platformInstall === true
|
|
140
|
+
};
|
|
134
141
|
await app.deployApp('dataplane', deployOpts);
|
|
135
142
|
}
|
|
136
143
|
|
|
@@ -160,6 +167,20 @@ function buildDataplaneImageRef(options = {}) {
|
|
|
160
167
|
}
|
|
161
168
|
}
|
|
162
169
|
|
|
170
|
+
function emitDataplaneManifestLineFromBuilder() {
|
|
171
|
+
const { emitSystemBuilderAppManifestLineIfTTY } = require('../utils/manifest-source-emit');
|
|
172
|
+
emitSystemBuilderAppManifestLineIfTTY(logger, 'dataplane');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function assertDevEnvironmentForDataplane(cfg) {
|
|
176
|
+
const environment = (cfg && cfg.environment) ? cfg.environment : 'dev';
|
|
177
|
+
if (environment !== 'dev') {
|
|
178
|
+
throw new Error(
|
|
179
|
+
'Dataplane is only supported in dev environment. Set with: aifabrix auth --set-environment dev.'
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
163
184
|
/**
|
|
164
185
|
* Handle up-dataplane command: ensure logged in, environment dev, ensure dataplane,
|
|
165
186
|
* register or rotate (if already registered), deploy (send manifest to controller),
|
|
@@ -171,40 +192,44 @@ function buildDataplaneImageRef(options = {}) {
|
|
|
171
192
|
* @param {string} [options.registry] - Override registry for dataplane
|
|
172
193
|
* @param {string} [options.registryMode] - Override registry mode (acr|external)
|
|
173
194
|
* @param {string} [options.image] - Override image reference for dataplane
|
|
195
|
+
* @param {boolean} [options.skipInfraCheck] - When true, skip Postgres/Redis gate (caller already verified, e.g. guided up-dataplane).
|
|
174
196
|
* @returns {Promise<void>}
|
|
175
|
-
* @throws {Error} If not logged in, environment not dev, or any step fails
|
|
197
|
+
* @throws {Error} If infra not up, controller unavailable, not logged in, environment not dev, or any step fails
|
|
176
198
|
*/
|
|
177
199
|
async function handleUpDataplane(options = {}) {
|
|
178
|
-
const builderDir = await config.getAifabrixBuilderDir();
|
|
179
|
-
if (builderDir) {
|
|
180
|
-
process.env.AIFABRIX_BUILDER_DIR = path.resolve(builderDir);
|
|
181
|
-
}
|
|
182
200
|
logger.log(chalk.blue('Starting up-dataplane (register/rotate, deploy, then run dataplane locally)...\n'));
|
|
183
201
|
|
|
202
|
+
if (options.skipInfraCheck !== true) {
|
|
203
|
+
await assertDevInfraUp();
|
|
204
|
+
}
|
|
205
|
+
|
|
184
206
|
const controllerUrl = await resolveControllerUrlWithHealthCheck();
|
|
185
207
|
const environmentKey = await resolveEnvironment();
|
|
186
208
|
const authConfig = await checkAuthentication(controllerUrl, environmentKey, { throwOnFailure: true });
|
|
187
209
|
|
|
188
210
|
const cfg = await config.getConfig();
|
|
189
|
-
|
|
190
|
-
if (environment !== 'dev') {
|
|
191
|
-
throw new Error(
|
|
192
|
-
'Dataplane is only supported in dev environment. Set with: aifabrix auth --set-environment dev.'
|
|
193
|
-
);
|
|
194
|
-
}
|
|
211
|
+
assertDevEnvironmentForDataplane(cfg);
|
|
195
212
|
logger.log(formatSuccessLine('Logged in and environment is dev'));
|
|
196
213
|
|
|
197
214
|
await ensureAppFromTemplate('dataplane');
|
|
198
215
|
// If envOutputPath target folder does not exist, set envOutputPath to null
|
|
199
216
|
validateEnvOutputPathFolderOrNull('dataplane');
|
|
200
217
|
|
|
218
|
+
refreshUrlsLocalRegistryForCurrentProject();
|
|
219
|
+
|
|
220
|
+
if (options.platformInstall !== true) {
|
|
221
|
+
emitDataplaneManifestLineFromBuilder();
|
|
222
|
+
}
|
|
223
|
+
|
|
201
224
|
await registerOrRotateDataplane(options, controllerUrl, environmentKey, authConfig);
|
|
202
225
|
|
|
203
226
|
await deployDataplaneToController(options);
|
|
204
227
|
logger.log('');
|
|
205
228
|
await app.runApp('dataplane', {
|
|
206
229
|
skipEnvOutputPath: true,
|
|
207
|
-
registry: options.registry || undefined
|
|
230
|
+
registry: options.registry || undefined,
|
|
231
|
+
base: options.base !== false,
|
|
232
|
+
skipManifestMetadataLine: true
|
|
208
233
|
});
|
|
209
234
|
|
|
210
235
|
logger.log(formatSuccessParagraph('up-dataplane complete. Dataplane is registered, deployed in dev, and running locally.'));
|
package/lib/commands/up-miso.js
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { formatSuccessParagraph } = require('../utils/cli-test-layout-chalk');
|
|
2
2
|
/**
|
|
3
3
|
* AI Fabrix Builder - Up Miso Command
|
|
4
4
|
*
|
|
5
5
|
* Installs keycloak and miso-controller from images (no build). For dataplane, use up-dataplane.
|
|
6
|
-
*
|
|
6
|
+
* Ensures dev Postgres/Redis are up, then sets dev secrets and resolves (no force; existing .env values preserved).
|
|
7
7
|
*
|
|
8
8
|
* @fileoverview up-miso command implementation
|
|
9
9
|
* @author AI Fabrix Team
|
|
10
10
|
* @version 2.0.0
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
const path = require('path');
|
|
14
13
|
const chalk = require('chalk');
|
|
15
14
|
const logger = require('../utils/logger');
|
|
16
|
-
const config = require('../core/config');
|
|
17
|
-
const infra = require('../infrastructure');
|
|
18
15
|
const app = require('../app');
|
|
19
|
-
const {
|
|
16
|
+
const { assertDevInfraUp } = require('./dev-infra-gate');
|
|
17
|
+
const {
|
|
18
|
+
ensureAppFromTemplate,
|
|
19
|
+
patchEnvOutputPathForDeployOnly,
|
|
20
|
+
validateEnvOutputPathFolderOrNull,
|
|
21
|
+
refreshUrlsLocalRegistryForCurrentProject
|
|
22
|
+
} = require('./up-common');
|
|
20
23
|
|
|
21
24
|
/**
|
|
22
25
|
* Parse --image options array into map { keycloak?: string, 'miso-controller'?: string }
|
|
@@ -45,11 +48,14 @@ function parseImageOptions(imageOpts) {
|
|
|
45
48
|
*/
|
|
46
49
|
async function runMisoApps(options) {
|
|
47
50
|
const imageMap = parseImageOptions(options.image);
|
|
51
|
+
const useBaseImage = options.base !== false;
|
|
48
52
|
const common = {
|
|
49
53
|
registry: options.registry,
|
|
50
54
|
registryMode: options.registryMode,
|
|
51
55
|
skipEnvOutputPath: true,
|
|
52
|
-
skipInfraCheck: true
|
|
56
|
+
skipInfraCheck: true,
|
|
57
|
+
base: useBaseImage,
|
|
58
|
+
skipManifestMetadataLine: true
|
|
53
59
|
};
|
|
54
60
|
const keycloakRunOpts = { ...common };
|
|
55
61
|
if (imageMap.keycloak) {
|
|
@@ -59,9 +65,12 @@ async function runMisoApps(options) {
|
|
|
59
65
|
if (imageMap['miso-controller']) {
|
|
60
66
|
misoRunOpts.image = imageMap['miso-controller'];
|
|
61
67
|
}
|
|
68
|
+
const { emitSystemBuilderAppManifestLineIfTTY } = require('../utils/manifest-source-emit');
|
|
62
69
|
logger.log(chalk.blue('Starting keycloak...'));
|
|
70
|
+
emitSystemBuilderAppManifestLineIfTTY(logger, 'keycloak');
|
|
63
71
|
await app.runApp('keycloak', keycloakRunOpts);
|
|
64
72
|
logger.log(chalk.blue('Starting miso-controller...'));
|
|
73
|
+
emitSystemBuilderAppManifestLineIfTTY(logger, 'miso-controller');
|
|
65
74
|
await app.runApp('miso-controller', misoRunOpts);
|
|
66
75
|
}
|
|
67
76
|
|
|
@@ -78,18 +87,8 @@ async function runMisoApps(options) {
|
|
|
78
87
|
* @throws {Error} If infra not up or any step fails
|
|
79
88
|
*/
|
|
80
89
|
async function handleUpMiso(options = {}) {
|
|
81
|
-
const builderDir = await config.getAifabrixBuilderDir();
|
|
82
|
-
if (builderDir) {
|
|
83
|
-
process.env.AIFABRIX_BUILDER_DIR = path.resolve(builderDir);
|
|
84
|
-
}
|
|
85
90
|
logger.log(chalk.blue('Starting up-miso (keycloak + miso-controller from images)...\n'));
|
|
86
|
-
|
|
87
|
-
const health = await infra.checkInfraHealth(undefined, { strict: true });
|
|
88
|
-
const allHealthy = Object.values(health).every(status => status === 'healthy');
|
|
89
|
-
if (!allHealthy) {
|
|
90
|
-
throw new Error('Infrastructure is not up. Run \'aifabrix up-infra\' first.');
|
|
91
|
-
}
|
|
92
|
-
logger.log(formatSuccessLine('Infrastructure is up'));
|
|
91
|
+
await assertDevInfraUp();
|
|
93
92
|
await ensureAppFromTemplate('keycloak');
|
|
94
93
|
await ensureAppFromTemplate('miso-controller');
|
|
95
94
|
// If envOutputPath target folder does not exist, set envOutputPath to null
|
|
@@ -98,6 +97,7 @@ async function handleUpMiso(options = {}) {
|
|
|
98
97
|
// Deploy-only: do not copy .env to repo paths; patch variables so envOutputPath is null
|
|
99
98
|
patchEnvOutputPathForDeployOnly('keycloak');
|
|
100
99
|
patchEnvOutputPathForDeployOnly('miso-controller');
|
|
100
|
+
refreshUrlsLocalRegistryForCurrentProject();
|
|
101
101
|
await runMisoApps(options);
|
|
102
102
|
logger.log(formatSuccessParagraph('up-miso complete. Keycloak and miso-controller are running.') +
|
|
103
103
|
chalk.gray('\n Run onboarding and register Keycloak from the miso-controller repo if needed. Use \'aifabrix up-dataplane\' for dataplane.'));
|