@underpostnet/cyberia 3.3.73 → 3.3.76
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/.env.example +17 -5
- package/.github/workflows/coverall.cyberia.ci.yml +5 -0
- package/.github/workflows/docker-image.cyberia-client.ci.yml +1 -1
- package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +1 -1
- package/.github/workflows/docker-image.cyberia-server.ci.yml +1 -1
- package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +1 -1
- package/.github/workflows/docker-image.engine-cyberia.ci.yml +1 -1
- package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +1 -1
- package/.github/workflows/publish.cyberia.ci.yml +44 -0
- package/AGENTS.md +61 -12
- package/CHANGELOG.md +126 -41
- package/CLI-HELP.md +19 -12
- package/Dockerfile +1 -1
- package/Dockerfile.dev +1 -1
- package/Dockerfile.test +2 -2
- package/README.md +28 -28
- package/bin/build.js +37 -17
- package/bin/cyberia.js +1247 -1373
- package/bin/index.js +1247 -1373
- package/compose.env +17 -5
- package/conf.js +7 -3
- package/deploy/cyberia-client/deploy.sh +10 -11
- package/deploy/cyberia-client/package.sh +0 -1
- package/deploy/cyberia-client/state.sh +3 -2
- package/deploy/cyberia-server/deploy.sh +10 -11
- package/deploy/cyberia-server/package.sh +0 -1
- package/deploy/cyberia-server/state.sh +3 -2
- package/deploy/dd-cyberia/deploy.sh +5 -5
- package/deploy/dd-cyberia/init.sh +15 -14
- package/deploy/dd-cyberia/package.sh +0 -1
- package/deploy/dd-cyberia/state.sh +2 -2
- package/deploy/dd-cyberia/sync-deploy.sh +139 -75
- package/deploy/lib/config.sh +29 -0
- package/deploy/lib/github-actions-logging.sh +92 -76
- package/deploy/lib/host.sh +27 -18
- package/deploy/lib/state.sh +4 -1
- package/deploy/pwa-microservices-template/deploy.sh +10 -8
- package/deploy/release/deploy.sh +0 -2
- package/deployment.yaml +1 -1
- package/docker-compose.yml +23 -17
- package/hardhat/package-lock.json +2 -2
- package/hardhat/package.json +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +1 -1
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +1 -1
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/mongo-express/deployment.yaml +46 -27
- package/manifests/deployment/mongo-express/kustomization.yaml +9 -0
- package/manifests/deployment/mongo-express/mongo-express-nodeport.yaml +18 -0
- package/manifests/deployment/mongo-express/service.yaml +16 -0
- package/manifests/deployment/mongo-express-no-auth/disable-mongodb-auth.yaml +16 -0
- package/manifests/deployment/mongo-express-no-auth/kustomization.yaml +16 -0
- package/package.json +19 -17
- package/scripts/test-monitor.sh +3 -3
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +14 -9
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +36 -5
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +5 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +88 -184
- package/src/api/cyberia-action/cyberia-action.router.js +2 -2
- package/src/api/cyberia-action/cyberia-action.service.js +3 -4
- package/src/api/cyberia-audio/cyberia-audio.controller.js +6 -0
- package/src/api/cyberia-audio/cyberia-audio.model.js +61 -0
- package/src/api/cyberia-audio/cyberia-audio.router.js +21 -0
- package/src/api/cyberia-audio/cyberia-audio.service.js +220 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +1 -3
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +10 -19
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +12 -34
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +15 -32
- package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +1 -1
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +1 -1
- package/src/api/cyberia-entity/cyberia-entity.model.js +2 -0
- package/src/api/cyberia-entity/cyberia-entity.service.js +1 -1
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +8 -2
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +31 -20
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +16 -1
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +466 -3
- package/src/api/cyberia-instance/cyberia-fallback-capture.js +87 -51
- package/src/api/cyberia-instance/cyberia-fallback-world.js +21 -40
- package/src/api/cyberia-instance/cyberia-instance-boot.service.js +5 -5
- package/src/api/cyberia-instance/cyberia-instance-items.js +98 -0
- package/src/api/cyberia-instance/cyberia-instance-map.service.js +34 -141
- package/src/api/cyberia-instance/cyberia-instance.controller.js +1 -4
- package/src/api/cyberia-instance/cyberia-instance.model.js +0 -14
- package/src/api/cyberia-instance/cyberia-instance.router.js +3 -16
- package/src/api/cyberia-instance/cyberia-instance.service.js +3 -43
- package/src/api/cyberia-instance/cyberia-world-generator.js +8 -13
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +49 -75
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +74 -1
- package/src/api/cyberia-map/cyberia-map.service.js +6 -2
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.controller.js +31 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.model.js +56 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.router.js +33 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +189 -0
- package/src/api/cyberia-quest/cyberia-quest.router.js +3 -3
- package/src/api/cyberia-quest/cyberia-quest.service.js +3 -3
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +1 -1
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +403 -188
- package/src/api/cyberia-skill/cyberia-skill.model.js +6 -6
- package/src/api/file/file.ref.js +153 -0
- package/src/api/file/file.ref.json +11 -2
- package/src/api/object-layer/object-layer.model.js +47 -12
- package/src/api/object-layer/object-layer.router.js +10 -3
- package/src/api/object-layer/object-layer.service.js +113 -120
- package/src/cli/app.js +12 -1
- package/src/cli/client.js +2 -2
- package/src/cli/cluster.js +7 -0
- package/src/cli/deploy.js +4 -4
- package/src/cli/docker-compose.js +1 -1
- package/src/cli/fs-selection.js +115 -0
- package/src/cli/fs.js +158 -342
- package/src/cli/index.js +22 -10
- package/src/cli/repository.js +28 -0
- package/src/cli/run.js +71 -197
- package/src/cli/test.js +4 -0
- package/src/cli/wireguard.js +32 -31
- package/src/client/components/core/Docs.js +77 -100
- package/src/client/components/core/Modal.js +56 -1
- package/src/client/components/cyberia/ActionEngineCyberia.js +12 -36
- package/src/client/components/cyberia/EntityEngineCyberia.js +492 -121
- package/src/client/components/cyberia/InstanceEngineCyberia.js +129 -160
- package/src/client/components/cyberia/InstanceSelectionView.js +7 -1
- package/src/client/components/cyberia/MapEngineCyberia.js +175 -69
- package/src/client/components/cyberia/ObjectLayerEngine.js +1011 -97
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +81 -155
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +113 -98
- package/src/client/components/cyberia/SharedDefaultsCyberia.js +215 -56
- package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +0 -34
- package/src/client/components/cyberia-portal/CssCyberiaPortal.js +1 -1
- package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +712 -76
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +0 -4
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +15 -15
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +280 -24
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +51 -29
- package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +52 -53
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +16 -11
- package/src/client/public/cyberia-docs/CYBERIA.md +28 -28
- package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +11 -5
- package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
- package/src/client/public/cyberia-docs/STATS-PROGRESSION.md +217 -0
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +20 -12
- package/src/client/services/cyberia-audio/cyberia-audio.service.js +99 -0
- package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +38 -0
- package/src/client/services/cyberia-instance/cyberia-instance.management.js +5 -4
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +0 -40
- package/src/client/services/cyberia-map/cyberia-map.management.js +5 -4
- package/src/client/services/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +138 -0
- package/src/client/services/object-layer/object-layer.management.js +6 -10
- package/src/client/services/object-layer/object-layer.service.js +3 -1
- package/src/client-builder/client-build-docs.js +52 -52
- package/src/client-builder/client-build.js +67 -44
- package/src/client-builder/client-bundle.js +347 -0
- package/src/db/mongo/MongoExpress.js +187 -0
- package/src/grpc/cyberia/grpc-server.js +5 -7
- package/src/index.js +1 -1
- package/src/projects/cyberia/atlas-sprite-sheet-generator.js +143 -146
- package/src/projects/cyberia/atlas-sprite-sheet-store.js +391 -0
- package/src/projects/cyberia/besu-genesis-generator.js +5 -14
- package/src/projects/cyberia/boot-contract-fixtures.js +32 -0
- package/src/projects/cyberia/catalog-cyberia.js +3 -2
- package/src/projects/cyberia/gemini-client.js +3 -3
- package/src/projects/cyberia/generate-saga.js +4 -11
- package/src/projects/cyberia/hot-reload-trigger.js +17 -28
- package/src/projects/cyberia/instance-backup.js +210 -0
- package/src/projects/cyberia/instance-data.js +177 -257
- package/src/projects/cyberia/map-preview-generator.js +32 -68
- package/src/projects/cyberia/object-layer.js +152 -319
- package/src/projects/cyberia/seed-audio.js +139 -0
- package/src/projects/cyberia/semantic-layer-generator-skin.js +2 -8
- package/src/projects/cyberia/semantic-layer-generator.js +2 -18
- package/src/projects/cyberia/stat-balance.js +81 -0
- package/src/projects/cyberia/stat-commands.js +23 -0
- package/src/projects/cyberia/stat-contract-generator.js +101 -0
- package/src/runtime/cyberia-client/Dockerfile +8 -4
- package/src/runtime/cyberia-client/Dockerfile.dev +5 -2
- package/src/runtime/cyberia-server/Dockerfile +9 -2
- package/src/runtime/cyberia-server/Dockerfile.dev +8 -1
- package/src/runtime/engine-cyberia/Dockerfile +1 -1
- package/src/runtime/engine-cyberia/Dockerfile.dev +1 -1
- package/src/runtime/engine-cyberia/Dockerfile.test +2 -2
- package/src/runtime/engine-cyberia/compose.env +17 -5
- package/src/runtime/engine-cyberia/docker-compose.yml +23 -17
- package/src/server/build/coverage.js +113 -42
- package/src/server/build/package.js +55 -12
- package/src/server/build/testing.js +59 -9
- package/src/server/network/middlewares.js +8 -2
- package/src/server/ops/logger.js +70 -35
- package/src/server/runtime/conf.js +4 -2
- package/src/server/storage/data-query.js +16 -0
- package/src/server/storage/downloader.js +62 -14
- package/src/server/storage/zip.js +153 -0
- package/test/integration/app/cyberia/atlas-sprite-sheet-store.test.js +402 -0
- package/test/integration/app/cyberia/atlas-sprite-sheet.test.js +86 -0
- package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +34 -0
- package/test/integration/app/cyberia/cyberia-entity-type-default.test.js +842 -0
- package/test/integration/app/cyberia/cyberia-instance-conf-coerce.test.js +53 -0
- package/test/integration/app/cyberia/cyberia-instance-conf-defaults.test.js +16 -22
- package/test/integration/app/cyberia/cyberia-instance-items.test.js +90 -0
- package/test/integration/app/cyberia/cyberia-load.test.js +6 -7
- package/test/integration/app/cyberia/cyberia-map-audio-conf.test.js +256 -0
- package/test/integration/app/cyberia/cyberia-stats.test.js +150 -0
- package/test/integration/app/cyberia/fallback-world-capture.test.js +87 -2
- package/test/integration/app/cyberia/object-layer-item-selection.test.js +56 -0
- package/test/integration/app/cyberia/object-layer-natural-key.test.js +32 -0
- package/test/integration/app/cyberia/seed-audio.test.js +275 -0
- package/test/integration/infra/2-network/wireguard-cli.test.js +33 -9
- package/test/integration/infra/2-network/wireguard-edge.test.js +58 -18
- package/test/integration/infra/3-cluster/mongo-express-deploy.test.js +156 -0
- package/test/integration/infra/4-ingress/api-cross-origin.test.js +79 -0
- package/test/unit/client-build-docs.test.js +97 -70
- package/test/unit/client-bundle.test.js +313 -0
- package/test/unit/conf-resolution.test.js +17 -0
- package/test/unit/coverage-artifact.test.js +120 -29
- package/test/unit/cyberia/instance-backup.test.js +183 -0
- package/test/unit/cyberia/instance-object-layer-items.test.js +46 -0
- package/test/unit/cyberia/publish-workflow.test.js +22 -0
- package/test/unit/cyberia/stat-balance.test.js +69 -0
- package/test/unit/deploy-log-table.test.js +76 -5
- package/test/unit/downloader-integrity.test.js +98 -0
- package/test/unit/file-reference-registry.test.js +141 -0
- package/test/unit/fs-storage-paths.test.js +596 -0
- package/test/unit/logger-redaction.test.js +29 -0
- package/test/unit/package.test.js +70 -16
- package/test/unit/prepare-host.test.js +84 -1
- package/test/unit/test-tiers.test.js +27 -0
- package/test/unit/zip-archive.test.js +142 -0
- package/vitest.config.js +11 -3
- package/src/api/cyberia-instance/cyberia-fallback-default-items.js +0 -63
- package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +0 -368
package/src/cli/run.js
CHANGED
|
@@ -28,10 +28,10 @@ import {
|
|
|
28
28
|
instancePortFactory,
|
|
29
29
|
instanceProxyRoutesFactory,
|
|
30
30
|
instanceStatusPageEntriesFactory,
|
|
31
|
+
instanceProjectPathFactory,
|
|
31
32
|
loadConfInstances,
|
|
32
33
|
loadProjectInstanceEnvBuilder,
|
|
33
34
|
loadConfServerJson,
|
|
34
|
-
loadReplicas,
|
|
35
35
|
resolveEnvScoped,
|
|
36
36
|
selectConfInstances,
|
|
37
37
|
waitForPort,
|
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
trafficFromRoutingInfoFactory,
|
|
50
50
|
} from '../server/runtime/conf.js';
|
|
51
51
|
import { buildKindPorts, deployRoutesExists, readDeployRoutes, resolveDeployList } from '../server/network/router.js';
|
|
52
|
+
import { clientBundleHostFilter, pullClientBundle, pushClientBundle } from '../client-builder/client-bundle.js';
|
|
52
53
|
import { cronDeployIdResolve } from '../server/ops/cron.js';
|
|
53
54
|
import { deployEnvFactory, getNpmRootPath, writeEnv } from '../server/runtime/environment.js';
|
|
54
55
|
import { actionInitLog, loggerFactory } from '../server/ops/logger.js';
|
|
@@ -62,6 +63,7 @@ import { domainContextFactory } from './domains.js';
|
|
|
62
63
|
import Underpost from '../index.js';
|
|
63
64
|
import dotenv from 'dotenv';
|
|
64
65
|
import { MongoBootstrap } from '../db/mongo/MongoBootstrap.js';
|
|
66
|
+
import { MongoExpress } from '../db/mongo/MongoExpress.js';
|
|
65
67
|
import {
|
|
66
68
|
UNDERPOST_GATEWAY,
|
|
67
69
|
assertStaticAssets,
|
|
@@ -140,6 +142,7 @@ const logger = loggerFactory(import.meta);
|
|
|
140
142
|
* @property {boolean} kind - Whether to run in kind mode.
|
|
141
143
|
* @property {boolean} k3s - Whether to run in k3s mode.
|
|
142
144
|
* @property {string} hosts - The hosts to use.
|
|
145
|
+
* @property {string} split - Zip part size in MB for push-bundle, or 'none' to upload a single zip.
|
|
143
146
|
* @property {string} deployId - The deployment ID.
|
|
144
147
|
* @property {string} instanceId - The instance ID.
|
|
145
148
|
* @property {string} user - The user to run as.
|
|
@@ -238,6 +241,7 @@ const DEFAULT_OPTION = {
|
|
|
238
241
|
kind: false,
|
|
239
242
|
k3s: false,
|
|
240
243
|
hosts: '',
|
|
244
|
+
split: '',
|
|
241
245
|
deployId: '',
|
|
242
246
|
instanceId: '',
|
|
243
247
|
user: '',
|
|
@@ -2267,19 +2271,25 @@ EOF
|
|
|
2267
2271
|
* If `--build` is supplied the image is built from the project Dockerfile and loaded into the
|
|
2268
2272
|
* cluster before the manifest is written (kind by default; `--kubeadm` / `--k3s` override).
|
|
2269
2273
|
*
|
|
2270
|
-
*
|
|
2271
|
-
*
|
|
2272
|
-
*
|
|
2273
|
-
*
|
|
2274
|
-
*
|
|
2275
|
-
*
|
|
2274
|
+
* The target is named by `--deploy-id` and `--instance-id`, like every other instance runner.
|
|
2275
|
+
* Where the artifacts land is not an argument: an instance's project directory is derived from
|
|
2276
|
+
* the conf entry itself (see {@link instanceProjectPathFactory}), so the caller cannot pair an
|
|
2277
|
+
* instance with someone else's checkout. Artifacts are written to
|
|
2278
|
+
* `<project>/manifests/deployments/<instance>-<env>/`, and in production the pair is also
|
|
2279
|
+
* copied to `<project>/Dockerfile` and `<project>/deployment.yaml`.
|
|
2280
|
+
*
|
|
2281
|
+
* @param {string} path - Unused; the target comes from `--deploy-id` and `--instance-id`.
|
|
2276
2282
|
* @param {UnderpostRunDefaultOptions} options - The default underpost runner options for customizing workflow
|
|
2277
2283
|
* @memberof UnderpostRun
|
|
2278
2284
|
*/
|
|
2279
2285
|
'instance-build-manifest': async (path, options = DEFAULT_OPTION) => {
|
|
2280
2286
|
const env = options.dev ? 'development' : 'production';
|
|
2281
|
-
|
|
2282
|
-
const
|
|
2287
|
+
const deployId = options.deployId;
|
|
2288
|
+
const id = options.instanceId;
|
|
2289
|
+
if (!deployId || !id) {
|
|
2290
|
+
logger.error('[instance-build-manifest] --deploy-id and --instance-id are required');
|
|
2291
|
+
return;
|
|
2292
|
+
}
|
|
2283
2293
|
|
|
2284
2294
|
const confInstances = loadConfInstances(deployId);
|
|
2285
2295
|
// Targeting a template id builds every world in the family. The fan-out
|
|
@@ -2297,20 +2307,23 @@ EOF
|
|
|
2297
2307
|
}
|
|
2298
2308
|
if (!options.instanceOnly && (selected.length > 1 || selected[0].id !== id)) {
|
|
2299
2309
|
for (const instance of selected)
|
|
2300
|
-
await UnderpostRun.RUNNERS['instance-build-manifest'](
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2310
|
+
await UnderpostRun.RUNNERS['instance-build-manifest']('', {
|
|
2311
|
+
...options,
|
|
2312
|
+
instanceId: instance.id,
|
|
2313
|
+
instanceOnly: true,
|
|
2314
|
+
});
|
|
2304
2315
|
return;
|
|
2305
2316
|
}
|
|
2306
2317
|
|
|
2318
|
+
const instance = selected[0];
|
|
2319
|
+
// The conf names the project: its repository, else its runtime, else its id. A world and the
|
|
2320
|
+
// checkout it publishes to cannot disagree, because only one of them is stated.
|
|
2321
|
+
const rootPath = instanceProjectPathFactory(instance);
|
|
2307
2322
|
const envManifestPath = `${rootPath}/manifests/deployments/${id}-${env}`;
|
|
2308
2323
|
const outputPath = `${envManifestPath}/deployment.yaml`;
|
|
2309
2324
|
const dockerfileManifestPath = `${envManifestPath}/Dockerfile`;
|
|
2310
2325
|
|
|
2311
2326
|
fs.mkdirpSync(envManifestPath);
|
|
2312
|
-
|
|
2313
|
-
const instance = selected[0];
|
|
2314
2327
|
const isDefaultInstance = instance.id === instance.templateId || !instance.templateId;
|
|
2315
2328
|
const instanceEnvBuilder = await loadProjectInstanceEnvBuilder(deployId);
|
|
2316
2329
|
|
|
@@ -2357,14 +2370,15 @@ EOF
|
|
|
2357
2370
|
const _fromPort = instancePortFactory({ instance, env });
|
|
2358
2371
|
const _toPort = instancePortFactory({ instance, env, container: true });
|
|
2359
2372
|
|
|
2360
|
-
// Build image from
|
|
2361
|
-
|
|
2373
|
+
// Build the image from the project's own Dockerfile and load it into the cluster when
|
|
2374
|
+
// --build is set.
|
|
2375
|
+
if (options.build) {
|
|
2362
2376
|
const isKind = !options.kubeadm && !options.k3s;
|
|
2363
2377
|
Underpost.image.build({
|
|
2364
|
-
path:
|
|
2378
|
+
path: rootPath,
|
|
2365
2379
|
imageName: _image,
|
|
2366
2380
|
podmanSave: true,
|
|
2367
|
-
imageOutPath:
|
|
2381
|
+
imageOutPath: rootPath,
|
|
2368
2382
|
kind: isKind,
|
|
2369
2383
|
kubeadm: !!options.kubeadm,
|
|
2370
2384
|
k3s: !!options.k3s,
|
|
@@ -2484,12 +2498,11 @@ EOF
|
|
|
2484
2498
|
// a rewrite never points at a document that cannot exist. The check is a
|
|
2485
2499
|
// read: placing the document into the gateway volume is `deploy
|
|
2486
2500
|
// --sync-static`'s job at apply time, and a build must not mutate the host.
|
|
2487
|
-
//
|
|
2488
|
-
//
|
|
2489
|
-
const statusPageEntries = instanceStatusPageEntriesFactory({
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
}).filter((entry) => fs.existsSync(entry.sourcePath));
|
|
2501
|
+
// No project override: this runner and the sync now derive the root from the same instance
|
|
2502
|
+
// by the same rule, so passing one here could only make them disagree.
|
|
2503
|
+
const statusPageEntries = instanceStatusPageEntriesFactory({ instances: [instance] }).filter((entry) =>
|
|
2504
|
+
fs.existsSync(entry.sourcePath),
|
|
2505
|
+
);
|
|
2493
2506
|
|
|
2494
2507
|
// httproute.yaml — this instance's own routes, including the status routes
|
|
2495
2508
|
// that reach the static utility instead of this workload. No Gateway is
|
|
@@ -3066,7 +3079,7 @@ EOF`);
|
|
|
3066
3079
|
const hostListenResult = etcHostFactory(hosts);
|
|
3067
3080
|
logger.info(hostListenResult.renderHosts);
|
|
3068
3081
|
}
|
|
3069
|
-
const version = 'v3.3.
|
|
3082
|
+
const version = 'v3.3.76';
|
|
3070
3083
|
const instanceOptionsFactory = (deployId, instanceId) => ({
|
|
3071
3084
|
...options,
|
|
3072
3085
|
...clusterContextFactory(clusterType),
|
|
@@ -3850,9 +3863,9 @@ EOF`);
|
|
|
3850
3863
|
);
|
|
3851
3864
|
switch (serviceId) {
|
|
3852
3865
|
case 'mongo-express-service': {
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3866
|
+
// One deploy path for the client, shared with `cluster --mongo-express`: the secret,
|
|
3867
|
+
// the auth-mode overlay selection and the readiness wait live there.
|
|
3868
|
+
await MongoExpress.deploy({ namespace: options.namespace, options });
|
|
3856
3869
|
podToMonitor = 'mongo-express';
|
|
3857
3870
|
break;
|
|
3858
3871
|
}
|
|
@@ -4398,186 +4411,47 @@ EOF`;
|
|
|
4398
4411
|
|
|
4399
4412
|
/**
|
|
4400
4413
|
* @method push-bundle
|
|
4401
|
-
* @description Builds the
|
|
4402
|
-
* Steps: set env, build
|
|
4403
|
-
*
|
|
4404
|
-
*
|
|
4405
|
-
*
|
|
4414
|
+
* @description Builds the deployment's client bundles and uploads them to file storage.
|
|
4415
|
+
* Steps: set env, build and split the zips, then upload each resolved route's artifacts
|
|
4416
|
+
* under the deployment's `storage.bundle.json`. Routes the client build skips — redirects,
|
|
4417
|
+
* rebuild-disabled routes, and `singleReplica` routes that carry their own deploy id —
|
|
4418
|
+
* produce no bundle and are not pushed.
|
|
4419
|
+
* @param {string} path - Optional comma-separated host filter (e.g. 'a.com' or 'a.com,b.com').
|
|
4420
|
+
* Empty selects every host in `engine-private/conf/<deployId>/conf.server.json`.
|
|
4406
4421
|
* @param {UnderpostRunDefaultOptions} options - The default underpost runner options for customizing workflow.
|
|
4407
|
-
* @param {string} [options.deployId] -
|
|
4422
|
+
* @param {string} [options.deployId] - Deploy ID for storage lookup (defaults to 'dd-default').
|
|
4423
|
+
* @param {string} [options.split] - Zip part size in MB, or 'none' to upload one zip. Defaults to 8.
|
|
4408
4424
|
* @param {boolean} [options.dev] - Use development environment; defaults to production.
|
|
4409
4425
|
* @memberof UnderpostRun
|
|
4410
4426
|
*/
|
|
4411
|
-
'push-bundle': (path = '', options = DEFAULT_OPTION) =>
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
let splitFlag = '--split 8';
|
|
4420
|
-
if (splitOption) {
|
|
4421
|
-
if (splitOption === 'none-split') {
|
|
4422
|
-
splitFlag = '';
|
|
4423
|
-
} else {
|
|
4424
|
-
const splitMb = Number(splitOption);
|
|
4425
|
-
if (Number.isFinite(splitMb) && splitMb > 0) {
|
|
4426
|
-
splitFlag = `--split ${splitMb}`;
|
|
4427
|
-
} else {
|
|
4428
|
-
logger.warn('push-bundle: invalid split option, using default split 8', {
|
|
4429
|
-
path,
|
|
4430
|
-
splitOption,
|
|
4431
|
-
});
|
|
4432
|
-
}
|
|
4433
|
-
}
|
|
4434
|
-
}
|
|
4435
|
-
|
|
4436
|
-
const confServerPath = `./engine-private/conf/${deployId}/conf.server.json`;
|
|
4437
|
-
const confServer = fs.existsSync(confServerPath)
|
|
4438
|
-
? loadReplicas(deployId, loadConfServerJson(confServerPath))
|
|
4439
|
-
: {};
|
|
4440
|
-
const storageFilePath = `engine-private/conf/${deployId}/storage.bundle.json`;
|
|
4441
|
-
|
|
4442
|
-
shellExec(`${baseCommand} env ${deployId} ${env}`);
|
|
4443
|
-
shellExec(`${baseCommand} client ${deployId} --env ${env} --build-zip${splitFlag ? ` ${splitFlag}` : ''}`);
|
|
4444
|
-
|
|
4445
|
-
const pushBundleFiles = (host, routePath) => {
|
|
4446
|
-
const buildId = `${host}-${routePath.replaceAll('/', '')}`;
|
|
4447
|
-
const buildDir = `./${fsPath}`;
|
|
4448
|
-
if (!fs.existsSync(buildDir)) return;
|
|
4449
|
-
const partFiles = fs
|
|
4450
|
-
.readdirSync(buildDir)
|
|
4451
|
-
.filter(
|
|
4452
|
-
(name) =>
|
|
4453
|
-
name.startsWith(`${buildId}.zip.part`) ||
|
|
4454
|
-
name.startsWith(`${buildId}.zip-part`) ||
|
|
4455
|
-
name === `${buildId}.zip`,
|
|
4456
|
-
)
|
|
4457
|
-
.map((name) => `${fsPath}/${name}`);
|
|
4458
|
-
if (partFiles.length === 0) {
|
|
4459
|
-
logger.warn(`push-bundle: no bundle files found for '${host}${routePath}'`, { buildId });
|
|
4460
|
-
return;
|
|
4461
|
-
}
|
|
4462
|
-
for (const partFile of partFiles) {
|
|
4463
|
-
shellExec(
|
|
4464
|
-
`${baseCommand} fs ${partFile} --deploy-id ${deployId} --storage-file-path ${storageFilePath} --force`,
|
|
4465
|
-
);
|
|
4466
|
-
}
|
|
4467
|
-
};
|
|
4468
|
-
|
|
4469
|
-
for (const host of Object.keys(confServer)) {
|
|
4470
|
-
for (const routePath of Object.keys(confServer[host])) {
|
|
4471
|
-
const routeConf = confServer[host][routePath] || {};
|
|
4472
|
-
if (routeConf.redirect || routeConf.disabledRebuild) continue;
|
|
4473
|
-
if (routeConf.singleReplica) {
|
|
4474
|
-
if (routeConf.replicas) {
|
|
4475
|
-
for (const replica of routeConf.replicas) {
|
|
4476
|
-
pushBundleFiles(host, replica);
|
|
4477
|
-
}
|
|
4478
|
-
}
|
|
4479
|
-
continue;
|
|
4480
|
-
}
|
|
4481
|
-
pushBundleFiles(host, routePath);
|
|
4482
|
-
}
|
|
4483
|
-
}
|
|
4484
|
-
},
|
|
4427
|
+
'push-bundle': (path = '', options = DEFAULT_OPTION) =>
|
|
4428
|
+
pushClientBundle({
|
|
4429
|
+
deployId: options.deployId || 'dd-default',
|
|
4430
|
+
hosts: clientBundleHostFilter(path),
|
|
4431
|
+
split: options.split,
|
|
4432
|
+
dev: options.dev,
|
|
4433
|
+
}),
|
|
4485
4434
|
|
|
4486
4435
|
/**
|
|
4487
4436
|
* @method pull-bundle
|
|
4488
|
-
* @description Downloads
|
|
4489
|
-
*
|
|
4490
|
-
*
|
|
4491
|
-
*
|
|
4492
|
-
*
|
|
4493
|
-
*
|
|
4437
|
+
* @description Downloads the deployment's client bundles from file storage and installs them
|
|
4438
|
+
* into the served public directory.
|
|
4439
|
+
* Steps: set env, download the parts, merge and extract each resolved route's zip, then
|
|
4440
|
+
* replace `public/<host>[<route>]` with the extracted tree. Route selection matches
|
|
4441
|
+
* push-bundle, so the two directions always address the same set of bundles.
|
|
4442
|
+
* @param {string} path - Optional comma-separated host filter (e.g. 'a.com' or 'a.com,b.com').
|
|
4443
|
+
* Empty selects every host in `engine-private/conf/<deployId>/conf.server.json`.
|
|
4494
4444
|
* @param {UnderpostRunDefaultOptions} options - The default underpost runner options for customizing workflow.
|
|
4495
4445
|
* @param {string} [options.deployId] - Deploy ID for storage lookup (defaults to 'dd-default').
|
|
4496
4446
|
* @param {boolean} [options.dev] - Use development environment; defaults to production.
|
|
4497
4447
|
* @memberof UnderpostRun
|
|
4498
4448
|
*/
|
|
4499
|
-
'pull-bundle': (path = '', options = DEFAULT_OPTION) =>
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
? loadReplicas(deployId, loadConfServerJson(confServerPath))
|
|
4506
|
-
: {};
|
|
4507
|
-
const hostsArg = path
|
|
4508
|
-
? path
|
|
4509
|
-
.split(',')
|
|
4510
|
-
.map((h) => h.trim())
|
|
4511
|
-
.filter(Boolean)
|
|
4512
|
-
: Object.keys(confServer);
|
|
4513
|
-
|
|
4514
|
-
if (hostsArg.length === 0) {
|
|
4515
|
-
logger.error('pull-bundle: no hosts resolved', { deployId, path, confServerPath });
|
|
4516
|
-
return;
|
|
4517
|
-
}
|
|
4518
|
-
|
|
4519
|
-
shellExec(`${baseCommand} env ${deployId} ${env}`);
|
|
4520
|
-
if (!fs.existsSync('./build')) fs.mkdirSync('./build', { recursive: true });
|
|
4521
|
-
shellExec(
|
|
4522
|
-
`${baseCommand} fs build --recursive --deploy-id ${deployId} --storage-file-path engine-private/conf/${deployId}/storage.bundle.json --pull --omit-unzip`,
|
|
4523
|
-
);
|
|
4524
|
-
|
|
4525
|
-
const pullBundleRoute = (host, routePath) => {
|
|
4526
|
-
const buildId = `${host}-${routePath.replaceAll('/', '')}`;
|
|
4527
|
-
const zipPath = `build/${buildId}.zip`;
|
|
4528
|
-
const buildDir = './build';
|
|
4529
|
-
const hasZip = fs.existsSync(zipPath);
|
|
4530
|
-
const hasParts =
|
|
4531
|
-
fs.existsSync(buildDir) &&
|
|
4532
|
-
fs
|
|
4533
|
-
.readdirSync(buildDir)
|
|
4534
|
-
.some((name) => name.startsWith(`${buildId}.zip.part`) || name.startsWith(`${buildId}.zip-part`));
|
|
4535
|
-
|
|
4536
|
-
if (!hasZip && !hasParts) {
|
|
4537
|
-
logger.warn(`Bundle not found for '${host}${routePath}'. Skipping.`, { zipPath, deployId });
|
|
4538
|
-
return;
|
|
4539
|
-
}
|
|
4540
|
-
|
|
4541
|
-
if (hasParts) shellExec(`${baseCommand} client --merge-zip ${zipPath}`);
|
|
4542
|
-
shellExec(`${baseCommand} client --unzip ${zipPath}`);
|
|
4543
|
-
shellExec(`sudo rm -rf ${zipPath}`);
|
|
4544
|
-
|
|
4545
|
-
if (fs.existsSync(buildDir)) {
|
|
4546
|
-
fs.readdirSync(buildDir)
|
|
4547
|
-
.filter((name) => name.startsWith(`${buildId}.zip.part`) || name.startsWith(`${buildId}.zip-part`))
|
|
4548
|
-
.forEach((partFile) => shellExec(`sudo rm -rf ${buildDir}/${partFile}`));
|
|
4549
|
-
}
|
|
4550
|
-
|
|
4551
|
-
const extractedDir = `build/${buildId.replace(/-$/, '')}`;
|
|
4552
|
-
if (!fs.existsSync(extractedDir)) {
|
|
4553
|
-
logger.warn(`Extracted build dir not found: ${extractedDir}. Skipping move for '${host}${routePath}'.`);
|
|
4554
|
-
return;
|
|
4555
|
-
}
|
|
4556
|
-
|
|
4557
|
-
const publicDestPath = routePath === '/' ? `public/${host}` : `public/${host}${routePath}`;
|
|
4558
|
-
if (fs.existsSync(publicDestPath)) shellExec(`sudo rm -rf ${publicDestPath}`);
|
|
4559
|
-
if (routePath !== '/') shellExec(`sudo mkdir -p public/${host}`);
|
|
4560
|
-
fs.copySync(`${extractedDir}`, `${publicDestPath}`);
|
|
4561
|
-
};
|
|
4562
|
-
|
|
4563
|
-
for (const host of hostsArg) {
|
|
4564
|
-
const routePaths = confServer[host] ? Object.keys(confServer[host]) : ['/'];
|
|
4565
|
-
|
|
4566
|
-
for (const routePath of routePaths) {
|
|
4567
|
-
const routeConf = confServer[host] ? confServer[host][routePath] || {} : {};
|
|
4568
|
-
if (routeConf.redirect || routeConf.disabledRebuild) continue;
|
|
4569
|
-
if (routeConf.singleReplica) {
|
|
4570
|
-
if (routeConf.replicas) {
|
|
4571
|
-
for (const replica of routeConf.replicas) {
|
|
4572
|
-
pullBundleRoute(host, replica);
|
|
4573
|
-
}
|
|
4574
|
-
}
|
|
4575
|
-
continue;
|
|
4576
|
-
}
|
|
4577
|
-
pullBundleRoute(host, routePath);
|
|
4578
|
-
}
|
|
4579
|
-
}
|
|
4580
|
-
},
|
|
4449
|
+
'pull-bundle': async (path = '', options = DEFAULT_OPTION) =>
|
|
4450
|
+
await pullClientBundle({
|
|
4451
|
+
deployId: options.deployId || 'dd-default',
|
|
4452
|
+
hosts: clientBundleHostFilter(path),
|
|
4453
|
+
dev: options.dev,
|
|
4454
|
+
}),
|
|
4581
4455
|
|
|
4582
4456
|
/**
|
|
4583
4457
|
* @method kubeadm-wireguard
|
package/src/cli/test.js
CHANGED
|
@@ -19,6 +19,7 @@ import { shellExec } from '../server/runtime/process.js';
|
|
|
19
19
|
import {
|
|
20
20
|
UNDERPOST_TESTING,
|
|
21
21
|
allureManifestsFactory,
|
|
22
|
+
coverageReportKey,
|
|
22
23
|
resolveTestSelection,
|
|
23
24
|
testJobManifestFactory,
|
|
24
25
|
vitestArgsFactory,
|
|
@@ -82,6 +83,9 @@ class UnderpostTest {
|
|
|
82
83
|
'NODE_ENV=test',
|
|
83
84
|
...(allureResultsDirectory ? [`${UNDERPOST_TESTING.allureResultsEnvKey}=${allureResultsDirectory}`] : []),
|
|
84
85
|
];
|
|
86
|
+
// Only this selection's report starts from nothing: the ones beside it belong to
|
|
87
|
+
// other selections a deploy on this host may publish.
|
|
88
|
+
if (coverage) fs.removeSync(`${root}/${UNDERPOST_TESTING.coverageDirectory}/${coverageReportKey(suite)}`);
|
|
85
89
|
shellExec(
|
|
86
90
|
`cd ${root} && ${env.join(' ')} npx vitest ${vitestArgsFactory({ projects, grep, watch, coverage }).join(' ')}`,
|
|
87
91
|
);
|
package/src/cli/wireguard.js
CHANGED
|
@@ -95,42 +95,27 @@ const EVENT_SERVICE_UNIT_PATH = '/etc/systemd/system/underpost-event.service';
|
|
|
95
95
|
|
|
96
96
|
/**
|
|
97
97
|
* @constant ENGINE_SYNC_STEPS
|
|
98
|
-
* @description
|
|
98
|
+
* @description Sequence of steps to bring a node's checkout up to date.
|
|
99
99
|
*
|
|
100
|
-
* The
|
|
101
|
-
* step between them is the node's own CLI, which cannot load from a checkout whose installed
|
|
102
|
-
* packages no longer match its manifest — so the first run repairs the tree it finds, and the
|
|
103
|
-
* second installs the manifest the switch just landed. The first is advisory because a node
|
|
104
|
-
* whose tree predates that script must still reach the switch that gives it one.
|
|
100
|
+
* The sync runs the node's own CLI, bracketed by two critical installs:
|
|
105
101
|
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* it that preparation resolves the default pairing and undoes the switch.
|
|
111
|
-
* - the cluster's CronJob manifests are regenerated and republished, because their pod bodies run
|
|
112
|
-
* the checkout that just changed.
|
|
113
|
-
* - the supervised services are reconciled through their own generators, on the unit file's
|
|
114
|
-
* existence rather than on the unit being active: one the previous scope's tree left dead is
|
|
115
|
-
* exactly the one that has to come back, and `is-active` skipped precisely that case.
|
|
102
|
+
* 1. **Bootstrap Install:** Restores the original `package.json` from git and installs it.
|
|
103
|
+
* This ensures the CLI remains runnable with the current code tree before any changes are applied.
|
|
104
|
+
* 2. **Deploy Install:** Installs the deploy's `package.json` and links the CLI. This happens
|
|
105
|
+
* after both the configuration and source code switches have landed.
|
|
116
106
|
*
|
|
117
|
-
* All of those are scoped to the role of the node reached — see {@link NODE_ROLE_STEPS}.
|
|
118
|
-
*
|
|
119
|
-
* A step whose placeholder resolves to nothing is dropped rather than run empty: a monorepo sync
|
|
120
|
-
* belongs to no deploy, a deploy that ships no package script has nothing to run, and a run
|
|
121
|
-
* without a token must not overwrite the node's with a blank.
|
|
122
107
|
* @memberof UnderpostWireguard
|
|
123
108
|
*/
|
|
124
109
|
const ENGINE_SYNC_STEPS = [
|
|
125
|
-
{ command: '
|
|
110
|
+
{ command: 'git checkout -- package.json; npm install', halt: false },
|
|
126
111
|
{ command: 'node bin host set GITHUB_TOKEN <github-token>' },
|
|
127
|
-
{ command: '
|
|
128
|
-
{ command: 'underpost cmt --switch-repo <engine> --target-branch <engine-branch>', halt: true },
|
|
112
|
+
{ command: 'node bin run clean', halt: true },
|
|
129
113
|
{
|
|
130
|
-
command: '
|
|
114
|
+
command: 'node bin cmt ./engine-private --switch-repo <engine-private> --target-branch <engine-private-branch>',
|
|
131
115
|
halt: true,
|
|
132
116
|
},
|
|
133
|
-
{ command: '
|
|
117
|
+
{ command: 'node bin cmt --switch-repo <engine> --target-branch <engine-branch>', halt: true },
|
|
118
|
+
{ command: '<package-install-command>', halt: true },
|
|
134
119
|
{ command: 'node bin host set ENGINE_SRC_REPO <engine>', halt: true },
|
|
135
120
|
{ command: 'node bin host set ENGINE_SRC_PRIVATE_REPO <engine-private>', halt: true },
|
|
136
121
|
{ command: '<cron-reconcile-command>', halt: false },
|
|
@@ -159,10 +144,9 @@ const deployIdFactory = (deployId) => {
|
|
|
159
144
|
* being synced actually ships one.
|
|
160
145
|
*
|
|
161
146
|
* Both halves have to hold. A monorepo sync belongs to no deploy, and a deploy that ships no
|
|
162
|
-
* script of its own would leave the node running `bash` against a path that does not exist
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
* completes, which is the only tree whose contents the step can be resolved against.
|
|
147
|
+
* script of its own would leave the node running `bash` against a path that does not exist. The
|
|
148
|
+
* check reads this checkout because it is the tree the node lands on once the switch completes,
|
|
149
|
+
* which is the only tree whose contents the step can be resolved against.
|
|
166
150
|
* @param {string} engine - Engine source repository the node is switched onto.
|
|
167
151
|
* @returns {string} Path to that deploy's package script, or `''` when there is none to run.
|
|
168
152
|
* @memberof UnderpostWireguard
|
|
@@ -173,6 +157,23 @@ const deployPackageScriptFactory = (engine = '') => {
|
|
|
173
157
|
return path && fs.existsSync(path) ? path : '';
|
|
174
158
|
};
|
|
175
159
|
|
|
160
|
+
/**
|
|
161
|
+
* @method packageInstallCommandFactory
|
|
162
|
+
* @description How a node installs against the source a switch just landed.
|
|
163
|
+
*
|
|
164
|
+
* A deploy's own script is preferred because it installs that deploy's manifest and links the
|
|
165
|
+
* CLI. Where there is none — a monorepo sync, or a deploy that ships no script — the checkout's
|
|
166
|
+
* own manifest is installed instead, so the step is never dropped: every sync replaces the
|
|
167
|
+
* source, and source the installed packages predate is what breaks the next command.
|
|
168
|
+
* @param {string} engine - Engine source repository the node is switched onto.
|
|
169
|
+
* @returns {string} The install command for that source.
|
|
170
|
+
* @memberof UnderpostWireguard
|
|
171
|
+
*/
|
|
172
|
+
const packageInstallCommandFactory = (engine = '') => {
|
|
173
|
+
const packageScript = deployPackageScriptFactory(engine);
|
|
174
|
+
return packageScript ? `bash ${packageScript}` : 'npm install';
|
|
175
|
+
};
|
|
176
|
+
|
|
176
177
|
/**
|
|
177
178
|
* @method deployListFactory
|
|
178
179
|
* @description The deploys whose hostnames a run publishes.
|
|
@@ -2666,7 +2667,7 @@ class UnderpostWireguard {
|
|
|
2666
2667
|
'<engine-private>': enginePrivate,
|
|
2667
2668
|
'<engine-branch>': Underpost.repo.getDefaultBranch(engine),
|
|
2668
2669
|
'<engine>': engine,
|
|
2669
|
-
'<
|
|
2670
|
+
'<package-install-command>': packageInstallCommandFactory(engine),
|
|
2670
2671
|
...nodeRoleStepsFactory(options.nodeRole),
|
|
2671
2672
|
'<github-token>': process.env.GITHUB_TOKEN || '',
|
|
2672
2673
|
};
|