cyberia 3.0.3 → 3.2.5
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.production → .env.example} +20 -4
- package/.github/workflows/engine-cyberia.cd.yml +43 -10
- package/.github/workflows/engine-cyberia.ci.yml +48 -26
- package/.github/workflows/ghpkg.ci.yml +5 -5
- package/.github/workflows/gitlab.ci.yml +1 -1
- package/.github/workflows/hardhat.ci.yml +82 -0
- package/.github/workflows/npmpkg.ci.yml +60 -14
- package/.github/workflows/publish.ci.yml +26 -7
- package/.github/workflows/publish.cyberia.ci.yml +5 -5
- package/.github/workflows/pwa-microservices-template-page.cd.yml +6 -7
- package/.github/workflows/pwa-microservices-template-test.ci.yml +4 -4
- package/.github/workflows/release.cd.yml +14 -8
- package/.vscode/extensions.json +9 -8
- package/.vscode/settings.json +3 -2
- package/CHANGELOG.md +643 -1
- package/CLI-HELP.md +132 -57
- package/Dockerfile +4 -2
- package/README.md +347 -22
- package/WHITE-PAPER.md +1540 -0
- package/bin/build.js +21 -12
- package/bin/cyberia.js +2640 -106
- package/bin/deploy.js +258 -372
- package/bin/file.js +5 -1
- package/bin/index.js +2640 -106
- package/bin/vs.js +3 -3
- package/conf.js +169 -105
- package/deployment.yaml +236 -20
- package/hardhat/.env.example +31 -0
- package/hardhat/README.md +531 -0
- package/hardhat/WHITE-PAPER.md +1540 -0
- package/hardhat/contracts/ObjectLayerToken.sol +391 -0
- package/hardhat/deployments/.gitkeep +0 -0
- package/hardhat/deployments/hardhat-ObjectLayerToken.json +11 -0
- package/hardhat/hardhat.config.js +136 -0
- package/hardhat/ignition/modules/ObjectLayerToken.js +21 -0
- package/hardhat/networks/besu-object-layer.network.json +138 -0
- package/hardhat/package-lock.json +4323 -0
- package/hardhat/package.json +36 -0
- package/hardhat/scripts/deployObjectLayerToken.js +98 -0
- package/hardhat/test/ObjectLayerToken.js +592 -0
- package/hardhat/types/ethers-contracts/ObjectLayerToken.ts +690 -0
- package/hardhat/types/ethers-contracts/common.ts +92 -0
- package/hardhat/types/ethers-contracts/factories/ObjectLayerToken__factory.ts +1055 -0
- package/hardhat/types/ethers-contracts/factories/index.ts +4 -0
- package/hardhat/types/ethers-contracts/hardhat.d.ts +47 -0
- package/hardhat/types/ethers-contracts/index.ts +6 -0
- package/jsdoc.dd-cyberia.json +68 -0
- package/jsdoc.json +65 -49
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +5 -4
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +5 -4
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +562 -0
- package/manifests/deployment/dd-cyberia-development/proxy.yaml +297 -0
- package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +132 -0
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +88 -74
- package/manifests/deployment/dd-test-development/proxy.yaml +13 -4
- package/manifests/deployment/playwright/deployment.yaml +1 -1
- package/manifests/pv-pvc-dd.yaml +1 -1
- package/nodemon.json +1 -1
- package/package.json +60 -48
- package/proxy.yaml +118 -10
- package/pv-pvc.yaml +132 -0
- package/scripts/k3s-node-setup.sh +1 -1
- package/scripts/ports-ls.sh +2 -0
- package/scripts/rhel-grpc-setup.sh +56 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +47 -1
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +17 -2
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +5 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +80 -7
- package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +93 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +36 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +29 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +51 -0
- package/src/api/cyberia-entity/cyberia-entity.controller.js +74 -0
- package/src/api/cyberia-entity/cyberia-entity.model.js +24 -0
- package/src/api/cyberia-entity/cyberia-entity.router.js +27 -0
- package/src/api/cyberia-entity/cyberia-entity.service.js +42 -0
- package/src/api/cyberia-instance/cyberia-fallback-world.js +368 -0
- package/src/api/cyberia-instance/cyberia-instance.controller.js +92 -0
- package/src/api/cyberia-instance/cyberia-instance.model.js +84 -0
- package/src/api/cyberia-instance/cyberia-instance.router.js +63 -0
- package/src/api/cyberia-instance/cyberia-instance.service.js +191 -0
- package/src/api/cyberia-instance/cyberia-portal-connector.js +486 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +74 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js +413 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +228 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +27 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +42 -0
- package/src/api/cyberia-map/cyberia-map.controller.js +79 -0
- package/src/api/cyberia-map/cyberia-map.model.js +30 -0
- package/src/api/cyberia-map/cyberia-map.router.js +40 -0
- package/src/api/cyberia-map/cyberia-map.service.js +74 -0
- package/src/api/document/document.service.js +1 -1
- package/src/api/file/file.controller.js +3 -1
- package/src/api/file/file.ref.json +18 -0
- package/src/api/file/file.service.js +28 -5
- package/src/api/ipfs/ipfs.controller.js +4 -25
- package/src/api/ipfs/ipfs.model.js +43 -34
- package/src/api/ipfs/ipfs.router.js +8 -13
- package/src/api/ipfs/ipfs.service.js +56 -104
- package/src/api/object-layer/README.md +347 -22
- package/src/api/object-layer/object-layer.controller.js +6 -2
- package/src/api/object-layer/object-layer.model.js +12 -8
- package/src/api/object-layer/object-layer.router.js +698 -42
- package/src/api/object-layer/object-layer.service.js +119 -37
- package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +1 -2
- package/src/api/user/user.router.js +10 -5
- package/src/api/user/user.service.js +15 -14
- package/src/cli/baremetal.js +6 -10
- package/src/cli/cloud-init.js +0 -3
- package/src/cli/cluster.js +7 -7
- package/src/cli/db.js +723 -857
- package/src/cli/deploy.js +215 -105
- package/src/cli/env.js +34 -5
- package/src/cli/fs.js +5 -4
- package/src/cli/image.js +0 -3
- package/src/cli/index.js +83 -15
- package/src/cli/kubectl.js +211 -0
- package/src/cli/monitor.js +5 -6
- package/src/cli/release.js +284 -0
- package/src/cli/repository.js +708 -62
- package/src/cli/run.js +371 -151
- package/src/cli/secrets.js +73 -2
- package/src/cli/ssh.js +1 -1
- package/src/cli/test.js +3 -3
- package/src/client/Cryptokoyn.index.js +3 -4
- package/src/client/CyberiaPortal.index.js +3 -4
- package/src/client/Default.index.js +3 -4
- package/src/client/Itemledger.index.js +4 -963
- package/src/client/Underpost.index.js +3 -4
- package/src/client/components/core/AgGrid.js +20 -5
- package/src/client/components/core/Alert.js +2 -2
- package/src/client/components/core/AppStore.js +69 -0
- package/src/client/components/core/CalendarCore.js +2 -2
- package/src/client/components/core/Content.js +22 -3
- package/src/client/components/core/Docs.js +30 -6
- package/src/client/components/core/DropDown.js +137 -17
- package/src/client/components/core/FileExplorer.js +71 -4
- package/src/client/components/core/Input.js +1 -1
- package/src/client/components/core/Keyboard.js +2 -2
- package/src/client/components/core/LogIn.js +2 -2
- package/src/client/components/core/LogOut.js +2 -2
- package/src/client/components/core/Modal.js +20 -7
- package/src/client/components/core/Panel.js +0 -1
- package/src/client/components/core/PanelForm.js +19 -19
- package/src/client/components/core/RichText.js +1 -2
- package/src/client/components/core/SocketIo.js +82 -29
- package/src/client/components/core/SocketIoHandler.js +75 -0
- package/src/client/components/core/Stream.js +143 -95
- package/src/client/components/core/Webhook.js +40 -7
- package/src/client/components/cryptokoyn/AppStoreCryptokoyn.js +5 -0
- package/src/client/components/cryptokoyn/LogInCryptokoyn.js +3 -3
- package/src/client/components/cryptokoyn/LogOutCryptokoyn.js +2 -2
- package/src/client/components/cryptokoyn/MenuCryptokoyn.js +3 -3
- package/src/client/components/cryptokoyn/SocketIoCryptokoyn.js +3 -51
- package/src/client/components/cyberia/InstanceEngineCyberia.js +700 -0
- package/src/client/components/cyberia/MapEngineCyberia.js +1359 -2
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +17 -6
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +92 -54
- package/src/client/components/cyberia-portal/AppStoreCyberiaPortal.js +5 -0
- package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +217 -30
- package/src/client/components/cyberia-portal/CssCyberiaPortal.js +44 -2
- package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +3 -4
- package/src/client/components/cyberia-portal/LogOutCyberiaPortal.js +2 -2
- package/src/client/components/cyberia-portal/MenuCyberiaPortal.js +104 -9
- package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +5 -0
- package/src/client/components/cyberia-portal/SocketIoCyberiaPortal.js +3 -49
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +4 -0
- package/src/client/components/default/AppStoreDefault.js +5 -0
- package/src/client/components/default/LogInDefault.js +3 -3
- package/src/client/components/default/LogOutDefault.js +2 -2
- package/src/client/components/default/MenuDefault.js +5 -5
- package/src/client/components/default/SocketIoDefault.js +3 -51
- package/src/client/components/itemledger/AppStoreItemledger.js +5 -0
- package/src/client/components/itemledger/LogInItemledger.js +3 -3
- package/src/client/components/itemledger/LogOutItemledger.js +2 -2
- package/src/client/components/itemledger/MenuItemledger.js +3 -3
- package/src/client/components/itemledger/SocketIoItemledger.js +3 -51
- package/src/client/components/underpost/AppStoreUnderpost.js +5 -0
- package/src/client/components/underpost/CssUnderpost.js +59 -0
- package/src/client/components/underpost/LogInUnderpost.js +6 -3
- package/src/client/components/underpost/LogOutUnderpost.js +4 -2
- package/src/client/components/underpost/MenuUnderpost.js +104 -18
- package/src/client/components/underpost/RoutesUnderpost.js +2 -0
- package/src/client/components/underpost/SocketIoUnderpost.js +3 -51
- package/src/client/public/cryptokoyn/assets/logo/base-icon.png +0 -0
- package/src/client/public/cryptokoyn/browserconfig.xml +12 -0
- package/src/client/public/cryptokoyn/microdata.json +85 -0
- package/src/client/public/cryptokoyn/site.webmanifest +57 -0
- package/src/client/public/cryptokoyn/sitemap +3 -3
- package/src/client/public/default/sitemap +3 -3
- package/src/client/public/itemledger/browserconfig.xml +2 -2
- package/src/client/public/itemledger/manifest.webmanifest +4 -4
- package/src/client/public/itemledger/microdata.json +71 -0
- package/src/client/public/itemledger/sitemap +3 -3
- package/src/client/public/itemledger/yandex-browser-manifest.json +2 -2
- package/src/client/public/test/sitemap +3 -3
- package/src/client/services/core/core.service.js +20 -8
- package/src/client/services/cyberia-dialogue/cyberia-dialogue.service.js +105 -0
- package/src/client/services/cyberia-entity/cyberia-entity.management.js +57 -0
- package/src/client/services/cyberia-entity/cyberia-entity.service.js +105 -0
- package/src/client/services/cyberia-instance/cyberia-instance.management.js +194 -0
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +122 -0
- package/src/client/services/cyberia-instance-conf/cyberia-instance-conf.service.js +105 -0
- package/src/client/services/cyberia-map/cyberia-map.management.js +193 -0
- package/src/client/services/cyberia-map/cyberia-map.service.js +126 -0
- package/src/client/services/instance/instance.management.js +2 -2
- package/src/client/services/ipfs/ipfs.service.js +3 -23
- package/src/client/services/object-layer/object-layer.management.js +3 -3
- package/src/client/services/object-layer/object-layer.service.js +21 -0
- package/src/client/services/user/user.management.js +2 -2
- package/src/client/ssr/body/404.js +15 -11
- package/src/client/ssr/body/500.js +15 -11
- package/src/client/ssr/body/SwaggerDarkMode.js +285 -0
- package/src/client/ssr/head/PwaItemledger.js +60 -0
- package/src/client/ssr/offline/NoNetworkConnection.js +11 -10
- package/src/client/ssr/pages/CyberiaServerMetrics.js +1 -1
- package/src/client/ssr/pages/Test.js +11 -10
- package/src/client.build.js +0 -3
- package/src/client.dev.js +0 -3
- package/src/db/DataBaseProvider.js +17 -2
- package/src/db/mariadb/MariaDB.js +14 -9
- package/src/db/mongo/MongooseDB.js +17 -1
- package/src/grpc/cyberia/OFF_CHAIN_ECONOMY.md +305 -0
- package/src/grpc/cyberia/README.md +326 -0
- package/src/grpc/cyberia/grpc-server.js +530 -0
- package/src/index.js +24 -1
- package/src/proxy.js +0 -3
- package/src/runtime/express/Dockerfile +4 -0
- package/src/runtime/express/Express.js +33 -10
- package/src/runtime/lampp/Dockerfile +13 -2
- package/src/runtime/lampp/Lampp.js +33 -17
- package/src/runtime/wp/Dockerfile +68 -0
- package/src/runtime/wp/Wp.js +639 -0
- package/src/server/auth.js +36 -15
- package/src/server/backup.js +39 -12
- package/src/server/besu-genesis-generator.js +1630 -0
- package/src/server/client-build-docs.js +133 -17
- package/src/server/client-build-live.js +9 -18
- package/src/server/client-build.js +229 -101
- package/src/server/client-dev-server.js +14 -13
- package/src/server/client-formatted.js +109 -57
- package/src/server/conf.js +391 -164
- package/src/server/cron.js +27 -24
- package/src/server/dns.js +29 -12
- package/src/server/downloader.js +0 -2
- package/src/server/ipfs-client.js +24 -1
- package/src/server/logger.js +27 -9
- package/src/server/object-layer.js +217 -103
- package/src/server/peer.js +8 -2
- package/src/server/process.js +1 -50
- package/src/server/proxy.js +4 -8
- package/src/server/runtime.js +30 -9
- package/src/server/semantic-layer-generator-floor.js +359 -0
- package/src/server/semantic-layer-generator-skin.js +1294 -0
- package/src/server/semantic-layer-generator.js +116 -555
- package/src/server/ssr.js +0 -3
- package/src/server/start.js +19 -12
- package/src/server/tls.js +0 -2
- package/src/server.js +0 -4
- package/src/ws/IoInterface.js +1 -10
- package/src/ws/IoServer.js +14 -33
- package/src/ws/core/channels/core.ws.chat.js +65 -20
- package/src/ws/core/channels/core.ws.mailer.js +113 -32
- package/src/ws/core/channels/core.ws.stream.js +90 -31
- package/src/ws/core/core.ws.connection.js +12 -33
- package/src/ws/core/core.ws.emit.js +10 -26
- package/src/ws/core/core.ws.server.js +25 -58
- package/src/ws/default/channels/default.ws.main.js +53 -12
- package/src/ws/default/default.ws.connection.js +26 -13
- package/src/ws/default/default.ws.server.js +30 -12
- package/.env.development +0 -43
- package/.env.test +0 -43
- package/hardhat/contracts/CryptoKoyn.sol +0 -59
- package/hardhat/contracts/ItemLedger.sol +0 -73
- package/hardhat/contracts/Lock.sol +0 -34
- package/hardhat/hardhat.config.cjs +0 -45
- package/hardhat/ignition/modules/Lock.js +0 -18
- package/hardhat/networks/cryptokoyn-itemledger.network.json +0 -29
- package/hardhat/scripts/deployCryptokoyn.cjs +0 -25
- package/hardhat/scripts/deployItemledger.cjs +0 -25
- package/hardhat/test/Lock.js +0 -126
- package/hardhat/white-paper.md +0 -581
- package/src/client/components/cryptokoyn/CommonCryptokoyn.js +0 -29
- package/src/client/components/cryptokoyn/ElementsCryptokoyn.js +0 -38
- package/src/client/components/cyberia-portal/ElementsCyberiaPortal.js +0 -38
- package/src/client/components/default/ElementsDefault.js +0 -38
- package/src/client/components/itemledger/CommonItemledger.js +0 -29
- package/src/client/components/itemledger/ElementsItemledger.js +0 -38
- package/src/client/components/underpost/CommonUnderpost.js +0 -29
- package/src/client/components/underpost/ElementsUnderpost.js +0 -38
- package/src/ws/core/management/core.ws.chat.js +0 -8
- package/src/ws/core/management/core.ws.mailer.js +0 -16
- package/src/ws/core/management/core.ws.stream.js +0 -8
- package/src/ws/default/management/default.ws.main.js +0 -8
- package/white-paper.md +0 -581
package/src/cli/run.js
CHANGED
|
@@ -4,24 +4,45 @@
|
|
|
4
4
|
* @namespace UnderpostRun
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { daemonProcess, getTerminalPid,
|
|
7
|
+
import { daemonProcess, getTerminalPid, pbcopy, shellCd, shellExec } from '../server/process.js';
|
|
8
|
+
import crypto from 'crypto';
|
|
8
9
|
import {
|
|
9
10
|
awaitDeployMonitor,
|
|
10
11
|
buildKindPorts,
|
|
11
12
|
Config,
|
|
12
13
|
getNpmRootPath,
|
|
13
14
|
isDeployRunnerContext,
|
|
15
|
+
loadConfServerJson,
|
|
14
16
|
writeEnv,
|
|
15
17
|
} from '../server/conf.js';
|
|
16
18
|
import { actionInitLog, loggerFactory } from '../server/logger.js';
|
|
17
19
|
|
|
18
20
|
import fs from 'fs-extra';
|
|
21
|
+
import net from 'net';
|
|
19
22
|
import { range, setPad, timer } from '../client/components/core/CommonJs.js';
|
|
20
23
|
|
|
21
24
|
import os from 'os';
|
|
22
25
|
import Underpost from '../index.js';
|
|
23
26
|
import dotenv from 'dotenv';
|
|
24
27
|
|
|
28
|
+
const waitForPort = (port, host = '127.0.0.1', { maxAttempts = 30, interval = 2000 } = {}) =>
|
|
29
|
+
new Promise((resolve, reject) => {
|
|
30
|
+
let attempts = 0;
|
|
31
|
+
const tryConnect = () => {
|
|
32
|
+
attempts++;
|
|
33
|
+
const socket = net.createConnection({ port, host }, () => {
|
|
34
|
+
socket.destroy();
|
|
35
|
+
resolve();
|
|
36
|
+
});
|
|
37
|
+
socket.on('error', () => {
|
|
38
|
+
socket.destroy();
|
|
39
|
+
if (attempts >= maxAttempts) return reject(new Error(`Port ${port} not ready after ${maxAttempts} attempts`));
|
|
40
|
+
setTimeout(tryConnect, interval);
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
tryConnect();
|
|
44
|
+
});
|
|
45
|
+
|
|
25
46
|
const logger = loggerFactory(import.meta);
|
|
26
47
|
|
|
27
48
|
/**
|
|
@@ -55,7 +76,6 @@ const logger = loggerFactory(import.meta);
|
|
|
55
76
|
* @property {string} apiVersion - The API version for the container.
|
|
56
77
|
* @property {string} claimName - The claim name for the volume.
|
|
57
78
|
* @property {string} kindType - The kind of resource to create.
|
|
58
|
-
* @property {boolean} terminal - Whether to open a terminal.
|
|
59
79
|
* @property {number} devProxyPortOffset - The port offset for the development proxy.
|
|
60
80
|
* @property {boolean} hostNetwork - Whether to use host networking.
|
|
61
81
|
* @property {string} requestsMemory - The memory request for the container.
|
|
@@ -87,6 +107,7 @@ const logger = loggerFactory(import.meta);
|
|
|
87
107
|
* @property {boolean} logs - Whether to enable logs.
|
|
88
108
|
* @property {boolean} dryRun - Whether to perform a dry run.
|
|
89
109
|
* @property {boolean} createJobNow - Whether to create the job immediately.
|
|
110
|
+
* @property {number} fromNCommit - Number of commits back to use for message propagation (default: 1, last commit only).
|
|
90
111
|
* @property {string|Array<{ip: string, hostnames: string[]}>} hostAliases - Adds entries to the Pod /etc/hosts via Kubernetes hostAliases.
|
|
91
112
|
* As a string (CLI): semicolon-separated entries of "ip=hostname1,hostname2" (e.g., "127.0.0.1=foo.local,bar.local;10.1.2.3=foo.remote").
|
|
92
113
|
* As an array (programmatic): objects with `ip` and `hostnames` fields (e.g., [{ ip: "127.0.0.1", hostnames: ["foo.local"] }]).
|
|
@@ -120,7 +141,6 @@ const DEFAULT_OPTION = {
|
|
|
120
141
|
apiVersion: '',
|
|
121
142
|
claimName: '',
|
|
122
143
|
kindType: '',
|
|
123
|
-
terminal: false,
|
|
124
144
|
devProxyPortOffset: 0,
|
|
125
145
|
hostNetwork: false,
|
|
126
146
|
requestsMemory: '',
|
|
@@ -152,7 +172,10 @@ const DEFAULT_OPTION = {
|
|
|
152
172
|
logs: false,
|
|
153
173
|
dryRun: false,
|
|
154
174
|
createJobNow: false,
|
|
175
|
+
fromNCommit: 0,
|
|
155
176
|
hostAliases: '',
|
|
177
|
+
gitClean: false,
|
|
178
|
+
copy: false,
|
|
156
179
|
};
|
|
157
180
|
|
|
158
181
|
/**
|
|
@@ -195,7 +218,7 @@ class UnderpostRun {
|
|
|
195
218
|
}
|
|
196
219
|
|
|
197
220
|
{
|
|
198
|
-
// Detect MongoDB primary pod using
|
|
221
|
+
// Detect MongoDB primary pod using method
|
|
199
222
|
let primaryMongoHost = 'mongodb-0.mongodb-service';
|
|
200
223
|
try {
|
|
201
224
|
const primaryPodName = Underpost.db.getMongoPrimaryPodName({
|
|
@@ -245,8 +268,15 @@ class UnderpostRun {
|
|
|
245
268
|
const ports = '6379,27017';
|
|
246
269
|
shellExec(`node bin run kill '${ports}'`);
|
|
247
270
|
shellExec(`node bin run dev-cluster --dev --expose --namespace ${options.namespace}`, { async: true });
|
|
248
|
-
|
|
249
|
-
|
|
271
|
+
logger.info('Waiting for port-forward services to be ready...');
|
|
272
|
+
try {
|
|
273
|
+
await Promise.all([waitForPort(27017), waitForPort(6379)]);
|
|
274
|
+
logger.info('Port-forward services are ready');
|
|
275
|
+
} catch (err) {
|
|
276
|
+
logger.error('Port-forward services failed to become ready', { error: err.message });
|
|
277
|
+
shellExec(`node bin run kill '${ports}'`);
|
|
278
|
+
throw err;
|
|
279
|
+
}
|
|
250
280
|
shellExec(`node bin metadata --generate ${path}`);
|
|
251
281
|
shellExec(`node bin db --dev --clean-fs-collection dd`);
|
|
252
282
|
shellExec(`node bin run kill '${ports}'`);
|
|
@@ -355,58 +385,140 @@ class UnderpostRun {
|
|
|
355
385
|
},
|
|
356
386
|
/**
|
|
357
387
|
* @method template-deploy
|
|
358
|
-
* @description
|
|
359
|
-
*
|
|
388
|
+
* @description Pushes `engine-private`, dispatches CI workflow to build `pwa-microservices-template`,
|
|
389
|
+
* and optionally triggers engine-<conf-id> CI with sync/init which in turn dispatches the CD workflow
|
|
390
|
+
* after the build chain completes (template → ghpkg → engine-<conf-id> → CD).
|
|
391
|
+
* @param {string} path - The deployment path identifier (e.g., 'sync-engine-core', 'init-engine-core', or empty for build-only).
|
|
360
392
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
361
393
|
* @memberof UnderpostRun
|
|
362
394
|
*/
|
|
363
395
|
'template-deploy': (path = '', options = DEFAULT_OPTION) => {
|
|
364
396
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
365
|
-
|
|
366
|
-
|
|
397
|
+
shellExec(`npm run security:secrets`);
|
|
398
|
+
const reportPath = './gitleaks-report.json';
|
|
399
|
+
if (fs.existsSync(reportPath) && JSON.parse(fs.readFileSync(reportPath, 'utf8')).length > 0) {
|
|
400
|
+
logger.error('Secrets detected in gitleaks-report.json, aborting template-deploy');
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
shellExec(`${baseCommand} run pull`);
|
|
404
|
+
|
|
405
|
+
// Capture last N commit messages for propagation.
|
|
406
|
+
// When --from-n-commit is not set, auto-detect unpushed commit count (same as --unpush flag).
|
|
407
|
+
const fromN =
|
|
408
|
+
options.fromNCommit && parseInt(options.fromNCommit) > 0
|
|
409
|
+
? parseInt(options.fromNCommit)
|
|
410
|
+
: Underpost.repo.getUnpushedCount('.').count;
|
|
411
|
+
const message = shellExec(`node bin cmt --changelog ${fromN} --changelog-no-hash`, {
|
|
412
|
+
silent: true,
|
|
413
|
+
stdout: true,
|
|
414
|
+
}).trim();
|
|
415
|
+
|
|
367
416
|
shellExec(
|
|
368
417
|
`${baseCommand} push ./engine-private ${options.force ? '-f ' : ''}${
|
|
369
418
|
process.env.GITHUB_USERNAME
|
|
370
419
|
}/engine-private`,
|
|
371
420
|
);
|
|
372
421
|
shellCd('/home/dd/engine');
|
|
422
|
+
|
|
423
|
+
const sanitizedMessage = Underpost.repo.sanitizeChangelogMessage(message);
|
|
424
|
+
|
|
425
|
+
// Push engine repo so workflow YAML changes reach GitHub
|
|
373
426
|
shellExec(`git reset`);
|
|
374
|
-
function replaceNthNewline(str, n, replacement = ' ') {
|
|
375
|
-
let count = 0;
|
|
376
|
-
return str.replace(/\r\n?|\n/g, (match) => {
|
|
377
|
-
count++;
|
|
378
|
-
return count === n ? replacement : match;
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
shellExec(
|
|
382
|
-
`${baseCommand} cmt . --empty ci package-pwa-microservices-template${
|
|
383
|
-
path.startsWith('sync') ? `-${path}` : ''
|
|
384
|
-
}${
|
|
385
|
-
message
|
|
386
|
-
? ` "${replaceNthNewline(
|
|
387
|
-
message.replaceAll('"', '').replaceAll('`', '').replaceAll('#', '').replaceAll('- ', ''),
|
|
388
|
-
2,
|
|
389
|
-
)}"`
|
|
390
|
-
: ''
|
|
391
|
-
}`,
|
|
392
|
-
);
|
|
393
427
|
shellExec(`${baseCommand} push . ${options.force ? '-f ' : ''}${process.env.GITHUB_USERNAME}/engine`);
|
|
428
|
+
|
|
429
|
+
// Determine deploy conf and type from path (sync-engine-core, init-engine-core, etc.)
|
|
430
|
+
let deployConfId = '';
|
|
431
|
+
let deployType = '';
|
|
432
|
+
if (path.startsWith('sync-')) {
|
|
433
|
+
deployConfId = path.replace(/^sync-/, '');
|
|
434
|
+
deployType = 'sync-and-deploy';
|
|
435
|
+
} else if (path.startsWith('init-')) {
|
|
436
|
+
deployConfId = path.replace(/^init-/, '');
|
|
437
|
+
deployType = 'init';
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Dispatch npmpkg CI workflow — this builds pwa-microservices-template first.
|
|
441
|
+
// If deployConfId is set, npmpkg.ci.yml will dispatch the engine-<conf-id> CI
|
|
442
|
+
// with sync=true after template build completes. The engine CI then dispatches
|
|
443
|
+
// the CD workflow after the engine repo build finishes — ensuring correct sequence:
|
|
444
|
+
// npmpkg.ci → engine-<id>.ci → engine-<id>.cd
|
|
445
|
+
const repo = `${process.env.GITHUB_USERNAME}/engine`;
|
|
446
|
+
const inputs = {};
|
|
447
|
+
if (sanitizedMessage) inputs.message = sanitizedMessage;
|
|
448
|
+
if (deployConfId) inputs.deploy_conf_id = deployConfId;
|
|
449
|
+
if (deployType) inputs.deploy_type = deployType;
|
|
450
|
+
|
|
451
|
+
Underpost.repo.dispatchWorkflow({
|
|
452
|
+
repo,
|
|
453
|
+
workflowFile: 'npmpkg.ci.yml',
|
|
454
|
+
ref: 'master',
|
|
455
|
+
inputs,
|
|
456
|
+
});
|
|
394
457
|
},
|
|
395
458
|
|
|
459
|
+
/**
|
|
460
|
+
* @method template-deploy-local
|
|
461
|
+
* @description Similar to `template-deploy` but runs the workflow locally without dispatching GitHub Actions. It pulls the latest changes, pushes to GitHub, builds the template, and optionally triggers a local release with CI push.
|
|
462
|
+
* @param {string} path - The deployment path identifier (e.g., 'sync-engine-core', 'init-engine-core', or empty for build-only).
|
|
463
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
464
|
+
* @memberof UnderpostRun
|
|
465
|
+
*/
|
|
466
|
+
'template-deploy-local': async (path, options = DEFAULT_OPTION) => {
|
|
467
|
+
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
468
|
+
shellExec(`npm run security:secrets`);
|
|
469
|
+
const reportPath = './gitleaks-report.json';
|
|
470
|
+
if (fs.existsSync(reportPath) && JSON.parse(fs.readFileSync(reportPath, 'utf8')).length > 0) {
|
|
471
|
+
logger.error('Secrets detected in gitleaks-report.json, aborting template-deploy');
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
shellExec(`${baseCommand} run pull`);
|
|
475
|
+
|
|
476
|
+
// Capture last N commit messages from the engine repo.
|
|
477
|
+
// When --from-n-commit is not set, auto-detect unpushed commit count (same as --unpush flag).
|
|
478
|
+
const fromN =
|
|
479
|
+
options.fromNCommit && parseInt(options.fromNCommit) > 0
|
|
480
|
+
? parseInt(options.fromNCommit)
|
|
481
|
+
: Underpost.repo.getUnpushedCount('.').count;
|
|
482
|
+
const rawMessage = shellExec(`node bin cmt --changelog ${fromN} --changelog-no-hash`, {
|
|
483
|
+
silent: true,
|
|
484
|
+
stdout: true,
|
|
485
|
+
}).trim();
|
|
486
|
+
const sanitizedMessage = Underpost.repo.sanitizeChangelogMessage(rawMessage);
|
|
487
|
+
|
|
488
|
+
const { triggerCmd } = path
|
|
489
|
+
? await Underpost.release.ci(path, sanitizedMessage, options)
|
|
490
|
+
: await Underpost.release.pwa(sanitizedMessage, options);
|
|
491
|
+
pbcopy(triggerCmd + ' && cd /home/dd/engine');
|
|
492
|
+
},
|
|
396
493
|
/**
|
|
397
494
|
* @method template-deploy-image
|
|
398
|
-
* @description
|
|
495
|
+
* @description Dispatches the Docker image CI workflow for the `engine` repository.
|
|
399
496
|
* @param {string} path - The input value, identifier, or path for the operation.
|
|
400
497
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
401
498
|
* @memberof UnderpostRun
|
|
402
499
|
*/
|
|
403
500
|
'template-deploy-image': (path, options = DEFAULT_OPTION) => {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
);
|
|
501
|
+
Underpost.repo.dispatchWorkflow({
|
|
502
|
+
repo: `${process.env.GITHUB_USERNAME}/engine`,
|
|
503
|
+
workflowFile: 'docker-image.ci.yml',
|
|
504
|
+
ref: 'master',
|
|
505
|
+
inputs: {},
|
|
506
|
+
});
|
|
507
|
+
},
|
|
508
|
+
/**
|
|
509
|
+
* @method docker-image
|
|
510
|
+
* @description Dispatches the Docker image CI workflow (`docker-image.ci.yml`) for the `engine` repository via `workflow_dispatch`.
|
|
511
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
512
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
513
|
+
* @memberof UnderpostRun
|
|
514
|
+
*/
|
|
515
|
+
'docker-image': (path, options = DEFAULT_OPTION) => {
|
|
516
|
+
Underpost.repo.dispatchWorkflow({
|
|
517
|
+
repo: `${process.env.GITHUB_USERNAME}/engine`,
|
|
518
|
+
workflowFile: 'docker-image.ci.yml',
|
|
519
|
+
ref: 'master',
|
|
520
|
+
inputs: {},
|
|
521
|
+
});
|
|
410
522
|
},
|
|
411
523
|
/**
|
|
412
524
|
* @method clean
|
|
@@ -467,18 +579,30 @@ class UnderpostRun {
|
|
|
467
579
|
},
|
|
468
580
|
/**
|
|
469
581
|
* @method ssh-deploy
|
|
470
|
-
* @description
|
|
471
|
-
* @param {string} path - The
|
|
582
|
+
* @description Dispatches the corresponding CD workflow for SSH-based deployment, replacing empty commits with workflow_dispatch.
|
|
583
|
+
* @param {string} path - The deployment identifier (e.g., 'engine-core', 'sync-engine-core', 'init-engine-core').
|
|
472
584
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
473
585
|
* @memberof UnderpostRun
|
|
474
586
|
*/
|
|
475
587
|
'ssh-deploy': (path, options = DEFAULT_OPTION) => {
|
|
476
588
|
actionInitLog();
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
589
|
+
|
|
590
|
+
let job = 'deploy';
|
|
591
|
+
let confId = path;
|
|
592
|
+
if (path.startsWith('sync-')) {
|
|
593
|
+
job = 'sync-and-deploy';
|
|
594
|
+
confId = path.replace(/^sync-/, '');
|
|
595
|
+
} else if (path.startsWith('init-')) {
|
|
596
|
+
job = 'init';
|
|
597
|
+
confId = path.replace(/^init-/, '');
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
Underpost.repo.dispatchWorkflow({
|
|
601
|
+
repo: `${process.env.GITHUB_USERNAME}/engine`,
|
|
602
|
+
workflowFile: `${confId}.cd.yml`,
|
|
603
|
+
ref: 'master',
|
|
604
|
+
inputs: { job },
|
|
605
|
+
});
|
|
482
606
|
},
|
|
483
607
|
/**
|
|
484
608
|
* @method ide
|
|
@@ -488,15 +612,25 @@ class UnderpostRun {
|
|
|
488
612
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
489
613
|
* @memberof UnderpostRun
|
|
490
614
|
*/
|
|
491
|
-
ide: (path, options = DEFAULT_OPTION) => {
|
|
492
|
-
const
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
shellExec(
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
615
|
+
ide: (path = '', options = DEFAULT_OPTION) => {
|
|
616
|
+
const underpostRoot = options.dev ? '.' : options.underpostRoot;
|
|
617
|
+
const [projectPath, customIde] = path.split(',');
|
|
618
|
+
if (projectPath === 'install') {
|
|
619
|
+
if (customIde === 'zed') shellExec(`sudo curl -f https://zed.dev/install.sh | sh`);
|
|
620
|
+
else if (customIde === 'subl') {
|
|
621
|
+
shellExec(
|
|
622
|
+
`sudo dnf config-manager --add-repo https://download.sublimetext.com/rpm/stable/x86_64/sublime-text.repo`,
|
|
623
|
+
);
|
|
624
|
+
shellExec(`sudo dnf install -y sublime-text`);
|
|
625
|
+
} else {
|
|
626
|
+
shellExec(`sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc &&
|
|
627
|
+
echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com/yumrepos/vscode\nenabled=1\nautorefresh=1\ntype=rpm-md\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" | sudo tee /etc/yum.repos.d/vscode.repo > /dev/null`);
|
|
628
|
+
shellExec(`sudo dnf install -y code`);
|
|
629
|
+
}
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
if (customIde === 'zed') shellExec(`node ${underpostRoot}/bin/zed ${projectPath}`);
|
|
633
|
+
else shellExec(`node ${underpostRoot}/bin/vs ${projectPath}`);
|
|
500
634
|
},
|
|
501
635
|
/**
|
|
502
636
|
* @method crypto-policy
|
|
@@ -520,12 +654,13 @@ class UnderpostRun {
|
|
|
520
654
|
const env = options.dev ? 'development' : 'production';
|
|
521
655
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
522
656
|
const baseClusterCommand = options.dev ? ' --dev' : '';
|
|
657
|
+
const clusterFlag = options.k3s ? ' --k3s' : options.kind ? ' --kind' : ' --kubeadm';
|
|
523
658
|
const defaultPath = [
|
|
524
659
|
'dd-default',
|
|
525
660
|
options.replicas,
|
|
526
661
|
``,
|
|
527
662
|
``,
|
|
528
|
-
options.
|
|
663
|
+
!options.kubeadm && !options.k3s ? 'kind-control-plane' : os.hostname(),
|
|
529
664
|
];
|
|
530
665
|
let [deployId, replicas, versions, image, node] = path ? path.split(',') : defaultPath;
|
|
531
666
|
deployId = deployId ? deployId : defaultPath[0];
|
|
@@ -540,7 +675,8 @@ class UnderpostRun {
|
|
|
540
675
|
if (!validVersion) throw new Error('Version mismatch');
|
|
541
676
|
}
|
|
542
677
|
if (options.timezone !== 'none') shellExec(`${baseCommand} run${baseClusterCommand} tz`);
|
|
543
|
-
if (options.deployIdCronJobs !== 'none')
|
|
678
|
+
if (options.deployIdCronJobs !== 'none')
|
|
679
|
+
shellExec(`node bin cron${baseClusterCommand}${clusterFlag} --setup-start --git --apply`);
|
|
544
680
|
}
|
|
545
681
|
|
|
546
682
|
const currentTraffic = isDeployRunnerContext(path, options)
|
|
@@ -553,20 +689,25 @@ class UnderpostRun {
|
|
|
553
689
|
const cmdString = options.cmd
|
|
554
690
|
? ' --cmd ' + (options.cmd.find((c) => c.match('"')) ? '"' + options.cmd + '"' : "'" + options.cmd + "'")
|
|
555
691
|
: '';
|
|
692
|
+
const gitCleanFlag = options.gitClean ? ' --git-clean' : '';
|
|
556
693
|
|
|
557
694
|
shellExec(
|
|
558
|
-
`${baseCommand} deploy --
|
|
695
|
+
`${baseCommand} deploy${clusterFlag} --build-manifest --sync --info-router --replicas ${replicas} --node ${node}${
|
|
559
696
|
image ? ` --image ${image}` : ''
|
|
560
697
|
}${versions ? ` --versions ${versions}` : ''}${
|
|
561
698
|
options.namespace ? ` --namespace ${options.namespace}` : ''
|
|
562
|
-
}${timeoutFlags}${cmdString}
|
|
699
|
+
}${timeoutFlags}${cmdString}${gitCleanFlag} ${deployId} ${env}`,
|
|
563
700
|
);
|
|
564
701
|
|
|
565
702
|
if (isDeployRunnerContext(path, options)) {
|
|
703
|
+
// Backup app/services repositories with repo-backup configured
|
|
566
704
|
shellExec(
|
|
567
|
-
`${baseCommand}
|
|
705
|
+
`${baseCommand} db ${deployId} ${clusterFlag}${baseClusterCommand} --repo-backup --primary-pod --git --force-clone --preserveUUID ${options.namespace ? ` --ns ${options.namespace}` : ''}`,
|
|
706
|
+
);
|
|
707
|
+
shellExec(
|
|
708
|
+
`${baseCommand} deploy${clusterFlag}${cmdString} --replicas ${replicas} --disable-update-proxy ${deployId} ${env} --versions ${versions}${
|
|
568
709
|
options.namespace ? ` --namespace ${options.namespace}` : ''
|
|
569
|
-
}${timeoutFlags}`,
|
|
710
|
+
}${timeoutFlags}${gitCleanFlag}`,
|
|
570
711
|
);
|
|
571
712
|
if (!targetTraffic)
|
|
572
713
|
targetTraffic = Underpost.deploy.getCurrentTraffic(deployId, { namespace: options.namespace });
|
|
@@ -778,6 +919,7 @@ class UnderpostRun {
|
|
|
778
919
|
const confInstances = JSON.parse(
|
|
779
920
|
fs.readFileSync(`./engine-private/conf/${deployId}/conf.instances.json`, 'utf8'),
|
|
780
921
|
);
|
|
922
|
+
let promotedTraffic = '';
|
|
781
923
|
for (const instance of confInstances) {
|
|
782
924
|
let {
|
|
783
925
|
id: _id,
|
|
@@ -797,6 +939,7 @@ class UnderpostRun {
|
|
|
797
939
|
namespace: options.namespace,
|
|
798
940
|
});
|
|
799
941
|
const targetTraffic = currentTraffic ? (currentTraffic === 'blue' ? 'green' : 'blue') : 'blue';
|
|
942
|
+
promotedTraffic = targetTraffic;
|
|
800
943
|
let proxyYaml =
|
|
801
944
|
Underpost.deploy.baseProxyYamlFactory({ host: _host, env: options.tls ? 'production' : env, options }) +
|
|
802
945
|
Underpost.deploy.deploymentYamlServiceFactory({
|
|
@@ -822,6 +965,18 @@ EOF
|
|
|
822
965
|
{ disableLog: true },
|
|
823
966
|
);
|
|
824
967
|
}
|
|
968
|
+
// Refresh the gRPC service to ensure it points to the parent deploy's current traffic.
|
|
969
|
+
if (promotedTraffic) {
|
|
970
|
+
const parentTraffic = Underpost.deploy.getCurrentTraffic(deployId, { namespace: options.namespace }) || 'blue';
|
|
971
|
+
const grpcServicePath = Underpost.deploy.buildGrpcServiceManifest({
|
|
972
|
+
deployId,
|
|
973
|
+
env,
|
|
974
|
+
confServer: loadConfServerJson(`./engine-private/conf/${deployId}/conf.server.json`),
|
|
975
|
+
namespace: options.namespace,
|
|
976
|
+
traffic: [parentTraffic],
|
|
977
|
+
});
|
|
978
|
+
if (grpcServicePath) shellExec(`kubectl apply -f ${grpcServicePath} -n ${options.namespace}`);
|
|
979
|
+
}
|
|
825
980
|
},
|
|
826
981
|
|
|
827
982
|
/**
|
|
@@ -861,12 +1016,12 @@ EOF
|
|
|
861
1016
|
// `localhost/rockylinux9-underpost:${Underpost.version}`
|
|
862
1017
|
if (!_image) _image = `underpost/underpost-engine:${Underpost.version}`;
|
|
863
1018
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
}
|
|
1019
|
+
Underpost.image.pullDockerHubImage({
|
|
1020
|
+
dockerhubImage: _image,
|
|
1021
|
+
kind: options.kind || (!options.nodeName && !options.kubeadm && !options.k3s),
|
|
1022
|
+
kubeadm: options.nodeName || options.kubeadm,
|
|
1023
|
+
k3s: options.k3s,
|
|
1024
|
+
});
|
|
870
1025
|
|
|
871
1026
|
const currentTraffic = Underpost.deploy.getCurrentTraffic(_deployId, {
|
|
872
1027
|
hostTest: _host,
|
|
@@ -875,7 +1030,7 @@ EOF
|
|
|
875
1030
|
|
|
876
1031
|
const targetTraffic = currentTraffic ? (currentTraffic === 'blue' ? 'green' : 'blue') : 'blue';
|
|
877
1032
|
const podId = `${_deployId}-${env}-${targetTraffic}`;
|
|
878
|
-
const ignorePods = Underpost.
|
|
1033
|
+
const ignorePods = Underpost.kubectl.get(podId, 'pods', options.namespace).map((p) => p.NAME);
|
|
879
1034
|
Underpost.deploy.configMap(env, options.namespace);
|
|
880
1035
|
shellExec(`kubectl delete service ${podId}-service --namespace ${options.namespace} --ignore-not-found`);
|
|
881
1036
|
shellExec(`kubectl delete deployment ${podId} --namespace ${options.namespace} --ignore-not-found`);
|
|
@@ -887,7 +1042,30 @@ EOF
|
|
|
887
1042
|
env,
|
|
888
1043
|
version: targetTraffic,
|
|
889
1044
|
nodeName: options.nodeName,
|
|
1045
|
+
clusterContext: options.k3s ? 'k3s' : options.kubeadm ? 'kubeadm' : 'kind',
|
|
1046
|
+
gitClean: options.gitClean || false,
|
|
890
1047
|
});
|
|
1048
|
+
// Regenerate the parent deploy's gRPC ClusterIP service pointing to the
|
|
1049
|
+
// parent's current traffic colour and apply it before the instance pod starts so
|
|
1050
|
+
// DNS is resolvable the moment the pod boots.
|
|
1051
|
+
const parentTraffic = Underpost.deploy.getCurrentTraffic(deployId, { namespace: options.namespace }) || 'blue';
|
|
1052
|
+
const grpcServicePath = Underpost.deploy.buildGrpcServiceManifest({
|
|
1053
|
+
deployId,
|
|
1054
|
+
env,
|
|
1055
|
+
confServer: loadConfServerJson(`./engine-private/conf/${deployId}/conf.server.json`),
|
|
1056
|
+
namespace: options.namespace,
|
|
1057
|
+
traffic: [targetTraffic],
|
|
1058
|
+
host: _host,
|
|
1059
|
+
});
|
|
1060
|
+
if (grpcServicePath) shellExec(`kubectl apply -f ${grpcServicePath} -n ${options.namespace}`);
|
|
1061
|
+
|
|
1062
|
+
const resolvedCmd = _cmd[env].map((c) =>
|
|
1063
|
+
c.replaceAll(
|
|
1064
|
+
'{{grpc-service-dns}}',
|
|
1065
|
+
`${deployId}-grpc-service-${env}-${parentTraffic}.${options.namespace || 'default'}.svc.cluster.local:50051`,
|
|
1066
|
+
),
|
|
1067
|
+
);
|
|
1068
|
+
|
|
891
1069
|
let deploymentYaml = `---
|
|
892
1070
|
${Underpost.deploy
|
|
893
1071
|
.deploymentYamlPartsFactory({
|
|
@@ -899,7 +1077,7 @@ ${Underpost.deploy
|
|
|
899
1077
|
image: _image,
|
|
900
1078
|
namespace: options.namespace,
|
|
901
1079
|
volumes: _volumes,
|
|
902
|
-
cmd:
|
|
1080
|
+
cmd: resolvedCmd,
|
|
903
1081
|
})
|
|
904
1082
|
.replace('{{ports}}', buildKindPorts(_fromPort, _toPort))}
|
|
905
1083
|
`;
|
|
@@ -945,7 +1123,7 @@ EOF
|
|
|
945
1123
|
* @memberof UnderpostRun
|
|
946
1124
|
*/
|
|
947
1125
|
'ls-deployments': async (path, options = DEFAULT_OPTION) => {
|
|
948
|
-
console.table(await Underpost.
|
|
1126
|
+
console.table(await Underpost.kubectl.get(path, 'deployments', options.namespace));
|
|
949
1127
|
},
|
|
950
1128
|
|
|
951
1129
|
/**
|
|
@@ -1008,9 +1186,7 @@ EOF
|
|
|
1008
1186
|
volumeMountPath: volumeHostPath,
|
|
1009
1187
|
...(options.dev ? { volumeHostPath } : { claimName }),
|
|
1010
1188
|
on: {
|
|
1011
|
-
init: async () => {
|
|
1012
|
-
// openTerminal(`kubectl logs -f ${podName}`);
|
|
1013
|
-
},
|
|
1189
|
+
init: async () => {},
|
|
1014
1190
|
},
|
|
1015
1191
|
args: [daemonProcess(path ? path : `cd /home/dd/engine && npm install && npm run test`)],
|
|
1016
1192
|
};
|
|
@@ -1041,15 +1217,13 @@ EOF
|
|
|
1041
1217
|
'db-client': async (path, options = DEFAULT_OPTION) => {
|
|
1042
1218
|
const { underpostRoot } = options;
|
|
1043
1219
|
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
}
|
|
1051
|
-
// For kubeadm/k3s, ensure it's available for containerd
|
|
1052
|
-
shellExec(`sudo crictl pull ${image}`);
|
|
1220
|
+
Underpost.image.pullDockerHubImage({
|
|
1221
|
+
dockerhubImage: 'adminer',
|
|
1222
|
+
version: '4.7.6-standalone',
|
|
1223
|
+
kind: options.kind,
|
|
1224
|
+
kubeadm: options.kubeadm,
|
|
1225
|
+
k3s: options.k3s,
|
|
1226
|
+
});
|
|
1053
1227
|
|
|
1054
1228
|
shellExec(`kubectl delete deployment adminer -n ${options.namespace} --ignore-not-found`);
|
|
1055
1229
|
shellExec(`kubectl apply -k ${underpostRoot}/manifests/deployment/adminer/. -n ${options.namespace}`);
|
|
@@ -1145,7 +1319,7 @@ EOF
|
|
|
1145
1319
|
const deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',');
|
|
1146
1320
|
let hosts = [];
|
|
1147
1321
|
for (const deployId of deployList) {
|
|
1148
|
-
const confServer =
|
|
1322
|
+
const confServer = loadConfServerJson(`./engine-private/conf/${deployId}/conf.server.json`);
|
|
1149
1323
|
hosts = hosts.concat(Object.keys(confServer));
|
|
1150
1324
|
}
|
|
1151
1325
|
shellExec(`node bin cluster --prom ${hosts.join(',')}`);
|
|
@@ -1318,34 +1492,31 @@ EOF
|
|
|
1318
1492
|
if (!subConf) subConf = 'local';
|
|
1319
1493
|
if (options.reset && fs.existsSync(`./engine-private/conf/${deployId}`))
|
|
1320
1494
|
fs.removeSync(`./engine-private/conf/${deployId}`);
|
|
1321
|
-
if (!fs.existsSync(`./engine-private/conf/${deployId}`)) Config.deployIdFactory(deployId, { subConf });
|
|
1322
1495
|
if (options.devProxyPortOffset) {
|
|
1323
1496
|
const envPath = `./engine-private/conf/${deployId}/.env.development`;
|
|
1324
1497
|
const envObj = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
1325
1498
|
envObj.DEV_PROXY_PORT_OFFSET = options.devProxyPortOffset;
|
|
1326
1499
|
writeEnv(envPath, envObj);
|
|
1327
1500
|
}
|
|
1501
|
+
dotenv.config({ path: `./engine-private/conf/${deployId}/.env.development`, override: true });
|
|
1328
1502
|
shellExec(`node bin run dev-cluster --expose --namespace ${options.namespace}`, { async: true });
|
|
1329
1503
|
{
|
|
1330
|
-
const cmd = `npm run dev
|
|
1504
|
+
const cmd = `npm run dev:api ${deployId} ${subConf} ${host} ${_path} ${clientHostPort} proxy${
|
|
1331
1505
|
options.tls ? ' tls' : ''
|
|
1332
1506
|
}`;
|
|
1333
|
-
|
|
1507
|
+
shellExec(cmd, { async: true });
|
|
1334
1508
|
}
|
|
1335
1509
|
await awaitDeployMonitor(true);
|
|
1336
1510
|
{
|
|
1337
|
-
const cmd = `npm run dev
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
:
|
|
1341
|
-
|
|
1342
|
-
});
|
|
1511
|
+
const cmd = `npm run dev:client ${deployId} ${subConf} ${host} ${_path} proxy${options.tls ? ' tls' : ''}`;
|
|
1512
|
+
|
|
1513
|
+
shellExec(cmd, {
|
|
1514
|
+
async: true,
|
|
1515
|
+
});
|
|
1343
1516
|
}
|
|
1344
1517
|
await awaitDeployMonitor(true);
|
|
1345
1518
|
shellExec(
|
|
1346
|
-
|
|
1347
|
-
options.tls ? ' tls' : ''
|
|
1348
|
-
}`,
|
|
1519
|
+
`NODE_ENV=development node src/proxy proxy ${deployId} ${subConf} ${host} ${_path}${options.tls ? ' tls' : ''}`,
|
|
1349
1520
|
);
|
|
1350
1521
|
},
|
|
1351
1522
|
|
|
@@ -1364,7 +1535,7 @@ EOF
|
|
|
1364
1535
|
let [deployId, serviceId, host, _path, replicas, image, node] = path.split(',');
|
|
1365
1536
|
if (!replicas) replicas = options.replicas;
|
|
1366
1537
|
// const confClient = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.client.json`, 'utf8'));
|
|
1367
|
-
const confServer =
|
|
1538
|
+
const confServer = loadConfServerJson(`./engine-private/conf/${deployId}/conf.server.json`);
|
|
1368
1539
|
// const confSSR = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.ssr.json`, 'utf8'));
|
|
1369
1540
|
// const packageData = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/package.json`, 'utf8'));
|
|
1370
1541
|
const services = fs.existsSync(`./engine-private/deploy/${deployId}/conf.services.json`)
|
|
@@ -1455,9 +1626,7 @@ EOF
|
|
|
1455
1626
|
'etc-hosts': async (path = '', options = DEFAULT_OPTION) => {
|
|
1456
1627
|
const hosts = path ? path.split(',') : [];
|
|
1457
1628
|
if (options.deployId) {
|
|
1458
|
-
const confServer =
|
|
1459
|
-
fs.readFileSync(`./engine-private/conf/${options.deployId}/conf.server.json`, 'utf8'),
|
|
1460
|
-
);
|
|
1629
|
+
const confServer = loadConfServerJson(`./engine-private/conf/${options.deployId}/conf.server.json`);
|
|
1461
1630
|
hosts.push(...Object.keys(confServer));
|
|
1462
1631
|
}
|
|
1463
1632
|
const hostListenResult = Underpost.deploy.etcHostFactory(hosts);
|
|
@@ -1527,29 +1696,75 @@ EOF
|
|
|
1527
1696
|
},
|
|
1528
1697
|
|
|
1529
1698
|
/**
|
|
1530
|
-
* @method
|
|
1531
|
-
* @description
|
|
1532
|
-
* @param {string} path - The
|
|
1699
|
+
* @method pid-info
|
|
1700
|
+
* @description Displays detailed information about a process by PID, including service details, command line, executable path, working directory, environment variables, and parent process tree.
|
|
1701
|
+
* @param {string} path - The PID of the process to inspect.
|
|
1533
1702
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
1534
1703
|
* @memberof UnderpostRun
|
|
1535
1704
|
*/
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1705
|
+
'pid-info': (path, options = DEFAULT_OPTION) => {
|
|
1706
|
+
const pid = path;
|
|
1707
|
+
if (!pid) {
|
|
1708
|
+
logger.error('PID is required. Usage: underpost run pid-info <pid>');
|
|
1709
|
+
return;
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
// Services
|
|
1713
|
+
logger.info('Process info');
|
|
1714
|
+
shellExec(`sudo ps -p ${pid} -o pid,ppid,user,stime,etime,cmd`);
|
|
1715
|
+
logger.info('Command line');
|
|
1716
|
+
shellExec(`sudo cat /proc/${pid}/cmdline | tr '\\0' ' ' ; echo`);
|
|
1717
|
+
logger.info('Executable path');
|
|
1718
|
+
shellExec(`sudo readlink -f /proc/${pid}/exe`);
|
|
1719
|
+
logger.info('Working directory');
|
|
1720
|
+
shellExec(`sudo readlink -f /proc/${pid}/cwd`);
|
|
1721
|
+
logger.info('Environment variables (first 200)');
|
|
1722
|
+
shellExec(`sudo tr '\\0' '\\n' </proc/${pid}/environ | head -200`);
|
|
1723
|
+
|
|
1724
|
+
// Parent
|
|
1725
|
+
logger.info('Parent process');
|
|
1726
|
+
const parentInfo = shellExec(`sudo ps -o pid,ppid,user,cmd -p ${pid}`, { stdout: true, silent: true });
|
|
1727
|
+
console.log(parentInfo);
|
|
1728
|
+
const ppidMatch = parentInfo.split('\n').find((l) => l.trim().startsWith(pid));
|
|
1729
|
+
if (ppidMatch) {
|
|
1730
|
+
const ppid = ppidMatch.trim().split(/\s+/)[1];
|
|
1731
|
+
logger.info(`Parent PID: ${ppid}`);
|
|
1732
|
+
shellExec(`ps -fp ${ppid}`);
|
|
1733
|
+
}
|
|
1734
|
+
logger.info('Process tree');
|
|
1735
|
+
shellExec(`pstree -s ${pid}`);
|
|
1736
|
+
},
|
|
1737
|
+
|
|
1738
|
+
/**
|
|
1739
|
+
* @method background
|
|
1740
|
+
* @description Runs a custom command in the background using nohup, logging output to `/var/log/<id>.log` and saving the PID to `/var/run/<id>.pid`.
|
|
1741
|
+
* @param {string} path - The command to run in the background (e.g. 'npm run prod:container dd-cyberia-r3').
|
|
1742
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
1743
|
+
* @memberof UnderpostRun
|
|
1744
|
+
*/
|
|
1745
|
+
background: (path, options = DEFAULT_OPTION) => {
|
|
1746
|
+
if (!path) {
|
|
1747
|
+
logger.error('Command is required. Usage: underpost run background <command>');
|
|
1748
|
+
return;
|
|
1749
|
+
}
|
|
1750
|
+
const id = path.split(/\s+/).pop();
|
|
1751
|
+
const logFile = `/var/log/${id}.log`;
|
|
1752
|
+
const pidFile = `/var/run/${id}.pid`;
|
|
1753
|
+
logger.info(`Starting background process`, { id, logFile, pidFile });
|
|
1754
|
+
shellExec(`nohup ${path} > ${logFile} 2>&1 & pid=$!; echo $pid > ${pidFile}; disown`);
|
|
1755
|
+
logger.info(`Background process started for '${id}'`);
|
|
1539
1756
|
},
|
|
1757
|
+
|
|
1540
1758
|
/**
|
|
1541
|
-
* @method
|
|
1542
|
-
* @description
|
|
1543
|
-
* @param {string} path - The input value, identifier, or path for the operation.
|
|
1759
|
+
* @method ports
|
|
1760
|
+
* @description Set on ~/.bashrc alias: ports <port> Command to list listening ports that match the given keyword.
|
|
1761
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as a keyword to filter listening ports).
|
|
1544
1762
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
1545
1763
|
* @memberof UnderpostRun
|
|
1546
1764
|
*/
|
|
1547
|
-
|
|
1548
|
-
shellExec(`
|
|
1549
|
-
shellExec(`
|
|
1550
|
-
shellCd(`/home/dd/engine`);
|
|
1551
|
-
shellExec(`underpost cmt --empty . ci engine ' New engine release $(underpost --version)'`);
|
|
1552
|
-
shellExec(`underpost push . ${process.env.GITHUB_USERNAME}/engine`, { silent: true });
|
|
1765
|
+
ports: async (path = '', options = DEFAULT_OPTION) => {
|
|
1766
|
+
shellExec(`chmod +x ${options.underpostRoot}/scripts/ports-ls.sh`);
|
|
1767
|
+
shellExec(`${options.underpostRoot}/scripts/ports-ls.sh`);
|
|
1553
1768
|
},
|
|
1554
1769
|
|
|
1555
1770
|
/**
|
|
@@ -1571,43 +1786,12 @@ EOF
|
|
|
1571
1786
|
: [
|
|
1572
1787
|
`npm install -g npm@11.2.0`,
|
|
1573
1788
|
`npm install -g underpost`,
|
|
1574
|
-
`${baseCommand} secret underpost --create-from-
|
|
1575
|
-
`${baseCommand} start --build --run ${deployId} ${env}
|
|
1789
|
+
`${baseCommand} secret underpost --create-from-env`,
|
|
1790
|
+
`${baseCommand} start --build --run ${deployId} ${env}`,
|
|
1576
1791
|
];
|
|
1577
1792
|
shellExec(`node bin run sync${baseClusterCommand} --deploy-id-cron-jobs none dd-test --cmd "${cmd}"`);
|
|
1578
1793
|
},
|
|
1579
1794
|
|
|
1580
|
-
/**
|
|
1581
|
-
* @method sync-replica
|
|
1582
|
-
* @description Syncs a replica for the dd.router
|
|
1583
|
-
* @param {string} path - The input value, identifier, or path for the operation.
|
|
1584
|
-
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
1585
|
-
* @memberof UnderpostRun
|
|
1586
|
-
*/
|
|
1587
|
-
'sync-replica': async (path, options = DEFAULT_OPTION) => {
|
|
1588
|
-
const env = options.dev ? 'development' : 'production';
|
|
1589
|
-
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
1590
|
-
|
|
1591
|
-
for (let deployId of fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',')) {
|
|
1592
|
-
deployId = deployId.trim();
|
|
1593
|
-
const _path = '/single-replica';
|
|
1594
|
-
const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
|
|
1595
|
-
shellExec(`${baseCommand} env ${deployId} ${env}`);
|
|
1596
|
-
for (const host of Object.keys(confServer))
|
|
1597
|
-
if (_path in confServer[host]) shellExec(`node bin/deploy build-single-replica ${deployId} ${host} ${_path}`);
|
|
1598
|
-
const node = options.nodeName
|
|
1599
|
-
? options.nodeName
|
|
1600
|
-
: options.dev || !isDeployRunnerContext(path, options)
|
|
1601
|
-
? 'kind-control-plane'
|
|
1602
|
-
: os.hostname();
|
|
1603
|
-
// deployId, replicas, versions, image, node
|
|
1604
|
-
let defaultPath = [deployId, 1, ``, ``, node];
|
|
1605
|
-
shellExec(`${baseCommand} run${options.dev === true ? ' --dev' : ''} --build sync ${defaultPath}`);
|
|
1606
|
-
shellExec(`node bin/deploy build-full-client ${deployId}`);
|
|
1607
|
-
}
|
|
1608
|
-
if (isDeployRunnerContext(path, options)) shellExec(`${baseCommand} run promote ${path} production`);
|
|
1609
|
-
},
|
|
1610
|
-
|
|
1611
1795
|
/**
|
|
1612
1796
|
* @method tf-vae-test
|
|
1613
1797
|
* @description Creates and runs a job pod (`tf-vae-test`) that installs TensorFlow dependencies, clones the TensorFlow docs, and runs the CVAE tutorial script, with a terminal monitor attached.
|
|
@@ -1633,7 +1817,7 @@ EOF
|
|
|
1633
1817
|
|
|
1634
1818
|
const { close } = await (async () => {
|
|
1635
1819
|
const checkAwaitPath = '/await';
|
|
1636
|
-
while (!Underpost.
|
|
1820
|
+
while (!Underpost.kubectl.existsFile({ podName, path: checkAwaitPath })) {
|
|
1637
1821
|
logger.info('monitor', checkAwaitPath);
|
|
1638
1822
|
await timer(1000);
|
|
1639
1823
|
}
|
|
@@ -1660,7 +1844,7 @@ EOF
|
|
|
1660
1844
|
logger.info('monitor', checkPath);
|
|
1661
1845
|
{
|
|
1662
1846
|
const checkAwaitPath = `/home/dd/docs${checkPath}`;
|
|
1663
|
-
while (!Underpost.
|
|
1847
|
+
while (!Underpost.kubectl.existsFile({ podName, path: checkAwaitPath })) {
|
|
1664
1848
|
logger.info('waiting for', checkAwaitPath);
|
|
1665
1849
|
await timer(1000);
|
|
1666
1850
|
}
|
|
@@ -1680,7 +1864,7 @@ EOF
|
|
|
1680
1864
|
shellExec(`sudo kubectl cp ${nameSpace}/${podName}:${basePath}/docs${fromPath} ${toPath}`);
|
|
1681
1865
|
}
|
|
1682
1866
|
|
|
1683
|
-
|
|
1867
|
+
shellExec(`firefox ${outsPaths.join(' ')}`);
|
|
1684
1868
|
process.exit(0);
|
|
1685
1869
|
}
|
|
1686
1870
|
})();
|
|
@@ -1726,7 +1910,8 @@ EOF
|
|
|
1726
1910
|
|
|
1727
1911
|
shellCd(dir);
|
|
1728
1912
|
|
|
1729
|
-
|
|
1913
|
+
Underpost.repo.initLocalRepo({ path: dir });
|
|
1914
|
+
shellExec(`git add . && git commit -m "Base implementation"`);
|
|
1730
1915
|
shellExec(`chmod +x ./replace_params.sh`);
|
|
1731
1916
|
shellExec(`chmod +x ./build.sh`);
|
|
1732
1917
|
|
|
@@ -1771,11 +1956,46 @@ EOF
|
|
|
1771
1956
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
1772
1957
|
* @memberof UnderpostRun
|
|
1773
1958
|
*/
|
|
1959
|
+
/**
|
|
1960
|
+
* @method generate-pass
|
|
1961
|
+
* @description Generates a cryptographically secure random password that satisfies all validatePassword
|
|
1962
|
+
* constraints (lowercase, uppercase, digit, special char, min 8 chars). Logs the plain password
|
|
1963
|
+
* to the console or, when `--copy` is set, copies it to the clipboard via pbcopy.
|
|
1964
|
+
* @param {string} path - Optional password length (default: 16).
|
|
1965
|
+
* @param {Object} options - The default underpost runner options for customizing workflow.
|
|
1966
|
+
* @param {boolean} options.copy - When true, copies to clipboard instead of logging.
|
|
1967
|
+
* @memberof UnderpostRun
|
|
1968
|
+
*/
|
|
1969
|
+
'generate-pass': (path, options = DEFAULT_OPTION) => {
|
|
1970
|
+
const length = path && parseInt(path) > 0 ? parseInt(path) : 16;
|
|
1971
|
+
const lower = 'abcdefghijklmnopqrstuvwxyz';
|
|
1972
|
+
const upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
1973
|
+
const digits = '0123456789';
|
|
1974
|
+
const special = '@#$%^&*()_+';
|
|
1975
|
+
const all = lower + upper + digits + special;
|
|
1976
|
+
const buf = crypto.randomBytes(length + 4);
|
|
1977
|
+
// Guarantee at least one character from each required class
|
|
1978
|
+
const chars = [
|
|
1979
|
+
lower[buf[0] % lower.length],
|
|
1980
|
+
upper[buf[1] % upper.length],
|
|
1981
|
+
digits[buf[2] % digits.length],
|
|
1982
|
+
special[buf[3] % special.length],
|
|
1983
|
+
];
|
|
1984
|
+
for (let i = 4; i < length; i++) chars.push(all[buf[i] % all.length]);
|
|
1985
|
+
// Fisher-Yates shuffle using an independent random buffer
|
|
1986
|
+
const shuf = crypto.randomBytes(length);
|
|
1987
|
+
for (let i = chars.length - 1; i > 0; i--) {
|
|
1988
|
+
const j = shuf[i % shuf.length] % (i + 1);
|
|
1989
|
+
[chars[i], chars[j]] = [chars[j], chars[i]];
|
|
1990
|
+
}
|
|
1991
|
+
const password = chars.join('');
|
|
1992
|
+
if (options.copy) pbcopy(password);
|
|
1993
|
+
else console.log(password);
|
|
1994
|
+
},
|
|
1995
|
+
|
|
1774
1996
|
secret: (path, options = DEFAULT_OPTION) => {
|
|
1775
1997
|
const secretPath = path ? path : `/home/dd/engine/engine-private/conf/dd-cron/.env.production`;
|
|
1776
|
-
const command =
|
|
1777
|
-
? `node bin secret underpost --create-from-file ${secretPath}`
|
|
1778
|
-
: `underpost secret underpost --create-from-file ${secretPath}`;
|
|
1998
|
+
const command = `node bin secret underpost --create-from-file ${secretPath}`;
|
|
1779
1999
|
shellExec(command);
|
|
1780
2000
|
},
|
|
1781
2001
|
/**
|