@underpostnet/cyberia 3.2.90 → 3.3.73
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 +16 -0
- package/.github/workflows/coverall.cyberia.ci.yml +107 -0
- package/.github/workflows/cyberia-client.cd.yml +6 -18
- package/.github/workflows/cyberia-server.cd.yml +6 -18
- 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 +6 -78
- package/.github/workflows/engine-cyberia.ci.yml +4 -5
- package/.github/workflows/ghpkg.ci.yml +42 -21
- package/.github/workflows/hardhat.ci.yml +12 -11
- package/.github/workflows/npmpkg.ci.yml +17 -15
- package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -16
- package/.github/workflows/pwa-microservices-template-test.ci.yml +2 -2
- package/.github/workflows/release.cd.yml +2 -9
- package/.prettierignore +1 -0
- package/AGENTS.md +47 -0
- package/CHANGELOG.md +581 -2417
- package/CLI-HELP.md +416 -127
- package/Dockerfile +25 -9
- package/Dockerfile.dev +25 -9
- package/Dockerfile.test +4 -4
- package/README.md +21 -1
- package/bin/build.js +70 -43
- package/bin/build.template.js +8 -3
- package/bin/cyberia.js +372 -135
- package/bin/deploy.js +18 -104
- package/bin/index.js +372 -135
- package/compose.env +16 -0
- package/conf.js +93 -4
- package/deploy/cyberia-client/deploy.sh +47 -0
- package/deploy/cyberia-client/package.sh +18 -0
- package/deploy/cyberia-client/state.sh +14 -0
- package/deploy/cyberia-server/deploy.sh +47 -0
- package/deploy/cyberia-server/package.sh +18 -0
- package/deploy/cyberia-server/state.sh +14 -0
- package/deploy/dd-cyberia/deploy.sh +22 -0
- package/deploy/dd-cyberia/init.sh +55 -0
- package/deploy/dd-cyberia/package.sh +17 -0
- package/deploy/dd-cyberia/state.sh +14 -0
- package/deploy/dd-cyberia/sync-deploy.sh +116 -0
- package/deploy/lib/github-actions-logging.sh +594 -0
- package/deploy/lib/host.sh +185 -0
- package/deploy/lib/state.sh +62 -0
- package/deploy/pwa-microservices-template/deploy.sh +45 -0
- package/deploy/release/deploy.sh +32 -0
- package/deployment.yaml +7 -2
- package/docker-compose.yml +31 -37
- 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 +104 -43
- package/hardhat/package.json +3 -3
- package/manifests/alertmanager/deployment.yaml +81 -0
- package/manifests/blackbox-exporter/deployment.yaml +75 -0
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +36 -7
- package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +77 -0
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +7 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- 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 +83 -10
- package/scripts/audit-selinux.sh +64 -0
- package/scripts/event-monitor.sh +56 -0
- package/scripts/gpu-diag.sh +0 -0
- package/scripts/ip-info.sh +0 -0
- package/scripts/k3s-node-setup.sh +30 -14
- package/scripts/kubeadm-node-setup.sh +40 -31
- package/scripts/lxd-vm-setup.sh +0 -0
- package/scripts/maas-nat-firewalld.sh +0 -0
- package/scripts/maas-setup.sh +8 -8
- package/scripts/nat-iptables.sh +2 -0
- package/scripts/rhel-grpc-setup.sh +0 -0
- package/scripts/rocky-kickstart.sh +25 -9
- package/scripts/selinux-normalize.sh +907 -0
- package/scripts/shutdown-machine.sh +843 -0
- package/scripts/test-monitor.sh +3 -3
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +1 -1
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +2 -2
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +2 -2
- 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 +1 -1
- package/src/api/cyberia-action/cyberia-action.service.js +2 -2
- package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +1 -1
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +1 -1
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +2 -2
- package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +1 -1
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +1 -1
- 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.router.js +1 -1
- package/src/api/cyberia-entity/cyberia-entity.service.js +2 -2
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +1 -1
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +1 -1
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +2 -2
- package/src/api/cyberia-instance/cyberia-fallback-capture.js +466 -0
- package/src/api/cyberia-instance/cyberia-fallback-default-items.js +63 -0
- package/src/api/cyberia-instance/cyberia-fallback-world.js +16 -1
- package/src/api/cyberia-instance/cyberia-instance-map.service.js +1 -1
- package/src/api/cyberia-instance/cyberia-instance.controller.js +4 -1
- package/src/api/cyberia-instance/cyberia-instance.router.js +15 -2
- package/src/api/cyberia-instance/cyberia-instance.service.js +45 -2
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +1 -1
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +1 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +1 -1
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +2 -2
- 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 +2 -2
- package/src/api/cyberia-quest/cyberia-quest.controller.js +1 -1
- package/src/api/cyberia-quest/cyberia-quest.router.js +1 -1
- package/src/api/cyberia-quest/cyberia-quest.service.js +2 -2
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.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 +16 -29
- package/src/api/cyberia-skill/cyberia-skill.controller.js +1 -1
- 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.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 +204 -3
- package/src/api/object-layer/object-layer.router.js +2 -2
- package/src/api/object-layer/object-layer.service.js +4 -17
- 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 +391 -0
- package/src/cli/baremetal.js +30 -36
- package/src/cli/client.js +306 -0
- package/src/cli/cloud-init.js +3 -3
- package/src/cli/cluster.js +242 -135
- package/src/cli/db.js +126 -67
- package/src/cli/deploy.js +158 -60
- 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.js +3 -3
- package/src/cli/host.js +672 -0
- package/src/cli/image.js +4 -7
- package/src/cli/index.js +426 -134
- 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 +73 -34
- package/src/cli/repository.js +564 -367
- package/src/cli/run.js +362 -654
- package/src/cli/secrets.js +2158 -964
- package/src/cli/ssh.js +651 -331
- package/src/cli/state.js +394 -0
- package/src/cli/static.js +2 -2
- package/src/cli/system.js +26 -13
- package/src/cli/test.js +199 -125
- package/src/cli/vultr.js +623 -0
- package/src/cli/wireguard.js +2930 -0
- package/src/client/components/core/CalendarCore.js +53 -96
- package/src/client/components/core/Docs.js +258 -211
- package/src/client/components/core/FileExplorer.js +0 -21
- 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/FallbackWorldEngineCyberia.js +368 -0
- package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +35 -1
- package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +4 -0
- package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +2 -2
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +4 -0
- 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 +17 -3
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +32 -5
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +1 -1
- package/src/client/public/cyberia-docs/CYBERIA.md +21 -1
- 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/WHITE-PAPER.md +1 -1
- 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-instance/cyberia-instance.service.js +40 -0
- package/src/client/services/object-layer/object-layer.management.js +4 -4
- 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 +61 -46
- package/src/client-builder/client-build-live.js +2 -2
- package/src/client-builder/client-build.js +58 -44
- 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/MongooseDB.js +11 -8
- package/src/{server/valkey.js → db/valkey/Valkey.js} +5 -4
- package/src/grpc/cyberia/grpc-server.js +1 -1
- package/src/index.js +103 -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 +1 -1
- package/src/projects/cyberia/besu-genesis-generator.js +3 -3
- package/src/projects/cyberia/catalog-cyberia.js +54 -6
- package/src/projects/cyberia/gemini-client.js +1 -1
- package/src/projects/cyberia/generate-saga.js +15 -24
- package/src/projects/cyberia/hot-reload-trigger.js +1 -1
- package/src/projects/cyberia/instance-data.js +22 -3
- package/src/projects/cyberia/ipfs-client.js +4 -4
- package/src/projects/cyberia/map-preview-generator.js +1 -1
- package/src/projects/cyberia/object-layer.js +12 -22
- package/src/projects/cyberia/semantic-layer-generator.js +1 -1
- package/src/projects/underpost/catalog-underpost.js +13 -2
- package/src/proxy.js +4 -7
- package/src/runtime/cyberia-client/Dockerfile +9 -4
- package/src/runtime/cyberia-client/Dockerfile.dev +8 -2
- package/src/runtime/cyberia-server/Dockerfile +9 -4
- package/src/runtime/cyberia-server/Dockerfile.dev +8 -2
- package/src/runtime/engine-cyberia/Dockerfile +25 -9
- package/src/runtime/engine-cyberia/Dockerfile.dev +25 -9
- package/src/runtime/engine-cyberia/Dockerfile.test +4 -4
- package/src/runtime/engine-cyberia/compose.env +16 -0
- package/src/runtime/engine-cyberia/docker-compose.yml +31 -37
- 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 +117 -0
- package/src/server/build/execution.js +402 -0
- package/src/server/build/package.js +465 -0
- package/src/server/build/testing.js +528 -0
- package/src/server/{dns.js → network/dns.js} +241 -14
- package/src/server/network/forward-proxy.js +541 -0
- package/src/server/{middlewares.js → network/middlewares.js} +59 -4
- 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/network/underpost-compression.js +186 -0
- package/src/server/{underpost-gateway.js → network/underpost-gateway.js} +26 -16
- package/src/server/{underpost-ingress.js → network/underpost-ingress.js} +19 -3
- package/src/server/{cri.js → ops/cri.js} +2 -2
- package/src/server/ops/cron.js +949 -0
- package/src/server/ops/event-notification.js +284 -0
- package/src/server/{logger.js → ops/logger.js} +108 -23
- package/src/server/ops/monitoring.js +1724 -0
- package/src/server/ops/systemd.js +259 -0
- package/src/server/{conf.js → runtime/conf.js} +521 -520
- 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 -13
- 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/security/selinux.js +185 -0
- package/src/server/{backup.js → storage/backup.js} +17 -8
- package/src/server/{data-query.js → storage/data-query.js} +1 -1
- package/src/server/{downloader.js → storage/downloader.js} +2 -2
- package/src/server/storage/repository.js +68 -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/cyberia-cli-plain-reads.test.js +30 -0
- package/test/{cyberia-instance-conf-defaults.test.js → integration/app/cyberia/cyberia-instance-conf-defaults.test.js} +2 -1
- package/test/integration/app/cyberia/cyberia-load.test.js +467 -0
- package/test/integration/app/cyberia/fallback-world-capture.test.js +253 -0
- package/test/integration/app/cyberia/object-layer-item-id.test.js +327 -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/integration/infra/1-security/selinux.test.js +69 -0
- 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 +1163 -0
- package/test/integration/infra/2-network/wireguard-edge.test.js +1731 -0
- 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/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} +47 -6
- package/test/{underpost-ingress.test.js → integration/infra/4-ingress/underpost-ingress.test.js} +56 -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 +334 -0
- package/test/unit/conf-loading.test.js +303 -0
- package/test/unit/conf-resolution.test.js +979 -0
- package/test/unit/coverage-artifact.test.js +130 -0
- package/test/{crypto.test.js → unit/crypto.test.js} +1 -1
- package/test/unit/deploy-env-resolution.test.js +38 -0
- package/test/unit/deploy-log-table.test.js +447 -0
- package/test/unit/execution-profiles.test.js +219 -0
- package/test/unit/fleet-sync-source.test.js +149 -0
- package/test/unit/logger-redaction.test.js +112 -0
- package/test/unit/package.test.js +403 -0
- package/test/unit/prepare-host.test.js +299 -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 +193 -0
- package/vitest.config.js +58 -0
- package/.nycrc +0 -9
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +0 -48
- package/manifests/mongodb/pv-pvc.yaml +0 -59
- package/scripts/link-local-underpost-cli.sh +0 -6
- 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/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/cron.js +0 -476
package/src/cli/ipfs.js
CHANGED
|
@@ -4,14 +4,19 @@
|
|
|
4
4
|
* @namespace UnderpostIPFS
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { loggerFactory } from '../server/logger.js';
|
|
8
|
-
import { shellExec } from '../server/process.js';
|
|
9
|
-
import { resolveReplicaCount } from '../server/conf.js';
|
|
7
|
+
import { loggerFactory } from '../server/ops/logger.js';
|
|
8
|
+
import { shellExec } from '../server/runtime/process.js';
|
|
9
|
+
import { resolveReplicaCount } from '../server/runtime/conf.js';
|
|
10
10
|
import fs from 'fs-extra';
|
|
11
|
+
import dir from 'node:path';
|
|
11
12
|
import Underpost from '../index.js';
|
|
12
13
|
|
|
13
14
|
const logger = loggerFactory(import.meta);
|
|
14
15
|
|
|
16
|
+
// The managed secret this module owns; its origin, its encrypted manifest and its Kubernetes
|
|
17
|
+
// projection all resolve from this one name.
|
|
18
|
+
const IPFS_SECRET_NAME = 'ipfs-cluster-secret';
|
|
19
|
+
|
|
15
20
|
const IPFS_DEFAULT_REPLICA_COUNT = 3;
|
|
16
21
|
|
|
17
22
|
/**
|
|
@@ -25,27 +30,32 @@ class UnderpostIPFS {
|
|
|
25
30
|
static API = {
|
|
26
31
|
/**
|
|
27
32
|
* @method resolveCredentials
|
|
28
|
-
* @description Resolves the IPFS cluster credentials
|
|
29
|
-
*
|
|
30
|
-
*
|
|
33
|
+
* @description Resolves the IPFS cluster origin credentials, generating them when absent
|
|
34
|
+
* (hex cluster secret + peer identity via ipfs-cluster-service init) and persisting them
|
|
35
|
+
* with mode 0o600.
|
|
36
|
+
*
|
|
37
|
+
* Paths come from the workload secret domain, so this module names no credential path of its
|
|
38
|
+
* own and the pair sits in the deploy secret area with every other origin credential.
|
|
39
|
+
*
|
|
31
40
|
* Idempotent and self-healing: an existing pair is reused untouched, and a missing or
|
|
32
41
|
* unreadable one is regenerated. Both files are always rewritten together — the peer id and
|
|
33
42
|
* the private key are two halves of one identity, so reusing one with a freshly minted other
|
|
34
43
|
* would advertise a peer id that does not match the key.
|
|
35
|
-
* @param {string} privateDir - Absolute path to the engine-private directory.
|
|
36
44
|
* @returns {{ CLUSTER_SECRET: string, IDENTITY_JSON: { id: string, private_key: string }, generated: boolean }}
|
|
37
45
|
* @memberof UnderpostIPFS
|
|
38
46
|
*/
|
|
39
|
-
resolveCredentials(
|
|
40
|
-
const
|
|
41
|
-
const
|
|
47
|
+
resolveCredentials() {
|
|
48
|
+
const sources = Underpost.secret.seedSources(IPFS_SECRET_NAME);
|
|
49
|
+
const secretPath = sources['cluster-secret'];
|
|
50
|
+
const identityPath = sources['bootstrap-peer-priv-key'];
|
|
51
|
+
const privateDir = dir.dirname(secretPath);
|
|
42
52
|
|
|
43
53
|
if (fs.existsSync(secretPath) && fs.existsSync(identityPath)) {
|
|
44
54
|
try {
|
|
45
55
|
const CLUSTER_SECRET = fs.readFileSync(secretPath, 'utf8').trim();
|
|
46
56
|
const IDENTITY_JSON = JSON.parse(fs.readFileSync(identityPath, 'utf8'));
|
|
47
57
|
if (CLUSTER_SECRET && IDENTITY_JSON?.id && IDENTITY_JSON?.private_key) {
|
|
48
|
-
logger.info('Reusing existing IPFS cluster credentials
|
|
58
|
+
logger.info('Reusing existing IPFS cluster credentials', { secretPath, identityPath });
|
|
49
59
|
return { CLUSTER_SECRET, IDENTITY_JSON, generated: false };
|
|
50
60
|
}
|
|
51
61
|
logger.warn('Existing IPFS cluster credentials are incomplete; regenerating');
|
|
@@ -54,7 +64,7 @@ class UnderpostIPFS {
|
|
|
54
64
|
}
|
|
55
65
|
}
|
|
56
66
|
|
|
57
|
-
logger.info('Generating new IPFS cluster credentials
|
|
67
|
+
logger.info('Generating new IPFS cluster credentials', { secretPath, identityPath });
|
|
58
68
|
|
|
59
69
|
// ipfs-cluster-service requires CLUSTER_SECRET as a 64-char hex string.
|
|
60
70
|
// base64 (openssl rand -base64 32) contains '/', '+', '=' which are invalid hex bytes.
|
|
@@ -115,7 +125,7 @@ class UnderpostIPFS {
|
|
|
115
125
|
);
|
|
116
126
|
fs.chmodSync(stagePath, 0o600);
|
|
117
127
|
// encrypt() stages, validates, moves into place, and shreds the plaintext source.
|
|
118
|
-
Underpost.secret.
|
|
128
|
+
Underpost.secret.encrypt(stagePath, options.namespace, { force: true });
|
|
119
129
|
logger.info('Re-encrypted regenerated IPFS credentials into the SOPS store');
|
|
120
130
|
} finally {
|
|
121
131
|
fs.removeSync(stageDir);
|
|
@@ -148,28 +158,22 @@ class UnderpostIPFS {
|
|
|
148
158
|
* @method applySecrets
|
|
149
159
|
* @description Creates (or idempotently updates) the Kubernetes Secret and env ConfigMap
|
|
150
160
|
* that the StatefulSet pods read at startup.
|
|
151
|
-
* - Secret `ipfs-cluster-secret`: cluster-secret + bootstrap-peer-priv-key
|
|
161
|
+
* - Secret `ipfs-cluster-secret`: cluster-secret + bootstrap-peer-priv-key, projected by the
|
|
162
|
+
* secret domain from the encrypted store or, failing that, from the origin credentials
|
|
152
163
|
* - ConfigMap `env-config`: bootstrap-peer-id + CLUSTER_SVC_NAME
|
|
153
|
-
* @param {{
|
|
164
|
+
* @param {{ IDENTITY_JSON: { id: string } }} credentials - Only the public peer id is read here; the Secret keys are projected by the secret domain.
|
|
154
165
|
* @param {object} options
|
|
155
166
|
* @param {string} options.namespace - Kubernetes namespace.
|
|
156
167
|
* @memberof UnderpostIPFS
|
|
157
168
|
*/
|
|
158
|
-
applySecrets({
|
|
169
|
+
applySecrets({ IDENTITY_JSON }, options) {
|
|
159
170
|
logger.info('Applying IPFS cluster Kubernetes Secret and env ConfigMap');
|
|
160
171
|
|
|
161
|
-
// Encrypted store first
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
shellExec(
|
|
167
|
-
`kubectl create secret generic ipfs-cluster-secret \
|
|
168
|
-
--from-literal=cluster-secret=${CLUSTER_SECRET} \
|
|
169
|
-
--from-literal=bootstrap-peer-priv-key=${IDENTITY_JSON.private_key} \
|
|
170
|
-
--dry-run=client -o yaml | kubectl apply -f - -n ${options.namespace}`,
|
|
171
|
-
{ disableLog: true },
|
|
172
|
-
);
|
|
172
|
+
// Encrypted store first; the origin projection runs only when no manifest is stored. Both
|
|
173
|
+
// paths keep the credentials out of the command string — the store streams a decrypt into
|
|
174
|
+
// kubectl, and the origin projection stages the values on tmpfs.
|
|
175
|
+
if (!Underpost.secret.applyIfPresent(IPFS_SECRET_NAME, options.namespace))
|
|
176
|
+
Underpost.secret.applyFromOriginSeed(IPFS_SECRET_NAME, options.namespace);
|
|
173
177
|
|
|
174
178
|
shellExec(
|
|
175
179
|
`kubectl create configmap env-config \
|
|
@@ -227,13 +231,13 @@ sudo sysctl -w net.core.wmem_max=7500000`,
|
|
|
227
231
|
Underpost.cluster.pullImage('ipfs/ipfs-cluster:latest', options);
|
|
228
232
|
}
|
|
229
233
|
|
|
230
|
-
const credentials = Underpost.ipfs.resolveCredentials(
|
|
234
|
+
const credentials = Underpost.ipfs.resolveCredentials();
|
|
231
235
|
|
|
232
236
|
// `env-config` advertises `bootstrap-peer-id` from the local identity file — the peer id is
|
|
233
237
|
// not carried in the Secret. So a regeneration invalidates any stored manifest: it would
|
|
234
238
|
// pair the previous private key with the new id and the cluster would never form. Re-encrypt
|
|
235
239
|
// the fresh pair so the store and the ConfigMap stay one identity.
|
|
236
|
-
if (credentials.generated && Underpost.secret.
|
|
240
|
+
if (credentials.generated && Underpost.secret.has(IPFS_SECRET_NAME, options.namespace))
|
|
237
241
|
Underpost.ipfs.storeCredentials(credentials, options);
|
|
238
242
|
|
|
239
243
|
const ipfsReplicas = resolveReplicaCount(options.replicas, IPFS_DEFAULT_REPLICA_COUNT);
|
package/src/cli/kickstart.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import fs from 'fs';
|
|
8
8
|
import path from 'path';
|
|
9
9
|
import { fileURLToPath } from 'url';
|
|
10
|
-
import { loggerFactory } from '../server/logger.js';
|
|
10
|
+
import { loggerFactory } from '../server/ops/logger.js';
|
|
11
11
|
|
|
12
12
|
const logger = loggerFactory(import.meta);
|
|
13
13
|
const __filename = fileURLToPath(import.meta.url);
|
package/src/cli/kubectl.js
CHANGED
|
@@ -6,26 +6,37 @@
|
|
|
6
6
|
* @namespace UnderpostKubectl
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { loggerFactory } from '../server/logger.js';
|
|
10
|
-
import { shellExec } from '../server/process.js';
|
|
9
|
+
import { loggerFactory, redactSensitiveText } from '../server/ops/logger.js';
|
|
10
|
+
import { shellExec, sleepSync } from '../server/runtime/process.js';
|
|
11
|
+
import { timer } from '../client/components/core/CommonJs.js';
|
|
11
12
|
import Underpost from '../index.js';
|
|
12
13
|
|
|
13
14
|
const logger = loggerFactory(import.meta);
|
|
14
15
|
|
|
16
|
+
const DEFAULT_POD_RETRIES = 2;
|
|
17
|
+
const RETRY_BASE_DELAY_MS = 2000;
|
|
18
|
+
const DEFAULT_EXEC_READY_ATTEMPTS = 5;
|
|
19
|
+
const DEFAULT_CREATION_TIMEOUT_SECONDS = 120;
|
|
20
|
+
const DEFAULT_READY_TIMEOUT_SECONDS = 180;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Exponential backoff for attempt `n`: 2s, 4s, 8s, …
|
|
24
|
+
* @param {number} attempt - 1-based attempt that just failed.
|
|
25
|
+
* @param {number} [baseDelayMs=2000] - Delay after the first failure.
|
|
26
|
+
* @returns {number} Milliseconds to wait before the next attempt.
|
|
27
|
+
* @memberof UnderpostKubectl
|
|
28
|
+
*/
|
|
29
|
+
const backoffDelayMs = (attempt, baseDelayMs = RETRY_BASE_DELAY_MS) => baseDelayMs * 2 ** (attempt - 1);
|
|
30
|
+
|
|
15
31
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* @param {
|
|
19
|
-
* @returns {string} The command
|
|
32
|
+
* Wraps a command in `timeout(1)` so a stalled API-server stream cannot hang a job forever.
|
|
33
|
+
* @param {string} command - Command to bound.
|
|
34
|
+
* @param {number} timeoutSeconds - Wall-clock budget; `0`/falsy returns the command unchanged.
|
|
35
|
+
* @returns {string} The bounded command.
|
|
20
36
|
* @memberof UnderpostKubectl
|
|
21
37
|
*/
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
return cmd
|
|
25
|
-
.replace(/-p['"]?[^\s'"]+/g, '-p***')
|
|
26
|
-
.replace(/--password=['"]?[^\s'"]+/g, '--password=***')
|
|
27
|
-
.replace(/-P\s+['"]?[^\s'"]+/g, '-P ***');
|
|
28
|
-
};
|
|
38
|
+
const withTimeout = (command, timeoutSeconds) =>
|
|
39
|
+
timeoutSeconds > 0 ? `timeout --kill-after=10s ${timeoutSeconds}s ${command}` : command;
|
|
29
40
|
|
|
30
41
|
/**
|
|
31
42
|
* @class UnderpostKubectl
|
|
@@ -80,22 +91,187 @@ class UnderpostKubectl {
|
|
|
80
91
|
|
|
81
92
|
/**
|
|
82
93
|
* Executes a kubectl command with credential-safe logging and error propagation.
|
|
94
|
+
* Retries any failure up to `retries` times with exponential backoff; callers whose
|
|
95
|
+
* command is not safe to replay pass `retries: 0`.
|
|
83
96
|
* @param {string} command - Full kubectl command string.
|
|
84
97
|
* @param {object} [options={}] - Execution options.
|
|
85
98
|
* @param {string} [options.context=''] - Human-readable label for log messages.
|
|
99
|
+
* @param {number} [options.retries=0] - Extra attempts allowed after a failure.
|
|
100
|
+
* @param {number} [options.baseDelayMs=2000] - Delay after the first failure; doubles per attempt.
|
|
101
|
+
* @param {number} [options.timeoutSeconds=0] - Wall-clock budget per attempt; `0` disables the bound.
|
|
102
|
+
* @param {string} [options.podName=''] - Pod the command targets; retries wait for it to accept exec again.
|
|
103
|
+
* @param {string} [options.namespace='default'] - Namespace of `podName`.
|
|
86
104
|
* @returns {string} stdout output from the command.
|
|
87
|
-
* @throws {Error} Re-throws
|
|
105
|
+
* @throws {Error} Re-throws the last execution error after logging.
|
|
88
106
|
* @memberof UnderpostKubectl
|
|
89
107
|
*/
|
|
90
108
|
run(command, options = {}) {
|
|
91
|
-
const {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
109
|
+
const {
|
|
110
|
+
context = '',
|
|
111
|
+
retries = 0,
|
|
112
|
+
baseDelayMs = RETRY_BASE_DELAY_MS,
|
|
113
|
+
timeoutSeconds = 0,
|
|
114
|
+
podName = '',
|
|
115
|
+
namespace = 'default',
|
|
116
|
+
} = options;
|
|
117
|
+
const attempts = Math.max(0, retries) + 1;
|
|
118
|
+
const boundedCommand = withTimeout(command, timeoutSeconds);
|
|
119
|
+
|
|
120
|
+
for (let attempt = 1; ; attempt++) {
|
|
121
|
+
try {
|
|
122
|
+
logger.info(`Executing kubectl command`, {
|
|
123
|
+
command: redactSensitiveText(command),
|
|
124
|
+
context,
|
|
125
|
+
...(attempts > 1 ? { attempt, attempts } : {}),
|
|
126
|
+
});
|
|
127
|
+
return shellExec(boundedCommand, { stdout: true, disableLog: true });
|
|
128
|
+
} catch (error) {
|
|
129
|
+
if (attempt === attempts) {
|
|
130
|
+
logger.error(`kubectl command failed`, {
|
|
131
|
+
command: redactSensitiveText(command),
|
|
132
|
+
error: error.message,
|
|
133
|
+
context,
|
|
134
|
+
attempts,
|
|
135
|
+
});
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
const delayMs = backoffDelayMs(attempt, baseDelayMs);
|
|
139
|
+
logger.warn(`kubectl command failed, retrying`, {
|
|
140
|
+
command: redactSensitiveText(command),
|
|
141
|
+
context,
|
|
142
|
+
attempt,
|
|
143
|
+
attempts,
|
|
144
|
+
delayMs,
|
|
145
|
+
error: error.message,
|
|
146
|
+
});
|
|
147
|
+
sleepSync(delayMs);
|
|
148
|
+
// An OOM kill takes the container with it (exit 137), so the replay would land on
|
|
149
|
+
// a container that is still coming back up. Wait for it rather than burning an attempt.
|
|
150
|
+
if (podName) Underpost.kubectl.ensureExecReady({ podName, namespace });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Polls until the pod can actually accept an exec stream.
|
|
157
|
+
*
|
|
158
|
+
* `kubectl wait --for=condition=Ready` reads the pod status the API server last
|
|
159
|
+
* recorded, which stays `Ready` for a window after the container underneath is
|
|
160
|
+
* gone — the exact gap that makes a dump fail with `container not found`. This
|
|
161
|
+
* probes the real thing: a no-op exec into the container.
|
|
162
|
+
*
|
|
163
|
+
* @param {object} params
|
|
164
|
+
* @param {string} params.podName - Pod to gate on.
|
|
165
|
+
* @param {string} [params.namespace='default'] - Pod namespace.
|
|
166
|
+
* @param {number} [params.attempts=5] - Probe attempts before giving up.
|
|
167
|
+
* @param {number} [params.baseDelayMs=2000] - Delay after the first probe; doubles per attempt.
|
|
168
|
+
* @param {number} [params.readyTimeoutSeconds=30] - Budget for the readiness condition wait.
|
|
169
|
+
* @param {number} [params.probeTimeoutSeconds=15] - Budget for the no-op exec probe.
|
|
170
|
+
* @returns {boolean} `true` when the pod accepted an exec stream.
|
|
171
|
+
* @memberof UnderpostKubectl
|
|
172
|
+
*/
|
|
173
|
+
ensureExecReady({
|
|
174
|
+
podName,
|
|
175
|
+
namespace = 'default',
|
|
176
|
+
attempts = DEFAULT_EXEC_READY_ATTEMPTS,
|
|
177
|
+
baseDelayMs = RETRY_BASE_DELAY_MS,
|
|
178
|
+
readyTimeoutSeconds = 30,
|
|
179
|
+
probeTimeoutSeconds = 15,
|
|
180
|
+
}) {
|
|
181
|
+
const probeOptions = { silent: true, silentOnError: true, disableLog: true };
|
|
182
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
183
|
+
shellExec(
|
|
184
|
+
`kubectl wait --for=condition=Ready pod/${podName} -n ${namespace} --timeout=${readyTimeoutSeconds}s`,
|
|
185
|
+
probeOptions,
|
|
186
|
+
);
|
|
187
|
+
const probe = shellExec(
|
|
188
|
+
withTimeout(`sudo kubectl exec -n ${namespace} -i ${podName} -- sh -c "exit 0"`, probeTimeoutSeconds),
|
|
189
|
+
probeOptions,
|
|
190
|
+
);
|
|
191
|
+
if (probe && probe.code === 0) return true;
|
|
192
|
+
if (attempt < attempts) sleepSync(backoffDelayMs(attempt, baseDelayMs));
|
|
193
|
+
}
|
|
194
|
+
logger.error('Pod never became exec-ready', { podName, namespace, attempts });
|
|
195
|
+
return false;
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Waits for a pod object to exist.
|
|
200
|
+
*
|
|
201
|
+
* `kubectl wait` fails on a missing object rather than waiting for one to appear, so any
|
|
202
|
+
* readiness wait issued while the controller is still creating the pod returns
|
|
203
|
+
* `Error from server (NotFound)`. A StatefulSet with `podManagementPolicy: OrderedReady`
|
|
204
|
+
* hits this every rollout: member N+1 is created only once N reports Ready.
|
|
205
|
+
*
|
|
206
|
+
* @param {object} params
|
|
207
|
+
* @param {string} params.podName - Pod to wait for.
|
|
208
|
+
* @param {string} [params.namespace='default'] - Pod namespace.
|
|
209
|
+
* @param {number} [params.timeoutSeconds=120] - Maximum wait window.
|
|
210
|
+
* @param {number} [params.intervalMs=2000] - Poll interval.
|
|
211
|
+
* @returns {Promise<boolean>} `true` once the pod object exists.
|
|
212
|
+
* @memberof UnderpostKubectl
|
|
213
|
+
*/
|
|
214
|
+
async waitForPodCreation({
|
|
215
|
+
podName,
|
|
216
|
+
namespace = 'default',
|
|
217
|
+
timeoutSeconds = DEFAULT_CREATION_TIMEOUT_SECONDS,
|
|
218
|
+
intervalMs = 2000,
|
|
219
|
+
}) {
|
|
220
|
+
const deadline = Date.now() + timeoutSeconds * 1000;
|
|
221
|
+
while (Date.now() < deadline) {
|
|
222
|
+
const found = shellExec(`kubectl get pod ${podName} -n ${namespace} --ignore-not-found -o name`, {
|
|
223
|
+
stdout: true,
|
|
224
|
+
silent: true,
|
|
225
|
+
silentOnError: true,
|
|
226
|
+
disableLog: true,
|
|
227
|
+
});
|
|
228
|
+
if (`${found || ''}`.trim()) return true;
|
|
229
|
+
await timer(intervalMs);
|
|
98
230
|
}
|
|
231
|
+
return false;
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Waits for each named pod to be created and then to report Ready.
|
|
236
|
+
*
|
|
237
|
+
* Never throws: a pod that never arrives or never becomes Ready is returned to the caller,
|
|
238
|
+
* which owns the diagnosis — a stalled rollout usually needs surrounding context (volume
|
|
239
|
+
* bindings, events) that a bare non-zero exit code cannot carry.
|
|
240
|
+
*
|
|
241
|
+
* @param {object} params
|
|
242
|
+
* @param {string[]} params.podNames - Pods to wait for, in order.
|
|
243
|
+
* @param {string} [params.namespace='default'] - Pod namespace.
|
|
244
|
+
* @param {number} [params.creationTimeoutSeconds=120] - Per-pod budget for the pod to appear.
|
|
245
|
+
* @param {number} [params.readyTimeoutSeconds=180] - Per-pod budget for the Ready condition.
|
|
246
|
+
* @returns {Promise<string[]>} Names of the pods that did not become ready (empty = all good).
|
|
247
|
+
* @memberof UnderpostKubectl
|
|
248
|
+
*/
|
|
249
|
+
async waitForPodsReady({
|
|
250
|
+
podNames,
|
|
251
|
+
namespace = 'default',
|
|
252
|
+
creationTimeoutSeconds = DEFAULT_CREATION_TIMEOUT_SECONDS,
|
|
253
|
+
readyTimeoutSeconds = DEFAULT_READY_TIMEOUT_SECONDS,
|
|
254
|
+
}) {
|
|
255
|
+
const failed = [];
|
|
256
|
+
for (const podName of podNames) {
|
|
257
|
+
if (
|
|
258
|
+
!(await Underpost.kubectl.waitForPodCreation({ podName, namespace, timeoutSeconds: creationTimeoutSeconds }))
|
|
259
|
+
) {
|
|
260
|
+
logger.error('Pod was never created', { podName, namespace, timeoutSeconds: creationTimeoutSeconds });
|
|
261
|
+
failed.push(podName);
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const result = shellExec(
|
|
266
|
+
`kubectl wait --for=condition=Ready pod/${podName} -n ${namespace} --timeout=${readyTimeoutSeconds}s`,
|
|
267
|
+
{ silentOnError: true },
|
|
268
|
+
);
|
|
269
|
+
if (result.code !== 0) {
|
|
270
|
+
logger.error('Pod did not become ready', { podName, namespace, timeoutSeconds: readyTimeoutSeconds });
|
|
271
|
+
failed.push(podName);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return failed;
|
|
99
275
|
},
|
|
100
276
|
|
|
101
277
|
/**
|
|
@@ -104,22 +280,21 @@ class UnderpostKubectl {
|
|
|
104
280
|
* @param {string} params.podName - Target pod name.
|
|
105
281
|
* @param {string} params.namespace - Pod namespace.
|
|
106
282
|
* @param {string} params.command - Shell command to run inside the container.
|
|
283
|
+
* @param {number} [params.retries=2] - Extra attempts allowed after a failure, with exponential backoff.
|
|
284
|
+
* @param {number} [params.timeoutSeconds=0] - Wall-clock budget per attempt; `0` disables the bound.
|
|
107
285
|
* @returns {string} stdout output from the in-pod command.
|
|
108
286
|
* @throws {Error} Re-throws any execution error after logging.
|
|
109
287
|
* @memberof UnderpostKubectl
|
|
110
288
|
*/
|
|
111
|
-
exec({ podName, namespace, command }) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
});
|
|
121
|
-
throw error;
|
|
122
|
-
}
|
|
289
|
+
exec({ podName, namespace, command, retries = DEFAULT_POD_RETRIES, timeoutSeconds = 0 }) {
|
|
290
|
+
const kubectlCmd = `sudo kubectl exec -n ${namespace} -i ${podName} -- sh -c "${command}"`;
|
|
291
|
+
return Underpost.kubectl.run(kubectlCmd, {
|
|
292
|
+
context: `exec in pod ${podName}`,
|
|
293
|
+
retries,
|
|
294
|
+
timeoutSeconds,
|
|
295
|
+
podName,
|
|
296
|
+
namespace,
|
|
297
|
+
});
|
|
123
298
|
},
|
|
124
299
|
|
|
125
300
|
/**
|
|
@@ -129,16 +304,16 @@ class UnderpostKubectl {
|
|
|
129
304
|
* @param {string} params.podName - Target pod name.
|
|
130
305
|
* @param {string} params.namespace - Pod namespace.
|
|
131
306
|
* @param {string} params.destPath - Destination path inside the container.
|
|
307
|
+
* @param {number} [params.retries=2] - Extra attempts allowed after a failure, with exponential backoff.
|
|
132
308
|
* @returns {boolean} `true` on success, `false` on error.
|
|
133
309
|
* @memberof UnderpostKubectl
|
|
134
310
|
*/
|
|
135
|
-
cpTo({ sourcePath, podName, namespace, destPath }) {
|
|
311
|
+
cpTo({ sourcePath, podName, namespace, destPath, retries = DEFAULT_POD_RETRIES }) {
|
|
136
312
|
try {
|
|
137
313
|
const command = `sudo kubectl cp ${sourcePath} ${namespace}/${podName}:${destPath}`;
|
|
138
|
-
Underpost.kubectl.run(command, { context: `copy to pod ${podName}
|
|
314
|
+
Underpost.kubectl.run(command, { context: `copy to pod ${podName}`, retries, podName, namespace });
|
|
139
315
|
return true;
|
|
140
|
-
} catch
|
|
141
|
-
logger.error('Failed to copy file to pod', { sourcePath, podName, destPath, error: error.message });
|
|
316
|
+
} catch {
|
|
142
317
|
return false;
|
|
143
318
|
}
|
|
144
319
|
},
|
|
@@ -150,16 +325,16 @@ class UnderpostKubectl {
|
|
|
150
325
|
* @param {string} params.namespace - Pod namespace.
|
|
151
326
|
* @param {string} params.sourcePath - Source path inside the container.
|
|
152
327
|
* @param {string} params.destPath - Local destination path.
|
|
328
|
+
* @param {number} [params.retries=2] - Extra attempts allowed after a failure, with exponential backoff.
|
|
153
329
|
* @returns {boolean} `true` on success, `false` on error.
|
|
154
330
|
* @memberof UnderpostKubectl
|
|
155
331
|
*/
|
|
156
|
-
cpFrom({ podName, namespace, sourcePath, destPath }) {
|
|
332
|
+
cpFrom({ podName, namespace, sourcePath, destPath, retries = DEFAULT_POD_RETRIES }) {
|
|
157
333
|
try {
|
|
158
334
|
const command = `sudo kubectl cp ${namespace}/${podName}:${sourcePath} ${destPath}`;
|
|
159
|
-
Underpost.kubectl.run(command, { context: `copy from pod ${podName}
|
|
335
|
+
Underpost.kubectl.run(command, { context: `copy from pod ${podName}`, retries, podName, namespace });
|
|
160
336
|
return true;
|
|
161
|
-
} catch
|
|
162
|
-
logger.error('Failed to copy file from pod', { podName, sourcePath, destPath, error: error.message });
|
|
337
|
+
} catch {
|
|
163
338
|
return false;
|
|
164
339
|
}
|
|
165
340
|
},
|
|
@@ -212,3 +387,5 @@ class UnderpostKubectl {
|
|
|
212
387
|
}
|
|
213
388
|
|
|
214
389
|
export default UnderpostKubectl;
|
|
390
|
+
|
|
391
|
+
export { backoffDelayMs, withTimeout };
|
package/src/cli/lxd.js
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
*
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { getNpmRootPath } from '../server/
|
|
9
|
-
import { pbcopy, shellExec } from '../server/process.js';
|
|
8
|
+
import { getNpmRootPath } from '../server/runtime/environment.js';
|
|
9
|
+
import { pbcopy, shellExec } from '../server/runtime/process.js';
|
|
10
10
|
import walk from 'ignore-walk';
|
|
11
11
|
import fs from 'fs-extra';
|
|
12
|
-
import { loggerFactory } from '../server/logger.js';
|
|
12
|
+
import { loggerFactory } from '../server/ops/logger.js';
|
|
13
13
|
import Underpost from '../index.js';
|
|
14
14
|
|
|
15
15
|
const logger = loggerFactory(import.meta);
|