cyberia 3.2.5 → 3.2.12
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 +8 -2
- package/.github/workflows/npmpkg.ci.yml +1 -0
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/.github/workflows/release.cd.yml +2 -2
- package/.vscode/extensions.json +9 -9
- package/.vscode/settings.json +20 -4
- package/CHANGELOG.md +563 -1
- package/CLI-HELP.md +130 -34
- package/Dockerfile +0 -4
- package/README.md +194 -607
- package/bin/build.js +42 -12
- package/bin/build.template.js +187 -0
- package/bin/cyberia.js +1367 -281
- package/bin/deploy.js +582 -3
- package/bin/index.js +1367 -281
- package/bump.config.js +26 -0
- package/conf.js +195 -111
- package/deployment.yaml +6 -222
- package/hardhat/package-lock.json +118 -149
- package/hardhat/package.json +5 -4
- 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 +6 -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 +138 -66
- package/manifests/deployment/dd-test-development/proxy.yaml +41 -5
- package/manifests/kind-config-dev.yaml +8 -0
- package/manifests/lxd/lxd-admin-profile.yaml +12 -3
- package/manifests/mongodb/pv-pvc.yaml +44 -8
- package/manifests/mongodb/statefulset.yaml +55 -68
- package/manifests/mongodb-4.4/headless-service.yaml +10 -0
- package/manifests/mongodb-4.4/kustomization.yaml +3 -1
- package/manifests/mongodb-4.4/mongodb-nodeport.yaml +17 -0
- package/manifests/mongodb-4.4/pv-pvc.yaml +10 -14
- package/manifests/mongodb-4.4/statefulset.yaml +79 -0
- package/manifests/mongodb-4.4/storage-class.yaml +9 -0
- package/manifests/valkey/statefulset.yaml +1 -1
- package/manifests/valkey/valkey-nodeport.yaml +17 -0
- package/package.json +45 -24
- package/proxy.yaml +10 -118
- package/scripts/ipxe-setup.sh +52 -49
- package/scripts/k3s-node-setup.sh +83 -48
- package/scripts/lxd-vm-setup.sh +193 -8
- package/scripts/maas-nat-firewalld.sh +145 -0
- 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.router.js +38 -33
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +91 -36
- package/src/api/core/core.controller.js +10 -10
- package/src/api/core/core.router.js +19 -14
- package/src/api/core/core.service.js +15 -15
- package/src/api/crypto/crypto.controller.js +8 -8
- package/src/api/crypto/crypto.router.js +18 -12
- package/src/api/crypto/crypto.service.js +11 -11
- 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 +31 -0
- package/src/api/cyberia-action/cyberia-action.service.js +42 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +74 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +99 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +98 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +152 -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 +25 -20
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +22 -22
- package/src/api/cyberia-entity/cyberia-entity.controller.js +10 -10
- package/src/api/cyberia-entity/cyberia-entity.router.js +22 -18
- package/src/api/cyberia-entity/cyberia-entity.service.js +15 -15
- package/src/api/cyberia-instance/cyberia-fallback-world.js +83 -198
- 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.router.js +57 -52
- package/src/api/cyberia-instance/cyberia-instance.service.js +32 -67
- 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.model.js +18 -49
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +22 -18
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +19 -15
- package/src/api/cyberia-map/cyberia-map.controller.js +10 -10
- package/src/api/cyberia-map/cyberia-map.router.js +35 -30
- package/src/api/cyberia-map/cyberia-map.service.js +17 -17
- 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 +31 -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 +31 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +42 -0
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +451 -0
- package/src/api/default/default.controller.js +10 -10
- package/src/api/default/default.router.js +22 -18
- package/src/api/default/default.service.js +15 -15
- package/src/api/document/document.controller.js +12 -12
- package/src/api/document/document.model.js +10 -16
- package/src/api/document/document.router.js +28 -23
- package/src/api/document/document.service.js +100 -23
- package/src/api/file/file.controller.js +8 -8
- package/src/api/file/file.model.js +10 -10
- package/src/api/file/file.router.js +19 -13
- package/src/api/file/file.service.js +45 -43
- package/src/api/instance/instance.controller.js +10 -10
- package/src/api/instance/instance.model.js +4 -10
- package/src/api/instance/instance.router.js +29 -24
- package/src/api/instance/instance.service.js +16 -16
- package/src/api/ipfs/ipfs.controller.js +12 -12
- package/src/api/ipfs/ipfs.model.js +4 -13
- package/src/api/ipfs/ipfs.router.js +21 -16
- package/src/api/ipfs/ipfs.service.js +22 -36
- 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.router.js +512 -507
- package/src/api/object-layer/object-layer.service.js +29 -26
- 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.router.js +22 -18
- package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +19 -15
- package/src/api/test/test.controller.js +8 -8
- package/src/api/test/test.router.js +17 -12
- package/src/api/test/test.service.js +8 -8
- package/src/api/types.js +24 -0
- package/src/api/user/guest.service.js +100 -0
- package/src/api/user/user.controller.js +6 -6
- package/src/api/user/user.model.js +8 -13
- package/src/api/user/user.router.js +297 -288
- package/src/api/user/user.service.js +103 -55
- package/src/cli/baremetal.js +132 -101
- package/src/cli/cluster.js +732 -217
- package/src/cli/db.js +106 -62
- package/src/cli/deploy.js +260 -149
- package/src/cli/fs.js +90 -9
- package/src/cli/image.js +43 -1
- package/src/cli/index.js +106 -16
- package/src/cli/ipfs.js +4 -6
- package/src/cli/kubectl.js +4 -1
- package/src/cli/lxd.js +1099 -223
- package/src/cli/monitor.js +9 -3
- package/src/cli/release.js +336 -86
- package/src/cli/repository.js +136 -53
- package/src/cli/run.js +599 -76
- package/src/cli/secrets.js +11 -2
- package/src/cli/ssh.js +1 -1
- package/src/cli/static.js +43 -115
- package/src/cli/test.js +9 -3
- package/src/client/Cryptokoyn.index.js +18 -21
- package/src/client/CyberiaPortal.index.js +19 -23
- package/src/client/Default.index.js +30 -36
- 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 +40 -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 +163 -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 +96 -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 +544 -219
- 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 +81 -177
- 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 +211 -276
- 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/SharedDefaultsCyberia.js +330 -0
- package/src/client/components/cyberia-portal/{MenuCyberiaPortal.js → AppShellCyberiaPortal.js} +102 -102
- 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 +83 -0
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +204 -0
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +291 -0
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +278 -0
- package/src/client/public/cyberia-docs/CYBERIA.md +259 -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/UNDERPOST-PLATFORM.md +106 -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-client-hints/cyberia-client-hints.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/views/CyberiaServerMetrics.js +982 -0
- package/src/client/ssr/{offline → views}/Maintenance.js +12 -11
- package/src/client/ssr/{offline → views}/NoNetworkConnection.js +3 -3
- package/src/client/ssr/{pages → views}/Test.js +2 -2
- package/src/client/sw/core.sw.js +274 -0
- package/src/db/DataBaseProvider.js +115 -15
- package/src/db/mariadb/MariaDB.js +2 -1
- package/src/db/mongo/MongoBootstrap.js +657 -0
- package/src/db/mongo/MongooseDB.js +129 -21
- package/src/grpc/cyberia/grpc-server.js +185 -105
- package/src/index.js +1 -1
- package/src/runtime/cyberia-client/Dockerfile +101 -0
- package/src/runtime/cyberia-client/Dockerfile.dev +82 -0
- package/src/runtime/cyberia-server/Dockerfile +62 -0
- package/src/runtime/cyberia-server/Dockerfile.dev +71 -0
- package/src/runtime/express/Dockerfile +4 -4
- package/src/runtime/express/Express.js +2 -2
- package/src/runtime/lampp/Dockerfile +8 -7
- package/src/runtime/wp/Dockerfile +11 -17
- package/src/runtime/wp/Wp.js +8 -5
- package/src/server/atlas-sprite-sheet-generator.js +4 -2
- package/src/server/auth.js +2 -2
- package/src/server/client-build-docs.js +46 -47
- package/src/server/client-build.js +371 -132
- package/src/server/client-formatted.js +47 -16
- package/src/server/conf.js +91 -87
- 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 +192 -45
- package/src/server/proxy.js +9 -2
- package/src/server/runtime.js +1 -1
- 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 +34 -8
- package/src/server/valkey.js +143 -235
- package/src/ws/IoInterface.js +16 -16
- package/src/ws/core/channels/core.ws.chat.js +11 -11
- package/src/ws/core/channels/core.ws.mailer.js +29 -29
- package/src/ws/core/channels/core.ws.stream.js +19 -19
- package/src/ws/core/core.ws.connection.js +8 -8
- package/src/ws/core/core.ws.server.js +6 -5
- package/src/ws/default/channels/default.ws.main.js +10 -10
- package/src/ws/default/default.ws.connection.js +4 -4
- package/src/ws/default/default.ws.server.js +4 -3
- 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/bin/file.js +0 -196
- package/bin/vs.js +0 -74
- package/bin/zed.js +0 -84
- 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/cyberia-instance-conf/cyberia-instance-conf.defaults.js +0 -413
- 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/CommonCyberiaPortal.js +0 -223
- 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/ssr/email/DefaultRecoverEmail.js +0 -21
- package/src/client/ssr/email/DefaultVerifyEmail.js +0 -17
- package/src/client/ssr/pages/CyberiaServerMetrics.js +0 -461
- 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/run.js
CHANGED
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
awaitDeployMonitor,
|
|
11
11
|
buildKindPorts,
|
|
12
12
|
Config,
|
|
13
|
+
cronDeployIdResolve,
|
|
14
|
+
etcHostFactory,
|
|
13
15
|
getNpmRootPath,
|
|
14
16
|
isDeployRunnerContext,
|
|
15
17
|
loadConfServerJson,
|
|
@@ -24,6 +26,7 @@ import { range, setPad, timer } from '../client/components/core/CommonJs.js';
|
|
|
24
26
|
import os from 'os';
|
|
25
27
|
import Underpost from '../index.js';
|
|
26
28
|
import dotenv from 'dotenv';
|
|
29
|
+
import { MongoBootstrap } from '../db/mongo/MongoBootstrap.js';
|
|
27
30
|
|
|
28
31
|
const waitForPort = (port, host = '127.0.0.1', { maxAttempts = 30, interval = 2000 } = {}) =>
|
|
29
32
|
new Promise((resolve, reject) => {
|
|
@@ -93,11 +96,11 @@ const logger = loggerFactory(import.meta);
|
|
|
93
96
|
* @property {boolean} kubeadm - Whether to run in kubeadm mode.
|
|
94
97
|
* @property {boolean} kind - Whether to run in kind mode.
|
|
95
98
|
* @property {boolean} k3s - Whether to run in k3s mode.
|
|
96
|
-
* @property {string} logType - The type of log to generate.
|
|
97
99
|
* @property {string} hosts - The hosts to use.
|
|
98
100
|
* @property {string} deployId - The deployment ID.
|
|
99
101
|
* @property {string} instanceId - The instance ID.
|
|
100
102
|
* @property {string} user - The user to run as.
|
|
103
|
+
* @property {string} group - The group to use.
|
|
101
104
|
* @property {string} pid - The process ID.
|
|
102
105
|
* @property {boolean} disablePrivateConfUpdate - Whether to disable private configuration updates.
|
|
103
106
|
* @property {string} monitorStatus - The monitor status option.
|
|
@@ -111,6 +114,11 @@ const logger = loggerFactory(import.meta);
|
|
|
111
114
|
* @property {string|Array<{ip: string, hostnames: string[]}>} hostAliases - Adds entries to the Pod /etc/hosts via Kubernetes hostAliases.
|
|
112
115
|
* 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").
|
|
113
116
|
* As an array (programmatic): objects with `ip` and `hostnames` fields (e.g., [{ ip: "127.0.0.1", hostnames: ["foo.local"] }]).
|
|
117
|
+
* @property {boolean} gitClean - Whether to perform a `git clean` before running.
|
|
118
|
+
* @property {boolean} copy - Whether to copy the command to the clipboard instead of executing it.
|
|
119
|
+
* @property {boolean} skipFullBuild - Whether to skip the full client bundle build during deployment (supported by: sync, template-deploy).
|
|
120
|
+
* @property {boolean} pullBundle - Whether to pull the bundle before running. Use together with --skip-full-build to skip the local build entirely (supported by: sync, template-deploy).
|
|
121
|
+
* @property {boolean} remove - Whether to remove/teardown resources instead of creating them (e.g. delete-expose for k3s proxy devices in dev-cluster).
|
|
114
122
|
* @memberof UnderpostRun
|
|
115
123
|
*/
|
|
116
124
|
const DEFAULT_OPTION = {
|
|
@@ -158,11 +166,11 @@ const DEFAULT_OPTION = {
|
|
|
158
166
|
kubeadm: false,
|
|
159
167
|
kind: false,
|
|
160
168
|
k3s: false,
|
|
161
|
-
logType: '',
|
|
162
169
|
hosts: '',
|
|
163
170
|
deployId: '',
|
|
164
171
|
instanceId: '',
|
|
165
172
|
user: '',
|
|
173
|
+
group: '',
|
|
166
174
|
pid: '',
|
|
167
175
|
disablePrivateConfUpdate: false,
|
|
168
176
|
monitorStatus: '',
|
|
@@ -176,6 +184,9 @@ const DEFAULT_OPTION = {
|
|
|
176
184
|
hostAliases: '',
|
|
177
185
|
gitClean: false,
|
|
178
186
|
copy: false,
|
|
187
|
+
skipFullBuild: false,
|
|
188
|
+
pullBundle: false,
|
|
189
|
+
remove: false,
|
|
179
190
|
};
|
|
180
191
|
|
|
181
192
|
/**
|
|
@@ -205,28 +216,39 @@ class UnderpostRun {
|
|
|
205
216
|
'dev-cluster': (path, options = DEFAULT_OPTION) => {
|
|
206
217
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
207
218
|
const mongoHosts = ['mongodb-0.mongodb-service'];
|
|
219
|
+
let primaryMongoHost = 'mongodb-0.mongodb-service';
|
|
208
220
|
if (!options.expose) {
|
|
209
221
|
shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --reset`);
|
|
210
222
|
shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''}`);
|
|
211
223
|
|
|
212
224
|
shellExec(
|
|
213
|
-
`${baseCommand} cluster${options.dev ? ' --dev' : ''} --
|
|
225
|
+
`${baseCommand} cluster${options.dev ? ' --dev' : ''} --mongodb4 --service-host ${mongoHosts.join(
|
|
214
226
|
',',
|
|
215
227
|
)} --pull-image`,
|
|
216
228
|
);
|
|
217
229
|
shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --valkey --pull-image`);
|
|
218
230
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
231
|
+
if (options.k3s) {
|
|
232
|
+
if (options.remove) {
|
|
233
|
+
shellExec(`${baseCommand} lxd --delete-expose k3s-control:27017`);
|
|
234
|
+
shellExec(`${baseCommand} lxd --delete-expose k3s-control:6379`);
|
|
235
|
+
} else {
|
|
236
|
+
shellExec(`${baseCommand} lxd --expose k3s-control:27017 --node-port 32017`);
|
|
237
|
+
shellExec(`${baseCommand} lxd --expose k3s-control:6379 --node-port 32079`);
|
|
238
|
+
}
|
|
239
|
+
shellExec(`lxc config device show k3s-control`);
|
|
240
|
+
} else {
|
|
223
241
|
try {
|
|
224
|
-
const primaryPodName =
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
242
|
+
const primaryPodName =
|
|
243
|
+
MongoBootstrap.getPrimaryPodName({
|
|
244
|
+
namespace: options.namespace,
|
|
245
|
+
podName: 'mongodb-0',
|
|
246
|
+
disableAuth: options.dev,
|
|
247
|
+
}) || 'mongodb-0';
|
|
248
|
+
shellExec(
|
|
249
|
+
`${baseCommand} deploy --expose --namespace ${options.namespace} --disable-update-underpost-config mongo`,
|
|
250
|
+
{ async: true },
|
|
251
|
+
);
|
|
230
252
|
shellExec(
|
|
231
253
|
`${baseCommand} deploy --expose --namespace ${options.namespace} --disable-update-underpost-config valkey`,
|
|
232
254
|
{ async: true },
|
|
@@ -237,10 +259,9 @@ class UnderpostRun {
|
|
|
237
259
|
default: primaryMongoHost,
|
|
238
260
|
});
|
|
239
261
|
}
|
|
240
|
-
|
|
241
|
-
const hostListenResult = Underpost.deploy.etcHostFactory([primaryMongoHost]);
|
|
242
|
-
logger.info(hostListenResult.renderHosts);
|
|
243
262
|
}
|
|
263
|
+
const hostListenResult = etcHostFactory([primaryMongoHost]);
|
|
264
|
+
logger.info(hostListenResult.renderHosts);
|
|
244
265
|
},
|
|
245
266
|
|
|
246
267
|
/**
|
|
@@ -437,6 +458,15 @@ class UnderpostRun {
|
|
|
437
458
|
deployType = 'init';
|
|
438
459
|
}
|
|
439
460
|
|
|
461
|
+
// If --build is set and path is a sync-engine-* target, push the pre-built client bundle
|
|
462
|
+
// to Cloudinary so the remote container can pull it instead of rebuilding from source.
|
|
463
|
+
if (options.build && deployConfId && deployConfId.startsWith('engine-')) {
|
|
464
|
+
const confName = deployConfId.replace(/^engine-/, '');
|
|
465
|
+
const pushDeployId = options.deployId || `dd-${confName}`;
|
|
466
|
+
logger.info(`[template-deploy] Running push-bundle for deployId: ${pushDeployId}`);
|
|
467
|
+
shellExec(`${baseCommand} run push-bundle --deploy-id ${pushDeployId}`);
|
|
468
|
+
}
|
|
469
|
+
|
|
440
470
|
// Dispatch npmpkg CI workflow — this builds pwa-microservices-template first.
|
|
441
471
|
// If deployConfId is set, npmpkg.ci.yml will dispatch the engine-<conf-id> CI
|
|
442
472
|
// with sync=true after template build completes. The engine CI then dispatches
|
|
@@ -490,32 +520,19 @@ class UnderpostRun {
|
|
|
490
520
|
: await Underpost.release.pwa(sanitizedMessage, options);
|
|
491
521
|
pbcopy(triggerCmd + ' && cd /home/dd/engine');
|
|
492
522
|
},
|
|
493
|
-
/**
|
|
494
|
-
* @method template-deploy-image
|
|
495
|
-
* @description Dispatches the Docker image CI workflow for the `engine` repository.
|
|
496
|
-
* @param {string} path - The input value, identifier, or path for the operation.
|
|
497
|
-
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
498
|
-
* @memberof UnderpostRun
|
|
499
|
-
*/
|
|
500
|
-
'template-deploy-image': (path, options = DEFAULT_OPTION) => {
|
|
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
523
|
/**
|
|
509
524
|
* @method docker-image
|
|
510
|
-
* @description Dispatches the Docker image CI workflow (`docker-image.ci.yml`)
|
|
511
|
-
*
|
|
525
|
+
* @description Dispatches the Docker image CI workflow (`docker-image[.<runtime>].ci.yml`) via `workflow_dispatch`.
|
|
526
|
+
* Repository resolution is delegated to `Underpost.repo.resolveInstanceRepo(path)`.
|
|
527
|
+
* @param {string} path - Optional runtime / workflow suffix (e.g. `cyberia-server`, `cyberia-client`).
|
|
512
528
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
513
529
|
* @memberof UnderpostRun
|
|
514
530
|
*/
|
|
515
531
|
'docker-image': (path, options = DEFAULT_OPTION) => {
|
|
532
|
+
const repo = Underpost.repo.resolveInstanceRepo(path);
|
|
516
533
|
Underpost.repo.dispatchWorkflow({
|
|
517
|
-
repo
|
|
518
|
-
workflowFile:
|
|
534
|
+
repo,
|
|
535
|
+
workflowFile: `docker-image${path ? `.${path}` : ''}.ci.yml`,
|
|
519
536
|
ref: 'master',
|
|
520
537
|
inputs: {},
|
|
521
538
|
});
|
|
@@ -529,6 +546,7 @@ class UnderpostRun {
|
|
|
529
546
|
*/
|
|
530
547
|
clean: (path = '', options = DEFAULT_OPTION) => {
|
|
531
548
|
Underpost.repo.clean({ paths: path ? path.split(',') : ['/home/dd/engine', '/home/dd/engine/engine-private'] });
|
|
549
|
+
if (options.dev) shellExec(`node bin run shared-dir ${path ? path : '/home/dd/engine'}`);
|
|
532
550
|
},
|
|
533
551
|
/**
|
|
534
552
|
* @method pull
|
|
@@ -538,16 +556,14 @@ class UnderpostRun {
|
|
|
538
556
|
* @memberof UnderpostRun
|
|
539
557
|
*/
|
|
540
558
|
pull: (path, options = DEFAULT_OPTION) => {
|
|
559
|
+
// shellExec is fail-fast by default — any non-zero exit throws and
|
|
560
|
+
// propagates up to the workflow step. No per-call flag required.
|
|
541
561
|
if (!fs.existsSync(`/home/dd`) || !fs.existsSync(`/home/dd/engine`)) {
|
|
542
562
|
fs.mkdirSync(`/home/dd`, { recursive: true });
|
|
543
|
-
shellExec(`cd /home/dd && underpost clone ${process.env.GITHUB_USERNAME}/engine`, {
|
|
544
|
-
silent: true,
|
|
545
|
-
});
|
|
563
|
+
shellExec(`cd /home/dd && underpost clone ${process.env.GITHUB_USERNAME}/engine`, { silent: true });
|
|
546
564
|
} else {
|
|
547
565
|
shellExec(`underpost run clean`);
|
|
548
|
-
shellExec(`cd /home/dd/engine && underpost pull . ${process.env.GITHUB_USERNAME}/engine`, {
|
|
549
|
-
silent: true,
|
|
550
|
-
});
|
|
566
|
+
shellExec(`cd /home/dd/engine && underpost pull . ${process.env.GITHUB_USERNAME}/engine`, { silent: true });
|
|
551
567
|
}
|
|
552
568
|
if (!fs.existsSync(`/home/dd/engine/engine-private`))
|
|
553
569
|
shellExec(`cd /home/dd/engine && underpost clone ${process.env.GITHUB_USERNAME}/engine-private`, {
|
|
@@ -556,9 +572,7 @@ class UnderpostRun {
|
|
|
556
572
|
else
|
|
557
573
|
shellExec(
|
|
558
574
|
`cd /home/dd/engine/engine-private && underpost pull . ${process.env.GITHUB_USERNAME}/engine-private`,
|
|
559
|
-
{
|
|
560
|
-
silent: true,
|
|
561
|
-
},
|
|
575
|
+
{ silent: true },
|
|
562
576
|
);
|
|
563
577
|
},
|
|
564
578
|
/**
|
|
@@ -645,6 +659,11 @@ echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com
|
|
|
645
659
|
/**
|
|
646
660
|
* @method sync
|
|
647
661
|
* @description Cleans up, and then runs a deployment synchronization command (`underpost deploy --kubeadm --build-manifest --sync...`) using parameters parsed from `path` (deployId, replicas, versions, image, node).
|
|
662
|
+
*
|
|
663
|
+
* Forwards `--image-pull-policy <policy>` to the underlying `deploy --build-manifest` invocation when `options.imagePullPolicy` is set,
|
|
664
|
+
* which then plumbs through `buildManifest` and `deploymentYamlPartsFactory` to override the container `imagePullPolicy` in the generated
|
|
665
|
+
* `deployment.yaml`. Useful when you want to force `Always` so the kubelet re-pulls a mutable tag on every rollout. Example:
|
|
666
|
+
* `node bin run sync dd-core --kubeadm --image-pull-policy Always`
|
|
648
667
|
* @param {string} path - The input value, identifier, or path for the operation (used as a comma-separated string containing deploy parameters).
|
|
649
668
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
650
669
|
* @memberof UnderpostRun
|
|
@@ -652,7 +671,7 @@ echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com
|
|
|
652
671
|
sync: async (path, options = DEFAULT_OPTION) => {
|
|
653
672
|
// Dev usage: node bin run --dev --build sync dd-default
|
|
654
673
|
const env = options.dev ? 'development' : 'production';
|
|
655
|
-
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
674
|
+
const baseCommand = 'node bin'; // options.dev ? 'node bin' : 'underpost';
|
|
656
675
|
const baseClusterCommand = options.dev ? ' --dev' : '';
|
|
657
676
|
const clusterFlag = options.k3s ? ' --k3s' : options.kind ? ' --kind' : ' --kubeadm';
|
|
658
677
|
const defaultPath = [
|
|
@@ -669,6 +688,15 @@ echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com
|
|
|
669
688
|
image = image ? image : defaultPath[3];
|
|
670
689
|
node = node ? node : defaultPath[4];
|
|
671
690
|
shellExec(`${baseCommand} cluster --ns-use ${options.namespace}`);
|
|
691
|
+
|
|
692
|
+
if (image && !image.startsWith('localhost'))
|
|
693
|
+
Underpost.image.pullDockerHubImage({
|
|
694
|
+
dockerhubImage: image,
|
|
695
|
+
kind: options.kind || (!options.nodeName && !options.kubeadm && !options.k3s),
|
|
696
|
+
kubeadm: options.nodeName || options.kubeadm,
|
|
697
|
+
k3s: options.k3s,
|
|
698
|
+
});
|
|
699
|
+
|
|
672
700
|
if (isDeployRunnerContext(path, options)) {
|
|
673
701
|
if (!options.disablePrivateConfUpdate) {
|
|
674
702
|
const { validVersion } = Underpost.repo.privateConfUpdate(deployId);
|
|
@@ -691,12 +719,16 @@ echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com
|
|
|
691
719
|
: '';
|
|
692
720
|
const gitCleanFlag = options.gitClean ? ' --git-clean' : '';
|
|
693
721
|
|
|
722
|
+
const skipFullBuildFlag = options.skipFullBuild ? ' --skip-full-build' : '';
|
|
723
|
+
const pullBundleFlag = options.pullBundle ? ' --pull-bundle' : '';
|
|
724
|
+
const imagePullPolicyFlag = options.imagePullPolicy ? ` --image-pull-policy ${options.imagePullPolicy}` : '';
|
|
725
|
+
|
|
694
726
|
shellExec(
|
|
695
727
|
`${baseCommand} deploy${clusterFlag} --build-manifest --sync --info-router --replicas ${replicas} --node ${node}${
|
|
696
728
|
image ? ` --image ${image}` : ''
|
|
697
729
|
}${versions ? ` --versions ${versions}` : ''}${
|
|
698
730
|
options.namespace ? ` --namespace ${options.namespace}` : ''
|
|
699
|
-
}${timeoutFlags}${cmdString}${gitCleanFlag} ${deployId} ${env}`,
|
|
731
|
+
}${timeoutFlags}${cmdString}${gitCleanFlag}${skipFullBuildFlag}${pullBundleFlag}${imagePullPolicyFlag} ${deployId} ${env}`,
|
|
700
732
|
);
|
|
701
733
|
|
|
702
734
|
if (isDeployRunnerContext(path, options)) {
|
|
@@ -707,7 +739,7 @@ echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com
|
|
|
707
739
|
shellExec(
|
|
708
740
|
`${baseCommand} deploy${clusterFlag}${cmdString} --replicas ${replicas} --disable-update-proxy ${deployId} ${env} --versions ${versions}${
|
|
709
741
|
options.namespace ? ` --namespace ${options.namespace}` : ''
|
|
710
|
-
}${timeoutFlags}${gitCleanFlag}`,
|
|
742
|
+
}${timeoutFlags}${gitCleanFlag}${imagePullPolicyFlag}`,
|
|
711
743
|
);
|
|
712
744
|
if (!targetTraffic)
|
|
713
745
|
targetTraffic = Underpost.deploy.getCurrentTraffic(deployId, { namespace: options.namespace });
|
|
@@ -928,12 +960,17 @@ echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com
|
|
|
928
960
|
image: _image,
|
|
929
961
|
fromPort: _fromPort,
|
|
930
962
|
toPort: _toPort,
|
|
963
|
+
fromDebugPort: _fromDebugPort,
|
|
964
|
+
toDebugPort: _toDebugPort,
|
|
931
965
|
cmd: _cmd,
|
|
932
966
|
volumes: _volumes,
|
|
933
967
|
metadata: _metadata,
|
|
934
968
|
} = instance;
|
|
935
969
|
if (id !== _id) continue;
|
|
936
970
|
const _deployId = `${deployId}-${_id}`;
|
|
971
|
+
// Use debug ports in development when defined, fall back to production ports.
|
|
972
|
+
if (env === 'development' && _fromDebugPort) _fromPort = _fromDebugPort;
|
|
973
|
+
if (env === 'development' && _toDebugPort) _toPort = _toDebugPort;
|
|
937
974
|
const currentTraffic = Underpost.deploy.getCurrentTraffic(_deployId, {
|
|
938
975
|
hostTest: _host,
|
|
939
976
|
namespace: options.namespace,
|
|
@@ -1003,12 +1040,20 @@ EOF
|
|
|
1003
1040
|
image: _image,
|
|
1004
1041
|
fromPort: _fromPort,
|
|
1005
1042
|
toPort: _toPort,
|
|
1043
|
+
fromDebugPort: _fromDebugPort,
|
|
1044
|
+
toDebugPort: _toDebugPort,
|
|
1006
1045
|
cmd: _cmd,
|
|
1007
1046
|
volumes: _volumes,
|
|
1008
1047
|
metadata: _metadata,
|
|
1048
|
+
lifecycle: _lifecycle,
|
|
1049
|
+
readinessProbe: _readinessProbe,
|
|
1050
|
+
livenessProbe: _livenessProbe,
|
|
1009
1051
|
} = instance;
|
|
1010
1052
|
if (id !== _id) continue;
|
|
1011
1053
|
const _deployId = `${deployId}-${_id}`;
|
|
1054
|
+
// Use debug ports in development when defined, fall back to production ports.
|
|
1055
|
+
if (env === 'development' && _fromDebugPort) _fromPort = _fromDebugPort;
|
|
1056
|
+
if (env === 'development' && _toDebugPort) _toPort = _toDebugPort;
|
|
1012
1057
|
etcHosts.push(_host);
|
|
1013
1058
|
if (options.expose) continue;
|
|
1014
1059
|
// Examples images:
|
|
@@ -1016,12 +1061,13 @@ EOF
|
|
|
1016
1061
|
// `localhost/rockylinux9-underpost:${Underpost.version}`
|
|
1017
1062
|
if (!_image) _image = `underpost/underpost-engine:${Underpost.version}`;
|
|
1018
1063
|
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1064
|
+
if (_image && !_image.startsWith('localhost'))
|
|
1065
|
+
Underpost.image.pullDockerHubImage({
|
|
1066
|
+
dockerhubImage: _image,
|
|
1067
|
+
kind: options.kind || (!options.nodeName && !options.kubeadm && !options.k3s),
|
|
1068
|
+
kubeadm: options.nodeName || options.kubeadm,
|
|
1069
|
+
k3s: options.k3s,
|
|
1070
|
+
});
|
|
1025
1071
|
|
|
1026
1072
|
const currentTraffic = Underpost.deploy.getCurrentTraffic(_deployId, {
|
|
1027
1073
|
hostTest: _host,
|
|
@@ -1066,6 +1112,20 @@ EOF
|
|
|
1066
1112
|
),
|
|
1067
1113
|
);
|
|
1068
1114
|
|
|
1115
|
+
// Resolve env-scoped lifecycle/probe blocks: each can be either
|
|
1116
|
+
// { ...envObj } // shared shape
|
|
1117
|
+
// { development: {...}, production: {...} } // env-specific
|
|
1118
|
+
const pickEnv = (v) => (v && (v.development || v.production) ? v[env] : v);
|
|
1119
|
+
|
|
1120
|
+
// Convention: an instance config may place `imagePullPolicy` inside
|
|
1121
|
+
// the env-scoped lifecycle block (alongside postStart/preStop).
|
|
1122
|
+
// Extract it onto the container spec (where K8S expects it) and
|
|
1123
|
+
// strip it from the lifecycle hash so the rendered YAML stays valid.
|
|
1124
|
+
// CLI override (`--image-pull-policy`) wins over the conf value.
|
|
1125
|
+
const { lifecycle: lifecycleForManifest, imagePullPolicy: lifecycleImagePullPolicy } =
|
|
1126
|
+
Underpost.deploy.extractInstanceImagePullPolicy(pickEnv(_lifecycle));
|
|
1127
|
+
const instanceImagePullPolicy = options.imagePullPolicy || lifecycleImagePullPolicy;
|
|
1128
|
+
|
|
1069
1129
|
let deploymentYaml = `---
|
|
1070
1130
|
${Underpost.deploy
|
|
1071
1131
|
.deploymentYamlPartsFactory({
|
|
@@ -1078,6 +1138,11 @@ ${Underpost.deploy
|
|
|
1078
1138
|
namespace: options.namespace,
|
|
1079
1139
|
volumes: _volumes,
|
|
1080
1140
|
cmd: resolvedCmd,
|
|
1141
|
+
lifecycle: lifecycleForManifest,
|
|
1142
|
+
readinessProbe: pickEnv(_readinessProbe),
|
|
1143
|
+
livenessProbe: pickEnv(_livenessProbe),
|
|
1144
|
+
containerPort: _toPort,
|
|
1145
|
+
imagePullPolicy: instanceImagePullPolicy,
|
|
1081
1146
|
})
|
|
1082
1147
|
.replace('{{ports}}', buildKindPorts(_fromPort, _toPort))}
|
|
1083
1148
|
`;
|
|
@@ -1095,7 +1160,6 @@ EOF
|
|
|
1095
1160
|
targetTraffic,
|
|
1096
1161
|
ignorePods,
|
|
1097
1162
|
options.namespace,
|
|
1098
|
-
options.logType,
|
|
1099
1163
|
);
|
|
1100
1164
|
|
|
1101
1165
|
if (!ready) {
|
|
@@ -1110,11 +1174,194 @@ EOF
|
|
|
1110
1174
|
);
|
|
1111
1175
|
}
|
|
1112
1176
|
if (options.etcHosts) {
|
|
1113
|
-
const hostListenResult =
|
|
1177
|
+
const hostListenResult = etcHostFactory(etcHosts);
|
|
1114
1178
|
logger.info(hostListenResult.renderHosts);
|
|
1115
1179
|
}
|
|
1116
1180
|
},
|
|
1117
1181
|
|
|
1182
|
+
/**
|
|
1183
|
+
* @method instance-build-manifest
|
|
1184
|
+
* @description Builds a Kubernetes Deployment + Service manifest for a specific instance entry
|
|
1185
|
+
* from `conf.instances.json` and writes it to a file.
|
|
1186
|
+
* Traffic colour is automatically chosen as the opposite of the current live colour (blue/green),
|
|
1187
|
+
* defaulting to `blue` when no deployment is running yet.
|
|
1188
|
+
*
|
|
1189
|
+
* If `--build` is supplied the image is built from the project Dockerfile and loaded into the
|
|
1190
|
+
* cluster before the manifest is written (kind by default; `--kubeadm` / `--k3s` override).
|
|
1191
|
+
*
|
|
1192
|
+
* @param {string} path - Comma-separated: `deployId,instanceId[,projectPath]`.
|
|
1193
|
+
* `projectPath` is the root directory that contains the `Dockerfile` (e.g. `./cyberia-client`).
|
|
1194
|
+
* Artifacts are written to `<projectPath>/manifests/<env>/Dockerfile` and
|
|
1195
|
+
* `<projectPath>/manifests/<env>/deployment.yaml`.
|
|
1196
|
+
* In production, files are also copied to `<projectPath>/Dockerfile` and
|
|
1197
|
+
* `<projectPath>/deployment.yaml`.
|
|
1198
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
1199
|
+
* @memberof UnderpostRun
|
|
1200
|
+
*/
|
|
1201
|
+
'instance-build-manifest': (path, options = DEFAULT_OPTION) => {
|
|
1202
|
+
const env = options.dev ? 'development' : 'production';
|
|
1203
|
+
let [deployId, id, projectPath] = path.split(',');
|
|
1204
|
+
const rootPath = projectPath ? projectPath : '.';
|
|
1205
|
+
const envManifestPath = `${rootPath}/manifests/deployments/${id}-${env}`;
|
|
1206
|
+
const outputPath = `${envManifestPath}/deployment.yaml`;
|
|
1207
|
+
const dockerfileManifestPath = `${envManifestPath}/Dockerfile`;
|
|
1208
|
+
|
|
1209
|
+
fs.mkdirpSync(envManifestPath);
|
|
1210
|
+
|
|
1211
|
+
const confInstances = JSON.parse(
|
|
1212
|
+
fs.readFileSync(`./engine-private/conf/${deployId}/conf.instances.json`, 'utf8'),
|
|
1213
|
+
);
|
|
1214
|
+
|
|
1215
|
+
const instance = confInstances.find((i) => i.id === id);
|
|
1216
|
+
if (!instance) {
|
|
1217
|
+
logger.error(`Instance with id '${id}' not found in conf.instances.json for deployId '${deployId}'`);
|
|
1218
|
+
return;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
let {
|
|
1222
|
+
id: _id,
|
|
1223
|
+
host: _host,
|
|
1224
|
+
path: _path,
|
|
1225
|
+
image: _image,
|
|
1226
|
+
fromPort: _fromPort,
|
|
1227
|
+
toPort: _toPort,
|
|
1228
|
+
fromDebugPort: _fromDebugPort,
|
|
1229
|
+
toDebugPort: _toDebugPort,
|
|
1230
|
+
cmd: _cmd,
|
|
1231
|
+
volumes: _volumes,
|
|
1232
|
+
metadata: _metadata,
|
|
1233
|
+
runtime: _runtime,
|
|
1234
|
+
lifecycle: _lifecycle,
|
|
1235
|
+
readinessProbe: _readinessProbe,
|
|
1236
|
+
livenessProbe: _livenessProbe,
|
|
1237
|
+
} = instance;
|
|
1238
|
+
|
|
1239
|
+
// Resolve Dockerfile source. Dev/prod variant rules:
|
|
1240
|
+
// - When the instance defines a `runtime`, look under
|
|
1241
|
+
// `src/runtime/<runtime>/`. In `--dev` mode prefer `Dockerfile.dev`
|
|
1242
|
+
// when it exists, falling back to `Dockerfile`.
|
|
1243
|
+
// - When `runtime` is not set, look in the project root with the
|
|
1244
|
+
// same `.dev` → no-suffix precedence.
|
|
1245
|
+
// Dockerfile.dev is a full Dockerfile (not an overlay) — each runtime
|
|
1246
|
+
// owns the contract between its dev image and its prod image (debug
|
|
1247
|
+
// build flags, extra tooling, default ports, etc.).
|
|
1248
|
+
const dockerfileBase = _runtime ? `src/runtime/${_runtime}` : rootPath;
|
|
1249
|
+
const dockerfileCandidates = options.dev
|
|
1250
|
+
? [`${dockerfileBase}/Dockerfile.dev`, `${dockerfileBase}/Dockerfile`]
|
|
1251
|
+
: [`${dockerfileBase}/Dockerfile`];
|
|
1252
|
+
const dockerfileSourcePath = dockerfileCandidates.find((p) => fs.existsSync(p));
|
|
1253
|
+
if (dockerfileSourcePath) {
|
|
1254
|
+
if (options.dev && !dockerfileSourcePath.endsWith('.dev')) {
|
|
1255
|
+
logger.warn(
|
|
1256
|
+
`[instance-build-manifest] --dev requested but no Dockerfile.dev present; falling back to ${dockerfileSourcePath}`,
|
|
1257
|
+
);
|
|
1258
|
+
}
|
|
1259
|
+
fs.copyFileSync(dockerfileSourcePath, dockerfileManifestPath);
|
|
1260
|
+
} else {
|
|
1261
|
+
logger.warn(`[instance-build-manifest] Dockerfile not found; tried: ${dockerfileCandidates.join(', ')}`);
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
const _deployId = `${deployId}-${_id}`;
|
|
1265
|
+
if (!_image) _image = `underpost/underpost-engine:${Underpost.version}`;
|
|
1266
|
+
// Use debug ports in development when defined, fall back to production ports.
|
|
1267
|
+
if (env === 'development' && _fromDebugPort) _fromPort = _fromDebugPort;
|
|
1268
|
+
if (env === 'development' && _toDebugPort) _toPort = _toDebugPort;
|
|
1269
|
+
|
|
1270
|
+
// Build image from projectPath Dockerfile and load into cluster when --build is set.
|
|
1271
|
+
if (options.build && projectPath) {
|
|
1272
|
+
const isKind = !options.kubeadm && !options.k3s;
|
|
1273
|
+
Underpost.image.build({
|
|
1274
|
+
path: projectPath,
|
|
1275
|
+
imageName: _image,
|
|
1276
|
+
podmanSave: true,
|
|
1277
|
+
imagePath: projectPath,
|
|
1278
|
+
kind: isKind,
|
|
1279
|
+
kubeadm: !!options.kubeadm,
|
|
1280
|
+
k3s: !!options.k3s,
|
|
1281
|
+
reset: !!options.reset,
|
|
1282
|
+
dev: options.dev,
|
|
1283
|
+
});
|
|
1284
|
+
logger.info(`[instance-build-manifest] Image built and loaded`, {
|
|
1285
|
+
image: _image,
|
|
1286
|
+
cluster: isKind ? 'kind' : options.kubeadm ? 'kubeadm' : 'k3s',
|
|
1287
|
+
});
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
// Determine target traffic: opposite of current, or 'blue' if nothing is running yet.
|
|
1291
|
+
const currentTraffic = Underpost.deploy.getCurrentTraffic(_deployId, {
|
|
1292
|
+
hostTest: _host,
|
|
1293
|
+
namespace: options.namespace,
|
|
1294
|
+
});
|
|
1295
|
+
const targetTraffic = currentTraffic ? (currentTraffic === 'blue' ? 'green' : 'blue') : 'blue';
|
|
1296
|
+
|
|
1297
|
+
// Resolve {{grpc-service-dns}} using the parent deploy's current (or default) traffic.
|
|
1298
|
+
const parentTraffic = Underpost.deploy.getCurrentTraffic(deployId, { namespace: options.namespace }) || 'blue';
|
|
1299
|
+
const resolvedCmd = _cmd[env].map((c) =>
|
|
1300
|
+
c.replaceAll(
|
|
1301
|
+
'{{grpc-service-dns}}',
|
|
1302
|
+
`${deployId}-grpc-service-${env}-${parentTraffic}.${options.namespace || 'default'}.svc.cluster.local:50051`,
|
|
1303
|
+
),
|
|
1304
|
+
);
|
|
1305
|
+
|
|
1306
|
+
// Env-aware lifecycle / probe selection. Each block may either be
|
|
1307
|
+
// a single object (shared across envs) or `{ development, production }`.
|
|
1308
|
+
const pickEnv = (v) => (v && (v.development || v.production) ? v[env] : v);
|
|
1309
|
+
|
|
1310
|
+
// Convention: an instance config may place `imagePullPolicy` inside
|
|
1311
|
+
// the env-scoped lifecycle block (alongside postStart/preStop).
|
|
1312
|
+
// Extract it onto the container spec and strip it from the lifecycle hash.
|
|
1313
|
+
const { lifecycle: lifecycleForManifest, imagePullPolicy: lifecycleImagePullPolicy } =
|
|
1314
|
+
Underpost.deploy.extractInstanceImagePullPolicy(pickEnv(_lifecycle));
|
|
1315
|
+
const instanceImagePullPolicy = options.imagePullPolicy || lifecycleImagePullPolicy;
|
|
1316
|
+
|
|
1317
|
+
const deploymentYaml =
|
|
1318
|
+
`---\n` +
|
|
1319
|
+
Underpost.deploy
|
|
1320
|
+
.deploymentYamlPartsFactory({
|
|
1321
|
+
deployId: _deployId,
|
|
1322
|
+
env,
|
|
1323
|
+
suffix: targetTraffic,
|
|
1324
|
+
resources: Underpost.deploy.resourcesFactory(options),
|
|
1325
|
+
replicas: options.replicas,
|
|
1326
|
+
image: _image,
|
|
1327
|
+
namespace: options.namespace,
|
|
1328
|
+
volumes: _volumes,
|
|
1329
|
+
cmd: resolvedCmd,
|
|
1330
|
+
lifecycle: lifecycleForManifest,
|
|
1331
|
+
readinessProbe: pickEnv(_readinessProbe),
|
|
1332
|
+
livenessProbe: pickEnv(_livenessProbe),
|
|
1333
|
+
containerPort: _toPort,
|
|
1334
|
+
imagePullPolicy: instanceImagePullPolicy,
|
|
1335
|
+
})
|
|
1336
|
+
.replace('{{ports}}', buildKindPorts(_fromPort, _toPort));
|
|
1337
|
+
|
|
1338
|
+
fs.writeFileSync(outputPath, deploymentYaml, 'utf8');
|
|
1339
|
+
logger.info(`[instance-build-manifest] Manifest written to ${outputPath}`, {
|
|
1340
|
+
deployId: _deployId,
|
|
1341
|
+
env,
|
|
1342
|
+
traffic: targetTraffic,
|
|
1343
|
+
image: _image,
|
|
1344
|
+
});
|
|
1345
|
+
|
|
1346
|
+
if (env === 'production') {
|
|
1347
|
+
if (fs.existsSync(dockerfileManifestPath)) {
|
|
1348
|
+
fs.copyFileSync(dockerfileManifestPath, `${rootPath}/Dockerfile`);
|
|
1349
|
+
}
|
|
1350
|
+
fs.copyFileSync(outputPath, `${rootPath}/deployment.yaml`);
|
|
1351
|
+
logger.info('[instance-build-manifest] Production artifacts copied to project root', {
|
|
1352
|
+
rootPath,
|
|
1353
|
+
dockerfile: `${rootPath}/Dockerfile`,
|
|
1354
|
+
deployment: `${rootPath}/deployment.yaml`,
|
|
1355
|
+
});
|
|
1356
|
+
const ciSrc = `./.github/workflows/docker-image.${_runtime}.ci.yml`;
|
|
1357
|
+
if (fs.existsSync(ciSrc)) {
|
|
1358
|
+
if (!fs.existsSync(`${rootPath}/.github/workflows`)) fs.mkdirpSync(`${rootPath}/.github/workflows`);
|
|
1359
|
+
fs.copyFileSync(ciSrc, `${rootPath}/.github/workflows/docker-image.${_runtime}.ci.yml`);
|
|
1360
|
+
logger.info(`[instance-build-manifest] CI workflow copied`, { src: ciSrc });
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
},
|
|
1364
|
+
|
|
1118
1365
|
/**
|
|
1119
1366
|
* @method ls-deployments
|
|
1120
1367
|
* @description Retrieves and logs a table of Kubernetes deployments using `Underpost.deploy.get`.
|
|
@@ -1139,6 +1386,44 @@ EOF
|
|
|
1139
1386
|
shellExec(`${options.underpostRoot}/scripts/rocky-setup.sh${options.dev ? ' --install-dev' : ``}`);
|
|
1140
1387
|
},
|
|
1141
1388
|
|
|
1389
|
+
/**
|
|
1390
|
+
* @method install-crio
|
|
1391
|
+
* @description Installs and configures CRI-O as the container runtime for kubeadm clusters.
|
|
1392
|
+
* Adds the stable v1.33 CRI-O yum repository, installs the `cri-o` package, configures
|
|
1393
|
+
* the systemd cgroup driver, enables the `crio` service, and writes `/etc/crictl.yaml`
|
|
1394
|
+
* so that `crictl` targets the CRI-O socket by default.
|
|
1395
|
+
* @param {string} path - Unused.
|
|
1396
|
+
* @param {Object} options - The default underpost runner options for customizing workflow.
|
|
1397
|
+
* @memberof UnderpostRun
|
|
1398
|
+
*/
|
|
1399
|
+
'install-crio': (path, options = DEFAULT_OPTION) => {
|
|
1400
|
+
logger.info('Installing CRI-O...');
|
|
1401
|
+
shellExec(`cat <<EOF | sudo tee /etc/yum.repos.d/cri-o.repo
|
|
1402
|
+
[cri-o]
|
|
1403
|
+
name=CRI-O
|
|
1404
|
+
baseurl=https://download.opensuse.org/repositories/isv:/cri-o:/stable:/v1.33/rpm/
|
|
1405
|
+
enabled=1
|
|
1406
|
+
gpgcheck=1
|
|
1407
|
+
gpgkey=https://download.opensuse.org/repositories/isv:/cri-o:/stable:/v1.33/rpm/repodata/repomd.xml.key
|
|
1408
|
+
EOF`);
|
|
1409
|
+
shellExec(`sudo dnf -y install cri-o`);
|
|
1410
|
+
// crictl is in the kubernetes repo but excluded by default — install it explicitly
|
|
1411
|
+
shellExec(`sudo yum install -y cri-tools --disableexcludes=kubernetes`);
|
|
1412
|
+
// Ensure CRI-O uses systemd cgroup driver (matches kubelet default)
|
|
1413
|
+
shellExec(`sudo sed -i 's/^#\?cgroup_manager =.*/cgroup_manager = "systemd"/' /etc/crio/crio.conf`, {
|
|
1414
|
+
silentOnError: true,
|
|
1415
|
+
});
|
|
1416
|
+
shellExec(`sudo systemctl enable --now crio`);
|
|
1417
|
+
logger.info('CRI-O installed and started.');
|
|
1418
|
+
// Write crictl config so all crictl calls default to the CRI-O socket
|
|
1419
|
+
shellExec(`cat <<EOF | sudo tee /etc/crictl.yaml
|
|
1420
|
+
runtime-endpoint: unix:///var/run/crio/crio.sock
|
|
1421
|
+
image-endpoint: unix:///var/run/crio/crio.sock
|
|
1422
|
+
timeout: 10
|
|
1423
|
+
debug: false
|
|
1424
|
+
EOF`);
|
|
1425
|
+
},
|
|
1426
|
+
|
|
1142
1427
|
/**
|
|
1143
1428
|
* @method dd-container
|
|
1144
1429
|
* @description Deploys a development or debug container tasks jobs, setting up necessary volumes and images, and running specified commands within the container.
|
|
@@ -1261,7 +1546,8 @@ EOF
|
|
|
1261
1546
|
`git config user.name '${username}' && ` +
|
|
1262
1547
|
`git config user.email '${email}' && ` +
|
|
1263
1548
|
`git config credential.interactive always &&` +
|
|
1264
|
-
`git config pull.rebase false
|
|
1549
|
+
`git config pull.rebase false && ` +
|
|
1550
|
+
`git config core.filemode false`,
|
|
1265
1551
|
{
|
|
1266
1552
|
disableLog: true,
|
|
1267
1553
|
silent: true,
|
|
@@ -1281,6 +1567,9 @@ EOF
|
|
|
1281
1567
|
/**
|
|
1282
1568
|
* @method promote
|
|
1283
1569
|
* @description Switches traffic between blue/green deployments for a specified deployment ID(s) (uses `dd.router` for 'dd', or a specific ID).
|
|
1570
|
+
* When `--tls` is set, rebuilds the proxy manifest with `--cert` so the HTTPProxy includes
|
|
1571
|
+
* TLS config, deletes stale Certificate resources, then reapplies the proxy and secret.yaml
|
|
1572
|
+
* (cert-manager Certificate resources) for each affected deployment.
|
|
1284
1573
|
* @param {string} path - The input value, identifier, or path for the operation (used as a comma-separated string: `deployId,env,replicas`).
|
|
1285
1574
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
1286
1575
|
* @memberof UnderpostRun
|
|
@@ -1289,11 +1578,34 @@ EOF
|
|
|
1289
1578
|
let [inputDeployId, inputEnv, inputReplicas] = path.split(',');
|
|
1290
1579
|
if (!inputEnv) inputEnv = 'production';
|
|
1291
1580
|
if (!inputReplicas) inputReplicas = 1;
|
|
1581
|
+
// TODO: normalize: --tls maps to --cert for deploy.js isValidTLSContext compatibility
|
|
1582
|
+
if (options.tls) options.cert = true;
|
|
1583
|
+
|
|
1584
|
+
const applyCerts = (deployId, targetTraffic) => {
|
|
1585
|
+
if (!options.tls) return;
|
|
1586
|
+
// Rebuild proxy.yaml with --cert so the HTTPProxy includes TLS virtualhost config
|
|
1587
|
+
shellExec(
|
|
1588
|
+
`node bin deploy --build-manifest --cert --traffic ${targetTraffic} --replicas ${inputReplicas} --namespace ${options.namespace} ${deployId} ${inputEnv}`,
|
|
1589
|
+
);
|
|
1590
|
+
// Delete stale Certificate resources before reapplying
|
|
1591
|
+
const confServerPath = `./engine-private/conf/${deployId}/conf.server.json`;
|
|
1592
|
+
if (fs.existsSync(confServerPath)) {
|
|
1593
|
+
for (const host of Object.keys(JSON.parse(fs.readFileSync(confServerPath, 'utf8'))))
|
|
1594
|
+
shellExec(`sudo kubectl delete Certificate ${host} -n ${options.namespace} --ignore-not-found`);
|
|
1595
|
+
}
|
|
1596
|
+
shellExec(
|
|
1597
|
+
`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${inputEnv}/proxy.yaml -n ${options.namespace}`,
|
|
1598
|
+
);
|
|
1599
|
+
const secretPath = `./engine-private/conf/${deployId}/build/${inputEnv}/secret.yaml`;
|
|
1600
|
+
if (fs.existsSync(secretPath)) shellExec(`kubectl apply -f ${secretPath} -n ${options.namespace}`);
|
|
1601
|
+
};
|
|
1602
|
+
|
|
1292
1603
|
if (inputDeployId === 'dd') {
|
|
1293
1604
|
for (const deployId of fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',')) {
|
|
1294
1605
|
const currentTraffic = Underpost.deploy.getCurrentTraffic(deployId, { namespace: options.namespace });
|
|
1295
1606
|
const targetTraffic = currentTraffic === 'blue' ? 'green' : 'blue';
|
|
1296
1607
|
Underpost.deploy.switchTraffic(deployId, inputEnv, targetTraffic, inputReplicas, options.namespace, options);
|
|
1608
|
+
applyCerts(deployId, targetTraffic);
|
|
1297
1609
|
}
|
|
1298
1610
|
} else {
|
|
1299
1611
|
const currentTraffic = Underpost.deploy.getCurrentTraffic(inputDeployId, { namespace: options.namespace });
|
|
@@ -1306,6 +1618,7 @@ EOF
|
|
|
1306
1618
|
options.namespace,
|
|
1307
1619
|
options,
|
|
1308
1620
|
);
|
|
1621
|
+
applyCerts(inputDeployId, targetTraffic);
|
|
1309
1622
|
}
|
|
1310
1623
|
},
|
|
1311
1624
|
/**
|
|
@@ -1506,7 +1819,7 @@ EOF
|
|
|
1506
1819
|
}`;
|
|
1507
1820
|
shellExec(cmd, { async: true });
|
|
1508
1821
|
}
|
|
1509
|
-
await awaitDeployMonitor(
|
|
1822
|
+
await awaitDeployMonitor();
|
|
1510
1823
|
{
|
|
1511
1824
|
const cmd = `npm run dev:client ${deployId} ${subConf} ${host} ${_path} proxy${options.tls ? ' tls' : ''}`;
|
|
1512
1825
|
|
|
@@ -1514,7 +1827,7 @@ EOF
|
|
|
1514
1827
|
async: true,
|
|
1515
1828
|
});
|
|
1516
1829
|
}
|
|
1517
|
-
await awaitDeployMonitor(
|
|
1830
|
+
await awaitDeployMonitor();
|
|
1518
1831
|
shellExec(
|
|
1519
1832
|
`NODE_ENV=development node src/proxy proxy ${deployId} ${subConf} ${host} ${_path}${options.tls ? ' tls' : ''}`,
|
|
1520
1833
|
);
|
|
@@ -1611,7 +1924,7 @@ EOF
|
|
|
1611
1924
|
);
|
|
1612
1925
|
} else logger.error(`Service pod ${podToMonitor} failed to start in time.`);
|
|
1613
1926
|
if (options.etcHosts === true) {
|
|
1614
|
-
const hostListenResult =
|
|
1927
|
+
const hostListenResult = etcHostFactory([host]);
|
|
1615
1928
|
logger.info(hostListenResult.renderHosts);
|
|
1616
1929
|
}
|
|
1617
1930
|
},
|
|
@@ -1629,7 +1942,7 @@ EOF
|
|
|
1629
1942
|
const confServer = loadConfServerJson(`./engine-private/conf/${options.deployId}/conf.server.json`);
|
|
1630
1943
|
hosts.push(...Object.keys(confServer));
|
|
1631
1944
|
}
|
|
1632
|
-
const hostListenResult =
|
|
1945
|
+
const hostListenResult = etcHostFactory(hosts);
|
|
1633
1946
|
logger.info(hostListenResult.renderHosts);
|
|
1634
1947
|
},
|
|
1635
1948
|
|
|
@@ -1920,6 +2233,16 @@ EOF
|
|
|
1920
2233
|
|
|
1921
2234
|
shellCd('/home/dd/engine');
|
|
1922
2235
|
},
|
|
2236
|
+
/**
|
|
2237
|
+
* @method pull-rocky-image
|
|
2238
|
+
* @description Pulls the base `rockylinux:9` image from Docker Hub via Podman.
|
|
2239
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
2240
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
2241
|
+
* @memberof UnderpostRun
|
|
2242
|
+
*/
|
|
2243
|
+
'pull-rocky-image': (path, options = DEFAULT_OPTION) => {
|
|
2244
|
+
shellExec(`sudo podman pull docker.io/library/rockylinux:9`);
|
|
2245
|
+
},
|
|
1923
2246
|
/**
|
|
1924
2247
|
* @method rmi
|
|
1925
2248
|
* @description Forces the removal of all local Podman images (`podman rmi $(podman images -qa) --force`).
|
|
@@ -1938,24 +2261,28 @@ EOF
|
|
|
1938
2261
|
* @memberof UnderpostRun
|
|
1939
2262
|
*/
|
|
1940
2263
|
kill: (path = '', options = DEFAULT_OPTION) => {
|
|
1941
|
-
if (options.pid)
|
|
2264
|
+
if (options.pid)
|
|
2265
|
+
return shellExec(`sudo kill -9 ${options.pid}`, {
|
|
2266
|
+
silentOnError: true,
|
|
2267
|
+
});
|
|
1942
2268
|
for (const _path of path.split(',')) {
|
|
1943
2269
|
if (_path.split('+')[1]) {
|
|
1944
2270
|
let [port, sumPortOffSet] = _path.split('+');
|
|
1945
2271
|
port = parseInt(port);
|
|
1946
2272
|
sumPortOffSet = parseInt(sumPortOffSet);
|
|
1947
2273
|
for (const sumPort of range(0, sumPortOffSet))
|
|
1948
|
-
shellExec(
|
|
1949
|
-
|
|
2274
|
+
shellExec(
|
|
2275
|
+
`PIDS=$(lsof -t -i:${parseInt(port) + parseInt(sumPort)}); [ -n "$PIDS" ] && sudo kill -9 $PIDS || true`,
|
|
2276
|
+
{
|
|
2277
|
+
silentOnError: true,
|
|
2278
|
+
},
|
|
2279
|
+
);
|
|
2280
|
+
} else
|
|
2281
|
+
shellExec(`PIDS=$(lsof -t -i:${_path}); [ -n "$PIDS" ] && sudo kill -9 $PIDS || true`, {
|
|
2282
|
+
silentOnError: true,
|
|
2283
|
+
});
|
|
1950
2284
|
}
|
|
1951
2285
|
},
|
|
1952
|
-
/**
|
|
1953
|
-
* @method secret
|
|
1954
|
-
* @description Creates an Underpost secret named 'underpost' from a file, defaulting to `/home/dd/engine/engine-private/conf/dd-cron/.env.production` if no path is provided.
|
|
1955
|
-
* @param {string} path - The input value, identifier, or path for the operation (used as the optional path to the secret file).
|
|
1956
|
-
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
1957
|
-
* @memberof UnderpostRun
|
|
1958
|
-
*/
|
|
1959
2286
|
/**
|
|
1960
2287
|
* @method generate-pass
|
|
1961
2288
|
* @description Generates a cryptographically secure random password that satisfies all validatePassword
|
|
@@ -1992,11 +2319,18 @@ EOF
|
|
|
1992
2319
|
if (options.copy) pbcopy(password);
|
|
1993
2320
|
else console.log(password);
|
|
1994
2321
|
},
|
|
1995
|
-
|
|
2322
|
+
/**
|
|
2323
|
+
* @method secret
|
|
2324
|
+
* @description Creates an Underpost secret named 'underpost' from a file, defaulting to `/home/dd/engine/engine-private/conf/dd-cron/.env.production` if no path is provided.
|
|
2325
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the optional path to the secret file).
|
|
2326
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
2327
|
+
* @memberof UnderpostRun
|
|
2328
|
+
*/
|
|
1996
2329
|
secret: (path, options = DEFAULT_OPTION) => {
|
|
1997
|
-
const
|
|
1998
|
-
|
|
1999
|
-
|
|
2330
|
+
const cronDeployId = cronDeployIdResolve() || 'dd-cron';
|
|
2331
|
+
Underpost.secret.underpost.createFromEnvFile(
|
|
2332
|
+
`/home/dd/engine/engine-private/conf/${cronDeployId}/.env.${options.dev ? 'development' : 'production'}`,
|
|
2333
|
+
);
|
|
2000
2334
|
},
|
|
2001
2335
|
/**
|
|
2002
2336
|
* @method underpost-config
|
|
@@ -2166,6 +2500,195 @@ EOF`;
|
|
|
2166
2500
|
if (options.logs) shellExec(`kubectl logs -f ${podName} -n ${namespace}`, { async: true });
|
|
2167
2501
|
}
|
|
2168
2502
|
},
|
|
2503
|
+
|
|
2504
|
+
/**
|
|
2505
|
+
* @method push-bundle
|
|
2506
|
+
* @description Builds the client zip for the specified deployment, splits it into parts, and uploads to file storage.
|
|
2507
|
+
* Steps: set env, build+split zip, switch to cron env, upload parts to storage.
|
|
2508
|
+
* @param {string} path - Optional `fsPath.splitOption` string.
|
|
2509
|
+
* Examples: `build` (default split 8), `build.16` (split 16 MB), `build.none-split` (no split flag).
|
|
2510
|
+
* @param {Object} options - The default underpost runner options for customizing workflow.
|
|
2511
|
+
* @param {string} [options.deployId] - Override deploy ID.
|
|
2512
|
+
* @param {boolean} [options.dev] - Use development environment; defaults to production.
|
|
2513
|
+
* @memberof UnderpostRun
|
|
2514
|
+
*/
|
|
2515
|
+
'push-bundle': (path = '', options = DEFAULT_OPTION) => {
|
|
2516
|
+
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
2517
|
+
const env = options.dev ? 'development' : 'production';
|
|
2518
|
+
const deployId = options.deployId || 'dd-default';
|
|
2519
|
+
const pathParts = (path || '').split('.');
|
|
2520
|
+
const fsPath = (pathParts[0] || '').trim() || 'build';
|
|
2521
|
+
const splitOption = (pathParts[1] || '').trim();
|
|
2522
|
+
|
|
2523
|
+
let splitFlag = '--split 8';
|
|
2524
|
+
if (splitOption) {
|
|
2525
|
+
if (splitOption === 'none-split') {
|
|
2526
|
+
splitFlag = '';
|
|
2527
|
+
} else {
|
|
2528
|
+
const splitMb = Number(splitOption);
|
|
2529
|
+
if (Number.isFinite(splitMb) && splitMb > 0) {
|
|
2530
|
+
splitFlag = `--split ${splitMb}`;
|
|
2531
|
+
} else {
|
|
2532
|
+
logger.warn('push-bundle: invalid split option, using default split 8', {
|
|
2533
|
+
path,
|
|
2534
|
+
splitOption,
|
|
2535
|
+
});
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
shellExec(`${baseCommand} env ${deployId} ${env}`);
|
|
2541
|
+
shellExec(`${baseCommand} client ${deployId} --build-zip${splitFlag ? ` ${splitFlag}` : ''}`);
|
|
2542
|
+
shellExec(
|
|
2543
|
+
`${baseCommand} fs ${fsPath} --recursive --deploy-id ${deployId} --storage-file-path engine-private/conf/${deployId}/storage.bundle.json --force`,
|
|
2544
|
+
);
|
|
2545
|
+
},
|
|
2546
|
+
|
|
2547
|
+
/**
|
|
2548
|
+
* @method pull-bundle
|
|
2549
|
+
* @description Downloads split zip parts from file storage, merges and extracts them, and moves the result into the public directory.
|
|
2550
|
+
* Steps: set env, download parts (omit-unzip), merge zip, unzip, remove zip + parts, move to public/<host>[/path].
|
|
2551
|
+
* Iterates over every non-singleReplica, non-redirect, non-disabledRebuild route in conf.server.json
|
|
2552
|
+
* so that multi-path deployments are handled correctly.
|
|
2553
|
+
* @param {string} path - Optional comma-separated host name(s) to restrict processing (e.g. 'underpost.net' or 'a.com,b.com').
|
|
2554
|
+
* If omitted, all hosts from `engine-private/conf/<deployId>/conf.server.json` are used.
|
|
2555
|
+
* @param {Object} options - The default underpost runner options for customizing workflow.
|
|
2556
|
+
* @param {string} [options.deployId] - Deploy ID for storage lookup (defaults to 'dd-default').
|
|
2557
|
+
* @param {boolean} [options.dev] - Use development environment; defaults to production.
|
|
2558
|
+
* @memberof UnderpostRun
|
|
2559
|
+
*/
|
|
2560
|
+
'pull-bundle': (path = '', options = DEFAULT_OPTION) => {
|
|
2561
|
+
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
2562
|
+
const env = options.dev ? 'development' : 'production';
|
|
2563
|
+
const deployId = options.deployId || 'dd-default';
|
|
2564
|
+
const confServerPath = `./engine-private/conf/${deployId}/conf.server.json`;
|
|
2565
|
+
const confServer = fs.existsSync(confServerPath) ? loadConfServerJson(confServerPath) : {};
|
|
2566
|
+
const hostsArg = path
|
|
2567
|
+
? path
|
|
2568
|
+
.split(',')
|
|
2569
|
+
.map((h) => h.trim())
|
|
2570
|
+
.filter(Boolean)
|
|
2571
|
+
: Object.keys(confServer);
|
|
2572
|
+
|
|
2573
|
+
if (hostsArg.length === 0) {
|
|
2574
|
+
logger.error('pull-bundle: no hosts resolved', { deployId, path, confServerPath });
|
|
2575
|
+
return;
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2578
|
+
shellExec(`${baseCommand} env ${deployId} ${env}`);
|
|
2579
|
+
if (!fs.existsSync('./build')) fs.mkdirSync('./build', { recursive: true });
|
|
2580
|
+
shellExec(
|
|
2581
|
+
`${baseCommand} fs build --recursive --deploy-id ${deployId} --storage-file-path engine-private/conf/${deployId}/storage.bundle.json --pull --omit-unzip`,
|
|
2582
|
+
);
|
|
2583
|
+
|
|
2584
|
+
for (const host of hostsArg) {
|
|
2585
|
+
// Gather all routes for this host; fall back to root '/' when host is not in confServer
|
|
2586
|
+
// (e.g. when hosts were provided explicitly via the path argument).
|
|
2587
|
+
const routePaths = confServer[host] ? Object.keys(confServer[host]) : ['/'];
|
|
2588
|
+
|
|
2589
|
+
for (const routePath of routePaths) {
|
|
2590
|
+
const routeConf = confServer[host] ? confServer[host][routePath] || {} : {};
|
|
2591
|
+
// Skip routes that are not built by buildClient (mirrors buildClient skip conditions)
|
|
2592
|
+
if (routeConf.singleReplica || routeConf.redirect || routeConf.disabledRebuild) continue;
|
|
2593
|
+
|
|
2594
|
+
// buildClient names the zip as "<host>-<path-no-slashes>.zip"
|
|
2595
|
+
// e.g. host="underpost.net", path="/" → buildId="underpost.net-", zip="build/underpost.net-.zip"
|
|
2596
|
+
// e.g. host="app.net", path="/admin" → buildId="app.net-admin", zip="build/app.net-admin.zip"
|
|
2597
|
+
const buildId = `${host}-${routePath.replaceAll('/', '')}`;
|
|
2598
|
+
const zipPath = `build/${buildId}.zip`;
|
|
2599
|
+
const buildDir = './build';
|
|
2600
|
+
const hasZip = fs.existsSync(zipPath);
|
|
2601
|
+
const hasParts =
|
|
2602
|
+
fs.existsSync(buildDir) &&
|
|
2603
|
+
fs
|
|
2604
|
+
.readdirSync(buildDir)
|
|
2605
|
+
.some((name) => name.startsWith(`${buildId}.zip.part`) || name.startsWith(`${buildId}.zip-part`));
|
|
2606
|
+
|
|
2607
|
+
if (!hasZip && !hasParts) {
|
|
2608
|
+
logger.warn(`Bundle not found for '${host}${routePath}'. Skipping.`, { zipPath, deployId });
|
|
2609
|
+
continue;
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
if (hasParts) shellExec(`${baseCommand} client --merge-zip ${zipPath}`);
|
|
2613
|
+
shellExec(`${baseCommand} client --unzip ${zipPath}`);
|
|
2614
|
+
shellExec(`sudo rm -rf ${zipPath}`);
|
|
2615
|
+
|
|
2616
|
+
// Clean up downloaded part wrapper zips left by --omit-unzip pull
|
|
2617
|
+
if (fs.existsSync(buildDir)) {
|
|
2618
|
+
fs.readdirSync(buildDir)
|
|
2619
|
+
.filter((name) => name.startsWith(`${buildId}.zip.part`) || name.startsWith(`${buildId}.zip-part`))
|
|
2620
|
+
.forEach((partFile) => shellExec(`sudo rm -rf ${buildDir}/${partFile}`));
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2623
|
+
// unzipClientBuild extracts to buildId with trailing '-' stripped
|
|
2624
|
+
// e.g. "build/underpost.net-" → "build/underpost.net"
|
|
2625
|
+
// e.g. "build/app.net-admin" → "build/app.net-admin" (no trailing dash, no change)
|
|
2626
|
+
const extractedDir = `build/${buildId.replace(/-$/, '')}`;
|
|
2627
|
+
if (!fs.existsSync(extractedDir)) {
|
|
2628
|
+
logger.warn(`Extracted build dir not found: ${extractedDir}. Skipping move for '${host}${routePath}'.`);
|
|
2629
|
+
continue;
|
|
2630
|
+
}
|
|
2631
|
+
|
|
2632
|
+
// Destination mirrors the public directory layout used by the server
|
|
2633
|
+
const publicDestPath = routePath === '/' ? `public/${host}` : `public/${host}${routePath}`;
|
|
2634
|
+
if (fs.existsSync(publicDestPath)) shellExec(`sudo rm -rf ${publicDestPath}`);
|
|
2635
|
+
// Ensure parent directory exists for sub-paths
|
|
2636
|
+
if (routePath !== '/') shellExec(`sudo mkdir -p public/${host}`);
|
|
2637
|
+
shellExec(`sudo mv ${extractedDir} ${publicDestPath}`);
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
},
|
|
2641
|
+
|
|
2642
|
+
/**
|
|
2643
|
+
* @method monitor-ui
|
|
2644
|
+
* @description Installs and enables the Cockpit KVM Dashboard (cockpit, cockpit-machines, libvirt)
|
|
2645
|
+
* and opens the cockpit firewall service. With `--remove`, closes the firewall service instead.
|
|
2646
|
+
* @param {string} path - Unused.
|
|
2647
|
+
* @param {Object} options - The default underpost runner options for customizing workflow.
|
|
2648
|
+
* `options.remove` — when true, removes the cockpit firewall rule instead of adding it.
|
|
2649
|
+
* @memberof UnderpostRun
|
|
2650
|
+
*/
|
|
2651
|
+
'monitor-ui': (path, options = DEFAULT_OPTION) => {
|
|
2652
|
+
if (options.remove) {
|
|
2653
|
+
shellExec(`sudo firewall-cmd --zone=public --remove-service=cockpit --permanent`);
|
|
2654
|
+
shellExec(`sudo firewall-cmd --reload`);
|
|
2655
|
+
return;
|
|
2656
|
+
}
|
|
2657
|
+
shellExec(`sudo dnf install -y cockpit cockpit-machines libvirt`);
|
|
2658
|
+
shellExec(`sudo systemctl enable --now cockpit.socket libvirtd`);
|
|
2659
|
+
shellExec(`sudo firewall-cmd --permanent --add-service=cockpit`);
|
|
2660
|
+
shellExec(`sudo firewall-cmd --reload`);
|
|
2661
|
+
},
|
|
2662
|
+
|
|
2663
|
+
/**
|
|
2664
|
+
* @method shared-dir
|
|
2665
|
+
* @description Run once for initial shared-directory setup. Creates the group, adds the user,
|
|
2666
|
+
* creates the directory, sets ownership, applies the SGID bit, and configures default ACLs so
|
|
2667
|
+
* all future files inside the directory automatically inherit group write permissions.
|
|
2668
|
+
* Use `reload-shared-dir` for subsequent permission repairs without recreating the group.
|
|
2669
|
+
* @param {string} path - Target directory to set up (defaults to `/home/dd/engine`).
|
|
2670
|
+
* Customise via the `path` argument or leave empty to use the default.
|
|
2671
|
+
* @param {Object} options - The default underpost runner options for customizing workflow.
|
|
2672
|
+
* Key fields: `options.user` (default `'admin'`), `options.group` (default `'engine-dev'`).
|
|
2673
|
+
* @memberof UnderpostRun
|
|
2674
|
+
*/
|
|
2675
|
+
'shared-dir': (path = '/home/dd/engine', options = DEFAULT_OPTION) => {
|
|
2676
|
+
const dir = path || '/home/dd/engine';
|
|
2677
|
+
const user = options.user || 'admin';
|
|
2678
|
+
const group = options.group || 'engine-dev';
|
|
2679
|
+
|
|
2680
|
+
logger.info(`[setup-shared-dir] dir=${dir} user=${user} group=${group}`);
|
|
2681
|
+
|
|
2682
|
+
shellExec(`sudo groupadd ${group} 2>/dev/null || true`);
|
|
2683
|
+
shellExec(`sudo usermod -aG ${group} ${user}`);
|
|
2684
|
+
shellExec(`sudo mkdir -p ${dir}`);
|
|
2685
|
+
shellExec(`sudo chown -R ${user}:${group} ${dir}`);
|
|
2686
|
+
shellExec(`sudo chmod -R 2775 ${dir}`);
|
|
2687
|
+
shellExec(`sudo setfacl -d -m g:${group}:rwx ${dir}`);
|
|
2688
|
+
shellExec(`sudo setfacl -m g:${group}:rwx ${dir}`);
|
|
2689
|
+
|
|
2690
|
+
logger.info(`[setup-shared-dir] Shared directory setup complete: ${dir}`);
|
|
2691
|
+
},
|
|
2169
2692
|
};
|
|
2170
2693
|
|
|
2171
2694
|
static API = {
|
|
@@ -2222,14 +2745,14 @@ EOF`;
|
|
|
2222
2745
|
if (options.replicas === '' || options.replicas === null || options.replicas === undefined)
|
|
2223
2746
|
options.replicas = 1;
|
|
2224
2747
|
options.npmRoot = npmRoot;
|
|
2225
|
-
logger.info(
|
|
2748
|
+
logger.info(`Executing runner`, { runner, namespace: options.namespace });
|
|
2226
2749
|
if (!Underpost.run.RUNNERS.includes(runner)) throw new Error(`Runner not found: ${runner}`);
|
|
2227
2750
|
const result = await Underpost.run.CALL(runner, path, options);
|
|
2228
2751
|
return result;
|
|
2229
2752
|
} catch (error) {
|
|
2230
2753
|
console.log(error);
|
|
2231
2754
|
logger.error(error);
|
|
2232
|
-
|
|
2755
|
+
process.exit(1);
|
|
2233
2756
|
}
|
|
2234
2757
|
},
|
|
2235
2758
|
};
|