@aifabrix/builder 2.45.5 → 2.47.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 +2 -0
- package/.cursor/rules/cli-product-neutral.mdc +43 -0
- package/.cursor/rules/project-rules.mdc +1 -0
- package/.npmrc.token +1 -0
- package/.temp/jest-protection-convert/run-IFN2nv/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-IvmKLO/.protection/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-convert/run-SdvblF/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-b51TsW/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-fiLmb1/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-qYGHMU/.protection/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-Mq5re8/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-f3u4YL/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-iQtd1O/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-mdmz5M/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-qbKYxQ/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-yzlJy6/hubspot-companies.yaml +17 -0
- package/.temp/validation/summary.txt +5 -0
- package/README.md +43 -17
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +1 -1
- package/jest.config.default.js +2 -1
- package/jest.config.isolated.js +2 -1
- package/jest.global-live-fabrix-hooks.js +36 -0
- package/jest.isolated-projects.js +146 -0
- package/jest.projects.js +65 -136
- package/lib/api/api-response-errors.js +124 -0
- package/lib/api/dataplane-health.api.js +19 -7
- package/lib/api/governance-scenario-pack.api.js +159 -0
- package/lib/api/index.js +43 -3
- package/lib/api/lifecycle.api.js +98 -0
- package/lib/api/pipeline.api.js +3 -1
- package/lib/api/records-bulk.api.js +14 -1
- package/lib/api/resource-types.api.js +107 -0
- package/lib/api/runtime-configuration.api.js +72 -0
- package/lib/api/types/resource-types.types.js +45 -0
- package/lib/api/user-groups.api.js +9 -9
- package/lib/api/users.api.js +8 -8
- package/lib/api/validation-runner.js +3 -1
- package/lib/api/wizard.api.js +10 -2
- package/lib/app/deploy-config.js +4 -1
- package/lib/app/down.js +78 -27
- package/lib/app/index.js +2 -2
- package/lib/app/push.js +4 -5
- package/lib/app/register.js +7 -4
- package/lib/app/run-env-compose.js +84 -30
- package/lib/app/run-resolve-image.js +2 -1
- package/lib/app/run-stop-containers.js +113 -0
- package/lib/app/run.js +1 -31
- package/lib/app/show-display.js +35 -0
- package/lib/app/show.js +32 -1
- package/lib/build/index.js +22 -5
- package/lib/build/miso-controller-npm-sdk-guard.js +25 -0
- package/lib/certification/sync-system-certification.js +13 -6
- package/lib/channels/add-channel.js +348 -0
- package/lib/channels/channel-artifact-generator.js +141 -0
- package/lib/channels/channel-audit.js +101 -0
- package/lib/channels/channel-auth-context.js +37 -0
- package/lib/channels/channel-credential.js +200 -0
- package/lib/channels/channel-display-name.js +64 -0
- package/lib/channels/channel-external-system.js +106 -0
- package/lib/channels/channel-integration-generator.js +274 -0
- package/lib/channels/channel-probe.js +89 -0
- package/lib/channels/channel-runtime-resolver.js +152 -0
- package/lib/channels/channel-status-display.js +141 -0
- package/lib/channels/channel-targets.js +115 -0
- package/lib/cli/index.js +20 -4
- package/lib/cli/infra-guided-auth.js +109 -0
- package/lib/cli/infra-guided.js +84 -81
- package/lib/cli/setup-app.help.js +0 -31
- package/lib/cli/setup-app.js +82 -5
- package/lib/cli/setup-app.test-commands.js +5 -57
- package/lib/cli/setup-auth.js +25 -0
- package/lib/cli/setup-certification-commands.js +147 -0
- package/lib/cli/setup-certification.help.js +141 -0
- package/lib/cli/setup-environment.js +19 -2
- package/lib/cli/setup-external-system-help.js +62 -0
- package/lib/cli/setup-external-system.js +25 -3
- package/lib/cli/setup-infra-up-dataplane-action.js +2 -2
- package/lib/cli/setup-infra-up-platform-action.js +2 -1
- package/lib/cli/setup-infra.js +9 -1
- package/lib/cli/setup-platform.js +6 -1
- package/lib/cli/setup-secrets.js +33 -1
- package/lib/cli/setup-utility-help-after.js +25 -2
- package/lib/cli/setup-utility-repair.js +198 -0
- package/lib/cli/setup-utility-resolve.js +44 -5
- package/lib/cli/setup-utility-validate.js +197 -0
- package/lib/cli/setup-utility.js +4 -239
- package/lib/commands/app-logs.js +54 -26
- package/lib/commands/app.js +41 -0
- package/lib/commands/auth-status-client-tokens.js +214 -0
- package/lib/commands/auth-status-dataplane-version.js +142 -68
- package/lib/commands/auth-status.js +43 -54
- package/lib/commands/channel.js +58 -0
- package/lib/commands/datasource-test-trust-cli.js +27 -23
- package/lib/commands/datasource-unified-test-cli.js +6 -3
- package/lib/commands/datasource-unified-test-cli.options.js +5 -1
- package/lib/commands/datasource.js +8 -8
- package/lib/commands/dev-show-display.js +8 -1
- package/lib/commands/governance-cli-shared.js +94 -0
- package/lib/commands/governance-command-action.js +132 -0
- package/lib/commands/governance-download-external.js +34 -0
- package/lib/commands/governance-generate-external.js +71 -0
- package/lib/commands/governance-upload-external.js +36 -0
- package/lib/commands/governance-verify-external.js +64 -0
- package/lib/commands/governance.js +144 -0
- package/lib/commands/identity-apply-sync.js +49 -8
- package/lib/commands/identity-group-cli.js +66 -26
- package/lib/commands/identity-membership-role-cache.js +58 -37
- package/lib/commands/identity-shared.js +22 -1
- package/lib/commands/identity-user-cli.js +80 -34
- package/lib/commands/lifecycle-command-action.js +123 -0
- package/lib/commands/lifecycle-external.js +268 -0
- package/lib/commands/login.js +11 -2
- package/lib/commands/repair-auth-apply.js +153 -0
- package/lib/commands/repair-auth-config.js +8 -13
- package/lib/commands/repair-changed-files.js +41 -0
- package/lib/commands/repair-datasource-com-v2.js +15 -0
- package/lib/commands/repair-datasource-keys.js +4 -1
- package/lib/commands/repair-datasource-run.js +59 -0
- package/lib/commands/repair-datasource-service-contract.js +206 -0
- package/lib/commands/repair-datasource-test-payload.js +259 -0
- package/lib/commands/repair-datasource.js +49 -64
- package/lib/commands/repair-env-template.js +76 -25
- package/lib/commands/repair-external-run.js +216 -0
- package/lib/commands/repair-openapi-sync.js +49 -4
- package/lib/commands/repair-persist.js +4 -0
- package/lib/commands/repair-rbac.js +52 -1
- package/lib/commands/repair-steps.js +160 -0
- package/lib/commands/repair-system-alignment.js +7 -4
- package/lib/commands/repair.js +29 -296
- package/lib/commands/resource-type.js +371 -0
- package/lib/commands/secrets-get.js +184 -0
- package/lib/commands/secrets-remove-all.js +3 -1
- package/lib/commands/setup-image-refresh.js +146 -0
- package/lib/commands/setup-modes.js +158 -162
- package/lib/commands/setup-platform-auth.js +76 -0
- package/lib/commands/setup-prompts-admin.js +244 -0
- package/lib/commands/setup-prompts-platform-mode.js +70 -0
- package/lib/commands/setup-prompts-validators.js +36 -0
- package/lib/commands/setup-prompts.js +24 -76
- package/lib/commands/setup-run-context.js +45 -0
- package/lib/commands/setup-spinners.js +39 -0
- package/lib/commands/setup.js +27 -5
- package/lib/commands/teardown.js +39 -0
- package/lib/commands/test-e2e-external.js +24 -8
- package/lib/commands/test-governance-external.js +3 -24
- package/lib/commands/test-trust-external.js +48 -100
- package/lib/commands/up-common.js +57 -13
- package/lib/commands/up-dataplane.js +56 -15
- package/lib/commands/upload-publish-context.js +75 -0
- package/lib/commands/upload-sidecar-followups.js +89 -0
- package/lib/commands/upload.js +113 -110
- package/lib/commands/verify-governance-combined-external.js +61 -0
- package/lib/commands/verify-governance-command-action.js +64 -0
- package/lib/commands/verify-governance-db.js +102 -0
- package/lib/commands/verify-governance-external.js +77 -0
- package/lib/commands/verify-governance-result-builders.js +71 -0
- package/lib/commands/verify-operations-command-action.js +68 -0
- package/lib/commands/verify-operations-external.js +268 -0
- package/lib/commands/verify-operations-persist.js +75 -0
- package/lib/commands/verify-operations-step-plan.js +68 -0
- package/lib/commands/verify-operations-steps.js +111 -0
- package/lib/commands/verify-trust-command-action.js +73 -0
- package/lib/commands/verify-trust-external.js +59 -0
- package/lib/commands/wizard-config-normalizer.js +43 -23
- package/lib/commands/wizard-core.js +2 -0
- package/lib/core/admin-password-generator.js +38 -0
- package/lib/core/admin-secrets-bundle.js +111 -0
- package/lib/core/admin-secrets-env-overlay.js +62 -0
- package/lib/core/admin-secrets.js +32 -4
- package/lib/core/config-attach-extensions.js +3 -0
- package/lib/core/config-platform-controller.js +44 -0
- package/lib/core/config-setup-installation-profile.js +42 -0
- package/lib/core/config-setup-platform-mode.js +46 -0
- package/lib/core/config.js +46 -36
- package/lib/core/secrets-admin-env.js +6 -2
- package/lib/core/secrets-ensure.js +4 -0
- package/lib/core/secrets-env-content.js +54 -48
- package/lib/core/secrets-env-write.js +10 -1
- package/lib/core/secrets-infra-placeholder-sync.js +2 -0
- package/lib/core/setup-installation-profile.js +43 -0
- package/lib/core/setup-platform-mode.js +90 -0
- package/lib/datasource/agent-trust-debug-log.js +1 -1
- package/lib/datasource/agent-trust-run.js +5 -3
- package/lib/datasource/audit-evidence-extract-debug.js +30 -18
- package/lib/datasource/audit-evidence-extract.js +7 -4
- package/lib/datasource/audit-evidence-verify-matrix.js +54 -26
- package/lib/datasource/bulk-loader-run-batches.js +15 -3
- package/lib/datasource/capability/capability-diff-slice.js +2 -2
- package/lib/datasource/capability/capability-manifest.js +254 -0
- package/lib/datasource/capability/capability-resolve.js +3 -4
- package/lib/datasource/capability/copy-operations.js +5 -3
- package/lib/datasource/capability/remove-operations.js +2 -1
- package/lib/datasource/capability/run-capability-copy.js +32 -4
- package/lib/datasource/capability/run-capability-diff.js +3 -3
- package/lib/datasource/capability/run-capability-dimension.js +2 -4
- package/lib/datasource/capability/run-capability-edit.js +4 -7
- package/lib/datasource/capability/run-capability-relate.js +2 -4
- package/lib/datasource/capability/run-capability-remove.js +2 -4
- package/lib/datasource/capability/validate-capability-slice.js +2 -1
- package/lib/datasource/datasource-identifier.js +2 -1
- package/lib/datasource/datasource-load-export-context.js +3 -0
- package/lib/datasource/datasource-validate-display.js +1 -1
- package/lib/datasource/field-reference-validator.js +24 -3
- package/lib/datasource/log-cleaner.js +2 -2
- package/lib/datasource/log-viewer.js +8 -8
- package/lib/datasource/orphan-profiles-validator.js +98 -0
- package/lib/datasource/test-e2e.js +4 -1
- package/lib/datasource/unified-validation-run-body.js +3 -1
- package/lib/datasource/unified-validation-run.js +5 -2
- package/lib/datasource/validate.js +41 -23
- package/lib/deployment/environment-poll-status.js +138 -0
- package/lib/deployment/environment.js +42 -34
- package/lib/external-system/download-helpers.js +87 -0
- package/lib/external-system/download.js +78 -138
- package/lib/external-system/generator.js +1 -55
- package/lib/external-system/integration-auth-context.js +45 -0
- package/lib/external-system/test-auth.js +12 -5
- package/lib/external-system/test.js +16 -21
- package/lib/generator/builders.js +11 -1
- package/lib/generator/external-controller-manifest.js +18 -0
- package/lib/generator/split.js +3 -1
- package/lib/generator/wizard.js +1 -28
- package/lib/governance/governance-cli-errors.js +96 -0
- package/lib/governance/governance-download-display.js +38 -0
- package/lib/governance/governance-run-display.js +215 -25
- package/lib/identity/fk-reference.js +65 -0
- package/lib/identity/identity-apply-core.js +13 -58
- package/lib/identity/identity-apply-phases.js +5 -1
- package/lib/identity/identity-display.js +243 -0
- package/lib/identity/identity-response-helpers.js +52 -0
- package/lib/identity/identity-sync-errors.js +62 -0
- package/lib/identity/resolve-user-id.js +129 -0
- package/lib/identity/username-default.js +31 -0
- package/lib/infrastructure/admin-secrets-apply.js +84 -0
- package/lib/infrastructure/admin-secrets-ensure.js +130 -0
- package/lib/infrastructure/admin-secrets-resolve.js +95 -0
- package/lib/infrastructure/admin-secrets-sync.js +91 -0
- package/lib/infrastructure/helpers.js +23 -129
- package/lib/infrastructure/index.js +5 -6
- package/lib/infrastructure/orphan-infra-docker-teardown.js +11 -5
- package/lib/lifecycle/certification-progress.js +231 -0
- package/lib/lifecycle/dataplane-ui-url.js +145 -0
- package/lib/lifecycle/exit-codes.js +24 -0
- package/lib/lifecycle/json-envelope.js +25 -0
- package/lib/lifecycle/lifecycle-governance-options.js +51 -0
- package/lib/lifecycle/logger-quiet.js +29 -0
- package/lib/lifecycle/open-api-published.js +59 -0
- package/lib/lifecycle/operations-readiness-metrics.js +101 -0
- package/lib/lifecycle/product-model.js +196 -0
- package/lib/lifecycle/report-display-trust.js +70 -0
- package/lib/lifecycle/report-display.js +472 -0
- package/lib/lifecycle/scenario-upload.js +191 -0
- package/lib/lifecycle/verify-step-progress.js +87 -0
- package/lib/parameters/infra-kv-discovery.js +27 -2
- package/lib/protection/auth-context.js +10 -4
- package/lib/resolvers/datasource-resolver.js +2 -3
- package/lib/resolvers/resource-type-file.js +159 -0
- package/lib/schema/application-schema.json +17 -1
- package/lib/schema/datasource-test-run.schema.json +89 -6
- package/lib/schema/deployment-rules.yaml +2 -1
- package/lib/schema/external-datasource.schema.json +2947 -2619
- package/lib/schema/external-system.schema.json +1418 -761
- package/lib/schema/infra.parameter.yaml +45 -0
- package/lib/schema/type/credential-field-registry.json +103 -97
- package/lib/schema/type/document-storage.json +9 -5
- package/lib/utils/aifabrix-test-runtime-guard.js +125 -0
- package/lib/utils/api.js +55 -31
- package/lib/utils/app-relative-path-env.js +112 -0
- package/lib/utils/app-run-containers.js +25 -2
- package/lib/utils/authentication-shape.js +224 -0
- package/lib/utils/build-copy.js +36 -5
- package/lib/utils/build-resolve-image.js +66 -12
- package/lib/utils/celery-companion-apps.js +53 -0
- package/lib/utils/cli-secrets-error-format.js +83 -21
- package/lib/utils/cli-utils.js +20 -4
- package/lib/utils/compose-celery-worker.js +23 -0
- package/lib/utils/compose-generate-docker-compose.js +13 -1
- package/lib/utils/compose-traefik-ingress-base.js +16 -1
- package/lib/utils/config-secrets-path.js +46 -0
- package/lib/utils/configuration-env-resolver.js +36 -0
- package/lib/utils/controller-url.js +88 -1
- package/lib/utils/credential-secrets-env-kv.js +216 -0
- package/lib/utils/credential-secrets-env.js +175 -257
- package/lib/utils/dataplane-resolver.js +18 -2
- package/lib/utils/declarative-url-ports.js +27 -4
- package/lib/utils/deployment-auth-mode.js +41 -0
- package/lib/utils/developer-volume-id.js +33 -0
- package/lib/utils/docker-build.js +1 -4
- package/lib/utils/env-copy.js +14 -9
- package/lib/utils/env-kv-orphan-lines.js +43 -0
- package/lib/utils/error-formatters/network-errors.js +13 -4
- package/lib/utils/external-env-template.js +11 -3
- package/lib/utils/external-system-readiness-core.js +10 -0
- package/lib/utils/external-system-readiness-display.js +80 -23
- package/lib/utils/external-system-validators.js +8 -2
- package/lib/utils/health-check.js +4 -1
- package/lib/utils/help-builder.js +13 -8
- package/lib/utils/keycloak-realm-ready.js +101 -0
- package/lib/utils/load-cip-capacity-display-config.js +61 -15
- package/lib/utils/manifest-source-emit.js +2 -0
- package/lib/utils/paths.js +25 -0
- package/lib/utils/pipeline-upload-auth-retry.js +82 -0
- package/lib/utils/platform-controller-url.js +157 -0
- package/lib/utils/platform-kv-ref.js +57 -0
- package/lib/utils/postgres-platform-bootstrap.js +199 -0
- package/lib/utils/postgres-wipe.js +9 -2
- package/lib/utils/resolve-env-mode.js +47 -0
- package/lib/utils/runtime-configuration-download.js +189 -0
- package/lib/utils/runtime-configuration-values.js +119 -0
- package/lib/utils/schema-loader.js +19 -4
- package/lib/utils/secrets-generator.js +31 -25
- package/lib/utils/secrets-missing-error.js +164 -0
- package/lib/utils/service-url-label.js +81 -0
- package/lib/utils/setup-quiet-output.js +25 -0
- package/lib/utils/template-helpers.js +15 -0
- package/lib/utils/token-manager-client-credentials.js +201 -0
- package/lib/utils/token-manager-messages.js +8 -0
- package/lib/utils/token-manager-refresh.js +12 -2
- package/lib/utils/token-manager.js +86 -105
- package/lib/utils/upload-pipeline-ui.js +12 -5
- package/lib/utils/upload-sync-options.js +42 -0
- package/lib/utils/url-declarative-public-base.js +21 -3
- package/lib/utils/url-declarative-vdir-inactive-env.js +14 -4
- package/lib/utils/validation-poll-ui.js +8 -0
- package/lib/utils/validation-run-stage.js +45 -0
- package/lib/utils/worker-sidecars.js +142 -0
- package/lib/validation/external-manifest-validator.js +2 -0
- package/lib/validation/runtime-configuration-rules.js +98 -0
- package/lib/validation/validate-display-dimensions.js +154 -0
- package/lib/validation/validate-display-sections.js +276 -0
- package/lib/validation/validate-display-steps.js +67 -0
- package/lib/validation/validate-display.js +24 -402
- package/package.json +1 -1
- package/templates/applications/dataplane/application.yaml +7 -1
- package/templates/applications/dataplane/env.template +50 -14
- package/templates/applications/dataplane/rbac.yaml +108 -1
- package/templates/applications/miso-controller/application.yaml +2 -2
- package/templates/applications/miso-controller/env.template +53 -122
- package/templates/applications/miso-controller/rbac.yaml +28 -13
- package/templates/channels/chatgpt/install.template.md.hbs +49 -0
- package/templates/channels/chatgpt/manifest.template.json.hbs +9 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +49 -0
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +8 -0
- package/templates/channels/slack/install.template.md.hbs +49 -0
- package/templates/channels/slack/manifest.template.json.hbs +66 -0
- package/templates/channels/teams-bot/install.template.md.hbs +49 -0
- package/templates/channels/teams-bot/manifest.template.json.hbs +13 -0
- package/templates/channels/web-embed/install.template.md.hbs +49 -0
- package/templates/channels/web-embed/manifest.template.json.hbs +8 -0
- package/templates/external-system/README.md.hbs +74 -17
- package/templates/python/docker-compose.hbs +75 -18
- package/templates/typescript/docker-compose.hbs +70 -17
- package/lib/commands/test-governance-command-action.js +0 -55
- package/lib/commands/test-trust-command-action.js +0 -118
package/lib/app/down.js
CHANGED
|
@@ -18,6 +18,13 @@ const logger = require('../utils/logger');
|
|
|
18
18
|
const config = require('../core/config');
|
|
19
19
|
const helpers = require('./run-helpers');
|
|
20
20
|
const { validateAppName } = require('./push');
|
|
21
|
+
const buildCopy = require('../utils/build-copy');
|
|
22
|
+
const {
|
|
23
|
+
getCeleryCompanionAppKeys,
|
|
24
|
+
loadBuilderApplicationConfig
|
|
25
|
+
} = require('../utils/celery-companion-apps');
|
|
26
|
+
const fsSync = require('fs');
|
|
27
|
+
const path = require('path');
|
|
21
28
|
|
|
22
29
|
/**
|
|
23
30
|
* Executes a shell command asynchronously.
|
|
@@ -48,6 +55,8 @@ function execAsync(command, options = {}) {
|
|
|
48
55
|
* @param {number|string} developerId - Developer ID
|
|
49
56
|
* @returns {string} Docker volume name
|
|
50
57
|
*/
|
|
58
|
+
const { collectDeveloperVolumeIdSuffixes } = require('../utils/developer-volume-id');
|
|
59
|
+
|
|
51
60
|
function getAppVolumeName(appName, developerId) {
|
|
52
61
|
const idNum = typeof developerId === 'string' ? parseInt(developerId, 10) : developerId;
|
|
53
62
|
if (idNum === 0) {
|
|
@@ -56,6 +65,69 @@ function getAppVolumeName(appName, developerId) {
|
|
|
56
65
|
return `aifabrix_dev${developerId}_${appName}_data`;
|
|
57
66
|
}
|
|
58
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Docker volume name candidates for an app (handles dev6 vs dev06 naming drift).
|
|
70
|
+
*
|
|
71
|
+
* @param {string} appName
|
|
72
|
+
* @param {string|number} developerId
|
|
73
|
+
* @returns {string[]}
|
|
74
|
+
*/
|
|
75
|
+
function getAppVolumeNameCandidates(appName, developerId) {
|
|
76
|
+
const idNum = typeof developerId === 'string' ? parseInt(developerId, 10) : developerId;
|
|
77
|
+
if (idNum === 0) {
|
|
78
|
+
return [`aifabrix_${appName}_data`, `aifabrix_dev0_${appName}_data`];
|
|
79
|
+
}
|
|
80
|
+
const suffixes = collectDeveloperVolumeIdSuffixes(developerId);
|
|
81
|
+
return suffixes.map((suffix) => `aifabrix_dev${suffix}_${appName}_data`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function buildVolumeRemovalCandidates(appName, developerId) {
|
|
85
|
+
const idNum = typeof developerId === 'string' ? parseInt(developerId, 10) : developerId;
|
|
86
|
+
const primaryName = getAppVolumeName(appName, developerId);
|
|
87
|
+
const legacyDev0Name = idNum === 0 ? `aifabrix_dev0_${appName}_data` : null;
|
|
88
|
+
return Array.from(new Set([primaryName, legacyDev0Name].filter(Boolean)));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function removeVolumeIfPresent(volumeName) {
|
|
92
|
+
logger.log(chalk.yellow(`Removing volume ${volumeName}...`));
|
|
93
|
+
try {
|
|
94
|
+
await execAsync(`docker volume rm -f ${volumeName}`);
|
|
95
|
+
logger.log(formatSuccessLine(`Volume ${volumeName} removed`));
|
|
96
|
+
} catch (volErr) {
|
|
97
|
+
logger.log(chalk.gray(`Volume ${volumeName} not found or already removed`));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function removeAppVolumes(appName, developerId) {
|
|
102
|
+
for (const volumeName of buildVolumeRemovalCandidates(appName, developerId)) {
|
|
103
|
+
await removeVolumeIfPresent(volumeName);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function stopAppContainers(appName, companionKeys, developerId) {
|
|
108
|
+
const devDir = buildCopy.getDevDirectory(appName, developerId);
|
|
109
|
+
const composePath = path.join(devDir, 'docker-compose.yaml');
|
|
110
|
+
|
|
111
|
+
if (companionKeys.length > 0 && fsSync.existsSync(composePath)) {
|
|
112
|
+
try {
|
|
113
|
+
await execAsync(`docker compose -f "${composePath}" down`);
|
|
114
|
+
return;
|
|
115
|
+
} catch (composeErr) {
|
|
116
|
+
logger.log(chalk.gray(`Compose down: ${composeErr.message}; stopping containers individually`));
|
|
117
|
+
for (const companionKey of companionKeys) {
|
|
118
|
+
await helpers.stopAndRemoveContainer(companionKey, developerId, false);
|
|
119
|
+
}
|
|
120
|
+
await helpers.stopAndRemoveContainer(appName, developerId, false);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
await helpers.stopAndRemoveContainer(appName, developerId, false);
|
|
126
|
+
for (const companionKey of companionKeys) {
|
|
127
|
+
await helpers.stopAndRemoveContainer(companionKey, developerId, false);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
59
131
|
/**
|
|
60
132
|
* Stops and removes a specific application's container.
|
|
61
133
|
* If --volumes is passed, attempts to remove the app's named Docker volume.
|
|
@@ -75,42 +147,20 @@ function getAppVolumeName(appName, developerId) {
|
|
|
75
147
|
*/
|
|
76
148
|
async function downApp(appName, options = {}) {
|
|
77
149
|
try {
|
|
78
|
-
// Input validation
|
|
79
150
|
if (!appName || typeof appName !== 'string') {
|
|
80
151
|
throw new Error('Application name is required and must be a string');
|
|
81
152
|
}
|
|
82
153
|
validateAppName(appName);
|
|
83
154
|
|
|
84
155
|
const volumes = !!options.volumes;
|
|
85
|
-
|
|
86
|
-
// Load developer ID
|
|
87
156
|
const developerId = await config.getDeveloperId();
|
|
157
|
+
const appConfig = loadBuilderApplicationConfig(appName);
|
|
158
|
+
const companionKeys = getCeleryCompanionAppKeys(appName, appConfig);
|
|
88
159
|
|
|
89
|
-
|
|
90
|
-
await helpers.stopAndRemoveContainer(appName, developerId, false);
|
|
160
|
+
await stopAppContainers(appName, companionKeys, developerId);
|
|
91
161
|
|
|
92
|
-
// Optionally remove named Docker volume (ignore if it doesn't exist)
|
|
93
162
|
if (volumes) {
|
|
94
|
-
|
|
95
|
-
// Primary expected name
|
|
96
|
-
const primaryName = getAppVolumeName(appName, developerId);
|
|
97
|
-
// Legacy name used when devId \"0\" was treated as string in templates
|
|
98
|
-
const legacyDev0Name = idNum === 0 ? `aifabrix_dev0_${appName}_data` : null;
|
|
99
|
-
// Build list of candidates, unique and non-empty
|
|
100
|
-
const candidates = Array.from(
|
|
101
|
-
new Set([primaryName, legacyDev0Name].filter(Boolean))
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
for (const volumeName of candidates) {
|
|
105
|
-
logger.log(chalk.yellow(`Removing volume ${volumeName}...`));
|
|
106
|
-
try {
|
|
107
|
-
await execAsync(`docker volume rm -f ${volumeName}`);
|
|
108
|
-
logger.log(formatSuccessLine(`Volume ${volumeName} removed`));
|
|
109
|
-
} catch (volErr) {
|
|
110
|
-
// Swallow errors for missing volume; provide neutral message
|
|
111
|
-
logger.log(chalk.gray(`Volume ${volumeName} not found or already removed`));
|
|
112
|
-
}
|
|
113
|
-
}
|
|
163
|
+
await removeAppVolumes(appName, developerId);
|
|
114
164
|
}
|
|
115
165
|
} catch (error) {
|
|
116
166
|
// Provide meaningful error while avoiding sensitive info
|
|
@@ -120,6 +170,7 @@ async function downApp(appName, options = {}) {
|
|
|
120
170
|
|
|
121
171
|
module.exports = {
|
|
122
172
|
downApp,
|
|
123
|
-
getAppVolumeName
|
|
173
|
+
getAppVolumeName,
|
|
174
|
+
getAppVolumeNameCandidates
|
|
124
175
|
};
|
|
125
176
|
|
package/lib/app/index.js
CHANGED
|
@@ -93,7 +93,7 @@ function validateAppNameAndSetup(appName, options) {
|
|
|
93
93
|
|
|
94
94
|
const initialType = options.type || 'external';
|
|
95
95
|
const baseDir = getBaseDirForAppType(initialType);
|
|
96
|
-
const appPath = paths.
|
|
96
|
+
const appPath = paths.getAppCreatePath(appName, initialType);
|
|
97
97
|
|
|
98
98
|
return { initialType, baseDir, appPath };
|
|
99
99
|
}
|
|
@@ -124,7 +124,7 @@ async function handleTemplateSetup(options) {
|
|
|
124
124
|
*/
|
|
125
125
|
async function prepareFinalAppPath(appName, config, initialAppPath) {
|
|
126
126
|
const finalBaseDir = getBaseDirForAppType(config.type);
|
|
127
|
-
const finalAppPath = paths.
|
|
127
|
+
const finalAppPath = paths.getAppCreatePath(appName, config.type);
|
|
128
128
|
|
|
129
129
|
// If path changed, validate the new path
|
|
130
130
|
if (finalAppPath !== initialAppPath) {
|
package/lib/app/push.js
CHANGED
|
@@ -19,7 +19,7 @@ const {
|
|
|
19
19
|
|
|
20
20
|
const pushUtils = require('../deployment/push');
|
|
21
21
|
const logger = require('../utils/logger');
|
|
22
|
-
const
|
|
22
|
+
const paths = require('../utils/paths');
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Validate application name format
|
|
@@ -92,11 +92,10 @@ function extractImageName(config, appName) {
|
|
|
92
92
|
* @throws {Error} If configuration cannot be loaded
|
|
93
93
|
*/
|
|
94
94
|
async function loadPushConfig(appName, options) {
|
|
95
|
-
const { detectAppType, resolveApplicationConfigPath } = require('../utils/paths');
|
|
96
95
|
const { loadConfigFile } = require('../utils/config-format');
|
|
97
|
-
const { appPath } = await detectAppType(appName);
|
|
98
96
|
try {
|
|
99
|
-
const
|
|
97
|
+
const { appPath } = await paths.detectAppType(appName);
|
|
98
|
+
const configPath = paths.resolveApplicationConfigPath(appPath);
|
|
100
99
|
const config = loadConfigFile(configPath);
|
|
101
100
|
const effective = getEffectiveConfig(config);
|
|
102
101
|
const registry = options.registry || effective.image?.registry;
|
|
@@ -242,7 +241,7 @@ function displayPushResults(registry, imageName, tags) {
|
|
|
242
241
|
*/
|
|
243
242
|
async function pushApp(appName, options = {}) {
|
|
244
243
|
try {
|
|
245
|
-
const { isExternal } = await detectAppType(appName);
|
|
244
|
+
const { isExternal } = await paths.detectAppType(appName);
|
|
246
245
|
if (isExternal) {
|
|
247
246
|
logExternalIntegrationPushNotice(appName);
|
|
248
247
|
return;
|
package/lib/app/register.js
CHANGED
|
@@ -25,6 +25,8 @@ const { callRegisterApi } = require('../utils/app-register-api');
|
|
|
25
25
|
const { displayRegistrationResults, getEnvironmentPrefix } = require('../utils/app-register-display');
|
|
26
26
|
const pathsUtil = require('../utils/paths');
|
|
27
27
|
const { refreshUrlsLocalRegistryFromBuilder } = require('../utils/urls-local-registry');
|
|
28
|
+
const { resolveControllerUrl } = require('../utils/controller-url');
|
|
29
|
+
const config = require('../core/config');
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
32
|
* Build registration data payload from app configuration
|
|
@@ -152,9 +154,6 @@ async function applyLocalhostPortAdjustment(appConfig, apiUrl, options) {
|
|
|
152
154
|
*/
|
|
153
155
|
async function registerApplication(appKey, options = {}) {
|
|
154
156
|
logger.log(chalk.blue('📋 Registering application...\n'));
|
|
155
|
-
|
|
156
|
-
const { resolveControllerUrl } = require('../utils/controller-url');
|
|
157
|
-
const config = require('../core/config');
|
|
158
157
|
await config.ensureSecretsEncryptionKey();
|
|
159
158
|
const { resolveEnvironment } = config;
|
|
160
159
|
|
|
@@ -168,7 +167,11 @@ async function registerApplication(appKey, options = {}) {
|
|
|
168
167
|
const appConfig = await extractAppConfiguration(finalVariables, appKey, options);
|
|
169
168
|
await validateAppRegistrationData(appConfig, appKey);
|
|
170
169
|
|
|
171
|
-
const
|
|
170
|
+
const controllerUrl = await resolveControllerUrl();
|
|
171
|
+
const environmentKey =
|
|
172
|
+
options && options.envKey
|
|
173
|
+
? String(options.envKey).trim().toLowerCase()
|
|
174
|
+
: await resolveEnvironment();
|
|
172
175
|
const authConfig = await checkAuthentication(controllerUrl, environmentKey);
|
|
173
176
|
const environment = registerApplicationSchema.environmentId(environmentKey);
|
|
174
177
|
|
|
@@ -14,9 +14,28 @@ const fs = require('fs').promises;
|
|
|
14
14
|
const fsSync = require('fs');
|
|
15
15
|
const pathsUtil = require('../utils/paths');
|
|
16
16
|
const adminSecrets = require('../core/admin-secrets');
|
|
17
|
+
const config = require('../core/config');
|
|
17
18
|
const secretsEnsure = require('../core/secrets-ensure');
|
|
18
19
|
const secretsEnvWrite = require('../core/secrets-env-write');
|
|
19
20
|
const { getContainerPort } = require('../utils/port-resolver');
|
|
21
|
+
const { applyAdminSecretsPlatformOverlay } = require('../core/admin-secrets-env-overlay');
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Merge app env with admin-secrets; overlay ensures platform keys come from admin file.
|
|
25
|
+
* @param {Object.<string, string>} merged
|
|
26
|
+
* @param {Object.<string, string>} adminObj
|
|
27
|
+
*/
|
|
28
|
+
function mergeRunEnvWithAdminOverlay(merged, adminObj) {
|
|
29
|
+
applyAdminSecretsPlatformOverlay(merged, adminObj);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function applyOnboardingPlatformModeIfNeeded(appName, merged) {
|
|
33
|
+
if (appName !== 'miso-controller') {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const mode = await config.getSetupPlatformMode();
|
|
37
|
+
merged.ONBOARDING_FULL_PLATFORM = mode === 'full' ? 'true' : 'false';
|
|
38
|
+
}
|
|
20
39
|
|
|
21
40
|
/**
|
|
22
41
|
* Backfill only secrets needed for `aifabrix run <app>`: kv:// keys from that app's env.template
|
|
@@ -194,31 +213,72 @@ async function readPasswordFromPgpassFile(pgpassPath) {
|
|
|
194
213
|
}
|
|
195
214
|
|
|
196
215
|
/**
|
|
197
|
-
* Read POSTGRES_PASSWORD from
|
|
198
|
-
*
|
|
199
|
-
*
|
|
216
|
+
* Read POSTGRES_PASSWORD from pgpass-style files beside the active infra compose
|
|
217
|
+
* (`resolveInfraStatePaths()`). Tries legacy `pgpass`, then `.pgpass.bootstrap` written at `up-infra`
|
|
218
|
+
* so db-init matches the password Postgres was started with when admin-secrets later drifted.
|
|
200
219
|
* @param {number|string} developerId - Developer ID
|
|
201
220
|
* @returns {Promise<string|undefined>} Password or undefined
|
|
202
221
|
*/
|
|
203
222
|
async function readPostgresPasswordFromPgpass(developerId) {
|
|
204
|
-
const { resolveInfraStatePaths } = require('../infrastructure/helpers');
|
|
223
|
+
const { resolveInfraStatePaths, PGPASS_BOOTSTRAP_BASENAME } = require('../infrastructure/helpers');
|
|
205
224
|
const { infraDir } = resolveInfraStatePaths(developerId);
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
225
|
+
const candidates = ['pgpass', PGPASS_BOOTSTRAP_BASENAME];
|
|
226
|
+
for (const name of candidates) {
|
|
227
|
+
const pgpassPath = path.join(infraDir, name);
|
|
228
|
+
if (!fsSync.existsSync(pgpassPath)) {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
try {
|
|
232
|
+
const pwd = await readPasswordFromPgpassFile(pgpassPath);
|
|
233
|
+
if (pwd !== undefined && pwd !== '') {
|
|
234
|
+
return pwd;
|
|
235
|
+
}
|
|
236
|
+
} catch {
|
|
237
|
+
// try next candidate
|
|
238
|
+
}
|
|
215
239
|
}
|
|
240
|
+
return undefined;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* @returns {Function}
|
|
245
|
+
*/
|
|
246
|
+
function resolveEnsureAdminSecretsFn() {
|
|
247
|
+
const infra = require('../infrastructure');
|
|
248
|
+
return typeof infra.ensureAdminSecrets === 'function'
|
|
249
|
+
? infra.ensureAdminSecrets
|
|
250
|
+
: require('../infrastructure/helpers').ensureAdminSecrets;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* @param {Object} merged
|
|
255
|
+
* @param {number|string|undefined} developerId
|
|
256
|
+
* @returns {Promise<void>}
|
|
257
|
+
*/
|
|
258
|
+
async function applyPostgresPasswordFromPgpass(merged, developerId) {
|
|
259
|
+
if (developerId === undefined) return;
|
|
260
|
+
const pgpassPwd = await readPostgresPasswordFromPgpass(developerId);
|
|
261
|
+
if (pgpassPwd !== undefined) merged.POSTGRES_PASSWORD = pgpassPwd;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* @param {string} runEnvPath
|
|
266
|
+
* @param {string} runEnvAdminPath
|
|
267
|
+
* @param {Object} appOnly
|
|
268
|
+
* @param {Object} dbInitOnly
|
|
269
|
+
* @returns {Promise<void>}
|
|
270
|
+
*/
|
|
271
|
+
async function writeRunEnvFiles(runEnvPath, runEnvAdminPath, appOnly, dbInitOnly) {
|
|
272
|
+
const toContent = adminSecrets.envObjectToContent;
|
|
273
|
+
await fs.writeFile(runEnvPath, toContent(appOnly), { mode: 0o600 });
|
|
274
|
+
await fs.writeFile(runEnvAdminPath, toContent(dbInitOnly), { mode: 0o600 });
|
|
216
275
|
}
|
|
217
276
|
|
|
218
277
|
/**
|
|
219
278
|
* Build two run env files: .env.run (app-only, no admin secrets) and .env.run.admin (start-only, for db-init).
|
|
220
279
|
* Admin password is never set in the app container; .env.run.admin is used only for start and then deleted.
|
|
221
|
-
* When `pgpass` exists beside the active infra compose, POSTGRES_PASSWORD is taken
|
|
280
|
+
* When `pgpass` or `.pgpass.bootstrap` exists beside the active infra compose, POSTGRES_PASSWORD is taken
|
|
281
|
+
* from it so db-init matches Postgres.
|
|
222
282
|
* @async
|
|
223
283
|
* @param {string} appName - Application name
|
|
224
284
|
* @param {Object} appConfig - Application configuration
|
|
@@ -227,12 +287,8 @@ async function readPostgresPasswordFromPgpass(developerId) {
|
|
|
227
287
|
* @returns {Promise<{ runEnvPath: string, runEnvAdminPath: string }>} Paths to .env.run and .env.run.admin
|
|
228
288
|
*/
|
|
229
289
|
async function buildMergedRunEnvAndWrite(appName, appConfig, devDir, developerId, scopeOpts = null) {
|
|
230
|
-
const infra = require('../infrastructure');
|
|
231
|
-
const ensureAdminSecretsFn = typeof infra.ensureAdminSecrets === 'function'
|
|
232
|
-
? infra.ensureAdminSecrets
|
|
233
|
-
: require('../infrastructure/helpers').ensureAdminSecrets;
|
|
234
290
|
await ensureRunSecretsForApp(appName);
|
|
235
|
-
await
|
|
291
|
+
await resolveEnsureAdminSecretsFn()();
|
|
236
292
|
const adminObj = await adminSecrets.readAndDecryptAdminSecrets();
|
|
237
293
|
const runEnvKey = scopeOpts && scopeOpts.runEnvKey ? String(scopeOpts.runEnvKey).toLowerCase() : 'dev';
|
|
238
294
|
const appObj = await secretsEnvWrite.resolveAndGetEnvMap(appName, {
|
|
@@ -242,22 +298,20 @@ async function buildMergedRunEnvAndWrite(appName, appConfig, devDir, developerId
|
|
|
242
298
|
runEnvKey
|
|
243
299
|
});
|
|
244
300
|
const merged = { ...adminObj, ...appObj };
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
301
|
+
mergeRunEnvWithAdminOverlay(merged, adminObj);
|
|
302
|
+
await applyOnboardingPlatformModeIfNeeded(appName, merged);
|
|
303
|
+
await applyPostgresPasswordFromPgpass(merged, developerId);
|
|
249
304
|
injectDatabaseNamesAndUsers(merged, appConfig, scopeOpts);
|
|
250
305
|
injectContainerPortForRun(merged, appConfig, appName);
|
|
251
306
|
|
|
252
307
|
const runEnvPath = path.join(devDir, '.env.run');
|
|
253
308
|
const runEnvAdminPath = path.join(devDir, '.env.run.admin');
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
309
|
+
await writeRunEnvFiles(
|
|
310
|
+
runEnvPath,
|
|
311
|
+
runEnvAdminPath,
|
|
312
|
+
buildAppOnlyEnv(merged),
|
|
313
|
+
buildDbInitOnlyEnv(merged)
|
|
314
|
+
);
|
|
261
315
|
return { runEnvPath, runEnvAdminPath };
|
|
262
316
|
}
|
|
263
317
|
|
|
@@ -10,6 +10,7 @@ const config = require('../core/config');
|
|
|
10
10
|
const { resolveDockerImageRef } = require('../utils/resolve-docker-image-ref');
|
|
11
11
|
const { checkImageExists } = require('../utils/app-run-containers');
|
|
12
12
|
const { buildDevImageRepositoryPath } = require('../utils/image-name');
|
|
13
|
+
const { wantsLocalDockerImageDiscovery } = require('../utils/build-resolve-image');
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* @param {string} appName
|
|
@@ -41,7 +42,7 @@ async function resolveRunImageWithLocalFallback(appName, appConfig, runOptions =
|
|
|
41
42
|
|
|
42
43
|
const baseRef = resolveDockerImageRef(appName, appConfig, opts);
|
|
43
44
|
|
|
44
|
-
if (opts.base === true) {
|
|
45
|
+
if (opts.base === true || !wantsLocalDockerImageDiscovery(appConfig)) {
|
|
45
46
|
return baseRef;
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stop running app containers (and celery companions) before `aifabrix run`.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Pre-run container teardown for port reuse
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { formatWarningLine } = require('../utils/cli-test-layout-chalk');
|
|
12
|
+
const config = require('../core/config');
|
|
13
|
+
const logger = require('../utils/logger');
|
|
14
|
+
const containerHelpers = require('../utils/app-run-containers');
|
|
15
|
+
const helpers = require('./run-helpers');
|
|
16
|
+
const { computeEffectiveEnvironmentScopedResources } = require('../utils/environment-scoped-resources');
|
|
17
|
+
const { getCeleryCompanionAppKeys } = require('../utils/celery-companion-apps');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {Object} appConfig
|
|
21
|
+
* @param {Object} options
|
|
22
|
+
* @returns {Promise<{ effectiveEnvironmentScopedResources: true, env: string }|null>}
|
|
23
|
+
*/
|
|
24
|
+
async function resolveRunScopeOpts(appConfig, options) {
|
|
25
|
+
const runEnvKey = (options.env || 'dev').toLowerCase();
|
|
26
|
+
const userCfg = await config.getConfig();
|
|
27
|
+
const effectiveEnvironmentScopedResources = computeEffectiveEnvironmentScopedResources(
|
|
28
|
+
Boolean(userCfg.useEnvironmentScopedResources),
|
|
29
|
+
appConfig.environmentScopedResources === true,
|
|
30
|
+
runEnvKey
|
|
31
|
+
);
|
|
32
|
+
if (!effectiveEnvironmentScopedResources) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
return { effectiveEnvironmentScopedResources: true, env: runEnvKey };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {string[]} companionKeys
|
|
40
|
+
* @param {string|number} developerId
|
|
41
|
+
* @param {boolean} debug
|
|
42
|
+
* @param {Object|null} scopeOpts
|
|
43
|
+
* @returns {Promise<string[]>}
|
|
44
|
+
*/
|
|
45
|
+
async function findRunningCompanionKeys(companionKeys, developerId, debug, scopeOpts) {
|
|
46
|
+
const running = [];
|
|
47
|
+
for (const companionKey of companionKeys) {
|
|
48
|
+
if (await helpers.checkContainerRunning(companionKey, developerId, debug, scopeOpts)) {
|
|
49
|
+
running.push(companionKey);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return running;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @param {string[]} companionKeys
|
|
57
|
+
* @param {string|number} developerId
|
|
58
|
+
* @param {boolean} debug
|
|
59
|
+
* @param {Object|null} scopeOpts
|
|
60
|
+
* @returns {Promise<void>}
|
|
61
|
+
*/
|
|
62
|
+
async function stopCompanionContainers(companionKeys, developerId, debug, scopeOpts) {
|
|
63
|
+
for (const companionKey of companionKeys) {
|
|
64
|
+
const companionName = containerHelpers.getContainerName(companionKey, developerId, scopeOpts);
|
|
65
|
+
logger.log(formatWarningLine(`Stopping companion container ${companionName}`));
|
|
66
|
+
await helpers.stopAndRemoveContainer(companionKey, developerId, debug, scopeOpts);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Check if container is running and stop it (and celery companions) if needed.
|
|
72
|
+
*
|
|
73
|
+
* @async
|
|
74
|
+
* @param {string} appName
|
|
75
|
+
* @param {Object} appConfig
|
|
76
|
+
* @param {Object} options
|
|
77
|
+
* @param {boolean} debug
|
|
78
|
+
* @returns {Promise<void>}
|
|
79
|
+
*/
|
|
80
|
+
async function checkAndStopContainer(appName, appConfig, options, debug) {
|
|
81
|
+
const developerId = appConfig.developerId;
|
|
82
|
+
const scopeOpts = await resolveRunScopeOpts(appConfig, options);
|
|
83
|
+
const companionKeys = getCeleryCompanionAppKeys(appName, appConfig);
|
|
84
|
+
const companionsToStop = await findRunningCompanionKeys(
|
|
85
|
+
companionKeys,
|
|
86
|
+
developerId,
|
|
87
|
+
debug,
|
|
88
|
+
scopeOpts
|
|
89
|
+
);
|
|
90
|
+
const containerRunning = await helpers.checkContainerRunning(
|
|
91
|
+
appName,
|
|
92
|
+
developerId,
|
|
93
|
+
debug,
|
|
94
|
+
scopeOpts
|
|
95
|
+
);
|
|
96
|
+
if (!containerRunning && companionsToStop.length === 0) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
await stopCompanionContainers(companionsToStop, developerId, debug, scopeOpts);
|
|
100
|
+
if (!containerRunning) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const containerName = containerHelpers.getContainerName(appName, developerId, scopeOpts);
|
|
104
|
+
logger.log(formatWarningLine(`Container ${containerName} is already running`));
|
|
105
|
+
await helpers.stopAndRemoveContainer(appName, developerId, debug, scopeOpts);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
module.exports = {
|
|
109
|
+
checkAndStopContainer,
|
|
110
|
+
resolveRunScopeOpts,
|
|
111
|
+
findRunningCompanionKeys,
|
|
112
|
+
stopCompanionContainers
|
|
113
|
+
};
|
package/lib/app/run.js
CHANGED
|
@@ -27,6 +27,7 @@ const containerHelpers = require('../utils/app-run-containers');
|
|
|
27
27
|
const helpers = require('./run-helpers');
|
|
28
28
|
const { ensureReloadSync, logReloadDevSummary } = require('./run-reload-sync');
|
|
29
29
|
const { logRestartDevMountSummary } = require('./restart-display');
|
|
30
|
+
const { checkAndStopContainer } = require('./run-stop-containers');
|
|
30
31
|
const { execWithDockerEnv } = require('../utils/docker-exec');
|
|
31
32
|
const { isRunCliNoProxy } = require('../utils/run-cli-flags');
|
|
32
33
|
|
|
@@ -111,37 +112,6 @@ async function validateAppForRun(appName, _debug) {
|
|
|
111
112
|
return true;
|
|
112
113
|
}
|
|
113
114
|
|
|
114
|
-
/**
|
|
115
|
-
* Check if container is running and stop it if needed
|
|
116
|
-
* @async
|
|
117
|
-
* @param {string} appName - Application name
|
|
118
|
-
* @param {number|string} developerId - Developer ID
|
|
119
|
-
* @param {boolean} debug - Debug flag
|
|
120
|
-
* @returns {Promise<void>}
|
|
121
|
-
*/
|
|
122
|
-
async function checkAndStopContainer(appName, appConfig, options, debug) {
|
|
123
|
-
const developerId = appConfig.developerId;
|
|
124
|
-
const runEnvKey = (options.env || 'dev').toLowerCase();
|
|
125
|
-
const userCfg = await config.getConfig();
|
|
126
|
-
const { computeEffectiveEnvironmentScopedResources } = require('../utils/environment-scoped-resources');
|
|
127
|
-
const effectiveEnvironmentScopedResources = computeEffectiveEnvironmentScopedResources(
|
|
128
|
-
Boolean(userCfg.useEnvironmentScopedResources),
|
|
129
|
-
appConfig.environmentScopedResources === true,
|
|
130
|
-
runEnvKey
|
|
131
|
-
);
|
|
132
|
-
const scopeOpts = effectiveEnvironmentScopedResources
|
|
133
|
-
? { effectiveEnvironmentScopedResources: true, env: runEnvKey }
|
|
134
|
-
: null;
|
|
135
|
-
const containerRunning = await helpers.checkContainerRunning(appName, developerId, debug, scopeOpts);
|
|
136
|
-
if (!containerRunning) {
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const containerName = containerHelpers.getContainerName(appName, developerId, scopeOpts);
|
|
141
|
-
logger.log(formatWarningLine(`Container ${containerName} is already running`));
|
|
142
|
-
await helpers.stopAndRemoveContainer(appName, developerId, debug, scopeOpts);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
115
|
/**
|
|
146
116
|
* Calculate host port and validate it's available
|
|
147
117
|
* @async
|
package/lib/app/show-display.js
CHANGED
|
@@ -49,6 +49,40 @@ function logApplicationOptional(a) {
|
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
function localRunProfileDiffers(application, localRunProfile) {
|
|
53
|
+
if (!localRunProfile || !application) return false;
|
|
54
|
+
if (localRunProfile.url && localRunProfile.url !== application.url) return true;
|
|
55
|
+
if (localRunProfile.internalUrl && localRunProfile.internalUrl !== application.internalUrl) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
return (
|
|
59
|
+
localRunProfile.port !== undefined &&
|
|
60
|
+
localRunProfile.port !== null &&
|
|
61
|
+
localRunProfile.port !== application.port
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function logLocalRunProfileSection(summary) {
|
|
66
|
+
const local = summary.localRunProfile;
|
|
67
|
+
if (!local || summary.source !== 'online' || !localRunProfileDiffers(summary.application, local)) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
logger.log('');
|
|
71
|
+
logger.log(chalk.gray(' Local run profile (docker manifest url://):'));
|
|
72
|
+
if (local.url && local.url !== summary.application.url) {
|
|
73
|
+
logger.log(chalk.gray(` URL: ${local.url}`));
|
|
74
|
+
}
|
|
75
|
+
if (local.internalUrl && local.internalUrl !== summary.application.internalUrl) {
|
|
76
|
+
logger.log(chalk.gray(` Internal URL: ${local.internalUrl}`));
|
|
77
|
+
}
|
|
78
|
+
if (local.port !== undefined && local.port !== summary.application.port) {
|
|
79
|
+
logger.log(chalk.gray(` Port: ${local.port}`));
|
|
80
|
+
}
|
|
81
|
+
logger.log(
|
|
82
|
+
chalk.gray(' Controller registry values above are what identity sync and pipeline use.')
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
52
86
|
function logApplicationFields(a) {
|
|
53
87
|
logApplicationRequired(a);
|
|
54
88
|
logApplicationOptional(a);
|
|
@@ -96,6 +130,7 @@ function logApplicationSection(a, summary) {
|
|
|
96
130
|
} else {
|
|
97
131
|
logApplicationFields(a);
|
|
98
132
|
}
|
|
133
|
+
logLocalRunProfileSection(summary);
|
|
99
134
|
if (summary.runReloadDefault && !summary.isExternal) {
|
|
100
135
|
logger.log(` ${'Run default:'.padEnd(16)} reload on (config)`);
|
|
101
136
|
}
|
package/lib/app/show.js
CHANGED
|
@@ -54,10 +54,22 @@ function attachRunDefaultsFromUserConfig(summary, appKey, userCfg) {
|
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* Overlay `application.url` / `application.internalUrl` from declarative url:// rules (same profile as run `.env`, default `docker`).
|
|
57
|
-
*
|
|
57
|
+
* Offline: replaces URL fields for local run hints. Online: keeps controller registry on `application` and adds `localRunProfile` when it differs.
|
|
58
58
|
* @param {Object} summary
|
|
59
59
|
* @param {string} appKey
|
|
60
60
|
*/
|
|
61
|
+
function portFromShowUrl(url) {
|
|
62
|
+
if (!url || typeof url !== 'string') return undefined;
|
|
63
|
+
try {
|
|
64
|
+
const parsed = new URL(url);
|
|
65
|
+
if (!parsed.port) return undefined;
|
|
66
|
+
const port = Number(parsed.port);
|
|
67
|
+
return Number.isFinite(port) ? port : undefined;
|
|
68
|
+
} catch {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
61
73
|
async function attachDeclarativeUrlsToShowApplication(summary, appKey) {
|
|
62
74
|
if (!summary || summary.isExternal) return;
|
|
63
75
|
const t = summary.application && summary.application.type;
|
|
@@ -68,8 +80,24 @@ async function attachDeclarativeUrlsToShowApplication(summary, appKey) {
|
|
|
68
80
|
const variablesPath = resolveApplicationConfigPath(appPath);
|
|
69
81
|
const urls = await resolveDeclarativeShowUrlsForApp(appKey, appPath, variablesPath, 'docker');
|
|
70
82
|
if (!urls) return;
|
|
83
|
+
|
|
84
|
+
const localPort = portFromShowUrl(urls.publicUrl);
|
|
85
|
+
const localRunProfile = {
|
|
86
|
+
url: urls.publicUrl,
|
|
87
|
+
internalUrl: urls.internalUrl,
|
|
88
|
+
port: localPort ?? summary.application.port
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
if (summary.source === 'online') {
|
|
92
|
+
summary.localRunProfile = localRunProfile;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
71
96
|
summary.application.url = urls.publicUrl;
|
|
72
97
|
summary.application.internalUrl = urls.internalUrl;
|
|
98
|
+
if (localPort !== undefined) {
|
|
99
|
+
summary.application.port = localPort;
|
|
100
|
+
}
|
|
73
101
|
} catch {
|
|
74
102
|
/* display-only */
|
|
75
103
|
}
|
|
@@ -830,6 +858,9 @@ function outputOnlineJson(summary, permissionsOnly, manifestSource) {
|
|
|
830
858
|
out.runReloadDefault = true;
|
|
831
859
|
}
|
|
832
860
|
out.runProxyDefault = Boolean(summary.runProxyDefault);
|
|
861
|
+
if (summary.localRunProfile) {
|
|
862
|
+
out.localRunProfile = summary.localRunProfile;
|
|
863
|
+
}
|
|
833
864
|
if (summary.externalSystem !== undefined && summary.externalSystem !== null) {
|
|
834
865
|
out.externalSystem = summary.externalSystem && summary.externalSystem.error
|
|
835
866
|
? { error: summary.externalSystem.error }
|