cyberia 3.2.5 → 3.2.9
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/.github/workflows/engine-cyberia.cd.yml +2 -2
- package/.github/workflows/release.cd.yml +1 -2
- package/CHANGELOG.md +351 -1
- package/CLI-HELP.md +40 -13
- package/Dockerfile +0 -4
- package/README.md +242 -497
- package/bin/build.js +19 -5
- package/bin/cyberia.js +1149 -240
- package/bin/deploy.js +570 -1
- package/bin/file.js +6 -0
- package/bin/index.js +1149 -240
- package/bin/vs.js +1 -1
- package/conf.js +67 -89
- package/deployment.yaml +4 -222
- package/hardhat/package-lock.json +32 -32
- package/hardhat/package.json +3 -3
- package/jsconfig.json +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +2 -2
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +2 -2
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +4 -222
- package/manifests/deployment/dd-cyberia-development/proxy.yaml +10 -118
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -6
- package/manifests/deployment/dd-test-development/deployment.yaml +136 -66
- package/manifests/deployment/dd-test-development/proxy.yaml +41 -5
- package/package.json +23 -14
- package/proxy.yaml +10 -118
- package/scripts/k3s-node-setup.sh +2 -2
- package/scripts/nat-iptables.sh +103 -18
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +18 -18
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +7 -14
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +76 -21
- package/src/api/core/core.controller.js +10 -10
- package/src/api/core/core.service.js +10 -10
- package/src/api/crypto/crypto.controller.js +8 -8
- package/src/api/crypto/crypto.service.js +8 -8
- package/src/api/cyberia-action/cyberia-action.controller.js +74 -0
- package/src/api/cyberia-action/cyberia-action.model.js +87 -0
- package/src/api/cyberia-action/cyberia-action.router.js +27 -0
- package/src/api/cyberia-action/cyberia-action.service.js +42 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +13 -13
- package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +11 -11
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +2 -2
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +16 -16
- package/src/api/cyberia-entity/cyberia-entity.controller.js +10 -10
- package/src/api/cyberia-entity/cyberia-entity.service.js +10 -10
- package/src/api/cyberia-instance/cyberia-fallback-world.js +19 -209
- package/src/api/cyberia-instance/cyberia-instance.controller.js +14 -14
- package/src/api/cyberia-instance/cyberia-instance.model.js +3 -0
- package/src/api/cyberia-instance/cyberia-instance.service.js +22 -57
- package/src/api/cyberia-instance/cyberia-portal-connector.js +20 -246
- package/src/api/cyberia-instance/cyberia-world-generator.js +505 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +10 -10
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js +216 -55
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +4 -1
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +18 -14
- package/src/api/cyberia-map/cyberia-map.controller.js +10 -10
- package/src/api/cyberia-map/cyberia-map.service.js +10 -10
- package/src/api/cyberia-quest/cyberia-quest.controller.js +74 -0
- package/src/api/cyberia-quest/cyberia-quest.model.js +67 -0
- package/src/api/cyberia-quest/cyberia-quest.router.js +27 -0
- package/src/api/cyberia-quest/cyberia-quest.service.js +42 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +74 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +49 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +27 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +42 -0
- package/src/api/default/default.controller.js +10 -10
- package/src/api/default/default.service.js +10 -10
- package/src/api/document/document.controller.js +12 -12
- package/src/api/document/document.model.js +10 -16
- package/src/api/file/file.controller.js +8 -8
- package/src/api/file/file.model.js +10 -10
- package/src/api/file/file.service.js +36 -36
- package/src/api/instance/instance.controller.js +10 -10
- package/src/api/instance/instance.model.js +4 -10
- package/src/api/instance/instance.service.js +10 -10
- package/src/api/ipfs/ipfs.controller.js +12 -12
- package/src/api/ipfs/ipfs.model.js +4 -13
- package/src/api/ipfs/ipfs.service.js +14 -28
- package/src/api/object-layer/object-layer.controller.js +12 -12
- package/src/api/object-layer/object-layer.model.js +4 -17
- package/src/api/object-layer/object-layer.service.js +12 -12
- package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +10 -10
- package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +6 -16
- package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +18 -14
- package/src/api/test/test.controller.js +8 -8
- package/src/api/test/test.service.js +8 -8
- package/src/api/user/guest.service.js +99 -0
- package/src/api/user/user.controller.js +6 -6
- package/src/api/user/user.model.js +8 -13
- package/src/api/user/user.service.js +3 -20
- package/src/cli/cluster.js +61 -14
- package/src/cli/db.js +47 -2
- package/src/cli/deploy.js +67 -35
- package/src/cli/fs.js +79 -8
- package/src/cli/image.js +43 -1
- package/src/cli/index.js +26 -1
- package/src/cli/release.js +57 -1
- package/src/cli/repository.js +69 -31
- package/src/cli/run.js +415 -36
- package/src/cli/ssh.js +1 -1
- package/src/cli/static.js +43 -115
- package/src/client/Cryptokoyn.index.js +18 -21
- package/src/client/CyberiaPortal.index.js +19 -23
- package/src/client/Default.index.js +21 -33
- package/src/client/Itemledger.index.js +20 -26
- package/src/client/Underpost.index.js +19 -23
- package/src/client/components/core/404.js +4 -4
- package/src/client/components/core/500.js +4 -4
- package/src/client/components/core/Account.js +73 -60
- package/src/client/components/core/AgGrid.js +23 -33
- package/src/client/components/core/Alert.js +12 -13
- package/src/client/components/core/AppStore.js +1 -1
- package/src/client/components/core/Auth.js +35 -37
- package/src/client/components/core/Badge.js +7 -13
- package/src/client/components/core/BtnIcon.js +15 -17
- package/src/client/components/core/CalendarCore.js +42 -63
- package/src/client/components/core/Chat.js +13 -15
- package/src/client/components/core/ClientEvents.js +87 -0
- package/src/client/components/core/ColorPaletteElement.js +309 -0
- package/src/client/components/core/Content.js +17 -14
- package/src/client/components/core/Css.js +15 -71
- package/src/client/components/core/CssCore.js +12 -16
- package/src/client/components/core/D3Chart.js +4 -4
- package/src/client/components/core/Docs.js +64 -91
- package/src/client/components/core/DropDown.js +69 -91
- package/src/client/components/core/EventBus.js +92 -0
- package/src/client/components/core/EventsUI.js +14 -17
- package/src/client/components/core/FileExplorer.js +96 -228
- package/src/client/components/core/FullScreen.js +47 -75
- package/src/client/components/core/Input.js +24 -69
- package/src/client/components/core/Keyboard.js +25 -18
- package/src/client/components/core/KeyboardAvoidance.js +145 -0
- package/src/client/components/core/LoadingAnimation.js +25 -31
- package/src/client/components/core/LogIn.js +41 -41
- package/src/client/components/core/LogOut.js +23 -14
- package/src/client/components/core/Modal.js +462 -178
- package/src/client/components/core/NotificationManager.js +14 -18
- package/src/client/components/core/Panel.js +54 -50
- package/src/client/components/core/PanelForm.js +25 -125
- package/src/client/components/core/Polyhedron.js +110 -214
- package/src/client/components/core/PublicProfile.js +39 -32
- package/src/client/components/core/Recover.js +48 -44
- package/src/client/components/core/Responsive.js +88 -32
- package/src/client/components/core/RichText.js +9 -18
- package/src/client/components/core/Router.js +24 -3
- package/src/client/components/core/SearchBox.js +37 -37
- package/src/client/components/core/SignUp.js +39 -30
- package/src/client/components/core/SocketIo.js +31 -2
- package/src/client/components/core/SocketIoHandler.js +6 -6
- package/src/client/components/core/ToggleSwitch.js +8 -20
- package/src/client/components/core/ToolTip.js +5 -17
- package/src/client/components/core/Translate.js +56 -59
- package/src/client/components/core/Validator.js +26 -16
- package/src/client/components/core/Wallet.js +15 -26
- package/src/client/components/core/Worker.js +163 -27
- package/src/client/components/core/windowGetDimensions.js +7 -7
- package/src/client/components/cryptokoyn/{MenuCryptokoyn.js → AppShellCryptokoyn.js} +57 -57
- package/src/client/components/cryptokoyn/CssCryptokoyn.js +15 -15
- package/src/client/components/cryptokoyn/LogInCryptokoyn.js +6 -4
- package/src/client/components/cryptokoyn/LogOutCryptokoyn.js +6 -4
- package/src/client/components/cryptokoyn/RouterCryptokoyn.js +37 -0
- package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +4 -4
- package/src/client/components/cryptokoyn/SignUpCryptokoyn.js +6 -4
- package/src/client/components/cyberia/InstanceEngineCyberia.js +141 -60
- package/src/client/components/cyberia/MapEngineCyberia.js +691 -214
- package/src/client/components/cyberia/ObjectLayerEngine.js +19 -0
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +1204 -94
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +196 -298
- package/src/client/components/cyberia-portal/{MenuCyberiaPortal.js → AppShellCyberiaPortal.js} +102 -102
- package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +305 -61
- package/src/client/components/cyberia-portal/CssCyberiaPortal.js +15 -15
- package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +6 -4
- package/src/client/components/cyberia-portal/LogOutCyberiaPortal.js +6 -4
- package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +4 -4
- package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +60 -0
- package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +4 -4
- package/src/client/components/cyberia-portal/SignUpCyberiaPortal.js +6 -4
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +4 -4
- package/src/client/components/default/{MenuDefault.js → AppShellDefault.js} +87 -87
- package/src/client/components/default/CssDefault.js +12 -12
- package/src/client/components/default/LogInDefault.js +6 -4
- package/src/client/components/default/LogOutDefault.js +6 -4
- package/src/client/components/default/RouterDefault.js +47 -0
- package/src/client/components/default/SettingsDefault.js +4 -4
- package/src/client/components/default/SignUpDefault.js +6 -4
- package/src/client/components/default/TranslateDefault.js +3 -3
- package/src/client/components/itemledger/{MenuItemledger.js → AppShellItemledger.js} +57 -57
- package/src/client/components/itemledger/CssItemledger.js +15 -15
- package/src/client/components/itemledger/LogInItemledger.js +6 -4
- package/src/client/components/itemledger/LogOutItemledger.js +6 -4
- package/src/client/components/itemledger/RouterItemledger.js +38 -0
- package/src/client/components/itemledger/SettingsItemledger.js +4 -4
- package/src/client/components/itemledger/SignUpItemledger.js +6 -4
- package/src/client/components/itemledger/TranslateItemledger.js +3 -3
- package/src/client/components/underpost/{MenuUnderpost.js → AppShellUnderpost.js} +88 -88
- package/src/client/components/underpost/CssUnderpost.js +14 -14
- package/src/client/components/underpost/CyberpunkBloggerUnderpost.js +4 -4
- package/src/client/components/underpost/DocumentSearchProvider.js +1 -1
- package/src/client/components/underpost/LabGalleryUnderpost.js +12 -15
- package/src/client/components/underpost/LogInUnderpost.js +6 -4
- package/src/client/components/underpost/LogOutUnderpost.js +6 -4
- package/src/client/components/underpost/RouterUnderpost.js +45 -0
- package/src/client/components/underpost/SettingsUnderpost.js +4 -4
- package/src/client/components/underpost/SignUpUnderpost.js +6 -4
- package/src/client/components/underpost/TranslateUnderpost.js +4 -4
- package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +235 -0
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +443 -0
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +417 -0
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +313 -0
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +260 -0
- package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +241 -0
- package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +300 -0
- package/src/client/public/cyberia-docs/OFF-CHAIN-ECONOMY.md +279 -0
- package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +206 -0
- package/src/client/public/cyberia-docs/ROADMAP.md +240 -0
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +732 -0
- package/src/client/services/atlas-sprite-sheet/atlas-sprite-sheet.service.js +14 -20
- package/src/client/services/core/core.service.js +17 -49
- package/src/client/services/crypto/crypto.service.js +8 -13
- package/src/client/services/cyberia-action/cyberia-action.service.js +99 -0
- package/src/client/services/cyberia-dialogue/cyberia-dialogue.service.js +10 -16
- package/src/client/services/cyberia-entity/cyberia-entity.management.js +5 -5
- package/src/client/services/cyberia-entity/cyberia-entity.service.js +10 -16
- package/src/client/services/cyberia-instance/cyberia-instance.management.js +6 -6
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +12 -18
- package/src/client/services/cyberia-instance-conf/cyberia-instance-conf.service.js +10 -16
- package/src/client/services/cyberia-map/cyberia-map.management.js +6 -6
- package/src/client/services/cyberia-map/cyberia-map.service.js +12 -18
- package/src/client/services/cyberia-quest/cyberia-quest.service.js +99 -0
- package/src/client/services/cyberia-quest-progress/cyberia-quest-progress.service.js +99 -0
- package/src/client/services/default/default.management.js +159 -267
- package/src/client/services/default/default.service.js +10 -16
- package/src/client/services/document/document.service.js +14 -19
- package/src/client/services/file/file.service.js +8 -13
- package/src/client/services/instance/instance.management.js +5 -5
- package/src/client/services/instance/instance.service.js +10 -15
- package/src/client/services/ipfs/ipfs.service.js +12 -18
- package/src/client/services/object-layer/object-layer.management.js +12 -12
- package/src/client/services/object-layer/object-layer.service.js +20 -26
- package/src/client/services/object-layer-render-frames/object-layer-render-frames.service.js +10 -16
- package/src/client/services/test/test.service.js +8 -13
- package/src/client/services/user/guest.service.js +86 -0
- package/src/client/services/user/user.management.js +5 -5
- package/src/client/services/user/user.service.js +14 -20
- package/src/client/ssr/body/404.js +3 -3
- package/src/client/ssr/body/500.js +3 -3
- package/src/client/ssr/body/CacheControl.js +5 -2
- package/src/client/ssr/body/DefaultSplashScreen.js +19 -12
- package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +13 -6
- package/src/client/ssr/head/PwaItemledger.js +197 -60
- package/src/client/ssr/mailer/DefaultRecoverEmail.js +19 -20
- package/src/client/ssr/mailer/DefaultVerifyEmail.js +15 -16
- package/src/client/ssr/offline/Maintenance.js +12 -11
- package/src/client/ssr/offline/NoNetworkConnection.js +3 -3
- package/src/client/ssr/pages/Test.js +2 -2
- package/src/client/sw/core.sw.js +212 -0
- package/src/grpc/cyberia/grpc-server.js +179 -67
- package/src/index.js +1 -1
- package/src/runtime/cyberia-client/Dockerfile +80 -0
- package/src/runtime/cyberia-server/Dockerfile +37 -0
- package/src/runtime/express/Dockerfile +4 -4
- package/src/runtime/lampp/Dockerfile +8 -7
- package/src/runtime/wp/Dockerfile +11 -17
- package/src/server/atlas-sprite-sheet-generator.js +4 -2
- package/src/server/client-build-docs.js +45 -46
- package/src/server/client-build.js +334 -60
- package/src/server/client-formatted.js +47 -16
- package/src/server/conf.js +5 -4
- package/src/server/data-query.js +32 -20
- package/src/server/dns.js +22 -0
- package/src/server/ipfs-client.js +232 -91
- package/src/server/object-layer.js +1 -6
- package/src/server/process.js +13 -27
- package/src/server/semantic-layer-generator-floor.js +11 -51
- package/src/server/semantic-layer-generator-resource.js +259 -0
- package/src/server/semantic-layer-generator-skin.js +41 -171
- package/src/server/semantic-layer-generator.js +122 -14
- package/src/server/shape-generator.js +108 -0
- package/src/server/start.js +17 -3
- package/src/server/valkey.js +141 -235
- package/tsconfig.docs.json +15 -0
- package/typedoc.dd-cyberia.json +29 -0
- package/typedoc.json +29 -0
- package/WHITE-PAPER.md +0 -1540
- package/hardhat/README.md +0 -531
- package/hardhat/WHITE-PAPER.md +0 -1540
- package/jsdoc.dd-cyberia.json +0 -68
- package/jsdoc.json +0 -68
- package/src/api/object-layer/README.md +0 -672
- package/src/client/components/core/ColorPalette.js +0 -5267
- package/src/client/components/core/JoyStick.js +0 -80
- package/src/client/components/cryptokoyn/RoutesCryptokoyn.js +0 -39
- package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +0 -62
- package/src/client/components/cyberia-portal/ServerCyberiaPortal.js +0 -136
- package/src/client/components/default/RoutesDefault.js +0 -49
- package/src/client/components/itemledger/RoutesItemledger.js +0 -40
- package/src/client/components/underpost/RoutesUnderpost.js +0 -47
- package/src/client/sw/default.sw.js +0 -127
- package/src/client/sw/template.sw.js +0 -84
- package/src/grpc/cyberia/OFF_CHAIN_ECONOMY.md +0 -305
- package/src/grpc/cyberia/README.md +0 -326
package/src/cli/cluster.js
CHANGED
|
@@ -172,9 +172,19 @@ class UnderpostCluster {
|
|
|
172
172
|
const podNetworkCidr = options.podNetworkCidr || '192.168.0.0/16';
|
|
173
173
|
const controlPlaneEndpoint = options.controlPlaneEndpoint || `${os.hostname()}:6443`;
|
|
174
174
|
|
|
175
|
-
// Initialize kubeadm control plane
|
|
175
|
+
// Initialize kubeadm control plane.
|
|
176
|
+
// Use CRI-O socket when available, otherwise fall back to containerd.
|
|
177
|
+
const crioSocket = 'unix:///var/run/crio/crio.sock';
|
|
178
|
+
const containerdSocket = 'unix:///run/containerd/containerd.sock';
|
|
179
|
+
const criSocket =
|
|
180
|
+
shellExec(`test -S /var/run/crio/crio.sock && echo crio || echo containerd`, {
|
|
181
|
+
stdout: true,
|
|
182
|
+
silent: true,
|
|
183
|
+
}).trim() === 'crio'
|
|
184
|
+
? crioSocket
|
|
185
|
+
: containerdSocket;
|
|
176
186
|
shellExec(
|
|
177
|
-
`sudo kubeadm init --pod-network-cidr=${podNetworkCidr} --control-plane-endpoint="${controlPlaneEndpoint}"`,
|
|
187
|
+
`sudo kubeadm init --pod-network-cidr=${podNetworkCidr} --control-plane-endpoint="${controlPlaneEndpoint}" --cri-socket=${criSocket}`,
|
|
178
188
|
);
|
|
179
189
|
// Configure kubectl for the current user
|
|
180
190
|
Underpost.cluster.chown('kubeadm'); // Pass 'kubeadm' to chown
|
|
@@ -389,8 +399,17 @@ EOF
|
|
|
389
399
|
);
|
|
390
400
|
shellExec(`rm -f ${tarPath}`);
|
|
391
401
|
} else if (options.kubeadm || options.k3s) {
|
|
392
|
-
// Kubeadm / K3s: use crictl to pull directly into
|
|
393
|
-
|
|
402
|
+
// Kubeadm / K3s: use crictl to pull directly into the active CRI runtime.
|
|
403
|
+
// crictl is not in sudo's secure_path; pass full PATH through env.
|
|
404
|
+
// Point crictl at CRI-O when the socket exists, otherwise fall back to containerd.
|
|
405
|
+
const criSock =
|
|
406
|
+
shellExec(`test -S /var/run/crio/crio.sock && echo crio || echo containerd`, {
|
|
407
|
+
stdout: true,
|
|
408
|
+
silent: true,
|
|
409
|
+
}).trim() === 'crio'
|
|
410
|
+
? 'unix:///var/run/crio/crio.sock'
|
|
411
|
+
: 'unix:///run/containerd/containerd.sock';
|
|
412
|
+
shellExec(`sudo env PATH="$PATH:/usr/local/bin:/usr/bin" crictl --runtime-endpoint ${criSock} pull ${image}`);
|
|
394
413
|
}
|
|
395
414
|
},
|
|
396
415
|
|
|
@@ -453,12 +472,11 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
|
|
|
453
472
|
shellExec(`sudo sysctl -w fs.inotify.max_queued_events=2099999999`);
|
|
454
473
|
|
|
455
474
|
// shellExec(`sudo sysctl --system`); // Apply sysctl changes immediately
|
|
456
|
-
// Apply NAT iptables rules.
|
|
475
|
+
// Apply NAT iptables rules and configure firewalld for Kubernetes.
|
|
476
|
+
// nat-iptables.sh enables firewalld and opens all required ports; do NOT stop it
|
|
477
|
+
// afterwards — keeping firewalld running with these rules is required for
|
|
478
|
+
// multi-machine kubeadm inter-node communication.
|
|
457
479
|
shellExec(`${underpostRoot}/scripts/nat-iptables.sh`, { silent: true });
|
|
458
|
-
|
|
459
|
-
// Disable firewalld (common cause of network issues in Kubernetes)
|
|
460
|
-
shellExec(`sudo systemctl stop firewalld`); // Stop if running
|
|
461
|
-
shellExec(`sudo systemctl disable firewalld`); // Disable from starting on boot
|
|
462
480
|
},
|
|
463
481
|
|
|
464
482
|
/**
|
|
@@ -575,8 +593,10 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
|
|
|
575
593
|
shellExec('sudo systemctl stop kubelet');
|
|
576
594
|
shellExec('sudo systemctl stop docker');
|
|
577
595
|
shellExec('sudo systemctl stop podman');
|
|
578
|
-
//
|
|
579
|
-
shellExec(
|
|
596
|
+
// Lazy-unmount all kubelet pod mounts to avoid 'Device or resource busy' on rm.
|
|
597
|
+
shellExec(
|
|
598
|
+
`sudo sh -c 'findmnt --raw --noheadings -o TARGET | grep /var/lib/kubelet | sort -r | xargs -r umount -l' 2>/dev/null || true`,
|
|
599
|
+
);
|
|
580
600
|
|
|
581
601
|
// Phase 3: Execute official uninstallation commands (type-specific)
|
|
582
602
|
const clusterType = options.clusterType || 'kind';
|
|
@@ -584,6 +604,14 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
|
|
|
584
604
|
`Phase 3/7: Executing official reset/uninstallation commands for cluster type: '${clusterType}'...`,
|
|
585
605
|
);
|
|
586
606
|
if (clusterType === 'kubeadm') {
|
|
607
|
+
// Kill control plane processes that hold ports (6443, 10257, 10259, 2379, 2380)
|
|
608
|
+
// so the next `kubeadm init` does not fail with [ERROR Port-xxxx].
|
|
609
|
+
logger.info(' -> Stopping and killing control plane containers and processes...');
|
|
610
|
+
shellExec('sudo crictl rm -a -f 2>/dev/null || true');
|
|
611
|
+
shellExec('sudo crictl rmp -a -f 2>/dev/null || true');
|
|
612
|
+
shellExec('sudo systemctl stop etcd 2>/dev/null || true');
|
|
613
|
+
for (const port of [6443, 10259, 10257, 2379, 2380])
|
|
614
|
+
shellExec(`sudo fuser -k ${port}/tcp 2>/dev/null || true`);
|
|
587
615
|
logger.info(' -> Executing kubeadm reset...');
|
|
588
616
|
shellExec('sudo kubeadm reset --force');
|
|
589
617
|
} else if (clusterType === 'k3s') {
|
|
@@ -600,7 +628,12 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
|
|
|
600
628
|
// Remove any leftover configurations and data.
|
|
601
629
|
shellExec('sudo rm -rf /etc/kubernetes/*');
|
|
602
630
|
shellExec('sudo rm -rf /etc/cni/net.d/*');
|
|
631
|
+
// Second-pass lazy umount before rm to clear any remaining busy mounts.
|
|
632
|
+
shellExec(
|
|
633
|
+
`sudo sh -c 'findmnt --raw --noheadings -o TARGET | grep /var/lib/kubelet | sort -r | xargs -r umount -l' 2>/dev/null || true`,
|
|
634
|
+
);
|
|
603
635
|
shellExec('sudo rm -rf /var/lib/kubelet/*');
|
|
636
|
+
shellExec('sudo rm -rf /var/lib/etcd');
|
|
604
637
|
shellExec('sudo rm -rf /var/lib/cni/*');
|
|
605
638
|
shellExec('sudo rm -rf /var/lib/docker/*');
|
|
606
639
|
shellExec('sudo rm -rf /var/lib/containerd/*');
|
|
@@ -613,11 +646,14 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
|
|
|
613
646
|
// Remove iptables rules and CNI network interfaces.
|
|
614
647
|
shellExec('sudo iptables -F');
|
|
615
648
|
shellExec('sudo iptables -t nat -F');
|
|
616
|
-
shellExec('sudo ip link del cni0');
|
|
617
|
-
shellExec('sudo ip link del flannel.1');
|
|
649
|
+
shellExec('sudo ip link del cni0 2>/dev/null || true');
|
|
650
|
+
shellExec('sudo ip link del flannel.1 2>/dev/null || true');
|
|
651
|
+
shellExec('sudo ip link del vxlan.calico 2>/dev/null || true');
|
|
652
|
+
shellExec('sudo ip link del tunl0 2>/dev/null || true');
|
|
618
653
|
|
|
619
654
|
logger.info('Phase 6/7: Clean up images');
|
|
620
|
-
shellExec(
|
|
655
|
+
shellExec('sudo podman rmi --all --force 2>/dev/null || true');
|
|
656
|
+
shellExec('sudo crictl rmi --prune 2>/dev/null || true');
|
|
621
657
|
|
|
622
658
|
// Phase 6: Reload daemon and finalize
|
|
623
659
|
logger.info('Phase 7/7: Reloading the system daemon and finalizing...');
|
|
@@ -687,6 +723,9 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
|
|
|
687
723
|
// Install Podman
|
|
688
724
|
shellExec(`sudo dnf -y install podman`);
|
|
689
725
|
|
|
726
|
+
// Install CRI-O (required for kubeadm with CRI-O socket)
|
|
727
|
+
shellExec(`node bin run install-crio`);
|
|
728
|
+
|
|
690
729
|
// Install Kind (Kubernetes in Docker)
|
|
691
730
|
shellExec(`[ $(uname -m) = ${archData.name} ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.29.0/kind-linux-${archData.alias}
|
|
692
731
|
chmod +x ./kind
|
|
@@ -744,6 +783,14 @@ EOF`);
|
|
|
744
783
|
console.log('Removing Podman...');
|
|
745
784
|
shellExec(`sudo dnf -y remove podman`);
|
|
746
785
|
|
|
786
|
+
// Remove CRI-O
|
|
787
|
+
console.log('Removing CRI-O...');
|
|
788
|
+
shellExec(`sudo systemctl stop crio 2>/dev/null || true`);
|
|
789
|
+
shellExec(`sudo systemctl disable crio 2>/dev/null || true`);
|
|
790
|
+
shellExec(`sudo dnf -y remove cri-o`);
|
|
791
|
+
shellExec(`sudo rm -f /etc/yum.repos.d/cri-o.repo`);
|
|
792
|
+
shellExec(`sudo rm -f /etc/crictl.yaml`);
|
|
793
|
+
|
|
747
794
|
// Remove Kubeadm, Kubelet, and Kubectl
|
|
748
795
|
console.log('Removing Kubernetes tools...');
|
|
749
796
|
shellExec(`sudo yum remove -y kubelet kubeadm kubectl`);
|
package/src/cli/db.js
CHANGED
|
@@ -839,6 +839,8 @@ class UnderpostDB {
|
|
|
839
839
|
pods: podsToProcess.map((p) => p.NAME),
|
|
840
840
|
});
|
|
841
841
|
|
|
842
|
+
let exportSucceeded = false;
|
|
843
|
+
|
|
842
844
|
// Process each pod
|
|
843
845
|
for (const pod of podsToProcess) {
|
|
844
846
|
logger.info('Processing pod', { podName: pod.NAME, node: pod.NODE, status: pod.STATUS });
|
|
@@ -871,7 +873,7 @@ class UnderpostDB {
|
|
|
871
873
|
|
|
872
874
|
if (options.export === true) {
|
|
873
875
|
const outputPath = options.outPath || toNewSqlPath;
|
|
874
|
-
await Underpost.db._exportMariaDB({
|
|
876
|
+
const success = await Underpost.db._exportMariaDB({
|
|
875
877
|
pod,
|
|
876
878
|
namespace,
|
|
877
879
|
dbName,
|
|
@@ -879,6 +881,7 @@ class UnderpostDB {
|
|
|
879
881
|
password,
|
|
880
882
|
outputPath,
|
|
881
883
|
});
|
|
884
|
+
exportSucceeded = exportSucceeded || success;
|
|
882
885
|
}
|
|
883
886
|
break;
|
|
884
887
|
}
|
|
@@ -909,13 +912,14 @@ class UnderpostDB {
|
|
|
909
912
|
|
|
910
913
|
if (options.export === true) {
|
|
911
914
|
const outputPath = options.outPath || toNewBsonPath;
|
|
912
|
-
Underpost.db._exportMongoDB({
|
|
915
|
+
const success = Underpost.db._exportMongoDB({
|
|
913
916
|
pod,
|
|
914
917
|
namespace,
|
|
915
918
|
dbName,
|
|
916
919
|
outputPath,
|
|
917
920
|
collections: options.collections,
|
|
918
921
|
});
|
|
922
|
+
exportSucceeded = exportSucceeded || success;
|
|
919
923
|
}
|
|
920
924
|
break;
|
|
921
925
|
}
|
|
@@ -926,6 +930,10 @@ class UnderpostDB {
|
|
|
926
930
|
}
|
|
927
931
|
}
|
|
928
932
|
|
|
933
|
+
if (options.export === true && exportSucceeded === true) {
|
|
934
|
+
Underpost.db._enforceBackupRetention(`../${repoName}/${hostFolder}`);
|
|
935
|
+
}
|
|
936
|
+
|
|
929
937
|
// Mark this host+path combination as processed
|
|
930
938
|
processedHostPaths.add(hostPathKey);
|
|
931
939
|
}
|
|
@@ -948,6 +956,43 @@ class UnderpostDB {
|
|
|
948
956
|
throw error;
|
|
949
957
|
}
|
|
950
958
|
},
|
|
959
|
+
/**
|
|
960
|
+
* Helper: Removes old timestamp backup folders and keeps only the newest ones.
|
|
961
|
+
* @method _enforceBackupRetention
|
|
962
|
+
* @memberof UnderpostDB
|
|
963
|
+
* @param {string} backupDir - Path to host-folder backup directory.
|
|
964
|
+
* @param {number} [maxRetention=MAX_BACKUP_RETENTION] - Maximum folders to keep.
|
|
965
|
+
* @return {number} Number of removed backup folders.
|
|
966
|
+
*/
|
|
967
|
+
_enforceBackupRetention(backupDir, maxRetention = MAX_BACKUP_RETENTION) {
|
|
968
|
+
try {
|
|
969
|
+
if (!fs.existsSync(backupDir)) return 0;
|
|
970
|
+
|
|
971
|
+
const timestamps = fs
|
|
972
|
+
.readdirSync(backupDir)
|
|
973
|
+
.filter((entry) => /^\d+$/.test(entry))
|
|
974
|
+
.sort((a, b) => parseInt(b, 10) - parseInt(a, 10));
|
|
975
|
+
|
|
976
|
+
if (timestamps.length <= maxRetention) return 0;
|
|
977
|
+
|
|
978
|
+
const staleTimestamps = timestamps.slice(maxRetention);
|
|
979
|
+
staleTimestamps.forEach((timestamp) => {
|
|
980
|
+
fs.removeSync(`${backupDir}/${timestamp}`);
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
logger.info('Pruned old backup timestamp folders', {
|
|
984
|
+
backupDir,
|
|
985
|
+
kept: maxRetention,
|
|
986
|
+
removed: staleTimestamps.length,
|
|
987
|
+
removedTimestamps: staleTimestamps,
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
return staleTimestamps.length;
|
|
991
|
+
} catch (error) {
|
|
992
|
+
logger.error('Failed to enforce backup retention', { backupDir, maxRetention, error: error.message });
|
|
993
|
+
return 0;
|
|
994
|
+
}
|
|
995
|
+
},
|
|
951
996
|
|
|
952
997
|
/**
|
|
953
998
|
* Creates cluster metadata for the specified deployment.
|
package/src/cli/deploy.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
buildPortProxyRouter,
|
|
10
10
|
buildProxyRouter,
|
|
11
11
|
Config,
|
|
12
|
+
cronDeployIdResolve,
|
|
12
13
|
deployRangePortFactory,
|
|
13
14
|
getDataDeploy,
|
|
14
15
|
loadConfServerJson,
|
|
@@ -124,24 +125,47 @@ class UnderpostDeploy {
|
|
|
124
125
|
* @param {string} namespace - Kubernetes namespace for the deployment.
|
|
125
126
|
* @param {Array<object>} volumes - Volume configurations for the deployment.
|
|
126
127
|
* @param {Array<string>} cmd - Command to run in the deployment container.
|
|
128
|
+
* @param {boolean} skipFullBuild - Whether to skip the full client bundle build during deployment.
|
|
129
|
+
* @param {boolean} pullBundle - Whether to pull the pre-built client bundle from Cloudinary before starting. Use together with skipFullBuild to skip the local build entirely.
|
|
127
130
|
* @returns {string} - YAML deployment configuration for the specified deployment.
|
|
128
131
|
* @memberof UnderpostDeploy
|
|
129
132
|
*/
|
|
130
|
-
deploymentYamlPartsFactory({
|
|
133
|
+
deploymentYamlPartsFactory({
|
|
134
|
+
deployId,
|
|
135
|
+
env,
|
|
136
|
+
suffix,
|
|
137
|
+
resources,
|
|
138
|
+
replicas,
|
|
139
|
+
image,
|
|
140
|
+
namespace,
|
|
141
|
+
volumes,
|
|
142
|
+
cmd,
|
|
143
|
+
skipFullBuild,
|
|
144
|
+
pullBundle,
|
|
145
|
+
}) {
|
|
131
146
|
if (!cmd)
|
|
132
|
-
cmd =
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
147
|
+
cmd =
|
|
148
|
+
pullBundle || skipFullBuild
|
|
149
|
+
? [
|
|
150
|
+
// When pullBundle (or skipFullBuild) is set the container pulls the pre-built client
|
|
151
|
+
// bundle from Cloudinary (push-bundle must have been run on the dev machine beforehand).
|
|
152
|
+
`underpost secret underpost --create-from-env`,
|
|
153
|
+
`underpost start --build --run --pull-bundle --skip-full-build ${deployId} ${env}`,
|
|
154
|
+
]
|
|
155
|
+
: [
|
|
156
|
+
// `npm install -g npm@11.2.0`,
|
|
157
|
+
// `npm install -g underpost`,
|
|
158
|
+
`underpost secret underpost --create-from-env`,
|
|
159
|
+
`underpost start --build --run ${deployId} ${env}`,
|
|
160
|
+
];
|
|
138
161
|
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
|
|
139
162
|
if (!volumes) volumes = [];
|
|
140
163
|
const confVolume = fs.existsSync(`./engine-private/conf/${deployId}/conf.volume.json`)
|
|
141
164
|
? JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.volume.json`, 'utf8'))
|
|
142
165
|
: [];
|
|
143
166
|
volumes = volumes.concat(confVolume);
|
|
144
|
-
const containerImage = image ? image : `localhost/rockylinux9-underpost:v${packageJson.version}`;
|
|
167
|
+
// const containerImage = image ? image : `localhost/rockylinux9-underpost:v${packageJson.version}`;
|
|
168
|
+
const containerImage = image ? image : `underpost/underpost-engine:v${packageJson.version}`;
|
|
145
169
|
return `apiVersion: apps/v1
|
|
146
170
|
kind: Deployment
|
|
147
171
|
metadata:
|
|
@@ -164,6 +188,7 @@ spec:
|
|
|
164
188
|
containers:
|
|
165
189
|
- name: ${deployId}-${env}-${suffix}
|
|
166
190
|
image: ${containerImage}
|
|
191
|
+
imagePullPolicy: ${containerImage.startsWith('localhost/') ? 'Never' : 'IfNotPresent'}
|
|
167
192
|
envFrom:
|
|
168
193
|
- secretRef:
|
|
169
194
|
name: underpost-config
|
|
@@ -221,6 +246,8 @@ spec:
|
|
|
221
246
|
* @param {string} [options.retryPerTryTimeout] - Retry per-try timeout setting for the deployment.
|
|
222
247
|
* @param {boolean} [options.disableDeploymentProxy] - Whether to disable deployment proxy.
|
|
223
248
|
* @param {string} [options.traffic] - Traffic status for the deployment.
|
|
249
|
+
* @param {boolean} [options.skipFullBuild] - Whether to skip the full client bundle build; forwarded to deploymentYamlPartsFactory to generate a pull-bundle startup command.
|
|
250
|
+
* @param {boolean} [options.pullBundle] - Whether to pull the pre-built client bundle from Cloudinary; forwarded to deploymentYamlPartsFactory. Use together with skipFullBuild.
|
|
224
251
|
* @returns {Promise<void>} - Promise that resolves when the manifest is built.
|
|
225
252
|
* @memberof UnderpostDeploy
|
|
226
253
|
*/
|
|
@@ -257,6 +284,8 @@ ${Underpost.deploy
|
|
|
257
284
|
image,
|
|
258
285
|
namespace: options.namespace,
|
|
259
286
|
cmd: options.cmd ? options.cmd.split(',').map((c) => c.trim()) : undefined,
|
|
287
|
+
skipFullBuild: options.skipFullBuild,
|
|
288
|
+
pullBundle: options.pullBundle,
|
|
260
289
|
})
|
|
261
290
|
.replace('{{ports}}', buildKindPorts(fromPort, toPort))}
|
|
262
291
|
`;
|
|
@@ -550,10 +579,13 @@ spec:
|
|
|
550
579
|
* @param {string} [options.kindType] - Type of Kubernetes resource to retrieve information for.
|
|
551
580
|
* @param {number} [options.port] - Port number for exposing the deployment.
|
|
552
581
|
* @param {string} [options.cmd] - Custom initialization command for deploymentYamlPartsFactory (comma-separated commands).
|
|
582
|
+
* @param {number} [options.exposePort] - Local:remote port override when --expose is active (overrides auto-detected service port).
|
|
553
583
|
* @param {boolean} [options.k3s] - Whether to use k3s cluster context.
|
|
554
584
|
* @param {boolean} [options.kubeadm] - Whether to use kubeadm cluster context.
|
|
555
585
|
* @param {boolean} [options.kind] - Whether to use kind cluster context.
|
|
556
586
|
* @param {boolean} [options.gitClean] - Whether to run git clean on volume mount paths before copying.
|
|
587
|
+
* @param {boolean} [options.skipFullBuild] - Whether to skip the full client bundle build; passed through to buildManifest/deploymentYamlPartsFactory.
|
|
588
|
+
* @param {boolean} [options.pullBundle] - Whether to pull the pre-built client bundle from Cloudinary; passed through to buildManifest/deploymentYamlPartsFactory. Use together with skipFullBuild.
|
|
557
589
|
* @returns {Promise<void>} - Promise that resolves when the deployment process is complete.
|
|
558
590
|
* @memberof UnderpostDeploy
|
|
559
591
|
*/
|
|
@@ -624,6 +656,8 @@ EOF`);
|
|
|
624
656
|
path: instance.path,
|
|
625
657
|
fromPort: instance.fromPort,
|
|
626
658
|
toPort: instance.toPort,
|
|
659
|
+
fromDebugPort: instance.fromDebugPort,
|
|
660
|
+
toDebugPort: instance.toDebugPort,
|
|
627
661
|
traffic: Underpost.deploy.getCurrentTraffic(_deployId, { namespace, hostTest: instance.host }),
|
|
628
662
|
});
|
|
629
663
|
}
|
|
@@ -801,9 +835,10 @@ EOF`);
|
|
|
801
835
|
* @memberof UnderpostDeploy
|
|
802
836
|
*/
|
|
803
837
|
configMap(env, namespace = 'default') {
|
|
838
|
+
const cronDeployId = cronDeployIdResolve() || 'dd-cron';
|
|
804
839
|
shellExec(`kubectl delete secret underpost-config -n ${namespace} --ignore-not-found`);
|
|
805
840
|
shellExec(
|
|
806
|
-
`kubectl create secret generic underpost-config --from-env-file=/home/dd/engine/engine-private/conf
|
|
841
|
+
`kubectl create secret generic underpost-config --from-env-file=/home/dd/engine/engine-private/conf/${cronDeployId}/.env.${env} --dry-run=client -o yaml | kubectl apply -f - -n ${namespace}`,
|
|
807
842
|
);
|
|
808
843
|
},
|
|
809
844
|
/**
|
|
@@ -1092,11 +1127,10 @@ ${renderHosts}`,
|
|
|
1092
1127
|
* @param {string} targetTraffic - Target traffic status for the deployment.
|
|
1093
1128
|
* @param {Array<string>} ignorePods - List of pod names to ignore.
|
|
1094
1129
|
* @param {string} [namespace='default'] - Kubernetes namespace for the deployment.
|
|
1095
|
-
* @param {string} [outLogType=''] - Type of log output.
|
|
1096
1130
|
* @returns {object} - Object containing the ready status of the deployment.
|
|
1097
1131
|
* @memberof UnderpostDeploy
|
|
1098
1132
|
*/
|
|
1099
|
-
async monitorReadyRunner(deployId, env, targetTraffic, ignorePods = [], namespace = 'default'
|
|
1133
|
+
async monitorReadyRunner(deployId, env, targetTraffic, ignorePods = [], namespace = 'default') {
|
|
1100
1134
|
let checkStatusIteration = 0;
|
|
1101
1135
|
const checkStatusIterationMsDelay = 1000;
|
|
1102
1136
|
const maxIterations = 3000;
|
|
@@ -1134,32 +1168,30 @@ ${renderHosts}`,
|
|
|
1134
1168
|
}
|
|
1135
1169
|
}
|
|
1136
1170
|
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
const { NAME, out } = pod;
|
|
1171
|
+
{
|
|
1172
|
+
let indexOf = -1;
|
|
1173
|
+
for (const pod of result.notReadyPods) {
|
|
1174
|
+
indexOf++;
|
|
1175
|
+
const { NAME, out } = pod;
|
|
1143
1176
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1177
|
+
if (out.match('not') && out.match('found') && checkStatusIteration <= 20 && out.match(deploymentId))
|
|
1178
|
+
lastMsg[NAME] = 'Starting deployment';
|
|
1179
|
+
// else if (out.match('not') && out.match('found') && checkStatusIteration <= 20 && out.match('underpost'))
|
|
1180
|
+
// lastMsg[NAME] = 'Installing underpost cli';
|
|
1181
|
+
else if (out.match('not') && out.match('found') && checkStatusIteration <= 20 && out.match('task'))
|
|
1182
|
+
lastMsg[NAME] = 'Initializing setup task';
|
|
1183
|
+
else if (out.match('Empty environment variables')) lastMsg[NAME] = 'Setup environment';
|
|
1184
|
+
else if (out.match(`${deployId}-${env}-build-deployment`)) lastMsg[NAME] = 'Building apps/services';
|
|
1185
|
+
else if (out.match(`${deployId}-${env}-initializing-deployment`))
|
|
1186
|
+
lastMsg[NAME] = 'Initializing apps/services';
|
|
1187
|
+
else if (!lastMsg[NAME]) lastMsg[NAME] = `Waiting for status`;
|
|
1155
1188
|
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
}
|
|
1189
|
+
console.log(
|
|
1190
|
+
'Target pod:',
|
|
1191
|
+
NAME[NAME.match('green') ? 'bgGreen' : 'bgBlue'].bold.black,
|
|
1192
|
+
'| Status:',
|
|
1193
|
+
lastMsg[NAME].bold.magenta,
|
|
1194
|
+
);
|
|
1163
1195
|
}
|
|
1164
1196
|
}
|
|
1165
1197
|
await timer(checkStatusIterationMsDelay);
|
package/src/cli/fs.js
CHANGED
|
@@ -75,6 +75,7 @@ class UnderpostFileStorage {
|
|
|
75
75
|
* @param {boolean} [options.force=false] - Flag to force file operations.
|
|
76
76
|
* @param {boolean} [options.pull=false] - Flag to pull files from storage.
|
|
77
77
|
* @param {boolean} [options.git=false] - Flag to use Git for file operations.
|
|
78
|
+
* @param {boolean} [options.omitUnzip=false] - If true, do not extract zip and keep downloaded zip file.
|
|
78
79
|
* @param {string} [options.storageFilePath=''] - The path to the storage configuration file.
|
|
79
80
|
* @returns {Promise<void>} A promise that resolves when the recursive callback is complete.
|
|
80
81
|
* @memberof UnderpostFileStorage
|
|
@@ -88,10 +89,50 @@ class UnderpostFileStorage {
|
|
|
88
89
|
force: false,
|
|
89
90
|
pull: false,
|
|
90
91
|
git: false,
|
|
92
|
+
omitUnzip: false,
|
|
91
93
|
storageFilePath: '',
|
|
92
94
|
},
|
|
93
95
|
) {
|
|
94
96
|
const { storage, storageConf } = Underpost.fs.getStorageConf(options);
|
|
97
|
+
|
|
98
|
+
// In recursive remove mode, delete every tracked storage key under the requested path,
|
|
99
|
+
// even when local files/directories are already missing.
|
|
100
|
+
if (options.rm === true) {
|
|
101
|
+
const normalizedPath = typeof path === 'string' ? path.trim() : '';
|
|
102
|
+
const basePath = normalizedPath.replace(/\/+$/, '');
|
|
103
|
+
const hasPathFilter = basePath.length > 0;
|
|
104
|
+
|
|
105
|
+
const associatedPaths = Object.keys(storage || {}).filter((storedPath) => {
|
|
106
|
+
if (!hasPathFilter) return true;
|
|
107
|
+
return storedPath === basePath || storedPath.startsWith(`${basePath}/`);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
for (const associatedPath of associatedPaths) {
|
|
111
|
+
await Underpost.fs.delete(associatedPath);
|
|
112
|
+
if (storage) delete storage[associatedPath];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (hasPathFilter && options.force === true && fs.existsSync(basePath)) fs.removeSync(basePath);
|
|
116
|
+
|
|
117
|
+
Underpost.fs.writeStorageConf(storage, storageConf);
|
|
118
|
+
|
|
119
|
+
if (associatedPaths.length === 0)
|
|
120
|
+
logger.warn('No associated tracked storage paths found', { path: hasPathFilter ? basePath : '*' });
|
|
121
|
+
else
|
|
122
|
+
logger.info('Removed associated tracked storage paths', {
|
|
123
|
+
path: hasPathFilter ? basePath : '*',
|
|
124
|
+
removed: associatedPaths.length,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
if (options.git === true) {
|
|
128
|
+
const gitPath = hasPathFilter ? basePath : '.';
|
|
129
|
+
shellExec(`cd ${gitPath} && git add .`);
|
|
130
|
+
shellExec(`underpost cmt ${gitPath} feat`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
95
136
|
const deleteFiles = options.pull === true ? [] : Underpost.repo.getDeleteFiles(path);
|
|
96
137
|
for (const relativePath of deleteFiles) {
|
|
97
138
|
const _path = path + '/' + relativePath;
|
|
@@ -109,8 +150,12 @@ class UnderpostFileStorage {
|
|
|
109
150
|
} else pullSkipCount++;
|
|
110
151
|
}
|
|
111
152
|
if (pullSkipCount > 0) logger.warn(`Pull skipped ${pullSkipCount} files that already exist`);
|
|
112
|
-
|
|
113
|
-
|
|
153
|
+
// Only run git init/commit when the caller explicitly requests git tracking (--git flag).
|
|
154
|
+
// For bundle pulls into ./build the git step is unwanted and would error on a non-repo path.
|
|
155
|
+
if (options.git === true) {
|
|
156
|
+
Underpost.repo.initLocalRepo({ path });
|
|
157
|
+
shellExec(`cd ${path} && git add . && git commit -m "Base pull state"`);
|
|
158
|
+
}
|
|
114
159
|
} else {
|
|
115
160
|
const files =
|
|
116
161
|
options.git === true ? Underpost.repo.getChangedFiles(path) : await fs.readdir(path, { recursive: true });
|
|
@@ -143,12 +188,13 @@ class UnderpostFileStorage {
|
|
|
143
188
|
* @param {boolean} [options.force=false] - Flag to force file operations.
|
|
144
189
|
* @param {boolean} [options.pull=false] - Flag to pull files from storage.
|
|
145
190
|
* @param {boolean} [options.git=false] - Flag to use Git for file operations.
|
|
191
|
+
* @param {boolean} [options.omitUnzip=false] - If true, do not extract zip and keep downloaded zip file.
|
|
146
192
|
* @returns {Promise<void>} A promise that resolves when the callback is complete.
|
|
147
193
|
* @memberof UnderpostFileStorage
|
|
148
194
|
*/
|
|
149
195
|
async callback(
|
|
150
196
|
path,
|
|
151
|
-
options = { rm: false, recursive: false, deployId: '', force: false, pull: false, git: false },
|
|
197
|
+
options = { rm: false, recursive: false, deployId: '', force: false, pull: false, git: false, omitUnzip: false },
|
|
152
198
|
) {
|
|
153
199
|
if (options.recursive === true || options.git === true)
|
|
154
200
|
return await Underpost.fs.recursiveCallback(path, options);
|
|
@@ -161,11 +207,13 @@ class UnderpostFileStorage {
|
|
|
161
207
|
* @description Uploads a file to Cloudinary.
|
|
162
208
|
* @param {string} path - The path to the file to upload.
|
|
163
209
|
* @param {object} [options] - An object containing options for the upload.
|
|
164
|
-
* @param {
|
|
210
|
+
* @param {string} [options.deployId=''] - The identifier for the deployment (used to locate the storage config file).
|
|
211
|
+
* @param {boolean} [options.force=false] - Flag to force file operations (overwrites existing remote asset).
|
|
165
212
|
* @param {string} [options.storageFilePath=''] - The path to the storage configuration file.
|
|
166
213
|
* @returns {Promise<object>} A promise that resolves to the upload result.
|
|
167
214
|
* @memberof UnderpostFileStorage
|
|
168
215
|
*/
|
|
216
|
+
|
|
169
217
|
async upload(
|
|
170
218
|
path,
|
|
171
219
|
options = { rm: false, recursive: false, deployId: '', force: false, pull: false, storageFilePath: '' },
|
|
@@ -191,22 +239,45 @@ class UnderpostFileStorage {
|
|
|
191
239
|
* @method pull
|
|
192
240
|
* @description Pulls a file from Cloudinary.
|
|
193
241
|
* @param {string} path - The path to the file to pull.
|
|
242
|
+
* @param {object} [options] - Pull options.
|
|
243
|
+
* @param {boolean} [options.omitUnzip=false] - If true, do not extract zip and keep downloaded zip file.
|
|
244
|
+
* @param {boolean} [options.force=false] - If true, re-download even if the local zip already exists.
|
|
194
245
|
* @returns {Promise<void>} A promise that resolves when the file is pulled.
|
|
195
246
|
* @memberof UnderpostFileStorage
|
|
196
247
|
*/
|
|
197
|
-
async pull(path) {
|
|
248
|
+
async pull(path, options = { omitUnzip: false, force: false }) {
|
|
198
249
|
Underpost.fs.cloudinaryConfig();
|
|
199
250
|
const folder = dir.dirname(path);
|
|
200
251
|
if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
|
|
252
|
+
const zipPath = `${path}.zip`;
|
|
253
|
+
|
|
254
|
+
if (options.omitUnzip === true && options.force !== true && fs.existsSync(zipPath)) {
|
|
255
|
+
logger.warn('pull skipped, zip already exists and omit-unzip is enabled', { path, zipPath });
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
201
259
|
const downloadResult = await cloudinary.utils.download_archive_url({
|
|
202
260
|
public_ids: [path],
|
|
203
261
|
resource_type: 'raw',
|
|
204
262
|
});
|
|
205
263
|
logger.info('download result', downloadResult);
|
|
206
|
-
await Downloader.downloadFile(downloadResult,
|
|
207
|
-
|
|
208
|
-
|
|
264
|
+
await Downloader.downloadFile(downloadResult, zipPath);
|
|
265
|
+
|
|
266
|
+
if (options.omitUnzip === true) {
|
|
267
|
+
logger.warn('omit unzip enabled, keeping downloaded zip file', { path, zipPath });
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
path = Underpost.fs.zip2File(zipPath);
|
|
272
|
+
fs.removeSync(`${path}.zip`);
|
|
209
273
|
},
|
|
274
|
+
/**
|
|
275
|
+
* @method delete
|
|
276
|
+
* @description Deletes a file from Cloudinary by its public ID.
|
|
277
|
+
* @param {string} path - The path (public ID) of the file to delete.
|
|
278
|
+
* @returns {Promise<object>} A promise that resolves to the Cloudinary delete result.
|
|
279
|
+
* @memberof UnderpostFileStorage
|
|
280
|
+
*/
|
|
210
281
|
async delete(path) {
|
|
211
282
|
Underpost.fs.cloudinaryConfig();
|
|
212
283
|
const deleteResult = await cloudinary.api
|
package/src/cli/image.js
CHANGED
|
@@ -99,6 +99,7 @@ class UnderpostImage {
|
|
|
99
99
|
if (!path) path = '.';
|
|
100
100
|
if (!imageName) imageName = `rockylinux9-underpost:${Underpost.version}`;
|
|
101
101
|
if (!imagePath) imagePath = '.';
|
|
102
|
+
if (imageName.match('/')) imageName = imageName.split('/')[1];
|
|
102
103
|
if (!version) version = 'latest';
|
|
103
104
|
version = imageName && imageName.match(':') ? '' : `:${version}`;
|
|
104
105
|
const podManImg = `localhost/${imageName}${version}`;
|
|
@@ -178,6 +179,12 @@ class UnderpostImage {
|
|
|
178
179
|
* @memberof UnderpostImage
|
|
179
180
|
*/
|
|
180
181
|
pullDockerHubImage(options = { k3s: false, kubeadm: false, kind: false, dockerhubImage: '', version: '' }) {
|
|
182
|
+
if (options.dockerhubImage && options.dockerhubImage.startsWith('localhost')) {
|
|
183
|
+
logger.warn(`[image] pullDockerHubImage skipped — local image cannot be pulled from Docker Hub`, {
|
|
184
|
+
dockerhubImage: options.dockerhubImage,
|
|
185
|
+
});
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
181
188
|
if (options.dockerhubImage === 'underpost') {
|
|
182
189
|
options.dockerhubImage = 'underpost/underpost-engine';
|
|
183
190
|
if (!options.version) options.version = Underpost.version;
|
|
@@ -185,7 +192,42 @@ class UnderpostImage {
|
|
|
185
192
|
if (!options.version) options.version = 'latest';
|
|
186
193
|
const version = options.dockerhubImage && options.dockerhubImage.match(':') ? '' : `:${options.version}`;
|
|
187
194
|
const image = `${options.dockerhubImage}${version}`;
|
|
188
|
-
|
|
195
|
+
const targetKind = options.kind === true;
|
|
196
|
+
const targetK3s = options.k3s === true;
|
|
197
|
+
const targetKubeadm = options.kubeadm === true || (!targetKind && !targetK3s);
|
|
198
|
+
|
|
199
|
+
const requestedRepo = image.replace(/:[^/]+$/, '');
|
|
200
|
+
const requestedTag = image.match(/:([^/]+)$/)?.[1] || 'latest';
|
|
201
|
+
const normalizeRepo = (repo = '') =>
|
|
202
|
+
repo
|
|
203
|
+
.trim()
|
|
204
|
+
.replace(/^localhost\//, '')
|
|
205
|
+
.replace(/^docker\.io\//, '')
|
|
206
|
+
.replace(/^library\//, '');
|
|
207
|
+
|
|
208
|
+
const currentImages = UnderpostImage.API.list({
|
|
209
|
+
kind: targetKind,
|
|
210
|
+
kubeadm: targetKubeadm,
|
|
211
|
+
k3s: targetK3s,
|
|
212
|
+
log: false,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const existsInCluster = currentImages.some((row) => {
|
|
216
|
+
const rowImageRaw = String(row.IMAGE || row.image || '').trim();
|
|
217
|
+
if (!rowImageRaw) return false;
|
|
218
|
+
const rowImage = rowImageRaw.replace(/:[^/]+$/, '');
|
|
219
|
+
const rowTag = String(row.TAG || rowImageRaw.match(/:([^/]+)$/)?.[1] || '').trim();
|
|
220
|
+
return normalizeRepo(rowImage) === normalizeRepo(requestedRepo) && rowTag === requestedTag;
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
if (existsInCluster) {
|
|
224
|
+
logger.info(`[image] pull skipped. Image already loaded`, {
|
|
225
|
+
image,
|
|
226
|
+
clusterType: targetKind ? 'kind' : targetK3s ? 'k3s' : 'kubeadm',
|
|
227
|
+
});
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (targetKind) {
|
|
189
231
|
shellExec(`docker pull ${image}`);
|
|
190
232
|
shellExec(`sudo kind load docker-image ${image}`);
|
|
191
233
|
} else {
|