@underpostnet/cyberia 3.3.0 → 3.3.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +1 -0
- package/.env.example +17 -5
- package/.github/workflows/coverall.cyberia.ci.yml +39 -14
- package/.github/workflows/cyberia-client.cd.yml +5 -0
- package/.github/workflows/cyberia-server.cd.yml +5 -0
- package/.github/workflows/docker-image.cyberia-client.ci.yml +8 -5
- package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +8 -3
- package/.github/workflows/docker-image.cyberia-server.ci.yml +8 -5
- package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +8 -5
- package/.github/workflows/docker-image.engine-cyberia.ci.yml +15 -1
- package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +15 -1
- package/.github/workflows/engine-cyberia.cd.yml +3 -0
- package/.github/workflows/engine-cyberia.ci.yml +4 -5
- package/.github/workflows/ghpkg.ci.yml +35 -20
- package/.github/workflows/hardhat.ci.yml +12 -11
- package/.github/workflows/npmpkg.ci.yml +17 -15
- package/.github/workflows/publish.cyberia.ci.yml +44 -0
- package/.github/workflows/pwa-microservices-template-test.ci.yml +2 -2
- package/.github/workflows/release.cd.yml +1 -0
- package/.prettierignore +1 -0
- package/AGENTS.md +96 -0
- package/CHANGELOG.md +653 -2513
- package/CLI-HELP.md +323 -157
- package/Dockerfile +25 -9
- package/Dockerfile.dev +25 -9
- package/Dockerfile.test +5 -5
- package/README.md +48 -28
- package/bin/build.js +86 -41
- package/bin/build.template.js +8 -3
- package/bin/cyberia.js +1494 -1403
- package/bin/deploy.js +18 -104
- package/bin/index.js +1494 -1403
- package/compose.env +17 -5
- package/conf.js +98 -7
- package/deploy/cyberia-client/deploy.sh +46 -0
- package/deploy/cyberia-client/package.sh +17 -0
- package/deploy/cyberia-client/state.sh +15 -0
- package/deploy/cyberia-server/deploy.sh +46 -0
- package/deploy/cyberia-server/package.sh +17 -0
- package/deploy/cyberia-server/state.sh +15 -0
- package/deploy/dd-cyberia/deploy.sh +9 -29
- package/deploy/dd-cyberia/init.sh +38 -45
- package/deploy/dd-cyberia/package.sh +16 -0
- package/deploy/dd-cyberia/state.sh +14 -0
- package/deploy/dd-cyberia/sync-deploy.sh +133 -147
- package/deploy/lib/config.sh +29 -0
- package/deploy/lib/github-actions-logging.sh +610 -0
- package/deploy/lib/host.sh +194 -0
- package/deploy/lib/state.sh +65 -0
- package/deploy/pwa-microservices-template/deploy.sh +17 -42
- package/deploy/release/deploy.sh +9 -41
- package/deployment.yaml +7 -2
- package/docker-compose.yml +23 -17
- package/examples/static-page/README.md +19 -19
- package/examples/static-page/ssr-components/CustomPage.js +2 -2
- package/hardhat/hardhat.config.js +1 -6
- package/hardhat/package-lock.json +101 -40
- package/hardhat/package.json +2 -2
- package/manifests/alertmanager/deployment.yaml +81 -0
- package/manifests/blackbox-exporter/deployment.yaml +75 -0
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +32 -7
- package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +32 -7
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +7 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/mongo-express/deployment.yaml +46 -27
- package/manifests/deployment/mongo-express/kustomization.yaml +9 -0
- package/manifests/deployment/mongo-express/mongo-express-nodeport.yaml +18 -0
- package/manifests/deployment/mongo-express/service.yaml +16 -0
- package/manifests/deployment/mongo-express-no-auth/disable-mongodb-auth.yaml +16 -0
- package/manifests/deployment/mongo-express-no-auth/kustomization.yaml +16 -0
- package/manifests/grafana/deployment.yaml +26 -7
- package/manifests/grafana/kustomization.yaml +1 -0
- package/manifests/grafana/service.yaml +6 -1
- package/manifests/mariadb/pv.yaml +1 -0
- package/manifests/mongodb/statefulset.yaml +9 -2
- package/manifests/mysql/pv-pvc.yaml +14 -1
- package/manifests/postgresql/pv.yaml +12 -1
- package/manifests/postgresql/pvc.yaml +1 -0
- package/manifests/prometheus/deployment.yaml +18 -22
- package/package.json +87 -12
- package/scripts/event-monitor.sh +56 -0
- package/scripts/k3s-node-setup.sh +27 -14
- package/scripts/kubeadm-node-setup.sh +31 -11
- package/scripts/maas-setup.sh +8 -8
- package/scripts/selinux-normalize.sh +907 -0
- package/scripts/shutdown-machine.sh +843 -0
- package/scripts/test-monitor.sh +5 -5
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +15 -10
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +36 -5
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +7 -2
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +90 -186
- package/src/api/core/core.controller.js +1 -1
- package/src/api/core/core.router.js +2 -2
- package/src/api/core/core.service.js +2 -2
- package/src/api/crypto/crypto.controller.js +1 -1
- package/src/api/crypto/crypto.service.js +1 -1
- package/src/api/cyberia-action/cyberia-action.controller.js +1 -1
- package/src/api/cyberia-action/cyberia-action.router.js +3 -3
- package/src/api/cyberia-action/cyberia-action.service.js +5 -6
- package/src/api/cyberia-audio/cyberia-audio.controller.js +6 -0
- package/src/api/cyberia-audio/cyberia-audio.model.js +61 -0
- package/src/api/cyberia-audio/cyberia-audio.router.js +21 -0
- package/src/api/cyberia-audio/cyberia-audio.service.js +220 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +2 -4
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +10 -19
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +13 -35
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +17 -34
- package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +1 -1
- package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +1 -1
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +2 -2
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +2 -2
- package/src/api/cyberia-entity/cyberia-entity.controller.js +1 -1
- package/src/api/cyberia-entity/cyberia-entity.model.js +2 -0
- package/src/api/cyberia-entity/cyberia-entity.router.js +1 -1
- package/src/api/cyberia-entity/cyberia-entity.service.js +3 -3
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +8 -2
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +31 -20
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +17 -2
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +468 -5
- package/src/api/cyberia-instance/cyberia-fallback-capture.js +502 -0
- package/src/api/cyberia-instance/cyberia-fallback-world.js +29 -40
- package/src/api/cyberia-instance/cyberia-instance-boot.service.js +5 -5
- package/src/api/cyberia-instance/cyberia-instance-items.js +98 -0
- package/src/api/cyberia-instance/cyberia-instance-map.service.js +35 -142
- package/src/api/cyberia-instance/cyberia-instance.controller.js +2 -5
- package/src/api/cyberia-instance/cyberia-instance.model.js +0 -14
- package/src/api/cyberia-instance/cyberia-instance.router.js +5 -18
- package/src/api/cyberia-instance/cyberia-instance.service.js +5 -45
- package/src/api/cyberia-instance/cyberia-world-generator.js +8 -13
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +1 -1
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +49 -75
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +1 -1
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +76 -3
- package/src/api/cyberia-map/cyberia-map.controller.js +1 -1
- package/src/api/cyberia-map/cyberia-map.router.js +1 -1
- package/src/api/cyberia-map/cyberia-map.service.js +8 -4
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.controller.js +31 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.model.js +56 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.router.js +33 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +189 -0
- package/src/api/cyberia-quest/cyberia-quest.controller.js +1 -1
- package/src/api/cyberia-quest/cyberia-quest.router.js +4 -4
- package/src/api/cyberia-quest/cyberia-quest.service.js +5 -5
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +1 -1
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +1 -1
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +1 -1
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +2 -2
- package/src/api/cyberia-saga/cyberia-saga.controller.js +1 -1
- package/src/api/cyberia-saga/cyberia-saga.router.js +1 -1
- package/src/api/cyberia-saga/cyberia-saga.service.js +2 -2
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +403 -214
- package/src/api/cyberia-skill/cyberia-skill.controller.js +1 -1
- package/src/api/cyberia-skill/cyberia-skill.model.js +6 -6
- package/src/api/cyberia-skill/cyberia-skill.router.js +1 -1
- package/src/api/cyberia-skill/cyberia-skill.service.js +2 -2
- package/src/api/default/default.controller.js +1 -1
- package/src/api/default/default.router.js +1 -1
- package/src/api/default/default.service.js +2 -2
- package/src/api/document/document.controller.js +1 -1
- package/src/api/document/document.router.js +1 -1
- package/src/api/document/document.service.js +2 -2
- package/src/api/file/file.controller.js +1 -1
- package/src/api/file/file.ref.js +153 -0
- package/src/api/file/file.ref.json +11 -2
- package/src/api/file/file.router.js +1 -1
- package/src/api/file/file.service.js +2 -2
- package/src/api/instance/instance.controller.js +1 -1
- package/src/api/instance/instance.router.js +1 -1
- package/src/api/instance/instance.service.js +2 -2
- package/src/api/ipfs/ipfs.controller.js +1 -1
- package/src/api/ipfs/ipfs.router.js +2 -2
- package/src/api/ipfs/ipfs.service.js +2 -2
- package/src/api/object-layer/object-layer.controller.js +1 -1
- package/src/api/object-layer/object-layer.model.js +47 -12
- package/src/api/object-layer/object-layer.router.js +12 -5
- package/src/api/object-layer/object-layer.service.js +116 -123
- package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +1 -1
- package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +1 -1
- package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +2 -2
- package/src/api/test/test.controller.js +1 -1
- package/src/api/test/test.service.js +1 -1
- package/src/api/user/guest.service.js +3 -3
- package/src/api/user/user.controller.js +1 -1
- package/src/api/user/user.router.js +2 -2
- package/src/api/user/user.service.js +4 -4
- package/src/api.js +5 -9
- package/src/cli/app.js +402 -0
- package/src/cli/baremetal.js +30 -35
- package/src/cli/client.js +306 -0
- package/src/cli/cloud-init.js +3 -3
- package/src/cli/cluster.js +191 -82
- package/src/cli/db.js +120 -68
- package/src/cli/deploy.js +157 -75
- package/src/cli/docker-compose.js +5 -5
- package/src/cli/domains.js +184 -0
- package/src/cli/dotenv-store.js +143 -0
- package/src/cli/event.js +2281 -0
- package/src/cli/fs-selection.js +115 -0
- package/src/cli/fs.js +159 -343
- package/src/cli/host.js +672 -0
- package/src/cli/image.js +4 -6
- package/src/cli/index.js +343 -151
- package/src/cli/ipfs.js +34 -30
- package/src/cli/kickstart.js +1 -1
- package/src/cli/kubectl.js +218 -41
- package/src/cli/lxd.js +3 -3
- package/src/cli/monitor.js +1359 -26
- package/src/cli/package.js +90 -0
- package/src/cli/release.js +16 -12
- package/src/cli/repository.js +586 -363
- package/src/cli/run.js +398 -843
- package/src/cli/secrets.js +2158 -964
- package/src/cli/ssh.js +478 -279
- package/src/cli/state.js +394 -0
- package/src/cli/static.js +2 -2
- package/src/cli/system.js +1 -1
- package/src/cli/test.js +203 -125
- package/src/cli/vultr.js +61 -21
- package/src/cli/wireguard.js +1112 -306
- package/src/client/components/core/CalendarCore.js +53 -96
- package/src/client/components/core/Docs.js +327 -303
- package/src/client/components/core/FileExplorer.js +0 -21
- package/src/client/components/core/Modal.js +56 -1
- package/src/client/components/core/PanelForm.js +4 -4
- package/src/client/components/core/Repository.js +56 -0
- package/src/client/components/core/Translate.js +7 -0
- package/src/client/components/core/{FullScreen.js → ViewModeController.js} +42 -39
- package/src/client/components/core/Wallet.js +0 -11
- package/src/client/components/core/Worker.js +7 -1
- package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +2 -2
- package/src/client/components/cyberia/ActionEngineCyberia.js +12 -36
- package/src/client/components/cyberia/EntityEngineCyberia.js +492 -121
- package/src/client/components/cyberia/InstanceEngineCyberia.js +129 -160
- package/src/client/components/cyberia/InstanceSelectionView.js +7 -1
- package/src/client/components/cyberia/MapEngineCyberia.js +175 -69
- package/src/client/components/cyberia/ObjectLayerEngine.js +1011 -97
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +81 -155
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +113 -98
- package/src/client/components/cyberia/SharedDefaultsCyberia.js +215 -56
- package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +2 -35
- package/src/client/components/cyberia-portal/CssCyberiaPortal.js +1 -1
- package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +712 -76
- package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +2 -2
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +0 -4
- package/src/client/components/default/AppShellDefault.js +1 -1
- package/src/client/components/default/SettingsDefault.js +2 -2
- package/src/client/components/itemledger/SettingsItemledger.js +2 -2
- package/src/client/components/underpost/AppShellUnderpost.js +3 -2
- package/src/client/components/underpost/SettingsUnderpost.js +2 -2
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +15 -15
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +313 -30
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +51 -29
- package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +52 -53
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +16 -11
- package/src/client/public/cyberia-docs/CYBERIA.md +48 -28
- package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +11 -5
- package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +23 -6
- package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
- package/src/client/public/cyberia-docs/STATS-PROGRESSION.md +217 -0
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +20 -12
- package/src/client/public/default/android-chrome-144x144.png +0 -0
- package/src/client/public/default/android-chrome-192x192.png +0 -0
- package/src/client/public/default/android-chrome-256x256.png +0 -0
- package/src/client/public/default/android-chrome-36x36.png +0 -0
- package/src/client/public/default/android-chrome-384x384.png +0 -0
- package/src/client/public/default/android-chrome-48x48.png +0 -0
- package/src/client/public/default/android-chrome-512x512.png +0 -0
- package/src/client/public/default/android-chrome-72x72.png +0 -0
- package/src/client/public/default/android-chrome-96x96.png +0 -0
- package/src/client/public/default/apple-touch-icon-1024x1024.png +0 -0
- package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
- package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
- package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
- package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
- package/src/client/public/default/apple-touch-icon-167x167.png +0 -0
- package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
- package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
- package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
- package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
- package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
- package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1125x2436.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1136x640.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1170x2532.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1179x2556.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1242x2208.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1242x2688.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1284x2778.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1290x2796.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1334x750.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1488x2266.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1536x2048.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1620x2160.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1640x2160.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1668x2224.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1668x2388.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1792x828.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2048x1536.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2048x2732.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2160x1620.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2160x1640.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2208x1242.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2224x1668.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2266x1488.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2388x1668.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2436x1125.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2532x1170.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2556x1179.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2688x1242.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2732x2048.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2778x1284.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2796x1290.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-640x1136.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-750x1334.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-828x1792.png +0 -0
- package/src/client/public/default/assets/background/white.jpg +0 -0
- package/src/client/public/default/browserconfig.xml +1 -1
- package/src/client/public/default/favicon-16x16.png +0 -0
- package/src/client/public/default/favicon-32x32.png +0 -0
- package/src/client/public/default/favicon-48x48.png +0 -0
- package/src/client/public/default/favicon.ico +0 -0
- package/src/client/public/default/manifest.webmanifest +5 -5
- package/src/client/public/default/mstile-144x144.png +0 -0
- package/src/client/public/default/mstile-150x150.png +0 -0
- package/src/client/public/default/mstile-310x150.png +0 -0
- package/src/client/public/default/mstile-310x310.png +0 -0
- package/src/client/public/default/mstile-70x70.png +0 -0
- package/src/client/public/default/yandex-browser-50x50.png +0 -0
- package/src/client/public/default/yandex-browser-manifest.json +1 -1
- package/src/client/services/cyberia-audio/cyberia-audio.service.js +99 -0
- package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +38 -0
- package/src/client/services/cyberia-instance/cyberia-instance.management.js +5 -4
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +0 -40
- package/src/client/services/cyberia-map/cyberia-map.management.js +5 -4
- package/src/client/services/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +138 -0
- package/src/client/services/object-layer/object-layer.management.js +6 -10
- package/src/client/services/object-layer/object-layer.service.js +3 -1
- package/src/client/ssr/RootDocument.js +1 -1
- package/src/client/ssr/body/404.js +1 -1
- package/src/client/ssr/body/500.js +1 -1
- package/src/client/ssr/body/CacheControl.js +1 -1
- package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +1 -1
- package/src/client/ssr/body/DefaultSplashScreen.js +1 -1
- package/src/client/ssr/body/SwaggerDarkMode.js +1 -1
- package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +1 -1
- package/src/client/ssr/head/CryptokoynScripts.js +1 -1
- package/src/client/ssr/head/Css.js +1 -1
- package/src/client/ssr/head/CyberiaPortalScripts.js +1 -1
- package/src/client/ssr/head/DefaultScripts.js +1 -1
- package/src/client/ssr/head/ItemledgerScripts.js +1 -1
- package/src/client/ssr/head/Microdata.js +1 -1
- package/src/client/ssr/head/Production.js +1 -1
- package/src/client/ssr/head/Pwa.js +1 -1
- package/src/client/ssr/head/PwaItemledger.js +1 -1
- package/src/client/ssr/head/Seo.js +1 -1
- package/src/client/ssr/head/UnderpostScripts.js +1 -1
- package/src/client/ssr/mailer/DefaultRecoverEmail.js +1 -1
- package/src/client/ssr/mailer/DefaultVerifyEmail.js +1 -1
- package/src/client/ssr/views/Cyberia404.js +7 -5
- package/src/client/ssr/views/CyberiaServerMetrics.js +1 -1
- package/src/client/ssr/views/Maintenance.js +1 -1
- package/src/client/ssr/views/NoNetworkConnection.js +1 -1
- package/src/client/ssr/views/Test.js +1 -1
- package/src/client/sw/core.sw.js +20 -14
- package/src/client-builder/client-build-docs.js +92 -77
- package/src/client-builder/client-build-live.js +2 -2
- package/src/client-builder/client-build.js +105 -74
- package/src/client-builder/client-bundle.js +347 -0
- package/src/client-builder/client-dev-server.js +3 -3
- package/src/client-builder/client-icons.js +2 -2
- package/src/client-builder/ssr.js +3 -3
- package/src/client.build.js +3 -6
- package/src/client.dev.js +3 -6
- package/src/db/DataBaseProvider.js +186 -3
- package/src/db/mariadb/MariaDB.js +3 -2
- package/src/db/mongo/MongoBootstrap.js +273 -101
- package/src/db/mongo/MongoExpress.js +187 -0
- package/src/db/mongo/MongooseDB.js +7 -8
- package/src/{server/valkey.js → db/valkey/Valkey.js} +5 -4
- package/src/grpc/cyberia/grpc-server.js +6 -8
- package/src/index.js +79 -23
- package/src/mailer/EmailRender.js +2 -2
- package/src/mailer/MailerInterceptor.js +87 -0
- package/src/mailer/MailerProvider.js +50 -6
- package/src/projects/cyberia/atlas-sprite-sheet-generator.js +144 -147
- package/src/projects/cyberia/atlas-sprite-sheet-store.js +391 -0
- package/src/projects/cyberia/besu-genesis-generator.js +8 -17
- package/src/projects/cyberia/boot-contract-fixtures.js +32 -0
- package/src/projects/cyberia/catalog-cyberia.js +54 -10
- package/src/projects/cyberia/gemini-client.js +4 -4
- package/src/projects/cyberia/generate-saga.js +5 -12
- package/src/projects/cyberia/hot-reload-trigger.js +18 -29
- package/src/projects/cyberia/instance-backup.js +210 -0
- package/src/projects/cyberia/instance-data.js +178 -258
- package/src/projects/cyberia/ipfs-client.js +4 -4
- package/src/projects/cyberia/map-preview-generator.js +33 -69
- package/src/projects/cyberia/object-layer.js +153 -320
- package/src/projects/cyberia/seed-audio.js +139 -0
- package/src/projects/cyberia/semantic-layer-generator-skin.js +2 -8
- package/src/projects/cyberia/semantic-layer-generator.js +3 -19
- package/src/projects/cyberia/stat-balance.js +81 -0
- package/src/projects/cyberia/stat-commands.js +23 -0
- package/src/projects/cyberia/stat-contract-generator.js +101 -0
- package/src/projects/underpost/catalog-underpost.js +9 -1
- package/src/proxy.js +4 -7
- package/src/runtime/cyberia-client/Dockerfile +17 -8
- package/src/runtime/cyberia-client/Dockerfile.dev +13 -4
- package/src/runtime/cyberia-server/Dockerfile +18 -6
- package/src/runtime/cyberia-server/Dockerfile.dev +16 -3
- package/src/runtime/engine-cyberia/Dockerfile +25 -9
- package/src/runtime/engine-cyberia/Dockerfile.dev +25 -9
- package/src/runtime/engine-cyberia/Dockerfile.test +5 -5
- package/src/runtime/engine-cyberia/compose.env +17 -5
- package/src/runtime/engine-cyberia/docker-compose.yml +23 -17
- package/src/runtime/express/Express.js +32 -27
- package/src/runtime/lampp/Lampp.js +22 -70
- package/src/runtime/nginx/Nginx.js +1 -1
- package/src/runtime/wp/Wp.js +16 -48
- package/src/server/{catalog.js → build/catalog.js} +15 -5
- package/src/server/build/coverage.js +188 -0
- package/src/server/build/execution.js +402 -0
- package/src/server/build/package.js +508 -0
- package/src/server/build/testing.js +578 -0
- package/src/server/{dns.js → network/dns.js} +144 -11
- package/src/server/{forward-proxy.js → network/forward-proxy.js} +10 -18
- package/src/server/{middlewares.js → network/middlewares.js} +11 -5
- package/src/server/network/node-capability.js +98 -0
- package/src/server/{peer.js → network/peer.js} +3 -3
- package/src/server/{proxy.js → network/proxy.js} +7 -13
- package/src/server/network/router.js +356 -0
- package/src/server/{tls.js → network/tls.js} +2 -2
- package/src/server/{underpost-compression.js → network/underpost-compression.js} +1 -1
- package/src/server/{underpost-gateway.js → network/underpost-gateway.js} +7 -7
- package/src/server/{underpost-ingress.js → network/underpost-ingress.js} +2 -2
- package/src/server/{cri.js → ops/cri.js} +2 -2
- package/src/server/{cron.js → ops/cron.js} +349 -74
- package/src/server/ops/event-notification.js +284 -0
- package/src/server/{logger.js → ops/logger.js} +143 -23
- package/src/server/ops/monitoring.js +1724 -0
- package/src/server/{systemd.js → ops/systemd.js} +55 -1
- package/src/server/{conf.js → runtime/conf.js} +516 -423
- package/src/server/runtime/config-scope.js +215 -0
- package/src/server/runtime/environment.js +149 -0
- package/src/server/{process.js → runtime/process.js} +153 -12
- package/src/server/{runtime-status.js → runtime/runtime-status.js} +155 -16
- package/src/server/{runtime.js → runtime/runtime.js} +12 -8
- package/src/server/{start.js → runtime/start.js} +128 -39
- package/src/server/{auth.js → security/auth.js} +7 -8
- package/src/server/security/container-storage.js +382 -0
- package/src/server/{crypto.js → security/crypto.js} +1 -1
- package/src/server/{selinux.js → security/selinux.js} +1 -1
- package/src/server/{backup.js → storage/backup.js} +17 -8
- package/src/server/{data-query.js → storage/data-query.js} +17 -1
- package/src/server/storage/downloader.js +121 -0
- package/src/server/storage/repository.js +68 -0
- package/src/server/storage/zip.js +153 -0
- package/src/server.js +4 -7
- package/src/ws/IoInterface.js +1 -1
- package/src/ws/IoServer.js +1 -1
- package/src/ws/core/core.ws.connection.js +1 -1
- package/src/ws/core/core.ws.emit.js +1 -1
- package/src/ws/core/core.ws.server.js +1 -1
- package/src/ws/default/default.ws.connection.js +1 -1
- package/src/ws/default/default.ws.emit.js +1 -1
- package/src/ws/default/default.ws.server.js +1 -1
- package/test/e2e/event-e2e-public-ingress-down.js +45 -0
- package/test/e2e/event-e2e-wireguard-server-down.js +38 -0
- package/test/e2e/event-e2e-wireguard-spoke-down.js +40 -0
- package/test/{api.test.js → integration/app/api.test.js} +33 -14
- package/test/integration/app/cyberia/atlas-sprite-sheet-store.test.js +402 -0
- package/test/integration/app/cyberia/atlas-sprite-sheet.test.js +86 -0
- package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +64 -0
- package/test/integration/app/cyberia/cyberia-entity-type-default.test.js +842 -0
- package/test/integration/app/cyberia/cyberia-instance-conf-coerce.test.js +53 -0
- package/test/{cyberia-instance-conf-defaults.test.js → integration/app/cyberia/cyberia-instance-conf-defaults.test.js} +17 -23
- package/test/integration/app/cyberia/cyberia-instance-items.test.js +90 -0
- package/test/integration/app/cyberia/cyberia-load.test.js +466 -0
- package/test/integration/app/cyberia/cyberia-map-audio-conf.test.js +256 -0
- package/test/integration/app/cyberia/cyberia-stats.test.js +150 -0
- package/test/integration/app/cyberia/fallback-world-capture.test.js +338 -0
- package/test/integration/app/cyberia/object-layer-item-id.test.js +327 -0
- package/test/integration/app/cyberia/object-layer-item-selection.test.js +56 -0
- package/test/integration/app/cyberia/object-layer-natural-key.test.js +32 -0
- package/test/integration/app/cyberia/seed-audio.test.js +275 -0
- package/test/{shape-generator.test.js → integration/app/cyberia/shape-generator.test.js} +1 -1
- package/test/integration/infra/1-security/config-scope.test.js +305 -0
- package/test/integration/infra/1-security/container-storage.test.js +356 -0
- package/test/integration/infra/1-security/in-pod-cli-surface.test.js +86 -0
- package/test/integration/infra/1-security/secret-onboarding.test.js +930 -0
- package/test/{selinux.test.js → integration/infra/1-security/selinux.test.js} +2 -4
- package/test/{sops-secret-store.test.js → integration/infra/1-security/sops-secret-store.test.js} +415 -61
- package/test/integration/infra/1-security/systemd-service.test.js +70 -0
- package/test/integration/infra/1-security/underpost-config-secret.test.js +367 -0
- package/test/integration/infra/2-network/dns-firewall.test.js +566 -0
- package/test/integration/infra/2-network/node-capability.test.js +182 -0
- package/test/integration/infra/2-network/wireguard-cli.test.js +1187 -0
- package/test/{wireguard-edge.test.js → integration/infra/2-network/wireguard-edge.test.js} +649 -55
- package/test/{cluster-instances.test.js → integration/infra/3-cluster/cluster-instances.test.js} +11 -15
- package/test/{deploy-node-placement.test.js → integration/infra/3-cluster/deploy-node-placement.test.js} +3 -3
- package/test/integration/infra/3-cluster/docker-compose-stack.test.js +313 -0
- package/test/integration/infra/3-cluster/mongo-express-deploy.test.js +156 -0
- package/test/integration/infra/4-ingress/api-cross-origin.test.js +79 -0
- package/test/integration/infra/4-ingress/deploy-routes.test.js +379 -0
- package/test/integration/infra/4-ingress/gateway-static-assets.test.js +453 -0
- package/test/{instance-traffic-plan.test.js → integration/infra/4-ingress/instance-traffic-plan.test.js} +10 -6
- package/test/{underpost-gateway.test.js → integration/infra/4-ingress/underpost-gateway.test.js} +6 -6
- package/test/{underpost-ingress.test.js → integration/infra/4-ingress/underpost-ingress.test.js} +4 -4
- package/test/integration/infra/5-observability/cron-jobs.test.js +652 -0
- package/test/{deploy-monitor.test.js → integration/infra/5-observability/deploy-monitor.test.js} +29 -31
- package/test/integration/infra/5-observability/event-notification.test.js +197 -0
- package/test/integration/infra/5-observability/event-remediation.test.js +502 -0
- package/test/integration/infra/5-observability/event-targets.test.js +1174 -0
- package/test/integration/infra/5-observability/monitoring-stack.test.js +902 -0
- package/test/support/shell-harness.js +73 -0
- package/test/unit/build-template.test.js +97 -0
- package/test/unit/build-workflow-offline.test.js +132 -0
- package/test/unit/catalog.test.js +71 -0
- package/test/unit/client-build-docs.test.js +361 -0
- package/test/unit/client-bundle.test.js +313 -0
- package/test/unit/conf-loading.test.js +303 -0
- package/test/unit/conf-resolution.test.js +996 -0
- package/test/unit/coverage-artifact.test.js +221 -0
- package/test/{crypto.test.js → unit/crypto.test.js} +1 -1
- package/test/unit/cyberia/instance-backup.test.js +183 -0
- package/test/unit/cyberia/instance-object-layer-items.test.js +46 -0
- package/test/unit/cyberia/publish-workflow.test.js +22 -0
- package/test/unit/cyberia/stat-balance.test.js +69 -0
- package/test/unit/deploy-env-resolution.test.js +38 -0
- package/test/unit/deploy-log-table.test.js +518 -0
- package/test/unit/downloader-integrity.test.js +98 -0
- package/test/unit/execution-profiles.test.js +219 -0
- package/test/unit/file-reference-registry.test.js +141 -0
- package/test/unit/fleet-sync-source.test.js +149 -0
- package/test/unit/fs-storage-paths.test.js +596 -0
- package/test/unit/logger-redaction.test.js +141 -0
- package/test/unit/package.test.js +457 -0
- package/test/unit/prepare-host.test.js +382 -0
- package/test/unit/process-environment.test.js +18 -0
- package/test/unit/propagation-message.test.js +78 -0
- package/test/unit/redeploy-plan.test.js +24 -0
- package/test/unit/release-bump.test.js +474 -0
- package/test/unit/ssh-output-redaction.test.js +28 -0
- package/test/unit/start-options.test.js +46 -0
- package/test/unit/test-tiers.test.js +220 -0
- package/test/unit/zip-archive.test.js +142 -0
- package/vitest.config.js +66 -0
- package/.nycrc +0 -9
- package/deploy/lib/logging.sh +0 -96
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +0 -48
- package/manifests/mongodb/pv-pvc.yaml +0 -59
- package/scripts/coverall-test-cyberia.sh +0 -24
- package/scripts/coverall-test.sh +0 -24
- package/scripts/link-local-underpost-cli.sh +0 -6
- package/src/api/cyberia-instance/cyberia-fallback-default-items.js +0 -63
- package/src/api/user/user.build.js +0 -16
- package/src/cli/env.js +0 -177
- package/src/client/components/core/Blockchain.js +0 -41
- package/src/client/components/core/Blog.js +0 -9
- package/src/client/components/core/KeyboardAvoidance.js +0 -145
- package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +0 -368
- package/src/client/public/default/assets/background/dark.jpg +0 -0
- package/src/client/public/default/assets/background/white0-min.jpg +0 -0
- package/src/client/public/default/assets/background/white0.jpg +0 -0
- package/src/client/public/doc/favicon.ico +0 -0
- package/src/client/public/doc/sitemap +0 -148
- package/src/server/downloader.js +0 -73
- package/src/server/environment.js +0 -98
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createPool } from 'mariadb';
|
|
2
2
|
import Underpost from '../../index.js';
|
|
3
|
-
import { loggerFactory } from '../../server/logger.js';
|
|
3
|
+
import { loggerFactory } from '../../server/ops/logger.js';
|
|
4
|
+
import { latchRuntimeError } from '../../server/runtime/runtime-status.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Module for interacting with MariaDB/MySQL databases using the mariadb connector.
|
|
@@ -51,7 +52,7 @@ class MariaDBService {
|
|
|
51
52
|
console.log(result);
|
|
52
53
|
} catch (error) {
|
|
53
54
|
logger.error('MariaDB query failed', { error: error.message });
|
|
54
|
-
|
|
55
|
+
latchRuntimeError();
|
|
55
56
|
} finally {
|
|
56
57
|
if (conn) conn.release(); // release to pool
|
|
57
58
|
await pool.end();
|
|
@@ -9,15 +9,18 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import fs from 'fs-extra';
|
|
12
|
-
import { loggerFactory } from '../../server/logger.js';
|
|
13
|
-
import { shellExec } from '../../server/process.js';
|
|
14
|
-
import { crictlCommandFactory } from '../../server/cri.js';
|
|
15
|
-
import {
|
|
12
|
+
import { loggerFactory } from '../../server/ops/logger.js';
|
|
13
|
+
import { shellExec } from '../../server/runtime/process.js';
|
|
14
|
+
import { crictlCommandFactory } from '../../server/ops/cri.js';
|
|
15
|
+
import { ensureContainerStorage } from '../../server/security/container-storage.js';
|
|
16
|
+
import { resolveReplicaCount } from '../../server/runtime/conf.js';
|
|
16
17
|
// Cyclic by construction (index -> cluster -> MongoBootstrap -> index), same as cluster.js.
|
|
17
18
|
// Safe because the binding is only dereferenced inside method bodies, never at module scope.
|
|
18
19
|
import Underpost from '../../index.js';
|
|
19
20
|
import {
|
|
20
21
|
MONGODB_DATA_ROOT,
|
|
22
|
+
MONGODB_DEFAULT_AUTH_SOURCE,
|
|
23
|
+
MONGODB_DEFAULT_PORT,
|
|
21
24
|
MONGODB_DEFAULT_REPLICA_COUNT,
|
|
22
25
|
MONGODB_DEFAULT_REPLICA_SET,
|
|
23
26
|
MONGODB_SERVICE_NAME,
|
|
@@ -29,6 +32,68 @@ import {
|
|
|
29
32
|
|
|
30
33
|
const logger = loggerFactory(import.meta);
|
|
31
34
|
|
|
35
|
+
const MONGODB_PRIMARY_PROBE_URI =
|
|
36
|
+
`mongodb://127.0.0.1:${MONGODB_DEFAULT_PORT}/${MONGODB_DEFAULT_AUTH_SOURCE}` +
|
|
37
|
+
`?directConnection=true&serverSelectionTimeoutMS=8000&connectTimeoutMS=8000&socketTimeoutMS=15000`;
|
|
38
|
+
|
|
39
|
+
const MONGODB_PRIMARY_PROBE_TIMEOUT_SECONDS = 45;
|
|
40
|
+
|
|
41
|
+
const MONGODB_PRIMARY_EVAL = {
|
|
42
|
+
hello: 'db.hello().primary',
|
|
43
|
+
isMaster: 'rs.isMaster().primary',
|
|
44
|
+
rsStatus: 'rs.status().members.filter(m=>m.stateStr=="PRIMARY").map(m=>m.name)[0]',
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Rejected verbatim probe results: a shell that answered but knows no primary.
|
|
48
|
+
const MONGODB_EMPTY_PRIMARY_TOKENS = ['null', 'undefined', '[]', '[ ]', 'false', ''];
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Extracts a pod name from a primary-host probe result.
|
|
52
|
+
*
|
|
53
|
+
* Normalises the two shapes the shells emit — a bare `host:port` string from
|
|
54
|
+
* `hello`, a quoted element from the `rs.status()` projection — and ignores any
|
|
55
|
+
* banner or warning lines printed alongside them.
|
|
56
|
+
*
|
|
57
|
+
* @param {string} output - Raw probe stdout.
|
|
58
|
+
* @returns {string|null} Pod name (`mongodb-0`), or null when no host was reported.
|
|
59
|
+
* @memberof MongoBootstrap
|
|
60
|
+
*/
|
|
61
|
+
const parsePrimaryHost = (output) => {
|
|
62
|
+
if (!output) return null;
|
|
63
|
+
const lines = `${output}`
|
|
64
|
+
.split('\n')
|
|
65
|
+
.map((line) => line.trim())
|
|
66
|
+
.filter(Boolean);
|
|
67
|
+
|
|
68
|
+
for (const line of lines.reverse()) {
|
|
69
|
+
const quoted = line.match(/['"]([^'"]+)['"]/);
|
|
70
|
+
const candidate = (quoted ? quoted[1] : line).trim();
|
|
71
|
+
if (MONGODB_EMPTY_PRIMARY_TOKENS.includes(candidate.toLowerCase())) continue;
|
|
72
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*(:\d+)?$/.test(candidate)) continue;
|
|
73
|
+
return candidate.split(':')[0].split('.')[0];
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Extracts the two replica set identities from a heartbeat rejection.
|
|
80
|
+
*
|
|
81
|
+
* mongod reports `Our replica set ID did not match that of our request target` when two
|
|
82
|
+
* members carry different set IDs — the signature of one member having been re-initiated on
|
|
83
|
+
* an empty volume while the others kept the original set.
|
|
84
|
+
*
|
|
85
|
+
* @param {string} output - Combined stdout/stderr of a mongosh bootstrap attempt.
|
|
86
|
+
* @returns {{selfSetId: string, target: string, targetSetId: string}|null} Parsed identities, or null.
|
|
87
|
+
* @memberof MongoBootstrap
|
|
88
|
+
*/
|
|
89
|
+
const parseDivergentSetIds = (output) => {
|
|
90
|
+
const match = `${output || ''}`.match(
|
|
91
|
+
/replSetId:\s*([0-9a-f]+),\s*requestTarget:\s*([^,]+),\s*requestTargetReplSetId:\s*([0-9a-f]+)/,
|
|
92
|
+
);
|
|
93
|
+
if (!match) return null;
|
|
94
|
+
return { selfSetId: match[1], target: match[2].trim(), targetSetId: match[3] };
|
|
95
|
+
};
|
|
96
|
+
|
|
32
97
|
// Teardown sweeps ordinals rather than a live replica count: the deployed count is not knowable
|
|
33
98
|
// during a reset, and a member left behind from a larger previous deployment keeps its volume and
|
|
34
99
|
// stale replica-set config, which a later deploy then trips over.
|
|
@@ -90,7 +155,7 @@ class MongoBootstrap {
|
|
|
90
155
|
rootUser,
|
|
91
156
|
rootPassword,
|
|
92
157
|
}) {
|
|
93
|
-
const mePort =
|
|
158
|
+
const mePort = MONGODB_DEFAULT_PORT;
|
|
94
159
|
const defaultShortHosts = Array.from(
|
|
95
160
|
{ length: replicaCount },
|
|
96
161
|
(_, i) => `${statefulSetName}-${i}.${serviceName}:${mePort}`,
|
|
@@ -102,8 +167,13 @@ class MongoBootstrap {
|
|
|
102
167
|
};
|
|
103
168
|
|
|
104
169
|
return [
|
|
105
|
-
`const mePort = "27017";`,
|
|
106
170
|
`const desiredConfig = ${JSON.stringify(desiredConfig)};`,
|
|
171
|
+
// Single-member bootstrap and recovery configs name this node by the same host it
|
|
172
|
+
// advertises in the final config, never `localhost`. A client that connects while the
|
|
173
|
+
// set is still one member long copies that member into its topology, and inside any
|
|
174
|
+
// other pod `localhost:27017` is that pod itself — the client then sits on an
|
|
175
|
+
// unreachable member and never recovers.
|
|
176
|
+
`const selfHost = desiredConfig.members[0].host;`,
|
|
107
177
|
`const rootUser = ${JSON.stringify(rootUser)};`,
|
|
108
178
|
`const rootPassword = ${JSON.stringify(rootPassword)};`,
|
|
109
179
|
|
|
@@ -166,7 +236,7 @@ class MongoBootstrap {
|
|
|
166
236
|
` const soloConfig = {`,
|
|
167
237
|
` _id: desiredConfig._id,`,
|
|
168
238
|
` version: currentConfigVersion() + 1,`,
|
|
169
|
-
` members: [{ _id: 0, host:
|
|
239
|
+
` members: [{ _id: 0, host: selfHost }],`,
|
|
170
240
|
` };`,
|
|
171
241
|
` rs.reconfig(soloConfig, { force: true });`,
|
|
172
242
|
` print("SUCCESS_FORCE_RECONFIGURED");`,
|
|
@@ -178,7 +248,12 @@ class MongoBootstrap {
|
|
|
178
248
|
` const curHosts = cur.members.map(m => m.host).sort().join(",");`,
|
|
179
249
|
` const nextHosts = desiredConfig.members.map(m => m.host).sort().join(",");`,
|
|
180
250
|
` if (curHosts !== nextHosts || cur._id !== desiredConfig._id) {`,
|
|
181
|
-
|
|
251
|
+
// Not forced: this runs on a node waitPrimary() just confirmed is writable, so an
|
|
252
|
+
// ordinary reconfig applies and bumps the version by one. A forced reconfig instead
|
|
253
|
+
// jumps the config version and election id by a random amount, and drivers that
|
|
254
|
+
// recorded the higher values reject the legitimate primary as stale for the rest of
|
|
255
|
+
// the process lifetime — pods come back as `ReplicaSetNoPrimary` and stay there.
|
|
256
|
+
` rs.reconfig({...desiredConfig, version: (cur.version || 1) + 1});`,
|
|
182
257
|
` print("SUCCESS_RECONFIGURED");`,
|
|
183
258
|
` } else {`,
|
|
184
259
|
` print("SUCCESS_ALREADY_MATCHES");`,
|
|
@@ -212,7 +287,7 @@ class MongoBootstrap {
|
|
|
212
287
|
|
|
213
288
|
`if (state === "pristine") {`,
|
|
214
289
|
` try {`,
|
|
215
|
-
` rs.initiate({ _id: desiredConfig._id, members: [{ _id: 0, host:
|
|
290
|
+
` rs.initiate({ _id: desiredConfig._id, members: [{ _id: 0, host: selfHost }] });`,
|
|
216
291
|
` } catch(e) {`,
|
|
217
292
|
` const msg = String(e);`,
|
|
218
293
|
` if (!msg.includes("already initialized") && !msg.includes("AlreadyInitialized")) throw e;`,
|
|
@@ -301,14 +376,15 @@ class MongoBootstrap {
|
|
|
301
376
|
}
|
|
302
377
|
|
|
303
378
|
/**
|
|
304
|
-
* Reads MongoDB root credentials from
|
|
305
|
-
*
|
|
379
|
+
* Reads MongoDB root credentials from their origin seed files.
|
|
380
|
+
* Paths come from the workload secret domain, so this never spells out a credential path.
|
|
306
381
|
* @returns {{ username: string, password: string }}
|
|
307
382
|
*/
|
|
308
|
-
static readMongoCredentials(
|
|
383
|
+
static readMongoCredentials() {
|
|
384
|
+
const sources = Underpost.secret.seedSources('mongodb-secret');
|
|
309
385
|
return {
|
|
310
|
-
username: MongoBootstrap.readCredential(
|
|
311
|
-
password: MongoBootstrap.readCredential(
|
|
386
|
+
username: MongoBootstrap.readCredential(sources.username),
|
|
387
|
+
password: MongoBootstrap.readCredential(sources.password),
|
|
312
388
|
};
|
|
313
389
|
}
|
|
314
390
|
|
|
@@ -324,32 +400,59 @@ class MongoBootstrap {
|
|
|
324
400
|
* in the process table and the command log; `disableLog` keeps it out of the log at least. The
|
|
325
401
|
* encrypted path has no such exposure — the value only ever crosses an anonymous pipe.
|
|
326
402
|
* @param {string} namespace - Target namespace.
|
|
327
|
-
* @param {string} enginePrivateRoot - Path to engine-private directory.
|
|
328
403
|
*/
|
|
329
|
-
static ensureMongoSecrets(namespace
|
|
330
|
-
|
|
331
|
-
|
|
404
|
+
static ensureMongoSecrets(namespace) {
|
|
405
|
+
const keyfilePath = Underpost.secret.seedSources('mongodb-keyfile')['mongodb-keyfile'];
|
|
406
|
+
if (!Underpost.secret.applyIfPresent('mongodb-keyfile', namespace)) {
|
|
407
|
+
const keyfile = MongoBootstrap.readCredential(keyfilePath);
|
|
332
408
|
shellExec(
|
|
333
409
|
`sudo kubectl create secret generic mongodb-keyfile` +
|
|
334
410
|
` --from-literal=mongodb-keyfile="${keyfile.replace(/'/g, "'\\''")}"` +
|
|
335
411
|
` --dry-run=client -o yaml | kubectl apply -f - -n ${namespace}`,
|
|
336
412
|
{ disableLog: true },
|
|
337
413
|
);
|
|
338
|
-
logger.info(`Seeded mongodb-keyfile from ${
|
|
414
|
+
logger.info(`Seeded mongodb-keyfile from ${keyfilePath}`);
|
|
339
415
|
}
|
|
340
416
|
|
|
341
|
-
if (!Underpost.secret.
|
|
342
|
-
const { username, password } = MongoBootstrap.readMongoCredentials(
|
|
417
|
+
if (!Underpost.secret.applyIfPresent('mongodb-secret', namespace)) {
|
|
418
|
+
const { username, password } = MongoBootstrap.readMongoCredentials();
|
|
343
419
|
shellExec(
|
|
344
420
|
`sudo kubectl create secret generic mongodb-secret` +
|
|
345
421
|
` --from-literal=username="${username}" --from-literal=password="${password}"` +
|
|
346
422
|
` --dry-run=client -o yaml | kubectl apply -f - -n ${namespace}`,
|
|
347
423
|
{ disableLog: true },
|
|
348
424
|
);
|
|
349
|
-
logger.info(
|
|
425
|
+
logger.info('Seeded mongodb-secret from origin seed files');
|
|
350
426
|
}
|
|
351
427
|
}
|
|
352
428
|
|
|
429
|
+
/**
|
|
430
|
+
* Creates the replica data directories and gives the tree the shared container label.
|
|
431
|
+
*
|
|
432
|
+
* The PVs are `hostPath` with `type: DirectoryOrCreate`, so kubelet will happily create a
|
|
433
|
+
* missing member directory — with whatever context its parent carries. `/data` has no mapping
|
|
434
|
+
* in the base RHEL policy, so that context is `default_t`, which `container_t` cannot write:
|
|
435
|
+
* mongod's checkpointer and `ftdc` writer then fail on every `WiredTiger.turtle.set` rename and
|
|
436
|
+
* `metrics.interim.temp` create. Registering the mapping and restoring the tree here makes the
|
|
437
|
+
* label a property of the directory rather than of whoever happened to create it, and it
|
|
438
|
+
* survives a policy update or a full relabel.
|
|
439
|
+
*
|
|
440
|
+
* Only the directories are created; ownership and mode are left to the StatefulSet's
|
|
441
|
+
* `data-dir-permissions` init container, which is the single owner of that concern.
|
|
442
|
+
* @param {number} replicaCount - Number of member directories to prepare.
|
|
443
|
+
* @param {{execute?: Function}} [options] - Command executor, injectable for tests.
|
|
444
|
+
* @returns {string[]} Prepared paths.
|
|
445
|
+
* @memberof MongoBootstrap
|
|
446
|
+
*/
|
|
447
|
+
static prepareReplicaDataRoot(replicaCount, { execute = shellExec } = {}) {
|
|
448
|
+
const paths = [
|
|
449
|
+
MONGODB_DATA_ROOT,
|
|
450
|
+
...Array.from({ length: Math.max(0, Number(replicaCount) || 0) }, (_, i) => `${MONGODB_DATA_ROOT}/v${i}`),
|
|
451
|
+
];
|
|
452
|
+
ensureContainerStorage(paths, { execute });
|
|
453
|
+
return paths;
|
|
454
|
+
}
|
|
455
|
+
|
|
353
456
|
/**
|
|
354
457
|
* Renders one hostPath PersistentVolume per replica, each pre-bound to that member's claim.
|
|
355
458
|
*
|
|
@@ -484,25 +587,6 @@ class MongoBootstrap {
|
|
|
484
587
|
);
|
|
485
588
|
}
|
|
486
589
|
|
|
487
|
-
/**
|
|
488
|
-
* Waits for all MongoDB statefulset pods to reach Running state.
|
|
489
|
-
* @param {string} namespace - Target namespace.
|
|
490
|
-
* @param {number} replicaCount - Expected number of pods.
|
|
491
|
-
* @returns {Promise<number>} Number of pods that failed to become ready (0 = all good).
|
|
492
|
-
*/
|
|
493
|
-
static async waitForPods(namespace, replicaCount) {
|
|
494
|
-
let failedCount = 0;
|
|
495
|
-
for (let i = 0; i < replicaCount; i++) {
|
|
496
|
-
const podName = `${MONGODB_STATEFULSET_NAME}-${i}`;
|
|
497
|
-
const result = shellExec(`kubectl wait --for=condition=Ready pod/${podName} -n ${namespace} --timeout=60s`);
|
|
498
|
-
if (result.code !== 0) {
|
|
499
|
-
logger.error(`Pod ${podName} did not become ready`);
|
|
500
|
-
failedCount++;
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
return failedCount;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
590
|
/**
|
|
507
591
|
* Full MongoDB replica set initialization.
|
|
508
592
|
*
|
|
@@ -523,7 +607,6 @@ class MongoBootstrap {
|
|
|
523
607
|
underpostRoot,
|
|
524
608
|
} = options;
|
|
525
609
|
|
|
526
|
-
const enginePrivateRoot = `${process.cwd()}/engine-private`;
|
|
527
610
|
// No upward clamp: an explicit `--replicas 2` must deploy two members, not be silently
|
|
528
611
|
// raised to the default.
|
|
529
612
|
const effectiveReplicaCount = resolveReplicaCount(replicaCount, MONGODB_DEFAULT_REPLICA_COUNT);
|
|
@@ -533,8 +616,7 @@ class MongoBootstrap {
|
|
|
533
616
|
`majority when one member is down, so the set becomes read-only on a single failure. ` +
|
|
534
617
|
`Odd counts (3, 5) are recommended.`,
|
|
535
618
|
);
|
|
536
|
-
const mongoRootUsername = MongoBootstrap.
|
|
537
|
-
const mongoRootPassword = MongoBootstrap.readCredential(`${enginePrivateRoot}/mongodb-password`);
|
|
619
|
+
const { username: mongoRootUsername, password: mongoRootPassword } = MongoBootstrap.readMongoCredentials();
|
|
538
620
|
const mongoReplicaHosts = resolveMongoReplicaHosts({
|
|
539
621
|
hostList,
|
|
540
622
|
replicaCount: effectiveReplicaCount,
|
|
@@ -578,7 +660,7 @@ class MongoBootstrap {
|
|
|
578
660
|
}
|
|
579
661
|
|
|
580
662
|
// Secrets
|
|
581
|
-
MongoBootstrap.ensureMongoSecrets(namespace
|
|
663
|
+
MongoBootstrap.ensureMongoSecrets(namespace);
|
|
582
664
|
|
|
583
665
|
// Tear down existing statefulset
|
|
584
666
|
shellExec(`kubectl delete statefulset ${MONGODB_STATEFULSET_NAME} -n ${namespace} --ignore-not-found`);
|
|
@@ -614,8 +696,11 @@ class MongoBootstrap {
|
|
|
614
696
|
shellExec(`sudo mkdir -p ${MONGODB_DATA_ROOT}`);
|
|
615
697
|
for (let i = 0; i < effectiveReplicaCount; i++) {
|
|
616
698
|
shellExec(`sudo rm -rf ${MONGODB_DATA_ROOT}/v${i}`);
|
|
617
|
-
shellExec(`sudo mkdir -p ${MONGODB_DATA_ROOT}/v${i}`);
|
|
618
699
|
}
|
|
700
|
+
// A directory recreated after a wipe inherits its parent's context, and the WiredTiger
|
|
701
|
+
// files mongod then creates inherit that in turn — so recreate and relabel here, before the
|
|
702
|
+
// Kind remount below binds these inodes into the node containers.
|
|
703
|
+
MongoBootstrap.prepareReplicaDataRoot(effectiveReplicaCount);
|
|
619
704
|
// Fix any stale bind mounts caused by prior deletion of /data/mongodb on the host
|
|
620
705
|
if (isKind) MongoBootstrap.remountKindMongoVolume(kindNodes, effectiveReplicaCount);
|
|
621
706
|
}
|
|
@@ -637,6 +722,10 @@ class MongoBootstrap {
|
|
|
637
722
|
shellExec(`kubectl delete storageclass ${MONGODB_STORAGE_CLASS_NAME} --ignore-not-found`);
|
|
638
723
|
}
|
|
639
724
|
shellExec(`kubectl apply -f ${underpostRoot}/manifests/mongodb/storage-class.yaml -n ${namespace}`);
|
|
725
|
+
// Unconditional, not only on the reset path: an existing cluster's member directories were
|
|
726
|
+
// created before the mapping existed (or by kubelet's `DirectoryOrCreate`), so they carry the
|
|
727
|
+
// policy default until this runs. Idempotent, and it never touches the data itself.
|
|
728
|
+
MongoBootstrap.prepareReplicaDataRoot(effectiveReplicaCount);
|
|
640
729
|
// One PV per member, generated from the effective replica count. A static manifest can only
|
|
641
730
|
// ever describe a fixed number, so any `--replicas` above it leaves the extra members with no
|
|
642
731
|
// volume to bind and the StatefulSet stalls forever on Pending.
|
|
@@ -647,13 +736,16 @@ class MongoBootstrap {
|
|
|
647
736
|
);
|
|
648
737
|
|
|
649
738
|
// Wait for all pods
|
|
650
|
-
const
|
|
651
|
-
|
|
739
|
+
const failedPods = await Underpost.kubectl.waitForPodsReady({
|
|
740
|
+
namespace,
|
|
741
|
+
podNames: Array.from({ length: effectiveReplicaCount }, (_, i) => `${MONGODB_STATEFULSET_NAME}-${i}`),
|
|
742
|
+
});
|
|
743
|
+
if (failedPods.length > 0) {
|
|
652
744
|
// Surface the volume topology before failing: a stalled rollout is far more often a binding
|
|
653
745
|
// problem than a MongoDB one, and the mapping names it immediately.
|
|
654
746
|
MongoBootstrap.reportReplicaVolumeBindings(namespace, effectiveReplicaCount);
|
|
655
747
|
throw new Error(
|
|
656
|
-
`MongoDB replica pods did not reach Running state in time. ` +
|
|
748
|
+
`MongoDB replica pods did not reach Running state in time: ${failedPods.join(', ')}. ` +
|
|
657
749
|
`Ensure podManagementPolicy is set to OrderedReady in statefulset.yaml.`,
|
|
658
750
|
);
|
|
659
751
|
}
|
|
@@ -663,7 +755,7 @@ class MongoBootstrap {
|
|
|
663
755
|
// Build the bootstrap script
|
|
664
756
|
const defaultHosts = Array.from(
|
|
665
757
|
{ length: effectiveReplicaCount },
|
|
666
|
-
(_, i) => `${MONGODB_STATEFULSET_NAME}-${i}.${MONGODB_SERVICE_NAME}
|
|
758
|
+
(_, i) => `${MONGODB_STATEFULSET_NAME}-${i}.${MONGODB_SERVICE_NAME}:${MONGODB_DEFAULT_PORT}`,
|
|
667
759
|
);
|
|
668
760
|
const desiredHosts = useExplicitHosts ? mongoReplicaHosts : defaultHosts;
|
|
669
761
|
|
|
@@ -697,32 +789,46 @@ class MongoBootstrap {
|
|
|
697
789
|
);
|
|
698
790
|
};
|
|
699
791
|
|
|
792
|
+
// Two members holding different replica set IDs cannot be merged — every heartbeat
|
|
793
|
+
// between them is rejected — so retrying only repeats the same failure. Diagnose it once
|
|
794
|
+
// and stop: choosing which identity survives means discarding the other member's data,
|
|
795
|
+
// which is never safe to decide automatically.
|
|
796
|
+
const assertSetIdentityMatch = (result) => {
|
|
797
|
+
const divergent = parseDivergentSetIds(`${result.stdout || ''}${result.stderr || ''}`);
|
|
798
|
+
if (!divergent) return;
|
|
799
|
+
throw new Error(
|
|
800
|
+
`MongoDB members belong to different replica sets: ${MONGODB_STATEFULSET_NAME}-0 holds replSetId ` +
|
|
801
|
+
`${divergent.selfSetId}, ${divergent.target} holds ${divergent.targetSetId}. A set cannot merge two ` +
|
|
802
|
+
`identities. Find which volume under ${MONGODB_DATA_ROOT} holds the data to keep, back it up, then ` +
|
|
803
|
+
`wipe the other members' volumes so they resync from the survivor.`,
|
|
804
|
+
);
|
|
805
|
+
};
|
|
806
|
+
|
|
700
807
|
let success = false;
|
|
701
808
|
const maxAttempts = 5;
|
|
702
809
|
|
|
703
810
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
704
811
|
const noAuthResult = execMongoCmd(false);
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
break;
|
|
711
|
-
}
|
|
712
|
-
logger.warn('No-auth bootstrap succeeded but auth verify failed, retrying...', { attempt });
|
|
713
|
-
} else {
|
|
714
|
-
success = true;
|
|
715
|
-
break;
|
|
716
|
-
}
|
|
717
|
-
} else {
|
|
718
|
-
const authResult = execMongoCmd(true);
|
|
719
|
-
if (authResult.code === 0) {
|
|
720
|
-
success = true;
|
|
721
|
-
break;
|
|
722
|
-
}
|
|
723
|
-
logger.warn('Both bootstrap paths failed, retrying...', { attempt });
|
|
812
|
+
assertSetIdentityMatch(noAuthResult);
|
|
813
|
+
|
|
814
|
+
if (noAuthResult.code === 0 && !(mongoRootUsername && mongoRootPassword)) {
|
|
815
|
+
success = true;
|
|
816
|
+
break;
|
|
724
817
|
}
|
|
725
818
|
|
|
819
|
+
const authResult = execMongoCmd(true);
|
|
820
|
+
assertSetIdentityMatch(authResult);
|
|
821
|
+
if (authResult.code === 0) {
|
|
822
|
+
success = true;
|
|
823
|
+
break;
|
|
824
|
+
}
|
|
825
|
+
logger.warn(
|
|
826
|
+
noAuthResult.code === 0
|
|
827
|
+
? 'No-auth bootstrap succeeded but auth verify failed, retrying...'
|
|
828
|
+
: 'Both bootstrap paths failed, retrying...',
|
|
829
|
+
{ attempt },
|
|
830
|
+
);
|
|
831
|
+
|
|
726
832
|
if (attempt < maxAttempts) {
|
|
727
833
|
await new Promise((r) => setTimeout(r, 3000));
|
|
728
834
|
}
|
|
@@ -780,7 +886,7 @@ class MongoBootstrap {
|
|
|
780
886
|
// Also catch any remaining PVs with the app=mongodb label
|
|
781
887
|
shellExec(`kubectl delete pv -l app=mongodb --ignore-not-found`);
|
|
782
888
|
// Wait for PVs to be fully deleted to avoid "object modified" conflict on re-apply
|
|
783
|
-
shellExec(`kubectl wait --for=delete pv mongodb-pv-0 mongodb-pv-1 mongodb-pv-2 mongodb-pv --timeout=
|
|
889
|
+
shellExec(`kubectl wait --for=delete pv mongodb-pv-0 mongodb-pv-1 mongodb-pv-2 mongodb-pv --timeout=180s`, {
|
|
784
890
|
silentOnError: true,
|
|
785
891
|
});
|
|
786
892
|
|
|
@@ -794,8 +900,8 @@ class MongoBootstrap {
|
|
|
794
900
|
shellExec(`sudo mkdir -p ${MONGODB_DATA_ROOT}`);
|
|
795
901
|
for (let i = 0; i < MONGODB_ORDINAL_SWEEP; i++) {
|
|
796
902
|
shellExec(`sudo rm -rf ${MONGODB_DATA_ROOT}/v${i}`);
|
|
797
|
-
shellExec(`sudo mkdir -p ${MONGODB_DATA_ROOT}/v${i}`);
|
|
798
903
|
}
|
|
904
|
+
MongoBootstrap.prepareReplicaDataRoot(MONGODB_ORDINAL_SWEEP);
|
|
799
905
|
// For Kind: repair any stale bind mounts via nsenter (overmounts with current host inode)
|
|
800
906
|
if (isKind) {
|
|
801
907
|
const nodesRaw = shellExec('kind get nodes', { stdout: true, silent: true, silentOnError: true });
|
|
@@ -819,13 +925,22 @@ class MongoBootstrap {
|
|
|
819
925
|
|
|
820
926
|
/**
|
|
821
927
|
* Gets the primary MongoDB pod name from replica set status.
|
|
928
|
+
*
|
|
929
|
+
* Probing is bounded on every axis, because an unbounded probe is what makes the
|
|
930
|
+
* backup pipeline stall: the driver connects `directConnection` so it never tries
|
|
931
|
+
* to reach sibling members by DNS, each shell call carries explicit server-selection
|
|
932
|
+
* timeouts, and the whole `kubectl exec` is wrapped in a wall-clock budget. The
|
|
933
|
+
* cheapest probe (`hello`, which the server answers before authentication) runs
|
|
934
|
+
* first, so a healthy replica set resolves without credentials at all.
|
|
935
|
+
*
|
|
822
936
|
* @param {object} [options] - Query options.
|
|
823
937
|
* @param {string} [options.namespace='default'] - Kubernetes namespace.
|
|
824
|
-
* @param {string} [options.podName='mongodb-0'] -
|
|
938
|
+
* @param {string} [options.podName='mongodb-0'] - Preferred MongoDB pod to query first.
|
|
825
939
|
* @param {string} [options.username] - MongoDB admin username.
|
|
826
940
|
* @param {string} [options.password] - MongoDB admin password.
|
|
827
941
|
* @param {string} [options.authDatabase='admin'] - Auth database.
|
|
828
942
|
* @param {boolean} [options.disableAuth=false] - Whether to disable auth in the query (for testing).
|
|
943
|
+
* @param {number} [options.probeTimeoutSeconds=45] - Wall-clock budget per shell probe.
|
|
829
944
|
* @returns {string|null} Primary pod name, or null if not found.
|
|
830
945
|
*/
|
|
831
946
|
static getPrimaryPodName(options = {}) {
|
|
@@ -836,6 +951,7 @@ class MongoBootstrap {
|
|
|
836
951
|
password,
|
|
837
952
|
authDatabase = 'admin',
|
|
838
953
|
disableAuth = false,
|
|
954
|
+
probeTimeoutSeconds = MONGODB_PRIMARY_PROBE_TIMEOUT_SECONDS,
|
|
839
955
|
} = options;
|
|
840
956
|
|
|
841
957
|
const readTrimmedFile = (filePath) => {
|
|
@@ -851,48 +967,104 @@ class MongoBootstrap {
|
|
|
851
967
|
username ||
|
|
852
968
|
process.env.MONGODB_USERNAME ||
|
|
853
969
|
process.env.DB_USER ||
|
|
854
|
-
readTrimmedFile('
|
|
970
|
+
readTrimmedFile(Underpost.secret.seedSources('mongodb-secret').username);
|
|
855
971
|
const mongoPass =
|
|
856
972
|
password ||
|
|
857
973
|
process.env.MONGODB_PASSWORD ||
|
|
858
974
|
process.env.DB_PASSWORD ||
|
|
859
|
-
readTrimmedFile('
|
|
975
|
+
readTrimmedFile(Underpost.secret.seedSources('mongodb-secret').password);
|
|
976
|
+
|
|
977
|
+
const candidates = MongoBootstrap.resolvePrimaryProbeCandidates({ namespace, podName });
|
|
978
|
+
const probes = MongoBootstrap.primaryProbeFactory({
|
|
979
|
+
disableAuth,
|
|
980
|
+
username: mongoUser,
|
|
981
|
+
password: mongoPass,
|
|
982
|
+
authDatabase,
|
|
983
|
+
});
|
|
860
984
|
|
|
861
|
-
|
|
862
|
-
|
|
985
|
+
for (const candidate of candidates) {
|
|
986
|
+
if (!Underpost.kubectl.ensureExecReady({ podName: candidate, namespace })) continue;
|
|
863
987
|
|
|
864
|
-
|
|
988
|
+
for (const probe of probes) {
|
|
989
|
+
const output = shellExec(
|
|
990
|
+
`timeout --kill-after=10s ${probeTimeoutSeconds}s ` +
|
|
991
|
+
`sudo kubectl exec -n ${namespace} -i ${candidate} -- ${probe.command}`,
|
|
992
|
+
{ stdout: true, silent: true, silentOnError: true, disableLog: true },
|
|
993
|
+
);
|
|
994
|
+
const primary = parsePrimaryHost(output);
|
|
995
|
+
if (primary) {
|
|
996
|
+
logger.info('Found MongoDB primary pod', { primary, probedFrom: candidate, probe: probe.id });
|
|
997
|
+
return primary;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
865
1000
|
|
|
866
|
-
|
|
1001
|
+
logger.warn('MongoDB pod answered no primary', { podName: candidate, namespace });
|
|
1002
|
+
}
|
|
867
1003
|
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
silentOnError: true,
|
|
872
|
-
});
|
|
1004
|
+
logger.warn('No MongoDB primary pod found.', { namespace, candidates });
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
873
1007
|
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
1008
|
+
/**
|
|
1009
|
+
* Resolves which pods to interrogate for the replica-set primary, preferred pod first.
|
|
1010
|
+
*
|
|
1011
|
+
* Any reachable member knows who the primary is, so a member that is mid-restart
|
|
1012
|
+
* must not end the search — the caller would otherwise fall back to a pod that is
|
|
1013
|
+
* merely first in the list rather than the one accepting writes.
|
|
1014
|
+
*
|
|
1015
|
+
* @param {object} params
|
|
1016
|
+
* @param {string} params.namespace - Kubernetes namespace.
|
|
1017
|
+
* @param {string} params.podName - Preferred pod to probe first.
|
|
1018
|
+
* @returns {string[]} Ordered, de-duplicated pod names.
|
|
1019
|
+
*/
|
|
1020
|
+
static resolvePrimaryProbeCandidates({ namespace, podName }) {
|
|
1021
|
+
const candidates = podName ? [podName] : [];
|
|
1022
|
+
try {
|
|
1023
|
+
for (const pod of Underpost.kubectl.get(MONGODB_STATEFULSET_NAME, 'pods', namespace)) {
|
|
1024
|
+
if (!pod.NAME || pod.STATUS !== 'Running') continue;
|
|
1025
|
+
if (!candidates.includes(pod.NAME)) candidates.push(pod.NAME);
|
|
1026
|
+
}
|
|
1027
|
+
} catch (error) {
|
|
1028
|
+
logger.warn('Could not list MongoDB pods, probing the requested pod only', {
|
|
1029
|
+
namespace,
|
|
1030
|
+
error: error.message,
|
|
1031
|
+
});
|
|
881
1032
|
}
|
|
1033
|
+
return candidates;
|
|
1034
|
+
}
|
|
882
1035
|
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
1036
|
+
/**
|
|
1037
|
+
* Builds the ordered probe list used to resolve the replica-set primary.
|
|
1038
|
+
* @param {object} params
|
|
1039
|
+
* @param {boolean} params.disableAuth - Legacy `mongo` shell without credentials.
|
|
1040
|
+
* @param {string} params.username - MongoDB username, when available.
|
|
1041
|
+
* @param {string} params.password - MongoDB password, when available.
|
|
1042
|
+
* @param {string} params.authDatabase - Auth database for credentialed probes.
|
|
1043
|
+
* @returns {Array<{id: string, command: string}>} Probes in cheapest-first order.
|
|
1044
|
+
*/
|
|
1045
|
+
static primaryProbeFactory({ disableAuth, username, password, authDatabase }) {
|
|
1046
|
+
if (disableAuth)
|
|
1047
|
+
return [
|
|
1048
|
+
{ id: 'legacy-isMaster', command: `mongo --quiet --eval '${MONGODB_PRIMARY_EVAL.isMaster}'` },
|
|
1049
|
+
{ id: 'legacy-rs-status', command: `mongo --quiet --eval '${MONGODB_PRIMARY_EVAL.rsStatus}'` },
|
|
1050
|
+
];
|
|
1051
|
+
|
|
1052
|
+
const shell = `mongosh ${JSON.stringify(MONGODB_PRIMARY_PROBE_URI)} --quiet`;
|
|
1053
|
+
const authFlags =
|
|
1054
|
+
username && password
|
|
1055
|
+
? ` --authenticationDatabase ${JSON.stringify(authDatabase)} -u ${JSON.stringify(username)} -p ${JSON.stringify(password)}`
|
|
1056
|
+
: '';
|
|
887
1057
|
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
1058
|
+
// `hello` is answered before authentication, so it resolves the primary even when
|
|
1059
|
+
// the credentials at hand are an app user without cluster-monitor rights.
|
|
1060
|
+
const probes = [{ id: 'hello', command: `${shell} --eval '${MONGODB_PRIMARY_EVAL.hello}'` }];
|
|
1061
|
+
if (authFlags) {
|
|
1062
|
+
probes.push({ id: 'hello-auth', command: `${shell}${authFlags} --eval '${MONGODB_PRIMARY_EVAL.hello}'` });
|
|
1063
|
+
probes.push({ id: 'rs-status-auth', command: `${shell}${authFlags} --eval '${MONGODB_PRIMARY_EVAL.rsStatus}'` });
|
|
893
1064
|
}
|
|
894
|
-
|
|
1065
|
+
probes.push({ id: 'rs-status', command: `${shell} --eval '${MONGODB_PRIMARY_EVAL.rsStatus}'` });
|
|
1066
|
+
return probes;
|
|
895
1067
|
}
|
|
896
1068
|
}
|
|
897
1069
|
|
|
898
|
-
export { MongoBootstrap };
|
|
1070
|
+
export { MongoBootstrap, parsePrimaryHost, parseDivergentSetIds, MONGODB_PRIMARY_PROBE_URI };
|