@aifabrix/builder 2.47.4 → 2.49.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/jest.isolated-projects.js +7 -0
- package/jest.projects.js +16 -0
- package/lib/api/applications.api.js +23 -0
- package/lib/api/dev.api.js +1 -1
- package/lib/api/index.js +5 -2
- package/lib/api/types/dev.types.js +4 -3
- package/lib/app/deploy-config.js +6 -4
- package/lib/app/register.js +21 -19
- package/lib/app/rotate-secret.js +39 -16
- package/lib/app/run-container-start.js +0 -9
- package/lib/app/run-helpers.js +8 -4
- package/lib/app/run-reload-sync.js +16 -18
- package/lib/app/run-stop-containers.js +48 -5
- package/lib/app/run.js +6 -3
- package/lib/app/show.js +2 -2
- package/lib/build/index.js +12 -49
- package/lib/build/integration-docker-staging.js +35 -0
- package/lib/build/standard-docker-build.js +113 -0
- package/lib/cli/infra-guided-auth.js +42 -6
- package/lib/cli/infra-guided-footers.js +164 -0
- package/lib/cli/infra-guided-spinners.js +57 -0
- package/lib/cli/infra-guided.js +41 -179
- package/lib/cli/setup-app.js +5 -1
- package/lib/cli/setup-dev.js +3 -2
- package/lib/cli/setup-infra.js +3 -2
- package/lib/cli/setup-platform.js +3 -0
- package/lib/commands/dev-init.js +18 -0
- package/lib/commands/login-device.js +6 -2
- package/lib/commands/login.js +4 -1
- package/lib/commands/setup-modes.js +19 -3
- package/lib/commands/setup-platform-auth.js +25 -0
- package/lib/commands/setup-prompts-admin.js +9 -0
- package/lib/commands/setup-prompts-platform-mode.js +11 -1
- package/lib/commands/setup.js +60 -7
- package/lib/commands/up-dataplane-bootstrap.js +149 -0
- package/lib/commands/up-dataplane-credentials.js +104 -6
- package/lib/commands/up-dataplane.js +74 -11
- package/lib/core/secrets-env-declarative-expand.js +35 -23
- package/lib/core/setup-platform-mode.js +59 -9
- package/lib/deployment/deployer-status.js +26 -3
- package/lib/deployment/deployer.js +7 -14
- package/lib/external-system/download-helpers.js +10 -1
- package/lib/infrastructure/compose.js +40 -12
- package/lib/infrastructure/services.js +15 -3
- package/lib/infrastructure/traefik-tls-dynamic.js +88 -0
- package/lib/parameters/infra-kv-discovery.js +4 -3
- package/lib/utils/aifabrix-runtime-config-dir.js +2 -1
- package/lib/utils/app-bootstrap-api.js +53 -0
- package/lib/utils/app-run-containers.js +14 -3
- package/lib/utils/applications-config-defaults.js +19 -3
- package/lib/utils/compose-generate-docker-compose.js +18 -6
- package/lib/utils/compose-generator.js +34 -15
- package/lib/utils/compose-traefik-ingress-base.js +13 -14
- package/lib/utils/config-paths.js +8 -3
- package/lib/utils/dev-ca-docker-augment.js +54 -0
- package/lib/utils/dev-user-groups.js +1 -0
- package/lib/utils/docker-daemon-tls-ca.js +363 -0
- package/lib/utils/docker-reload-mount.js +12 -1
- package/lib/utils/ensure-dev-certs-for-remote-docker.js +5 -0
- package/lib/utils/external-env-template.js +53 -18
- package/lib/utils/health-check-poll-ui.js +84 -0
- package/lib/utils/health-check-url.js +54 -34
- package/lib/utils/health-check.js +43 -16
- package/lib/utils/infra-optional-service-flags.js +31 -2
- package/lib/utils/mutagen.js +7 -4
- package/lib/utils/platform-controller-url.js +23 -1
- package/lib/utils/promote-dev-docker-image.js +170 -0
- package/lib/utils/refresh-remote-settings.js +67 -0
- package/lib/utils/remote-docker-env.js +22 -7
- package/lib/utils/remote-host-for-front-door.js +43 -0
- package/lib/utils/run-cli-flags.js +37 -1
- package/lib/utils/secrets-helpers.js +9 -14
- package/lib/utils/secrets-kv-refs.js +47 -3
- package/lib/utils/secrets-missing-error.js +1 -9
- package/lib/utils/token-manager-client-credentials.js +11 -1
- package/lib/utils/url-declarative-public-base.js +11 -4
- package/lib/utils/url-declarative-resolve-build-urls.js +11 -2
- package/lib/utils/url-declarative-resolve-expand-token.js +12 -1
- package/lib/utils/url-declarative-resolve-load-doc.js +30 -11
- package/lib/utils/url-declarative-resolve.js +2 -0
- package/lib/utils/urls-local-registry-scan.js +95 -10
- package/lib/utils/urls-local-registry.js +24 -1
- package/lib/utils/worker-sidecars.js +28 -1
- package/lib/validation/external-system-auth-rules.js +45 -7
- package/package.json +2 -1
- package/scripts/test-dataplane-bootstrap.js +331 -0
- package/templates/applications/dataplane/env.template +22 -5
- package/templates/applications/dataplane/rbac.yaml +11 -0
- package/templates/applications/miso-controller/application.yaml +1 -1
- package/templates/applications/miso-controller/env.template +3 -0
- package/templates/infra/compose.yaml.hbs +13 -9
- package/templates/python/docker-compose.hbs +3 -0
- package/templates/typescript/docker-compose.hbs +3 -0
package/lib/build/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const {
|
|
2
2
|
formatSuccessLine,
|
|
3
|
-
formatSuccessParagraph,
|
|
4
3
|
formatProgress,
|
|
5
4
|
formatWarningLine,
|
|
6
5
|
sectionTitle,
|
|
@@ -31,12 +30,10 @@ const secrets = require('../core/secrets');
|
|
|
31
30
|
const config = require('../core/config');
|
|
32
31
|
const logger = require('../utils/logger');
|
|
33
32
|
const dockerfileUtils = require('../utils/dockerfile-utils');
|
|
34
|
-
const dockerBuild = require('../utils/docker-build');
|
|
35
33
|
const buildCopy = require('../utils/build-copy');
|
|
36
34
|
const { resolveBuildDockerTagNames } = require('../utils/build-resolve-image');
|
|
37
35
|
const buildHelpers = require('../utils/build-helpers');
|
|
38
|
-
const {
|
|
39
|
-
const { resolveDockerBuildArgsForApp } = require('./docker-build-args');
|
|
36
|
+
const { runStandardDockerBuild } = require('./standard-docker-build');
|
|
40
37
|
|
|
41
38
|
/**
|
|
42
39
|
* Loads application config for an application
|
|
@@ -353,18 +350,6 @@ function prepareBuildContext(buildConfig, devDir) {
|
|
|
353
350
|
return contextPath;
|
|
354
351
|
}
|
|
355
352
|
|
|
356
|
-
/**
|
|
357
|
-
* Handle Dockerfile generation
|
|
358
|
-
* @async
|
|
359
|
-
* @param {string} appName - Application name
|
|
360
|
-
* @param {Object} params - Parameters
|
|
361
|
-
* @param {string} params.devDir - Developer directory
|
|
362
|
-
* @param {Object} params.buildConfig - Build configuration
|
|
363
|
-
* @param {string} params.contextPath - Build context path
|
|
364
|
-
* @param {Object} params.appConfig - Application configuration
|
|
365
|
-
* @param {Object} options - Build options
|
|
366
|
-
* @returns {Promise<string>} Dockerfile path
|
|
367
|
-
*/
|
|
368
353
|
async function handleDockerfileGeneration(appName, params, options, buildHelpers) {
|
|
369
354
|
const { devDir, buildConfig, contextPath, appConfig } = params;
|
|
370
355
|
const appDockerfilePath = path.join(devDir, 'Dockerfile');
|
|
@@ -393,38 +378,6 @@ async function handleDockerfileGeneration(appName, params, options, buildHelpers
|
|
|
393
378
|
}, generateDockerfile);
|
|
394
379
|
}
|
|
395
380
|
|
|
396
|
-
/**
|
|
397
|
-
* Standard Docker build path after CLI header is printed (non-external apps).
|
|
398
|
-
* @param {string} appName
|
|
399
|
-
* @param {Object} options
|
|
400
|
-
* @returns {Promise<string>} Built image ref e.g. name:tag
|
|
401
|
-
*/
|
|
402
|
-
async function runStandardDockerBuild(appName, options) {
|
|
403
|
-
const { buildConfig } = await buildHelpers.loadAndValidateConfig(appName);
|
|
404
|
-
const { emitManifestMetadataLineIfTTY } = require('../utils/manifest-source-emit');
|
|
405
|
-
const { appPath } = await detectAppType(appName);
|
|
406
|
-
emitManifestMetadataLineIfTTY(logger, { appKey: appName, appPath, envOnly: false, json: false });
|
|
407
|
-
const { devDir, effectiveImageName, imageName, appConfig } = await prepareDevDirectory(appName, buildConfig, options);
|
|
408
|
-
const contextPath = prepareBuildContext(buildConfig, devDir);
|
|
409
|
-
const dockerfilePath = await handleDockerfileGeneration(appName, {
|
|
410
|
-
devDir,
|
|
411
|
-
buildConfig,
|
|
412
|
-
contextPath,
|
|
413
|
-
appConfig
|
|
414
|
-
}, options, buildHelpers);
|
|
415
|
-
await ensureRunSecretsForApp(appName);
|
|
416
|
-
const buildArgs = await resolveDockerBuildArgsForApp(appName, contextPath);
|
|
417
|
-
const buildOptions = { ...options, buildArgs };
|
|
418
|
-
const tag = options.tag || 'latest';
|
|
419
|
-
if (typeof tag === 'string' && tag.includes(',')) {
|
|
420
|
-
throw new Error('Use a single image tag per build (comma-separated multiple tags are not supported).');
|
|
421
|
-
}
|
|
422
|
-
await dockerBuild.executeDockerBuildWithTag(effectiveImageName, imageName, dockerfilePath, contextPath, tag, buildOptions);
|
|
423
|
-
await postBuildTasks(appName, buildConfig);
|
|
424
|
-
logger.log(formatSuccessParagraph('Build completed successfully!'));
|
|
425
|
-
return `${effectiveImageName}:${tag}`;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
381
|
/**
|
|
429
382
|
* Builds a container image for the specified application
|
|
430
383
|
* Auto-detects runtime and generates Dockerfile if needed
|
|
@@ -458,4 +411,14 @@ async function buildApp(appName, options = {}) {
|
|
|
458
411
|
throw new Error(`Build failed: ${error.message}`);
|
|
459
412
|
}
|
|
460
413
|
}
|
|
461
|
-
module.exports = {
|
|
414
|
+
module.exports = {
|
|
415
|
+
loadVariablesYaml,
|
|
416
|
+
resolveContextPath,
|
|
417
|
+
detectLanguage,
|
|
418
|
+
generateDockerfile,
|
|
419
|
+
buildApp,
|
|
420
|
+
postBuildTasks,
|
|
421
|
+
prepareDevDirectory,
|
|
422
|
+
prepareBuildContext,
|
|
423
|
+
handleDockerfileGeneration
|
|
424
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-build integration manifest staging for Docker context.
|
|
3
|
+
* @fileoverview Runs scripts/stage_integration_for_docker.py when present in build context
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const fsSync = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { promisify } = require('util');
|
|
11
|
+
const { exec } = require('child_process');
|
|
12
|
+
const logger = require('../utils/logger');
|
|
13
|
+
const {
|
|
14
|
+
formatProgress,
|
|
15
|
+
formatSuccessLine
|
|
16
|
+
} = require('../utils/cli-test-layout-chalk');
|
|
17
|
+
|
|
18
|
+
const run = promisify(exec);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* When repo ships scripts/stage_integration_for_docker.py, run it before docker build.
|
|
22
|
+
* @param {string} contextPath
|
|
23
|
+
* @returns {Promise<void>}
|
|
24
|
+
*/
|
|
25
|
+
async function maybeStageIntegrationForDockerBuild(contextPath) {
|
|
26
|
+
const scriptPath = path.join(contextPath, 'scripts/stage_integration_for_docker.py');
|
|
27
|
+
if (!fsSync.existsSync(scriptPath)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
logger.log(formatProgress('Staging integration runtime manifests for Docker…'));
|
|
31
|
+
await run('python3 scripts/stage_integration_for_docker.py', { cwd: contextPath });
|
|
32
|
+
logger.log(formatSuccessLine('Integration staging ready'));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = { maybeStageIntegrationForDockerBuild };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard Docker build orchestration (dev-promote shortcut + full build).
|
|
3
|
+
* @fileoverview Extracted from lib/build/index.js for file-size limits
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const chalk = require('chalk');
|
|
9
|
+
const { detectAppType } = require('../utils/paths');
|
|
10
|
+
const logger = require('../utils/logger');
|
|
11
|
+
const dockerBuild = require('../utils/docker-build');
|
|
12
|
+
const buildHelpers = require('../utils/build-helpers');
|
|
13
|
+
const { ensureRunSecretsForApp } = require('../app/run-env-compose');
|
|
14
|
+
const { formatSuccessParagraph } = require('../utils/cli-test-layout-chalk');
|
|
15
|
+
const { resolveDockerBuildArgsForApp } = require('./docker-build-args');
|
|
16
|
+
const { maybeStageIntegrationForDockerBuild } = require('./integration-docker-staging');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Lazy require breaks circular dependency with lib/build/index.js.
|
|
20
|
+
* @returns {Object}
|
|
21
|
+
*/
|
|
22
|
+
function getBuildIndexDeps() {
|
|
23
|
+
return require('./index');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* When --from-dev --base: tag dev image as base and skip docker build when possible.
|
|
28
|
+
* @param {string} appName
|
|
29
|
+
* @param {Object} options
|
|
30
|
+
* @returns {Promise<string|null>} image ref when promote completed; null to continue full build
|
|
31
|
+
*/
|
|
32
|
+
async function tryCompleteDevPromoteBuild(appName, options) {
|
|
33
|
+
const { shouldAttemptDevPromote, tryPromoteDevImageToBase } = require('../utils/promote-dev-docker-image');
|
|
34
|
+
if (!shouldAttemptDevPromote(options)) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const promotedRef = await tryPromoteDevImageToBase(appName, options);
|
|
38
|
+
if (!promotedRef) {
|
|
39
|
+
logger.log(chalk.blue('No local dev-scoped image found; building base image...'));
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const { buildConfig } = await buildHelpers.loadAndValidateConfig(appName);
|
|
43
|
+
const { postBuildTasks } = getBuildIndexDeps();
|
|
44
|
+
await postBuildTasks(appName, buildConfig);
|
|
45
|
+
logger.log(formatSuccessParagraph('Build completed successfully! (promoted from dev image)'));
|
|
46
|
+
return promotedRef;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Run docker build after workspace prep (shared by standard build path).
|
|
51
|
+
* @param {string} appName
|
|
52
|
+
* @param {Object} options
|
|
53
|
+
* @param {Object} buildConfig
|
|
54
|
+
* @returns {Promise<string>}
|
|
55
|
+
*/
|
|
56
|
+
async function executeDockerImageBuild(appName, options, buildConfig) {
|
|
57
|
+
const { emitManifestMetadataLineIfTTY } = require('../utils/manifest-source-emit');
|
|
58
|
+
const {
|
|
59
|
+
prepareDevDirectory,
|
|
60
|
+
prepareBuildContext,
|
|
61
|
+
handleDockerfileGeneration,
|
|
62
|
+
postBuildTasks
|
|
63
|
+
} = getBuildIndexDeps();
|
|
64
|
+
const { appPath } = await detectAppType(appName);
|
|
65
|
+
emitManifestMetadataLineIfTTY(logger, { appKey: appName, appPath, envOnly: false, json: false });
|
|
66
|
+
const { devDir, effectiveImageName, imageName, appConfig } = await prepareDevDirectory(
|
|
67
|
+
appName,
|
|
68
|
+
buildConfig,
|
|
69
|
+
options
|
|
70
|
+
);
|
|
71
|
+
const contextPath = prepareBuildContext(buildConfig, devDir);
|
|
72
|
+
await maybeStageIntegrationForDockerBuild(contextPath);
|
|
73
|
+
const dockerfilePath = await handleDockerfileGeneration(
|
|
74
|
+
appName,
|
|
75
|
+
{ devDir, buildConfig, contextPath, appConfig },
|
|
76
|
+
options,
|
|
77
|
+
buildHelpers
|
|
78
|
+
);
|
|
79
|
+
await ensureRunSecretsForApp(appName);
|
|
80
|
+
const buildArgs = await resolveDockerBuildArgsForApp(appName, contextPath);
|
|
81
|
+
const tag = options.tag || 'latest';
|
|
82
|
+
if (typeof tag === 'string' && tag.includes(',')) {
|
|
83
|
+
throw new Error('Use a single image tag per build (comma-separated multiple tags are not supported).');
|
|
84
|
+
}
|
|
85
|
+
await dockerBuild.executeDockerBuildWithTag(
|
|
86
|
+
effectiveImageName,
|
|
87
|
+
imageName,
|
|
88
|
+
dockerfilePath,
|
|
89
|
+
contextPath,
|
|
90
|
+
tag,
|
|
91
|
+
{ ...options, buildArgs }
|
|
92
|
+
);
|
|
93
|
+
await postBuildTasks(appName, buildConfig);
|
|
94
|
+
logger.log(formatSuccessParagraph('Build completed successfully!'));
|
|
95
|
+
return `${effectiveImageName}:${tag}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Standard Docker build path after CLI header is printed (non-external apps).
|
|
100
|
+
* @param {string} appName
|
|
101
|
+
* @param {Object} options
|
|
102
|
+
* @returns {Promise<string>} Built image ref e.g. name:tag
|
|
103
|
+
*/
|
|
104
|
+
async function runStandardDockerBuild(appName, options) {
|
|
105
|
+
const promotedRef = await tryCompleteDevPromoteBuild(appName, options);
|
|
106
|
+
if (promotedRef) {
|
|
107
|
+
return promotedRef;
|
|
108
|
+
}
|
|
109
|
+
const { buildConfig } = await buildHelpers.loadAndValidateConfig(appName);
|
|
110
|
+
return executeDockerImageBuild(appName, options, buildConfig);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = { runStandardDockerBuild };
|
|
@@ -16,6 +16,7 @@ const { withMutedLogger } = require('../utils/with-muted-logger');
|
|
|
16
16
|
const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
|
|
17
17
|
const { isAuthenticationError } = require('../utils/cli-utils');
|
|
18
18
|
const { resolveControllerUrl, isPlatformAuthValidForController } = require('../utils/controller-url');
|
|
19
|
+
const { canUseBootstrapProvision } = require('../commands/up-dataplane-bootstrap');
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* @param {Object} authOpts
|
|
@@ -59,7 +60,10 @@ async function runGuidedDeviceLogin(handleLoginFn, controllerUrl, opts = {}) {
|
|
|
59
60
|
compact: true,
|
|
60
61
|
skipControllerUrlPersist: Boolean(opts.tokenControllerUrl),
|
|
61
62
|
skipDataplaneVersionRefresh: opts.skipDataplaneVersionRefresh === true,
|
|
62
|
-
exitOnFailure: false
|
|
63
|
+
exitOnFailure: false,
|
|
64
|
+
guidedInstall: opts.guidedInstall === true,
|
|
65
|
+
onProgressText: opts.onProgressText,
|
|
66
|
+
suppressSuccessLine: opts.suppressSuccessLine === true
|
|
63
67
|
});
|
|
64
68
|
}
|
|
65
69
|
|
|
@@ -74,12 +78,17 @@ async function runGuidedAuthStep(handleLoginFn, authOpts, spinners) {
|
|
|
74
78
|
const spin = spinners.startSpinner('Authenticating...');
|
|
75
79
|
const { apiUrl, tokenUrl } = await resolveGuidedAuthControllerUrls(authOpts);
|
|
76
80
|
const loginOpts = { skipDataplaneVersionRefresh: true, tokenControllerUrl: tokenUrl };
|
|
81
|
+
const bootstrapEligible = await canUseBootstrapProvision({ skipInfraCheck: true });
|
|
77
82
|
const skipLogin =
|
|
83
|
+
bootstrapEligible ||
|
|
78
84
|
authOpts.skipLoginIfAuthenticated === true ||
|
|
79
85
|
(await isPlatformAuthValidForController(tokenUrl));
|
|
80
86
|
try {
|
|
81
87
|
if (skipLogin) {
|
|
82
|
-
spinners.stopSpinnerSuccess(
|
|
88
|
+
spinners.stopSpinnerSuccess(
|
|
89
|
+
spin,
|
|
90
|
+
bootstrapEligible ? 'Bootstrap provision (no device login)' : 'Already authenticated'
|
|
91
|
+
);
|
|
83
92
|
return;
|
|
84
93
|
}
|
|
85
94
|
await runGuidedDeviceLogin(handleLoginFn, apiUrl, loginOpts);
|
|
@@ -103,9 +112,17 @@ async function runGuidedAuthStep(handleLoginFn, authOpts, spinners) {
|
|
|
103
112
|
* @param {Function} handleUpDataplane
|
|
104
113
|
* @param {Function} handleLoginFn
|
|
105
114
|
* @param {string} controllerUrl
|
|
115
|
+
* @param {{ onSpinnerText?: (text: string) => void }} [ui]
|
|
106
116
|
* @returns {Promise<void>}
|
|
107
117
|
*/
|
|
108
|
-
async function runGuidedDataplaneWithAuthRecovery(
|
|
118
|
+
async function runGuidedDataplaneWithAuthRecovery(
|
|
119
|
+
options,
|
|
120
|
+
handleUpDataplane,
|
|
121
|
+
handleLoginFn,
|
|
122
|
+
controllerUrl,
|
|
123
|
+
ui = {}
|
|
124
|
+
) {
|
|
125
|
+
const onSpinnerText = typeof ui.onSpinnerText === 'function' ? ui.onSpinnerText : null;
|
|
109
126
|
try {
|
|
110
127
|
await withMutedLogger(() =>
|
|
111
128
|
handleUpDataplane({ ...options, platformInstall: true, skipInfraCheck: true })
|
|
@@ -114,10 +131,29 @@ async function runGuidedDataplaneWithAuthRecovery(options, handleUpDataplane, ha
|
|
|
114
131
|
if (!isAuthenticationError(error)) {
|
|
115
132
|
throw error;
|
|
116
133
|
}
|
|
134
|
+
const bootstrapEligible = await canUseBootstrapProvision({
|
|
135
|
+
skipInfraCheck: true,
|
|
136
|
+
allowNonDev: options.allowNonDev
|
|
137
|
+
});
|
|
138
|
+
if (bootstrapEligible) {
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
117
141
|
const loginUrl = error.controllerUrl || controllerUrl || (await resolveControllerUrl());
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
142
|
+
if (onSpinnerText) {
|
|
143
|
+
onSpinnerText('Authenticating...');
|
|
144
|
+
} else {
|
|
145
|
+
logger.log('');
|
|
146
|
+
logger.log(chalk.yellow('Device login required to register and deploy Dataplane.'));
|
|
147
|
+
}
|
|
148
|
+
await runGuidedDeviceLogin(handleLoginFn, loginUrl, {
|
|
149
|
+
skipDataplaneVersionRefresh: false,
|
|
150
|
+
compact: true,
|
|
151
|
+
guidedInstall: true,
|
|
152
|
+
onProgressText: onSpinnerText || undefined
|
|
153
|
+
});
|
|
154
|
+
if (onSpinnerText) {
|
|
155
|
+
onSpinnerText('Validating Dataplane...');
|
|
156
|
+
}
|
|
121
157
|
await withMutedLogger(() =>
|
|
122
158
|
handleUpDataplane({ ...options, platformInstall: true, skipInfraCheck: true })
|
|
123
159
|
);
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Footer and header layout for guided infra/platform CLI flows.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const logger = require('../utils/logger');
|
|
9
|
+
const config = require('../core/config');
|
|
10
|
+
const { computeAppBaseUrl, resolvePlatformControllerUrl } = require('../utils/platform-controller-url');
|
|
11
|
+
const { successGlyph } = require('../utils/cli-test-layout-chalk');
|
|
12
|
+
|
|
13
|
+
const SEPARATOR = '────────────────────────────────────────';
|
|
14
|
+
|
|
15
|
+
function title(text) {
|
|
16
|
+
return chalk.bold(text);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function logSection(label, value) {
|
|
20
|
+
logger.log(title(label));
|
|
21
|
+
logger.log(` ${value}`);
|
|
22
|
+
logger.log('');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function logFooterStart(label) {
|
|
26
|
+
logger.log('');
|
|
27
|
+
logger.log(SEPARATOR);
|
|
28
|
+
logger.log(title(label));
|
|
29
|
+
logger.log(SEPARATOR);
|
|
30
|
+
logger.log('');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function logFooterEnd() {
|
|
34
|
+
logger.log(SEPARATOR);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @async
|
|
39
|
+
* @returns {Promise<string>}
|
|
40
|
+
*/
|
|
41
|
+
async function resolvePlatformControllerUrlForDisplay() {
|
|
42
|
+
const stored = await config.getPlatformControllerUrl();
|
|
43
|
+
if (stored) {
|
|
44
|
+
return stored;
|
|
45
|
+
}
|
|
46
|
+
return resolvePlatformControllerUrl();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function logPlatformReadyFooter() {
|
|
50
|
+
const [controllerUrl, dataplaneUrl, keycloakUrl] = await Promise.all([
|
|
51
|
+
resolvePlatformControllerUrlForDisplay(),
|
|
52
|
+
computeAppBaseUrl('dataplane'),
|
|
53
|
+
computeAppBaseUrl('keycloak')
|
|
54
|
+
]);
|
|
55
|
+
const cfg = await config.getConfig();
|
|
56
|
+
const env = cfg && cfg.environment ? cfg.environment : 'dev';
|
|
57
|
+
|
|
58
|
+
logFooterStart('Platform Ready');
|
|
59
|
+
logSection('Environment', env);
|
|
60
|
+
logSection('Miso Controller', controllerUrl);
|
|
61
|
+
logSection('Dataplane (DEV)', dataplaneUrl);
|
|
62
|
+
logSection('Keycloak', keycloakUrl);
|
|
63
|
+
logSection('API Documentation', `${dataplaneUrl}/api/docs`);
|
|
64
|
+
logSection('Knowledge Base', 'https://docs.aifabrix.ai');
|
|
65
|
+
logSection('Getting Started', 'https://docs.aifabrix.ai/get-started');
|
|
66
|
+
logFooterEnd();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function logMisoReadyFooter() {
|
|
70
|
+
const [controllerUrl, keycloakUrl] = await Promise.all([
|
|
71
|
+
resolvePlatformControllerUrlForDisplay(),
|
|
72
|
+
computeAppBaseUrl('keycloak')
|
|
73
|
+
]);
|
|
74
|
+
logFooterStart('Miso Ready');
|
|
75
|
+
logSection('Miso Controller', controllerUrl);
|
|
76
|
+
logSection('Keycloak', keycloakUrl);
|
|
77
|
+
logFooterEnd();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function logDataplaneReadyFooter() {
|
|
81
|
+
const dataplaneUrl = await computeAppBaseUrl('dataplane');
|
|
82
|
+
const cfg = await config.getConfig();
|
|
83
|
+
const env = cfg && cfg.environment ? cfg.environment : 'dev';
|
|
84
|
+
logFooterStart('Dataplane Ready');
|
|
85
|
+
logSection('Environment', env);
|
|
86
|
+
logSection('Dataplane (DEV)', dataplaneUrl);
|
|
87
|
+
logSection('API Documentation', `${dataplaneUrl}/api/docs`);
|
|
88
|
+
logFooterEnd();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @param {'platform'|'dataplane'} [scope]
|
|
93
|
+
*/
|
|
94
|
+
function logPlatformSetupDurationHint(scope = 'platform') {
|
|
95
|
+
const line =
|
|
96
|
+
scope === 'dataplane'
|
|
97
|
+
? 'Installation may take a few minutes. Authenticating and starting Dataplane — please wait.'
|
|
98
|
+
: 'Installation may take a few minutes. Keycloak, Miso Controller, and Dataplane are starting — please wait.';
|
|
99
|
+
logger.log(chalk.yellow(`⚠ ${line}`));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function logGuidedPlatformSetupHeader() {
|
|
103
|
+
logger.log('');
|
|
104
|
+
logger.log(title('AI Fabrix Platform Setup'));
|
|
105
|
+
logger.log(SEPARATOR);
|
|
106
|
+
logger.log('');
|
|
107
|
+
logPlatformSetupDurationHint('platform');
|
|
108
|
+
logger.log('');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @param {{ deviceCleared: number, clientCleared: number, environment: string, defaultControllerUrl: string }} forceSummary
|
|
113
|
+
* @param {string[]} cleanedApps
|
|
114
|
+
*/
|
|
115
|
+
function logUpPlatformForceCleanSummary(forceSummary, cleanedApps) {
|
|
116
|
+
const { isSetupQuietOutput } = require('../utils/setup-quiet-output');
|
|
117
|
+
if (isSetupQuietOutput()) return;
|
|
118
|
+
const check = successGlyph();
|
|
119
|
+
logger.log(chalk.bold('Clean installation files'));
|
|
120
|
+
logger.log(
|
|
121
|
+
chalk.gray(
|
|
122
|
+
` ${check} Cleared ${forceSummary.deviceCleared} device token(s) and ${forceSummary.clientCleared} client token(s)`
|
|
123
|
+
)
|
|
124
|
+
);
|
|
125
|
+
logger.log(chalk.gray(` ${check} Environment set to ${forceSummary.environment}`));
|
|
126
|
+
logger.log(
|
|
127
|
+
chalk.gray(
|
|
128
|
+
` ${check} Default controller set to ${forceSummary.defaultControllerUrl} (run aifabrix login after platform is up)`
|
|
129
|
+
)
|
|
130
|
+
);
|
|
131
|
+
for (const appName of cleanedApps || []) {
|
|
132
|
+
logger.log(chalk.gray(` ${check} Cleaned builder/${appName}`));
|
|
133
|
+
}
|
|
134
|
+
logger.log('');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @param {Object} cfg
|
|
139
|
+
*/
|
|
140
|
+
function logStoppedServices(cfg) {
|
|
141
|
+
logger.log(title('Stopped'));
|
|
142
|
+
logger.log(' postgres');
|
|
143
|
+
logger.log(' redis');
|
|
144
|
+
if (cfg.pgadmin !== false) logger.log(' pgadmin');
|
|
145
|
+
if (cfg.redisCommander !== false) logger.log(' redis-commander');
|
|
146
|
+
if (cfg.traefik) logger.log(' traefik');
|
|
147
|
+
logger.log('');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
module.exports = {
|
|
151
|
+
SEPARATOR,
|
|
152
|
+
title,
|
|
153
|
+
logSection,
|
|
154
|
+
logFooterStart,
|
|
155
|
+
logFooterEnd,
|
|
156
|
+
resolvePlatformControllerUrlForDisplay,
|
|
157
|
+
logPlatformReadyFooter,
|
|
158
|
+
logMisoReadyFooter,
|
|
159
|
+
logDataplaneReadyFooter,
|
|
160
|
+
logPlatformSetupDurationHint,
|
|
161
|
+
logGuidedPlatformSetupHeader,
|
|
162
|
+
logUpPlatformForceCleanSummary,
|
|
163
|
+
logStoppedServices
|
|
164
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Spinner helpers for guided infra/platform CLI flows.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const ora = require('ora');
|
|
8
|
+
const logger = require('../utils/logger');
|
|
9
|
+
const { formatProgress, formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
10
|
+
|
|
11
|
+
function shouldUseSpinner() {
|
|
12
|
+
return Boolean(process && process.stdout && process.stdout.isTTY);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {string} text
|
|
17
|
+
* @returns {import('ora').Ora|null}
|
|
18
|
+
*/
|
|
19
|
+
function startSpinner(text) {
|
|
20
|
+
if (!shouldUseSpinner()) {
|
|
21
|
+
logger.log(formatProgress(text));
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return ora({ text, spinner: 'dots' }).start();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {import('ora').Ora|null} spinner
|
|
29
|
+
* @param {string} text
|
|
30
|
+
*/
|
|
31
|
+
function stopSpinnerSuccess(spinner, text) {
|
|
32
|
+
if (!spinner) {
|
|
33
|
+
logger.log(formatSuccessLine(text));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
spinner.succeed(text);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {import('ora').Ora|null} spinner
|
|
41
|
+
* @returns {(text: string) => void}
|
|
42
|
+
*/
|
|
43
|
+
function createSpinnerTextUpdater(spinner) {
|
|
44
|
+
return (text) => {
|
|
45
|
+
if (spinner) {
|
|
46
|
+
spinner.text = text;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
logger.log(formatProgress(text));
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
startSpinner,
|
|
55
|
+
stopSpinnerSuccess,
|
|
56
|
+
createSpinnerTextUpdater
|
|
57
|
+
};
|