@omnitron-dev/omnitron 0.2.0 → 0.3.1
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/README.md +4 -0
- package/dist/BUILD.json +5 -0
- package/dist/cli/omnitron.js +375 -29
- package/dist/cli/omnitron.js.map +1 -1
- package/dist/cluster/cluster.rpc-service.d.ts +40 -0
- package/dist/cluster/cluster.rpc-service.d.ts.map +1 -1
- package/dist/cluster/cluster.rpc-service.js +49 -3
- package/dist/cluster/cluster.rpc-service.js.map +1 -1
- package/dist/cluster/config-sync.d.ts.map +1 -1
- package/dist/cluster/config-sync.js.map +1 -1
- package/dist/cluster/leader-election.d.ts +90 -2
- package/dist/cluster/leader-election.d.ts.map +1 -1
- package/dist/cluster/leader-election.js +176 -22
- package/dist/cluster/leader-election.js.map +1 -1
- package/dist/cluster/mesh-link.d.ts +136 -0
- package/dist/cluster/mesh-link.d.ts.map +1 -0
- package/dist/cluster/mesh-link.js +212 -0
- package/dist/cluster/mesh-link.js.map +1 -0
- package/dist/cluster/mesh.d.ts +59 -0
- package/dist/cluster/mesh.d.ts.map +1 -0
- package/dist/cluster/mesh.js +117 -0
- package/dist/cluster/mesh.js.map +1 -0
- package/dist/cluster/slave-connector.d.ts +193 -9
- package/dist/cluster/slave-connector.d.ts.map +1 -1
- package/dist/cluster/slave-connector.js +409 -37
- package/dist/cluster/slave-connector.js.map +1 -1
- package/dist/commands/audit.d.ts +65 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +233 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/backup.d.ts +4 -0
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +255 -33
- package/dist/commands/backup.js.map +1 -1
- package/dist/commands/cluster.d.ts.map +1 -1
- package/dist/commands/cluster.js +78 -47
- package/dist/commands/cluster.js.map +1 -1
- package/dist/commands/daemon-cmd.d.ts +7 -1
- package/dist/commands/daemon-cmd.d.ts.map +1 -1
- package/dist/commands/daemon-cmd.js +87 -21
- package/dist/commands/daemon-cmd.js.map +1 -1
- package/dist/commands/daemon-required.d.ts +34 -0
- package/dist/commands/daemon-required.d.ts.map +1 -0
- package/dist/commands/daemon-required.js +92 -0
- package/dist/commands/daemon-required.js.map +1 -0
- package/dist/commands/deploy.d.ts +70 -8
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +99 -64
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/discover.d.ts +25 -4
- package/dist/commands/discover.d.ts.map +1 -1
- package/dist/commands/discover.js +155 -102
- package/dist/commands/discover.js.map +1 -1
- package/dist/commands/doctor.d.ts +293 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +1706 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/env.d.ts +8 -1
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +13 -8
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/exec.d.ts.map +1 -1
- package/dist/commands/exec.js +3 -2
- package/dist/commands/exec.js.map +1 -1
- package/dist/commands/fleet-asking.d.ts +87 -0
- package/dist/commands/fleet-asking.d.ts.map +1 -0
- package/dist/commands/fleet-asking.js +176 -0
- package/dist/commands/fleet-asking.js.map +1 -0
- package/dist/commands/fleet-recover.d.ts +2 -0
- package/dist/commands/fleet-recover.d.ts.map +1 -0
- package/dist/commands/fleet-recover.js +30 -0
- package/dist/commands/fleet-recover.js.map +1 -0
- package/dist/commands/fleet.d.ts +18 -0
- package/dist/commands/fleet.d.ts.map +1 -1
- package/dist/commands/fleet.js +314 -74
- package/dist/commands/fleet.js.map +1 -1
- package/dist/commands/health-check.d.ts +8 -6
- package/dist/commands/health-check.d.ts.map +1 -1
- package/dist/commands/health-check.js +26 -23
- package/dist/commands/health-check.js.map +1 -1
- package/dist/commands/health.d.ts.map +1 -1
- package/dist/commands/health.js +22 -8
- package/dist/commands/health.js.map +1 -1
- package/dist/commands/host-ingress.d.ts +3 -0
- package/dist/commands/host-ingress.d.ts.map +1 -0
- package/dist/commands/host-ingress.js +31 -0
- package/dist/commands/host-ingress.js.map +1 -0
- package/dist/commands/infra.d.ts +42 -1
- package/dist/commands/infra.d.ts.map +1 -1
- package/dist/commands/infra.js +418 -49
- package/dist/commands/infra.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +21 -36
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/inspect-graph.d.ts.map +1 -1
- package/dist/commands/inspect-graph.js +2 -6
- package/dist/commands/inspect-graph.js.map +1 -1
- package/dist/commands/inspect.d.ts.map +1 -1
- package/dist/commands/inspect.js +110 -14
- package/dist/commands/inspect.js.map +1 -1
- package/dist/commands/k8s.d.ts.map +1 -1
- package/dist/commands/k8s.js +23 -18
- package/dist/commands/k8s.js.map +1 -1
- package/dist/commands/kb.d.ts.map +1 -1
- package/dist/commands/kb.js +88 -29
- package/dist/commands/kb.js.map +1 -1
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +21 -9
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/log-health.d.ts +120 -0
- package/dist/commands/log-health.d.ts.map +1 -0
- package/dist/commands/log-health.js +212 -0
- package/dist/commands/log-health.js.map +1 -0
- package/dist/commands/logs.d.ts +96 -2
- package/dist/commands/logs.d.ts.map +1 -1
- package/dist/commands/logs.js +522 -196
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/metrics.d.ts.map +1 -1
- package/dist/commands/metrics.js +35 -17
- package/dist/commands/metrics.js.map +1 -1
- package/dist/commands/monit.d.ts.map +1 -1
- package/dist/commands/monit.js +3 -2
- package/dist/commands/monit.js.map +1 -1
- package/dist/commands/node.d.ts +56 -0
- package/dist/commands/node.d.ts.map +1 -1
- package/dist/commands/node.js +297 -69
- package/dist/commands/node.js.map +1 -1
- package/dist/commands/output.d.ts +10 -0
- package/dist/commands/output.d.ts.map +1 -1
- package/dist/commands/output.js +41 -1
- package/dist/commands/output.js.map +1 -1
- package/dist/commands/pipeline.d.ts.map +1 -1
- package/dist/commands/pipeline.js +33 -19
- package/dist/commands/pipeline.js.map +1 -1
- package/dist/commands/project.d.ts +19 -0
- package/dist/commands/project.d.ts.map +1 -1
- package/dist/commands/project.js +125 -27
- package/dist/commands/project.js.map +1 -1
- package/dist/commands/release-store.d.ts +28 -0
- package/dist/commands/release-store.d.ts.map +1 -0
- package/dist/commands/release-store.js +158 -0
- package/dist/commands/release-store.js.map +1 -0
- package/dist/commands/release.d.ts +61 -0
- package/dist/commands/release.d.ts.map +1 -0
- package/dist/commands/release.js +555 -0
- package/dist/commands/release.js.map +1 -0
- package/dist/commands/reload.d.ts +16 -0
- package/dist/commands/reload.d.ts.map +1 -1
- package/dist/commands/reload.js +21 -5
- package/dist/commands/reload.js.map +1 -1
- package/dist/commands/remote.d.ts +40 -0
- package/dist/commands/remote.d.ts.map +1 -1
- package/dist/commands/remote.js +146 -35
- package/dist/commands/remote.js.map +1 -1
- package/dist/commands/restart.d.ts +16 -0
- package/dist/commands/restart.d.ts.map +1 -1
- package/dist/commands/restart.js +21 -5
- package/dist/commands/restart.js.map +1 -1
- package/dist/commands/scale.d.ts.map +1 -1
- package/dist/commands/scale.js +4 -3
- package/dist/commands/scale.js.map +1 -1
- package/dist/commands/secret.d.ts +54 -0
- package/dist/commands/secret.d.ts.map +1 -1
- package/dist/commands/secret.js +236 -34
- package/dist/commands/secret.js.map +1 -1
- package/dist/commands/service-units.d.ts +181 -0
- package/dist/commands/service-units.d.ts.map +1 -0
- package/dist/commands/service-units.js +291 -0
- package/dist/commands/service-units.js.map +1 -0
- package/dist/commands/service.d.ts +39 -0
- package/dist/commands/service.d.ts.map +1 -0
- package/dist/commands/service.js +370 -0
- package/dist/commands/service.js.map +1 -0
- package/dist/commands/spinner.d.ts +29 -0
- package/dist/commands/spinner.d.ts.map +1 -0
- package/dist/commands/spinner.js +44 -0
- package/dist/commands/spinner.js.map +1 -0
- package/dist/commands/stack.d.ts +49 -1
- package/dist/commands/stack.d.ts.map +1 -1
- package/dist/commands/stack.js +325 -12
- package/dist/commands/stack.js.map +1 -1
- package/dist/commands/start.d.ts +16 -0
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +20 -3
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/status.d.ts +9 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +45 -29
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/stop.d.ts +16 -0
- package/dist/commands/stop.d.ts.map +1 -1
- package/dist/commands/stop.js +34 -6
- package/dist/commands/stop.js.map +1 -1
- package/dist/commands/tor.d.ts +14 -7
- package/dist/commands/tor.d.ts.map +1 -1
- package/dist/commands/tor.js +113 -33
- package/dist/commands/tor.js.map +1 -1
- package/dist/commands/up.d.ts +85 -1
- package/dist/commands/up.d.ts.map +1 -1
- package/dist/commands/up.js +180 -32
- package/dist/commands/up.js.map +1 -1
- package/dist/commands/webapp.d.ts.map +1 -1
- package/dist/commands/webapp.js +2 -1
- package/dist/commands/webapp.js.map +1 -1
- package/dist/config/defaults.d.ts +16 -0
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +26 -3
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/define-ecosystem.d.ts.map +1 -1
- package/dist/config/define-ecosystem.js +2 -0
- package/dist/config/define-ecosystem.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/loader.d.ts +45 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +64 -6
- package/dist/config/loader.js.map +1 -1
- package/dist/config/omnitron-config.schema.d.ts.map +1 -1
- package/dist/config/omnitron-config.schema.js +16 -0
- package/dist/config/omnitron-config.schema.js.map +1 -1
- package/dist/config/types.d.ts +416 -44
- package/dist/config/types.d.ts.map +1 -1
- package/dist/daemon/config-reload.d.ts +27 -0
- package/dist/daemon/config-reload.d.ts.map +1 -0
- package/dist/daemon/config-reload.js +42 -0
- package/dist/daemon/config-reload.js.map +1 -0
- package/dist/daemon/daemon-client.d.ts +136 -2
- package/dist/daemon/daemon-client.d.ts.map +1 -1
- package/dist/daemon/daemon-client.js +307 -21
- package/dist/daemon/daemon-client.js.map +1 -1
- package/dist/daemon/daemon-entry.js +90 -30
- package/dist/daemon/daemon-entry.js.map +1 -1
- package/dist/daemon/daemon-scheduler.d.ts +4 -0
- package/dist/daemon/daemon-scheduler.d.ts.map +1 -1
- package/dist/daemon/daemon-scheduler.js +137 -7
- package/dist/daemon/daemon-scheduler.js.map +1 -1
- package/dist/daemon/daemon-state-store.service.d.ts +263 -0
- package/dist/daemon/daemon-state-store.service.d.ts.map +1 -0
- package/dist/daemon/daemon-state-store.service.js +446 -0
- package/dist/daemon/daemon-state-store.service.js.map +1 -0
- package/dist/daemon/daemon.d.ts +194 -4
- package/dist/daemon/daemon.d.ts.map +1 -1
- package/dist/daemon/daemon.js +1160 -157
- package/dist/daemon/daemon.js.map +1 -1
- package/dist/daemon/daemon.module.d.ts.map +1 -1
- package/dist/daemon/daemon.module.js +163 -85
- package/dist/daemon/daemon.module.js.map +1 -1
- package/dist/daemon/daemon.rpc-service.d.ts +90 -1
- package/dist/daemon/daemon.rpc-service.d.ts.map +1 -1
- package/dist/daemon/daemon.rpc-service.js +439 -97
- package/dist/daemon/daemon.rpc-service.js.map +1 -1
- package/dist/daemon/pid-manager.d.ts +16 -3
- package/dist/daemon/pid-manager.d.ts.map +1 -1
- package/dist/daemon/pid-manager.js +31 -4
- package/dist/daemon/pid-manager.js.map +1 -1
- package/dist/daemon/spawn-daemon.d.ts +73 -0
- package/dist/daemon/spawn-daemon.d.ts.map +1 -0
- package/dist/daemon/spawn-daemon.js +101 -0
- package/dist/daemon/spawn-daemon.js.map +1 -0
- package/dist/daemon/state-store.d.ts +65 -3
- package/dist/daemon/state-store.d.ts.map +1 -1
- package/dist/daemon/state-store.js +100 -58
- package/dist/daemon/state-store.js.map +1 -1
- package/dist/database/connection.d.ts +71 -0
- package/dist/database/connection.d.ts.map +1 -0
- package/dist/database/connection.js +129 -0
- package/dist/database/connection.js.map +1 -0
- package/dist/database/dialect.d.ts +60 -0
- package/dist/database/dialect.d.ts.map +1 -0
- package/dist/database/dialect.js +80 -0
- package/dist/database/dialect.js.map +1 -0
- package/dist/database/migrate.d.ts +5 -2
- package/dist/database/migrate.d.ts.map +1 -1
- package/dist/database/migrate.js +23 -33
- package/dist/database/migrate.js.map +1 -1
- package/dist/database/migration-runner.d.ts +50 -0
- package/dist/database/migration-runner.d.ts.map +1 -0
- package/dist/database/migration-runner.js +143 -0
- package/dist/database/migration-runner.js.map +1 -0
- package/dist/database/migrations/006_login_throttle.d.ts +17 -0
- package/dist/database/migrations/006_login_throttle.d.ts.map +1 -0
- package/dist/database/migrations/006_login_throttle.js +33 -0
- package/dist/database/migrations/006_login_throttle.js.map +1 -0
- package/dist/database/migrations/007_sync_ingested.d.ts +21 -0
- package/dist/database/migrations/007_sync_ingested.d.ts.map +1 -0
- package/dist/database/migrations/007_sync_ingested.js +39 -0
- package/dist/database/migrations/007_sync_ingested.js.map +1 -0
- package/dist/database/migrations/008_node_health_version_text.d.ts +24 -0
- package/dist/database/migrations/008_node_health_version_text.d.ts.map +1 -0
- package/dist/database/migrations/008_node_health_version_text.js +35 -0
- package/dist/database/migrations/008_node_health_version_text.js.map +1 -0
- package/dist/database/migrations/009_node_health_unmeasured.d.ts +40 -0
- package/dist/database/migrations/009_node_health_unmeasured.d.ts.map +1 -0
- package/dist/database/migrations/009_node_health_unmeasured.js +63 -0
- package/dist/database/migrations/009_node_health_unmeasured.js.map +1 -0
- package/dist/database/migrations/010_metrics_raw_had_no_reader.d.ts +22 -0
- package/dist/database/migrations/010_metrics_raw_had_no_reader.d.ts.map +1 -0
- package/dist/database/migrations/010_metrics_raw_had_no_reader.js +26 -0
- package/dist/database/migrations/010_metrics_raw_had_no_reader.js.map +1 -0
- package/dist/database/migrations/011_alerts_nobody_had_to_write.d.ts +56 -0
- package/dist/database/migrations/011_alerts_nobody_had_to_write.d.ts.map +1 -0
- package/dist/database/migrations/011_alerts_nobody_had_to_write.js +79 -0
- package/dist/database/migrations/011_alerts_nobody_had_to_write.js.map +1 -0
- package/dist/database/migrations/012_a_disk_nobody_watched.d.ts +26 -0
- package/dist/database/migrations/012_a_disk_nobody_watched.d.ts.map +1 -0
- package/dist/database/migrations/012_a_disk_nobody_watched.js +40 -0
- package/dist/database/migrations/012_a_disk_nobody_watched.js.map +1 -0
- package/dist/database/migrations/013_an_alarm_delivered.d.ts +14 -0
- package/dist/database/migrations/013_an_alarm_delivered.d.ts.map +1 -0
- package/dist/database/migrations/013_an_alarm_delivered.js +28 -0
- package/dist/database/migrations/013_an_alarm_delivered.js.map +1 -0
- package/dist/database/migrations/index.d.ts +21 -0
- package/dist/database/migrations/index.d.ts.map +1 -0
- package/dist/database/migrations/index.js +47 -0
- package/dist/database/migrations/index.js.map +1 -0
- package/dist/database/schema.d.ts +27 -11
- package/dist/database/schema.d.ts.map +1 -1
- package/dist/database/sqlite-date-binding.d.ts +71 -0
- package/dist/database/sqlite-date-binding.d.ts.map +1 -0
- package/dist/database/sqlite-date-binding.js +174 -0
- package/dist/database/sqlite-date-binding.js.map +1 -0
- package/dist/execution/data-channel.d.ts +48 -0
- package/dist/execution/data-channel.d.ts.map +1 -0
- package/dist/execution/data-channel.js +55 -0
- package/dist/execution/data-channel.js.map +1 -0
- package/dist/execution/execution.service.d.ts +146 -0
- package/dist/execution/execution.service.d.ts.map +1 -1
- package/dist/execution/execution.service.js +330 -10
- package/dist/execution/execution.service.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/infrastructure/bare-metal-plan.d.ts +208 -0
- package/dist/infrastructure/bare-metal-plan.d.ts.map +1 -0
- package/dist/infrastructure/bare-metal-plan.js +363 -0
- package/dist/infrastructure/bare-metal-plan.js.map +1 -0
- package/dist/infrastructure/bare-metal-runner.d.ts +65 -0
- package/dist/infrastructure/bare-metal-runner.d.ts.map +1 -0
- package/dist/infrastructure/bare-metal-runner.js +354 -0
- package/dist/infrastructure/bare-metal-runner.js.map +1 -0
- package/dist/infrastructure/config-payload.d.ts +149 -0
- package/dist/infrastructure/config-payload.d.ts.map +1 -0
- package/dist/infrastructure/config-payload.js +235 -0
- package/dist/infrastructure/config-payload.js.map +1 -0
- package/dist/infrastructure/container-runtime.d.ts +170 -10
- package/dist/infrastructure/container-runtime.d.ts.map +1 -1
- package/dist/infrastructure/container-runtime.js +565 -52
- package/dist/infrastructure/container-runtime.js.map +1 -1
- package/dist/infrastructure/gateway-reachability.d.ts +85 -0
- package/dist/infrastructure/gateway-reachability.d.ts.map +1 -0
- package/dist/infrastructure/gateway-reachability.js +116 -0
- package/dist/infrastructure/gateway-reachability.js.map +1 -0
- package/dist/infrastructure/gateway-redis-db.d.ts +29 -0
- package/dist/infrastructure/gateway-redis-db.d.ts.map +1 -0
- package/dist/infrastructure/gateway-redis-db.js +32 -0
- package/dist/infrastructure/gateway-redis-db.js.map +1 -0
- package/dist/infrastructure/host-ingress-config.d.ts +12 -0
- package/dist/infrastructure/host-ingress-config.d.ts.map +1 -0
- package/dist/infrastructure/host-ingress-config.js +197 -0
- package/dist/infrastructure/host-ingress-config.js.map +1 -0
- package/dist/infrastructure/host-ingress-lock.d.ts +4 -0
- package/dist/infrastructure/host-ingress-lock.d.ts.map +1 -0
- package/dist/infrastructure/host-ingress-lock.js +36 -0
- package/dist/infrastructure/host-ingress-lock.js.map +1 -0
- package/dist/infrastructure/host-ingress-runtime.d.ts +25 -0
- package/dist/infrastructure/host-ingress-runtime.d.ts.map +1 -0
- package/dist/infrastructure/host-ingress-runtime.js +114 -0
- package/dist/infrastructure/host-ingress-runtime.js.map +1 -0
- package/dist/infrastructure/host-ingress-takeover.d.ts +18 -0
- package/dist/infrastructure/host-ingress-takeover.d.ts.map +1 -0
- package/dist/infrastructure/host-ingress-takeover.js +142 -0
- package/dist/infrastructure/host-ingress-takeover.js.map +1 -0
- package/dist/infrastructure/host-ingress-types.d.ts +173 -0
- package/dist/infrastructure/host-ingress-types.d.ts.map +1 -0
- package/dist/infrastructure/host-ingress-types.js +2 -0
- package/dist/infrastructure/host-ingress-types.js.map +1 -0
- package/dist/infrastructure/host-ingress.service.d.ts +47 -0
- package/dist/infrastructure/host-ingress.service.d.ts.map +1 -0
- package/dist/infrastructure/host-ingress.service.js +514 -0
- package/dist/infrastructure/host-ingress.service.js.map +1 -0
- package/dist/infrastructure/host-inspection.d.ts +223 -0
- package/dist/infrastructure/host-inspection.d.ts.map +1 -0
- package/dist/infrastructure/host-inspection.js +501 -0
- package/dist/infrastructure/host-inspection.js.map +1 -0
- package/dist/infrastructure/infrastructure-gate.d.ts.map +1 -1
- package/dist/infrastructure/infrastructure.service.d.ts +223 -7
- package/dist/infrastructure/infrastructure.service.d.ts.map +1 -1
- package/dist/infrastructure/infrastructure.service.js +500 -93
- package/dist/infrastructure/infrastructure.service.js.map +1 -1
- package/dist/infrastructure/known-machines.d.ts +76 -0
- package/dist/infrastructure/known-machines.d.ts.map +1 -0
- package/dist/infrastructure/known-machines.js +94 -0
- package/dist/infrastructure/known-machines.js.map +1 -0
- package/dist/infrastructure/node-credentials.d.ts +45 -0
- package/dist/infrastructure/node-credentials.d.ts.map +1 -0
- package/dist/infrastructure/node-credentials.js +80 -0
- package/dist/infrastructure/node-credentials.js.map +1 -0
- package/dist/infrastructure/orphan-containers.d.ts +99 -0
- package/dist/infrastructure/orphan-containers.d.ts.map +1 -0
- package/dist/infrastructure/orphan-containers.js +106 -0
- package/dist/infrastructure/orphan-containers.js.map +1 -0
- package/dist/infrastructure/phantom-endpoint-janitor.d.ts +20 -0
- package/dist/infrastructure/phantom-endpoint-janitor.d.ts.map +1 -1
- package/dist/infrastructure/phantom-endpoint-janitor.js +56 -6
- package/dist/infrastructure/phantom-endpoint-janitor.js.map +1 -1
- package/dist/infrastructure/presets/gateway-openresty.d.ts.map +1 -1
- package/dist/infrastructure/presets/gateway-openresty.js +29 -3
- package/dist/infrastructure/presets/gateway-openresty.js.map +1 -1
- package/dist/infrastructure/presets/minio.d.ts.map +1 -1
- package/dist/infrastructure/presets/minio.js +36 -3
- package/dist/infrastructure/presets/minio.js.map +1 -1
- package/dist/infrastructure/presets/postgres.d.ts.map +1 -1
- package/dist/infrastructure/presets/postgres.js +69 -2
- package/dist/infrastructure/presets/postgres.js.map +1 -1
- package/dist/infrastructure/presets/redis.d.ts.map +1 -1
- package/dist/infrastructure/presets/redis.js +13 -0
- package/dist/infrastructure/presets/redis.js.map +1 -1
- package/dist/infrastructure/presets/registry.d.ts.map +1 -1
- package/dist/infrastructure/presets/registry.js +81 -12
- package/dist/infrastructure/presets/registry.js.map +1 -1
- package/dist/infrastructure/presets/tor.d.ts +38 -0
- package/dist/infrastructure/presets/tor.d.ts.map +1 -1
- package/dist/infrastructure/presets/tor.js +78 -69
- package/dist/infrastructure/presets/tor.js.map +1 -1
- package/dist/infrastructure/presets/torrc.d.ts +54 -0
- package/dist/infrastructure/presets/torrc.d.ts.map +1 -0
- package/dist/infrastructure/presets/torrc.js +153 -0
- package/dist/infrastructure/presets/torrc.js.map +1 -0
- package/dist/infrastructure/presets/types.d.ts +17 -0
- package/dist/infrastructure/presets/types.d.ts.map +1 -1
- package/dist/infrastructure/provisioning-outcome.d.ts +85 -0
- package/dist/infrastructure/provisioning-outcome.d.ts.map +1 -0
- package/dist/infrastructure/provisioning-outcome.js +122 -0
- package/dist/infrastructure/provisioning-outcome.js.map +1 -0
- package/dist/infrastructure/server-registry.d.ts +27 -0
- package/dist/infrastructure/server-registry.d.ts.map +1 -1
- package/dist/infrastructure/server-registry.js +60 -5
- package/dist/infrastructure/server-registry.js.map +1 -1
- package/dist/infrastructure/service-binding.d.ts +60 -0
- package/dist/infrastructure/service-binding.d.ts.map +1 -0
- package/dist/infrastructure/service-binding.js +90 -0
- package/dist/infrastructure/service-binding.js.map +1 -0
- package/dist/infrastructure/service-credentials.d.ts +105 -0
- package/dist/infrastructure/service-credentials.d.ts.map +1 -0
- package/dist/infrastructure/service-credentials.js +141 -0
- package/dist/infrastructure/service-credentials.js.map +1 -0
- package/dist/infrastructure/service-resolver.d.ts +166 -12
- package/dist/infrastructure/service-resolver.d.ts.map +1 -1
- package/dist/infrastructure/service-resolver.js +535 -82
- package/dist/infrastructure/service-resolver.js.map +1 -1
- package/dist/infrastructure/shipped-config.d.ts +43 -0
- package/dist/infrastructure/shipped-config.d.ts.map +1 -0
- package/dist/infrastructure/shipped-config.js +159 -0
- package/dist/infrastructure/shipped-config.js.map +1 -0
- package/dist/infrastructure/stack-infra-manager.d.ts +16 -1
- package/dist/infrastructure/stack-infra-manager.d.ts.map +1 -1
- package/dist/infrastructure/stack-infra-manager.js +81 -53
- package/dist/infrastructure/stack-infra-manager.js.map +1 -1
- package/dist/infrastructure/types.d.ts +263 -6
- package/dist/infrastructure/types.d.ts.map +1 -1
- package/dist/mcp/mcp-bridge.d.ts.map +1 -1
- package/dist/mcp/mcp-bridge.js.map +1 -1
- package/dist/mcp/tool-groups/apps.tools.d.ts +2 -1
- package/dist/mcp/tool-groups/apps.tools.d.ts.map +1 -1
- package/dist/mcp/tool-groups/apps.tools.js +2 -2
- package/dist/mcp/tool-groups/apps.tools.js.map +1 -1
- package/dist/mcp/tool-groups/infra.tools.d.ts +16 -2
- package/dist/mcp/tool-groups/infra.tools.d.ts.map +1 -1
- package/dist/mcp/tool-groups/infra.tools.js +51 -41
- package/dist/mcp/tool-groups/infra.tools.js.map +1 -1
- package/dist/mcp/tool-groups/kb.tools.d.ts.map +1 -1
- package/dist/mcp/tool-groups/kb.tools.js +4 -6
- package/dist/mcp/tool-groups/kb.tools.js.map +1 -1
- package/dist/mcp/tool-groups/management.tools.d.ts +20 -3
- package/dist/mcp/tool-groups/management.tools.d.ts.map +1 -1
- package/dist/mcp/tool-groups/management.tools.js +158 -125
- package/dist/mcp/tool-groups/management.tools.js.map +1 -1
- package/dist/mcp/tool-groups/monitoring.tools.d.ts +10 -1
- package/dist/mcp/tool-groups/monitoring.tools.d.ts.map +1 -1
- package/dist/mcp/tool-groups/monitoring.tools.js +65 -18
- package/dist/mcp/tool-groups/monitoring.tools.js.map +1 -1
- package/dist/mcp/unavailable-tools.d.ts +35 -0
- package/dist/mcp/unavailable-tools.d.ts.map +1 -0
- package/dist/mcp/unavailable-tools.js +59 -0
- package/dist/mcp/unavailable-tools.js.map +1 -0
- package/dist/monitoring/app-health.indicator.d.ts.map +1 -1
- package/dist/monitoring/app-health.indicator.js +12 -0
- package/dist/monitoring/app-health.indicator.js.map +1 -1
- package/dist/monitoring/desktop-notifier.d.ts +26 -0
- package/dist/monitoring/desktop-notifier.d.ts.map +1 -0
- package/dist/monitoring/desktop-notifier.js +49 -0
- package/dist/monitoring/desktop-notifier.js.map +1 -0
- package/dist/monitoring/docker-health.indicator.d.ts +17 -1
- package/dist/monitoring/docker-health.indicator.d.ts.map +1 -1
- package/dist/monitoring/docker-health.indicator.js +38 -8
- package/dist/monitoring/docker-health.indicator.js.map +1 -1
- package/dist/monitoring/event-loop-stall.indicator.d.ts +26 -0
- package/dist/monitoring/event-loop-stall.indicator.d.ts.map +1 -0
- package/dist/monitoring/event-loop-stall.indicator.js +47 -0
- package/dist/monitoring/event-loop-stall.indicator.js.map +1 -0
- package/dist/monitoring/event-loop-watch.d.ts +124 -0
- package/dist/monitoring/event-loop-watch.d.ts.map +1 -0
- package/dist/monitoring/event-loop-watch.js +179 -0
- package/dist/monitoring/event-loop-watch.js.map +1 -0
- package/dist/monitoring/host-disk.d.ts +6 -0
- package/dist/monitoring/host-disk.d.ts.map +1 -0
- package/dist/monitoring/host-disk.js +26 -0
- package/dist/monitoring/host-disk.js.map +1 -0
- package/dist/monitoring/log-line.d.ts +188 -0
- package/dist/monitoring/log-line.d.ts.map +1 -0
- package/dist/monitoring/log-line.js +458 -0
- package/dist/monitoring/log-line.js.map +1 -0
- package/dist/monitoring/log-manager.d.ts +89 -8
- package/dist/monitoring/log-manager.d.ts.map +1 -1
- package/dist/monitoring/log-manager.js +246 -77
- package/dist/monitoring/log-manager.js.map +1 -1
- package/dist/observability/metrics-bridge.d.ts.map +1 -1
- package/dist/observability/metrics-server.d.ts.map +1 -1
- package/dist/operations.d.ts +16 -0
- package/dist/operations.d.ts.map +1 -0
- package/dist/operations.js +13 -0
- package/dist/operations.js.map +1 -0
- package/dist/orchestrator/app-handle.d.ts +157 -2
- package/dist/orchestrator/app-handle.d.ts.map +1 -1
- package/dist/orchestrator/app-handle.js +165 -3
- package/dist/orchestrator/app-handle.js.map +1 -1
- package/dist/orchestrator/app-health.d.ts +33 -0
- package/dist/orchestrator/app-health.d.ts.map +1 -0
- package/dist/orchestrator/app-health.js +74 -0
- package/dist/orchestrator/app-health.js.map +1 -0
- package/dist/orchestrator/app-traffic.d.ts +14 -0
- package/dist/orchestrator/app-traffic.d.ts.map +1 -0
- package/dist/orchestrator/app-traffic.js +33 -0
- package/dist/orchestrator/app-traffic.js.map +1 -0
- package/dist/orchestrator/bootstrap-loader-child.d.ts +19 -0
- package/dist/orchestrator/bootstrap-loader-child.d.ts.map +1 -0
- package/dist/orchestrator/bootstrap-loader-child.js +43 -0
- package/dist/orchestrator/bootstrap-loader-child.js.map +1 -0
- package/dist/orchestrator/bootstrap-loader.d.ts +72 -0
- package/dist/orchestrator/bootstrap-loader.d.ts.map +1 -1
- package/dist/orchestrator/bootstrap-loader.js +350 -5
- package/dist/orchestrator/bootstrap-loader.js.map +1 -1
- package/dist/orchestrator/bootstrap-process.d.ts +99 -4
- package/dist/orchestrator/bootstrap-process.d.ts.map +1 -1
- package/dist/orchestrator/bootstrap-process.js +332 -20
- package/dist/orchestrator/bootstrap-process.js.map +1 -1
- package/dist/orchestrator/build-service.d.ts +6 -12
- package/dist/orchestrator/build-service.d.ts.map +1 -1
- package/dist/orchestrator/build-service.js +120 -83
- package/dist/orchestrator/build-service.js.map +1 -1
- package/dist/orchestrator/call-exposed-service.d.ts +7 -0
- package/dist/orchestrator/call-exposed-service.d.ts.map +1 -0
- package/dist/orchestrator/call-exposed-service.js +50 -0
- package/dist/orchestrator/call-exposed-service.js.map +1 -0
- package/dist/orchestrator/classic-launcher.d.ts +1 -0
- package/dist/orchestrator/classic-launcher.d.ts.map +1 -1
- package/dist/orchestrator/classic-launcher.js +40 -4
- package/dist/orchestrator/classic-launcher.js.map +1 -1
- package/dist/orchestrator/file-watcher.d.ts +79 -1
- package/dist/orchestrator/file-watcher.d.ts.map +1 -1
- package/dist/orchestrator/file-watcher.js +193 -7
- package/dist/orchestrator/file-watcher.js.map +1 -1
- package/dist/orchestrator/http-routes.d.ts +4 -0
- package/dist/orchestrator/http-routes.d.ts.map +1 -0
- package/dist/orchestrator/http-routes.js +19 -0
- package/dist/orchestrator/http-routes.js.map +1 -0
- package/dist/orchestrator/module-worker-process.d.ts.map +1 -1
- package/dist/orchestrator/module-worker-process.js +10 -0
- package/dist/orchestrator/module-worker-process.js.map +1 -1
- package/dist/orchestrator/orchestrator.service.d.ts +385 -11
- package/dist/orchestrator/orchestrator.service.d.ts.map +1 -1
- package/dist/orchestrator/orchestrator.service.js +1738 -364
- package/dist/orchestrator/orchestrator.service.js.map +1 -1
- package/dist/orchestrator/owned-pids.d.ts +83 -0
- package/dist/orchestrator/owned-pids.d.ts.map +1 -0
- package/dist/orchestrator/owned-pids.js +93 -0
- package/dist/orchestrator/owned-pids.js.map +1 -0
- package/dist/orchestrator/port-conflict.d.ts +102 -0
- package/dist/orchestrator/port-conflict.d.ts.map +1 -0
- package/dist/orchestrator/port-conflict.js +131 -0
- package/dist/orchestrator/port-conflict.js.map +1 -0
- package/dist/orchestrator/process-janitor.d.ts +78 -4
- package/dist/orchestrator/process-janitor.d.ts.map +1 -1
- package/dist/orchestrator/process-janitor.js +246 -30
- package/dist/orchestrator/process-janitor.js.map +1 -1
- package/dist/orchestrator/ps-metrics.d.ts +37 -0
- package/dist/orchestrator/ps-metrics.d.ts.map +1 -0
- package/dist/orchestrator/ps-metrics.js +60 -0
- package/dist/orchestrator/ps-metrics.js.map +1 -0
- package/dist/orchestrator/service-router.d.ts +58 -2
- package/dist/orchestrator/service-router.d.ts.map +1 -1
- package/dist/orchestrator/service-router.js +157 -25
- package/dist/orchestrator/service-router.js.map +1 -1
- package/dist/orchestrator/topology-query.d.ts +49 -0
- package/dist/orchestrator/topology-query.d.ts.map +1 -0
- package/dist/orchestrator/topology-query.js +54 -0
- package/dist/orchestrator/topology-query.js.map +1 -0
- package/dist/project/artifact-builder.d.ts +174 -3
- package/dist/project/artifact-builder.d.ts.map +1 -1
- package/dist/project/artifact-builder.js +454 -42
- package/dist/project/artifact-builder.js.map +1 -1
- package/dist/project/build-decision.d.ts +58 -0
- package/dist/project/build-decision.d.ts.map +1 -0
- package/dist/project/build-decision.js +59 -0
- package/dist/project/build-decision.js.map +1 -0
- package/dist/project/config-resolver.d.ts +6 -4
- package/dist/project/config-resolver.d.ts.map +1 -1
- package/dist/project/config-resolver.js +128 -74
- package/dist/project/config-resolver.js.map +1 -1
- package/dist/project/declared-config.d.ts +42 -0
- package/dist/project/declared-config.d.ts.map +1 -0
- package/dist/project/declared-config.js +60 -0
- package/dist/project/declared-config.js.map +1 -0
- package/dist/project/dependency-analyzer.d.ts.map +1 -1
- package/dist/project/dependency-analyzer.js.map +1 -1
- package/dist/project/deploy-phases.d.ts +35 -0
- package/dist/project/deploy-phases.d.ts.map +1 -0
- package/dist/project/deploy-phases.js +75 -0
- package/dist/project/deploy-phases.js.map +1 -0
- package/dist/project/exec-in-group.d.ts +49 -0
- package/dist/project/exec-in-group.d.ts.map +1 -0
- package/dist/project/exec-in-group.js +100 -0
- package/dist/project/exec-in-group.js.map +1 -0
- package/dist/project/node-app-config.d.ts +101 -0
- package/dist/project/node-app-config.d.ts.map +1 -0
- package/dist/project/node-app-config.js +134 -0
- package/dist/project/node-app-config.js.map +1 -0
- package/dist/project/node-app-health.d.ts +76 -0
- package/dist/project/node-app-health.d.ts.map +1 -0
- package/dist/project/node-app-health.js +119 -0
- package/dist/project/node-app-health.js.map +1 -0
- package/dist/project/operator-account.d.ts +293 -0
- package/dist/project/operator-account.d.ts.map +1 -0
- package/dist/project/operator-account.js +373 -0
- package/dist/project/operator-account.js.map +1 -0
- package/dist/project/registry.d.ts +45 -8
- package/dist/project/registry.d.ts.map +1 -1
- package/dist/project/registry.js +214 -64
- package/dist/project/registry.js.map +1 -1
- package/dist/project/requirements-scanner.d.ts +1 -0
- package/dist/project/requirements-scanner.d.ts.map +1 -1
- package/dist/project/requirements-scanner.js +28 -3
- package/dist/project/requirements-scanner.js.map +1 -1
- package/dist/project/stack-env.d.ts +37 -0
- package/dist/project/stack-env.d.ts.map +1 -0
- package/dist/project/stack-env.js +85 -0
- package/dist/project/stack-env.js.map +1 -0
- package/dist/project/stand-containers.d.ts +11 -0
- package/dist/project/stand-containers.d.ts.map +1 -0
- package/dist/project/stand-containers.js +27 -0
- package/dist/project/stand-containers.js.map +1 -0
- package/dist/project/working-tree.d.ts +62 -0
- package/dist/project/working-tree.d.ts.map +1 -0
- package/dist/project/working-tree.js +101 -0
- package/dist/project/working-tree.js.map +1 -0
- package/dist/release/artifact-store.d.ts +360 -0
- package/dist/release/artifact-store.d.ts.map +1 -0
- package/dist/release/artifact-store.js +1040 -0
- package/dist/release/artifact-store.js.map +1 -0
- package/dist/release/attest-on-node.d.ts +93 -0
- package/dist/release/attest-on-node.d.ts.map +1 -0
- package/dist/release/attest-on-node.js +207 -0
- package/dist/release/attest-on-node.js.map +1 -0
- package/dist/release/attest.d.ts +135 -0
- package/dist/release/attest.d.ts.map +1 -0
- package/dist/release/attest.js +199 -0
- package/dist/release/attest.js.map +1 -0
- package/dist/release/build-run.d.ts +151 -0
- package/dist/release/build-run.d.ts.map +1 -0
- package/dist/release/build-run.js +609 -0
- package/dist/release/build-run.js.map +1 -0
- package/dist/release/builder.d.ts +57 -0
- package/dist/release/builder.d.ts.map +1 -0
- package/dist/release/builder.js +120 -0
- package/dist/release/builder.js.map +1 -0
- package/dist/release/daemon-omni.d.ts +41 -0
- package/dist/release/daemon-omni.d.ts.map +1 -0
- package/dist/release/daemon-omni.js +59 -0
- package/dist/release/daemon-omni.js.map +1 -0
- package/dist/release/definition-inputs.d.ts +34 -0
- package/dist/release/definition-inputs.d.ts.map +1 -0
- package/dist/release/definition-inputs.js +90 -0
- package/dist/release/definition-inputs.js.map +1 -0
- package/dist/release/delivered.d.ts +53 -0
- package/dist/release/delivered.d.ts.map +1 -0
- package/dist/release/delivered.js +81 -0
- package/dist/release/delivered.js.map +1 -0
- package/dist/release/layout.d.ts +61 -0
- package/dist/release/layout.d.ts.map +1 -0
- package/dist/release/layout.js +114 -0
- package/dist/release/layout.js.map +1 -0
- package/dist/release/load.d.ts +44 -0
- package/dist/release/load.d.ts.map +1 -0
- package/dist/release/load.js +84 -0
- package/dist/release/load.js.map +1 -0
- package/dist/release/manifest.d.ts +299 -0
- package/dist/release/manifest.d.ts.map +1 -0
- package/dist/release/manifest.js +176 -0
- package/dist/release/manifest.js.map +1 -0
- package/dist/release/migrations.d.ts +32 -0
- package/dist/release/migrations.d.ts.map +1 -0
- package/dist/release/migrations.js +51 -0
- package/dist/release/migrations.js.map +1 -0
- package/dist/release/publish.d.ts +71 -0
- package/dist/release/publish.d.ts.map +1 -0
- package/dist/release/publish.js +102 -0
- package/dist/release/publish.js.map +1 -0
- package/dist/release/store.d.ts +174 -0
- package/dist/release/store.d.ts.map +1 -0
- package/dist/release/store.js +257 -0
- package/dist/release/store.js.map +1 -0
- package/dist/services/alert.rpc-service.d.ts +11 -15
- package/dist/services/alert.rpc-service.d.ts.map +1 -1
- package/dist/services/alert.rpc-service.js +29 -14
- package/dist/services/alert.rpc-service.js.map +1 -1
- package/dist/services/alert.service.d.ts +96 -59
- package/dist/services/alert.service.d.ts.map +1 -1
- package/dist/services/alert.service.js +455 -70
- package/dist/services/alert.service.js.map +1 -1
- package/dist/services/anonymous-input.d.ts +26 -0
- package/dist/services/anonymous-input.d.ts.map +1 -0
- package/dist/services/anonymous-input.js +44 -0
- package/dist/services/anonymous-input.js.map +1 -0
- package/dist/services/audit.rpc-service.d.ts +27 -0
- package/dist/services/audit.rpc-service.d.ts.map +1 -0
- package/dist/services/audit.rpc-service.js +57 -0
- package/dist/services/audit.rpc-service.js.map +1 -0
- package/dist/services/audit.service.d.ts +165 -0
- package/dist/services/audit.service.d.ts.map +1 -0
- package/dist/services/audit.service.js +242 -0
- package/dist/services/audit.service.js.map +1 -0
- package/dist/services/auth-context.d.ts +21 -1
- package/dist/services/auth-context.d.ts.map +1 -1
- package/dist/services/auth-context.js +51 -5
- package/dist/services/auth-context.js.map +1 -1
- package/dist/services/auth.rpc-service.d.ts +0 -1
- package/dist/services/auth.rpc-service.d.ts.map +1 -1
- package/dist/services/auth.rpc-service.js +23 -9
- package/dist/services/auth.rpc-service.js.map +1 -1
- package/dist/services/auth.service.d.ts +47 -33
- package/dist/services/auth.service.d.ts.map +1 -1
- package/dist/services/auth.service.js +155 -23
- package/dist/services/auth.service.js.map +1 -1
- package/dist/services/backup-pipeline.d.ts +97 -0
- package/dist/services/backup-pipeline.d.ts.map +1 -0
- package/dist/services/backup-pipeline.js +286 -0
- package/dist/services/backup-pipeline.js.map +1 -0
- package/dist/services/backup-schedule.d.ts +69 -0
- package/dist/services/backup-schedule.d.ts.map +1 -0
- package/dist/services/backup-schedule.js +132 -0
- package/dist/services/backup-schedule.js.map +1 -0
- package/dist/services/backup.rpc-service.d.ts +31 -2
- package/dist/services/backup.rpc-service.d.ts.map +1 -1
- package/dist/services/backup.rpc-service.js +53 -0
- package/dist/services/backup.rpc-service.js.map +1 -1
- package/dist/services/backup.service.d.ts +458 -14
- package/dist/services/backup.service.d.ts.map +1 -1
- package/dist/services/backup.service.js +1368 -170
- package/dist/services/backup.service.js.map +1 -1
- package/dist/services/bundle-build-worker.d.ts +19 -0
- package/dist/services/bundle-build-worker.d.ts.map +1 -0
- package/dist/services/bundle-build-worker.js +40 -0
- package/dist/services/bundle-build-worker.js.map +1 -0
- package/dist/services/bundle-builder.d.ts +490 -0
- package/dist/services/bundle-builder.d.ts.map +1 -0
- package/dist/services/bundle-builder.js +1159 -0
- package/dist/services/bundle-builder.js.map +1 -0
- package/dist/services/bundle-worker-protocol.d.ts +19 -0
- package/dist/services/bundle-worker-protocol.d.ts.map +1 -0
- package/dist/services/bundle-worker-protocol.js +32 -0
- package/dist/services/bundle-worker-protocol.js.map +1 -0
- package/dist/services/deploy.rpc-service.d.ts +4 -1
- package/dist/services/deploy.rpc-service.d.ts.map +1 -1
- package/dist/services/deploy.rpc-service.js +10 -0
- package/dist/services/deploy.rpc-service.js.map +1 -1
- package/dist/services/deploy.service.d.ts +14 -24
- package/dist/services/deploy.service.d.ts.map +1 -1
- package/dist/services/deploy.service.js +46 -5
- package/dist/services/deploy.service.js.map +1 -1
- package/dist/services/discovery.rpc-service.d.ts +2 -1
- package/dist/services/discovery.rpc-service.d.ts.map +1 -1
- package/dist/services/discovery.rpc-service.js.map +1 -1
- package/dist/services/discovery.service.d.ts +32 -28
- package/dist/services/discovery.service.d.ts.map +1 -1
- package/dist/services/discovery.service.js +108 -133
- package/dist/services/discovery.service.js.map +1 -1
- package/dist/services/event-broadcaster.rpc-service.d.ts +36 -23
- package/dist/services/event-broadcaster.rpc-service.d.ts.map +1 -1
- package/dist/services/event-broadcaster.rpc-service.js +70 -32
- package/dist/services/event-broadcaster.rpc-service.js.map +1 -1
- package/dist/services/event-broadcaster.service.d.ts.map +1 -1
- package/dist/services/event-broadcaster.service.js.map +1 -1
- package/dist/services/fleet.rpc-service.d.ts +2 -1
- package/dist/services/fleet.rpc-service.d.ts.map +1 -1
- package/dist/services/fleet.rpc-service.js +3 -1
- package/dist/services/fleet.rpc-service.js.map +1 -1
- package/dist/services/fleet.service.d.ts +32 -34
- package/dist/services/fleet.service.d.ts.map +1 -1
- package/dist/services/fleet.service.js +66 -10
- package/dist/services/fleet.service.js.map +1 -1
- package/dist/services/health-check.rpc-service.d.ts +2 -1
- package/dist/services/health-check.rpc-service.d.ts.map +1 -1
- package/dist/services/health-check.rpc-service.js.map +1 -1
- package/dist/services/health-check.service.d.ts +50 -36
- package/dist/services/health-check.service.d.ts.map +1 -1
- package/dist/services/health-check.service.js +179 -182
- package/dist/services/health-check.service.js.map +1 -1
- package/dist/services/host-operation-barrier.d.ts +8 -0
- package/dist/services/host-operation-barrier.d.ts.map +1 -0
- package/dist/services/host-operation-barrier.js +44 -0
- package/dist/services/host-operation-barrier.js.map +1 -0
- package/dist/services/host-upgrade.d.ts +129 -0
- package/dist/services/host-upgrade.d.ts.map +1 -0
- package/dist/services/host-upgrade.js +352 -0
- package/dist/services/host-upgrade.js.map +1 -0
- package/dist/services/infrastructure.rpc-service.d.ts +312 -2
- package/dist/services/infrastructure.rpc-service.d.ts.map +1 -1
- package/dist/services/infrastructure.rpc-service.js +584 -11
- package/dist/services/infrastructure.rpc-service.js.map +1 -1
- package/dist/services/kubernetes.rpc-service.d.ts +2 -1
- package/dist/services/kubernetes.rpc-service.d.ts.map +1 -1
- package/dist/services/kubernetes.rpc-service.js.map +1 -1
- package/dist/services/kubernetes.service.d.ts +5 -39
- package/dist/services/kubernetes.service.d.ts.map +1 -1
- package/dist/services/kubernetes.service.js +29 -5
- package/dist/services/kubernetes.service.js.map +1 -1
- package/dist/services/local-bundle.d.ts +160 -0
- package/dist/services/local-bundle.d.ts.map +1 -0
- package/dist/services/local-bundle.js +242 -0
- package/dist/services/local-bundle.js.map +1 -0
- package/dist/services/lockout.d.ts +28 -0
- package/dist/services/lockout.d.ts.map +1 -0
- package/dist/services/lockout.js +41 -0
- package/dist/services/lockout.js.map +1 -0
- package/dist/services/log-collector.rpc-service.d.ts +16 -0
- package/dist/services/log-collector.rpc-service.d.ts.map +1 -1
- package/dist/services/log-collector.rpc-service.js +16 -0
- package/dist/services/log-collector.rpc-service.js.map +1 -1
- package/dist/services/log-collector.service.d.ts +172 -54
- package/dist/services/log-collector.service.d.ts.map +1 -1
- package/dist/services/log-collector.service.js +492 -102
- package/dist/services/log-collector.service.js.map +1 -1
- package/dist/services/log-retention.d.ts +50 -0
- package/dist/services/log-retention.d.ts.map +1 -0
- package/dist/services/log-retention.js +52 -0
- package/dist/services/log-retention.js.map +1 -0
- package/dist/services/maintenance-lock.d.ts +162 -0
- package/dist/services/maintenance-lock.d.ts.map +1 -0
- package/dist/services/maintenance-lock.js +316 -0
- package/dist/services/maintenance-lock.js.map +1 -0
- package/dist/services/master-address.d.ts +107 -0
- package/dist/services/master-address.d.ts.map +1 -0
- package/dist/services/master-address.js +154 -0
- package/dist/services/master-address.js.map +1 -0
- package/dist/services/migration-output.d.ts +16 -0
- package/dist/services/migration-output.d.ts.map +1 -0
- package/dist/services/migration-output.js +22 -0
- package/dist/services/migration-output.js.map +1 -0
- package/dist/services/netron-telemetry-transport.d.ts.map +1 -1
- package/dist/services/netron-telemetry-transport.js.map +1 -1
- package/dist/services/node-deploy-lease.d.ts +171 -0
- package/dist/services/node-deploy-lease.d.ts.map +1 -0
- package/dist/services/node-deploy-lease.js +460 -0
- package/dist/services/node-deploy-lease.js.map +1 -0
- package/dist/services/node-health.repository.d.ts +63 -4
- package/dist/services/node-health.repository.d.ts.map +1 -1
- package/dist/services/node-health.repository.js +108 -67
- package/dist/services/node-health.repository.js.map +1 -1
- package/dist/services/node-manager.rpc-service.d.ts +360 -10
- package/dist/services/node-manager.rpc-service.d.ts.map +1 -1
- package/dist/services/node-manager.rpc-service.js +754 -34
- package/dist/services/node-manager.rpc-service.js.map +1 -1
- package/dist/services/node-manager.service.d.ts +267 -95
- package/dist/services/node-manager.service.d.ts.map +1 -1
- package/dist/services/node-manager.service.js +805 -103
- package/dist/services/node-manager.service.js.map +1 -1
- package/dist/services/node-upgrade.d.ts +129 -0
- package/dist/services/node-upgrade.d.ts.map +1 -0
- package/dist/services/node-upgrade.js +161 -0
- package/dist/services/node-upgrade.js.map +1 -0
- package/dist/services/node-upgrade.service.d.ts +232 -0
- package/dist/services/node-upgrade.service.d.ts.map +1 -0
- package/dist/services/node-upgrade.service.js +468 -0
- package/dist/services/node-upgrade.service.js.map +1 -0
- package/dist/services/pipeline.rpc-service.d.ts +6 -1
- package/dist/services/pipeline.rpc-service.d.ts.map +1 -1
- package/dist/services/pipeline.rpc-service.js +9 -0
- package/dist/services/pipeline.rpc-service.js.map +1 -1
- package/dist/services/pipeline.service.d.ts +17 -46
- package/dist/services/pipeline.service.d.ts.map +1 -1
- package/dist/services/pipeline.service.js +84 -9
- package/dist/services/pipeline.service.js.map +1 -1
- package/dist/services/project.rpc-service.d.ts +140 -5
- package/dist/services/project.rpc-service.d.ts.map +1 -1
- package/dist/services/project.rpc-service.js +260 -22
- package/dist/services/project.rpc-service.js.map +1 -1
- package/dist/services/project.service.d.ts +687 -15
- package/dist/services/project.service.d.ts.map +1 -1
- package/dist/services/project.service.js +2846 -337
- package/dist/services/project.service.js.map +1 -1
- package/dist/services/redeploy-decision.d.ts +176 -0
- package/dist/services/redeploy-decision.d.ts.map +1 -0
- package/dist/services/redeploy-decision.js +142 -0
- package/dist/services/redeploy-decision.js.map +1 -0
- package/dist/services/release.rpc-service.d.ts +159 -0
- package/dist/services/release.rpc-service.d.ts.map +1 -0
- package/dist/services/release.rpc-service.js +395 -0
- package/dist/services/release.rpc-service.js.map +1 -0
- package/dist/services/release.service.d.ts +114 -0
- package/dist/services/release.service.d.ts.map +1 -0
- package/dist/services/release.service.js +208 -0
- package/dist/services/release.service.js.map +1 -0
- package/dist/services/remote-deployer.service.d.ts +580 -8
- package/dist/services/remote-deployer.service.d.ts.map +1 -1
- package/dist/services/remote-deployer.service.js +1786 -169
- package/dist/services/remote-deployer.service.js.map +1 -1
- package/dist/services/remote-ops.service.d.ts +51 -9
- package/dist/services/remote-ops.service.d.ts.map +1 -1
- package/dist/services/remote-ops.service.js +235 -39
- package/dist/services/remote-ops.service.js.map +1 -1
- package/dist/services/remote-provisioner.d.ts +124 -0
- package/dist/services/remote-provisioner.d.ts.map +1 -0
- package/dist/services/remote-provisioner.js +258 -0
- package/dist/services/remote-provisioner.js.map +1 -0
- package/dist/services/secrets.rpc-service.d.ts +51 -2
- package/dist/services/secrets.rpc-service.d.ts.map +1 -1
- package/dist/services/secrets.rpc-service.js +81 -2
- package/dist/services/secrets.rpc-service.js.map +1 -1
- package/dist/services/secrets.service.d.ts +108 -9
- package/dist/services/secrets.service.d.ts.map +1 -1
- package/dist/services/secrets.service.js +313 -48
- package/dist/services/secrets.service.js.map +1 -1
- package/dist/services/slave-storage.service.d.ts +107 -0
- package/dist/services/slave-storage.service.d.ts.map +1 -1
- package/dist/services/slave-storage.service.js +171 -2
- package/dist/services/slave-storage.service.js.map +1 -1
- package/dist/services/static-carry-forward.d.ts +110 -0
- package/dist/services/static-carry-forward.d.ts.map +1 -0
- package/dist/services/static-carry-forward.js +433 -0
- package/dist/services/static-carry-forward.js.map +1 -0
- package/dist/services/sync-policy.d.ts +167 -0
- package/dist/services/sync-policy.d.ts.map +1 -0
- package/dist/services/sync-policy.js +161 -0
- package/dist/services/sync-policy.js.map +1 -0
- package/dist/services/sync-summary.d.ts +39 -0
- package/dist/services/sync-summary.d.ts.map +1 -0
- package/dist/services/sync-summary.js +62 -0
- package/dist/services/sync-summary.js.map +1 -0
- package/dist/services/sync.rpc-service.d.ts +19 -7
- package/dist/services/sync.rpc-service.d.ts.map +1 -1
- package/dist/services/sync.rpc-service.js +36 -5
- package/dist/services/sync.rpc-service.js.map +1 -1
- package/dist/services/sync.service.d.ts +350 -18
- package/dist/services/sync.service.d.ts.map +1 -1
- package/dist/services/sync.service.js +864 -116
- package/dist/services/sync.service.js.map +1 -1
- package/dist/services/system-info.rpc-service.d.ts +2 -1
- package/dist/services/system-info.rpc-service.d.ts.map +1 -1
- package/dist/services/system-info.rpc-service.js.map +1 -1
- package/dist/services/system-info.service.d.ts +56 -68
- package/dist/services/system-info.service.d.ts.map +1 -1
- package/dist/services/system-info.service.js +240 -127
- package/dist/services/system-info.service.js.map +1 -1
- package/dist/services/telemetry.rpc-service.d.ts.map +1 -1
- package/dist/services/telemetry.rpc-service.js +9 -3
- package/dist/services/telemetry.rpc-service.js.map +1 -1
- package/dist/services/telemetry.service.d.ts +4 -2
- package/dist/services/telemetry.service.d.ts.map +1 -1
- package/dist/services/telemetry.service.js +4 -2
- package/dist/services/telemetry.service.js.map +1 -1
- package/dist/services/trace-collector.rpc-service.d.ts +2 -1
- package/dist/services/trace-collector.rpc-service.d.ts.map +1 -1
- package/dist/services/trace-collector.rpc-service.js.map +1 -1
- package/dist/services/trace-collector.service.d.ts +2 -41
- package/dist/services/trace-collector.service.d.ts.map +1 -1
- package/dist/services/trace-collector.service.js +27 -7
- package/dist/services/trace-collector.service.js.map +1 -1
- package/dist/services/wait-for-postgres.d.ts +28 -0
- package/dist/services/wait-for-postgres.d.ts.map +1 -0
- package/dist/services/wait-for-postgres.js +77 -0
- package/dist/services/wait-for-postgres.js.map +1 -0
- package/dist/shared/alert-expression.d.ts +60 -0
- package/dist/shared/alert-expression.d.ts.map +1 -0
- package/dist/shared/alert-expression.js +124 -0
- package/dist/shared/alert-expression.js.map +1 -0
- package/dist/shared/audit-outcome.d.ts +39 -0
- package/dist/shared/audit-outcome.d.ts.map +1 -0
- package/dist/shared/audit-outcome.js +45 -0
- package/dist/shared/audit-outcome.js.map +1 -0
- package/dist/shared/build-freshness.d.ts +59 -0
- package/dist/shared/build-freshness.d.ts.map +1 -0
- package/dist/shared/build-freshness.js +113 -0
- package/dist/shared/build-freshness.js.map +1 -0
- package/dist/shared/build-stamp.d.ts +26 -0
- package/dist/shared/build-stamp.d.ts.map +1 -0
- package/dist/shared/build-stamp.js +36 -0
- package/dist/shared/build-stamp.js.map +1 -0
- package/dist/shared/describe-error.d.ts +22 -0
- package/dist/shared/describe-error.d.ts.map +1 -0
- package/dist/shared/describe-error.js +39 -0
- package/dist/shared/describe-error.js.map +1 -0
- package/dist/shared/dto/alerts.d.ts +101 -0
- package/dist/shared/dto/alerts.d.ts.map +1 -0
- package/dist/shared/dto/alerts.js +9 -0
- package/dist/shared/dto/alerts.js.map +1 -0
- package/dist/shared/dto/auth.d.ts +49 -0
- package/dist/shared/dto/auth.d.ts.map +1 -0
- package/dist/shared/dto/auth.js +14 -0
- package/dist/shared/dto/auth.js.map +1 -0
- package/dist/shared/dto/backups.d.ts +16 -0
- package/dist/shared/dto/backups.d.ts.map +1 -0
- package/dist/shared/dto/backups.js +9 -0
- package/dist/shared/dto/backups.js.map +1 -0
- package/dist/shared/dto/deploy.d.ts +28 -0
- package/dist/shared/dto/deploy.d.ts.map +1 -0
- package/dist/shared/dto/deploy.js +8 -0
- package/dist/shared/dto/deploy.js.map +1 -0
- package/dist/shared/dto/discovery.d.ts +24 -0
- package/dist/shared/dto/discovery.d.ts.map +1 -0
- package/dist/shared/dto/discovery.js +9 -0
- package/dist/shared/dto/discovery.js.map +1 -0
- package/dist/shared/dto/fleet.d.ts +35 -0
- package/dist/shared/dto/fleet.d.ts.map +1 -0
- package/dist/shared/dto/fleet.js +8 -0
- package/dist/shared/dto/fleet.js.map +1 -0
- package/dist/shared/dto/health.d.ts +26 -0
- package/dist/shared/dto/health.d.ts.map +1 -0
- package/dist/shared/dto/health.js +9 -0
- package/dist/shared/dto/health.js.map +1 -0
- package/dist/shared/dto/kubernetes.d.ts +44 -0
- package/dist/shared/dto/kubernetes.d.ts.map +1 -0
- package/dist/shared/dto/kubernetes.js +9 -0
- package/dist/shared/dto/kubernetes.js.map +1 -0
- package/dist/shared/dto/logs.d.ts +77 -0
- package/dist/shared/dto/logs.d.ts.map +1 -0
- package/dist/shared/dto/logs.js +10 -0
- package/dist/shared/dto/logs.js.map +1 -0
- package/dist/shared/dto/metrics.d.ts +65 -0
- package/dist/shared/dto/metrics.d.ts.map +1 -0
- package/dist/shared/dto/metrics.js +17 -0
- package/dist/shared/dto/metrics.js.map +1 -0
- package/dist/shared/dto/nodes.d.ts +347 -0
- package/dist/shared/dto/nodes.d.ts.map +1 -0
- package/dist/shared/dto/nodes.js +8 -0
- package/dist/shared/dto/nodes.js.map +1 -0
- package/dist/shared/dto/pipelines.d.ts +53 -0
- package/dist/shared/dto/pipelines.d.ts.map +1 -0
- package/dist/shared/dto/pipelines.js +9 -0
- package/dist/shared/dto/pipelines.js.map +1 -0
- package/dist/shared/dto/project.d.ts +142 -8
- package/dist/shared/dto/project.d.ts.map +1 -1
- package/dist/shared/dto/services.d.ts +858 -7
- package/dist/shared/dto/services.d.ts.map +1 -1
- package/dist/shared/dto/system-info.d.ts +93 -0
- package/dist/shared/dto/system-info.d.ts.map +1 -0
- package/dist/shared/dto/system-info.js +9 -0
- package/dist/shared/dto/system-info.js.map +1 -0
- package/dist/shared/dto/traces.d.ts +49 -0
- package/dist/shared/dto/traces.d.ts.map +1 -0
- package/dist/shared/dto/traces.js +9 -0
- package/dist/shared/dto/traces.js.map +1 -0
- package/dist/shared/env-config.d.ts +74 -0
- package/dist/shared/env-config.d.ts.map +1 -0
- package/dist/shared/env-config.js +99 -0
- package/dist/shared/env-config.js.map +1 -0
- package/dist/shared/events.d.ts +45 -39
- package/dist/shared/events.d.ts.map +1 -1
- package/dist/shared/events.js +6 -0
- package/dist/shared/events.js.map +1 -1
- package/dist/shared/format.d.ts +1 -1
- package/dist/shared/format.d.ts.map +1 -1
- package/dist/shared/format.js +4 -0
- package/dist/shared/format.js.map +1 -1
- package/dist/shared/local-infra-host.d.ts +28 -0
- package/dist/shared/local-infra-host.d.ts.map +1 -0
- package/dist/shared/local-infra-host.js +28 -0
- package/dist/shared/local-infra-host.js.map +1 -0
- package/dist/shared/node-check.d.ts +37 -0
- package/dist/shared/node-check.d.ts.map +1 -0
- package/dist/shared/node-check.js +41 -0
- package/dist/shared/node-check.js.map +1 -0
- package/dist/shared/paths.d.ts +29 -0
- package/dist/shared/paths.d.ts.map +1 -0
- package/dist/shared/paths.js +54 -0
- package/dist/shared/paths.js.map +1 -0
- package/dist/shared/pnpm.d.ts +29 -0
- package/dist/shared/pnpm.d.ts.map +1 -0
- package/dist/shared/pnpm.js +57 -0
- package/dist/shared/pnpm.js.map +1 -0
- package/dist/shared/private-files.d.ts +29 -0
- package/dist/shared/private-files.d.ts.map +1 -0
- package/dist/shared/private-files.js +109 -0
- package/dist/shared/private-files.js.map +1 -0
- package/dist/shared/redact-env.d.ts +24 -0
- package/dist/shared/redact-env.d.ts.map +1 -0
- package/dist/shared/redact-env.js +36 -0
- package/dist/shared/redact-env.js.map +1 -0
- package/dist/shared/release-reading.d.ts +85 -0
- package/dist/shared/release-reading.d.ts.map +1 -0
- package/dist/shared/release-reading.js +81 -0
- package/dist/shared/release-reading.js.map +1 -0
- package/dist/shared/roles.d.ts +58 -3
- package/dist/shared/roles.d.ts.map +1 -1
- package/dist/shared/roles.js +55 -0
- package/dist/shared/roles.js.map +1 -1
- package/dist/shared/rpcauth.d.ts +13 -0
- package/dist/shared/rpcauth.d.ts.map +1 -0
- package/dist/shared/rpcauth.js +23 -0
- package/dist/shared/rpcauth.js.map +1 -0
- package/dist/shared/shell-escape.d.ts +9 -0
- package/dist/shared/shell-escape.d.ts.map +1 -0
- package/dist/shared/shell-escape.js +11 -0
- package/dist/shared/shell-escape.js.map +1 -0
- package/dist/shared/sync-reading.d.ts +45 -0
- package/dist/shared/sync-reading.d.ts.map +1 -0
- package/dist/shared/sync-reading.js +42 -0
- package/dist/shared/sync-reading.js.map +1 -0
- package/dist/shared/tokens.d.ts +19 -0
- package/dist/shared/tokens.d.ts.map +1 -1
- package/dist/shared/tokens.js +28 -0
- package/dist/shared/tokens.js.map +1 -1
- package/dist/webapp/webapp.service.d.ts +33 -2
- package/dist/webapp/webapp.service.d.ts.map +1 -1
- package/dist/webapp/webapp.service.js +143 -31
- package/dist/webapp/webapp.service.js.map +1 -1
- package/dist/workers/health-monitor-process.d.ts.map +1 -1
- package/dist/workers/health-monitor-process.js +10 -0
- package/dist/workers/health-monitor-process.js.map +1 -1
- package/dist/workers/health-monitor.service.d.ts +45 -3
- package/dist/workers/health-monitor.service.d.ts.map +1 -1
- package/dist/workers/health-monitor.service.js +152 -25
- package/dist/workers/health-monitor.service.js.map +1 -1
- package/dist/workers/system-worker-manager.d.ts +43 -0
- package/dist/workers/system-worker-manager.d.ts.map +1 -1
- package/dist/workers/system-worker-manager.js +150 -3
- package/dist/workers/system-worker-manager.js.map +1 -1
- package/dist/workers/types.d.ts +8 -2
- package/dist/workers/types.d.ts.map +1 -1
- package/package.json +68 -30
- package/webapp/dist/BUILD.json +5 -0
- package/webapp/dist/assets/FormControlLabel-BbSxpQwN.js +1 -0
- package/webapp/dist/assets/Grid-DizFZYue.js +1 -0
- package/webapp/dist/assets/Switch-Bfiqzx8l.js +1 -0
- package/webapp/dist/assets/alerts-DH_RVRS3.js +1 -0
- package/webapp/dist/assets/apps-B96355sz.js +1 -0
- package/webapp/dist/assets/audit-CYGtbi4k.js +1 -0
- package/webapp/dist/assets/client-BmqFExWT.js +1 -0
- package/webapp/dist/assets/constants-veKGFkC6.js +1 -0
- package/webapp/dist/assets/containers-B_TpThln.js +2 -0
- package/webapp/dist/assets/daemon-memory-CCPZ4cV_.js +1 -0
- package/webapp/dist/assets/dashboard-DHf2_65N.js +1 -0
- package/webapp/dist/assets/dashboard-builder-CWY2pjeG.js +1 -0
- package/webapp/dist/assets/deploy-release-dialog-Dp-zpSAd.js +1 -0
- package/webapp/dist/assets/deployments-tJI6O3fK.js +1 -0
- package/webapp/dist/assets/detail-B2zP1Hto.js +8 -0
- package/webapp/dist/assets/detail-CoIrwmsy.js +1 -0
- package/webapp/dist/assets/detail-DWaGaOtL.js +2 -0
- package/webapp/dist/assets/formatters-BqjL73N3.js +1 -0
- package/webapp/dist/assets/index-Dvo0iprx.css +1 -0
- package/webapp/dist/assets/index-vMnY_4jR.js +412 -0
- package/webapp/dist/assets/logs-DTRjOfX8.js +12 -0
- package/webapp/dist/assets/maplibre-gl-DowHoZAx.js +814 -0
- package/webapp/dist/assets/metrics-UCajtdox.js +2 -0
- package/webapp/dist/assets/nodes-DuTVU0f6.js +7 -0
- package/webapp/dist/assets/pipelines-C8BeDcAl.js +4 -0
- package/webapp/dist/assets/projects-Dp_zFfLY.js +1 -0
- package/webapp/dist/assets/react-DlmbjZJV.js +1 -0
- package/webapp/dist/assets/react-apexcharts.esm-C8pn45ml.js +97 -0
- package/webapp/dist/assets/release-bits-BzTKz5fM.js +1 -0
- package/webapp/dist/assets/release-build-panel-DcW9YcXQ.js +1 -0
- package/webapp/dist/assets/releases-B4hcr1bE.js +2 -0
- package/webapp/dist/assets/rolldown-runtime-XKyaHtl9.js +1 -0
- package/webapp/dist/assets/settings-DIteZTbe.js +1 -0
- package/webapp/dist/assets/settled-pair-C7SjZuns.js +1 -0
- package/webapp/dist/assets/sign-in-D4kMBOHp.js +1 -0
- package/webapp/dist/assets/stacks-Brnf-EB7.js +1 -0
- package/webapp/dist/assets/sync-reading-C3PnJ7AX.js +1 -0
- package/webapp/dist/assets/system-info-CFDNVKkU.js +1 -0
- package/webapp/dist/assets/topology-7WeTUsDN.js +12 -0
- package/webapp/dist/assets/topology-DLioOiRN.css +1 -0
- package/webapp/dist/assets/traces-9c3gwCN-.js +1 -0
- package/webapp/dist/assets/use-stack-context-CnA5FTHu.js +1 -0
- package/webapp/dist/index.html +6 -6
- package/dist/commands/dev.d.ts +0 -23
- package/dist/commands/dev.d.ts.map +0 -1
- package/dist/commands/dev.js +0 -76
- package/dist/commands/dev.js.map +0 -1
- package/dist/config/define-app.d.ts +0 -6
- package/dist/config/define-app.d.ts.map +0 -1
- package/dist/config/define-app.js +0 -38
- package/dist/config/define-app.js.map +0 -1
- package/dist/infrastructure/gateway-generator.d.ts +0 -63
- package/dist/infrastructure/gateway-generator.d.ts.map +0 -1
- package/dist/infrastructure/gateway-generator.js +0 -253
- package/dist/infrastructure/gateway-generator.js.map +0 -1
- package/dist/monitoring/health.service.d.ts +0 -14
- package/dist/monitoring/health.service.d.ts.map +0 -1
- package/dist/monitoring/health.service.js +0 -50
- package/dist/monitoring/health.service.js.map +0 -1
- package/dist/monitoring/metrics.service.d.ts +0 -14
- package/dist/monitoring/metrics.service.d.ts.map +0 -1
- package/dist/monitoring/metrics.service.js +0 -40
- package/dist/monitoring/metrics.service.js.map +0 -1
- package/dist/orchestrator/bootstrap-runner.d.ts +0 -15
- package/dist/orchestrator/bootstrap-runner.d.ts.map +0 -1
- package/dist/orchestrator/bootstrap-runner.js +0 -152
- package/dist/orchestrator/bootstrap-runner.js.map +0 -1
- package/dist/orchestrator/topology-proxy.d.ts +0 -65
- package/dist/orchestrator/topology-proxy.d.ts.map +0 -1
- package/dist/orchestrator/topology-proxy.js +0 -209
- package/dist/orchestrator/topology-proxy.js.map +0 -1
- package/dist/orchestrator/topology-relay.d.ts +0 -111
- package/dist/orchestrator/topology-relay.d.ts.map +0 -1
- package/dist/orchestrator/topology-relay.js +0 -255
- package/dist/orchestrator/topology-relay.js.map +0 -1
- package/dist/services/auth-middleware.d.ts +0 -47
- package/dist/services/auth-middleware.d.ts.map +0 -1
- package/dist/services/auth-middleware.js +0 -158
- package/dist/services/auth-middleware.js.map +0 -1
- package/dist/services/environment.rpc-service.d.ts +0 -22
- package/dist/services/environment.rpc-service.d.ts.map +0 -1
- package/dist/services/environment.rpc-service.js +0 -65
- package/dist/services/environment.rpc-service.js.map +0 -1
- package/dist/services/environment.service.d.ts +0 -87
- package/dist/services/environment.service.d.ts.map +0 -1
- package/dist/services/environment.service.js +0 -220
- package/dist/services/environment.service.js.map +0 -1
- package/dist/services/metrics-collector.service.d.ts +0 -103
- package/dist/services/metrics-collector.service.d.ts.map +0 -1
- package/dist/services/metrics-collector.service.js +0 -235
- package/dist/services/metrics-collector.service.js.map +0 -1
- package/dist/services/metrics.rpc-service.d.ts +0 -41
- package/dist/services/metrics.rpc-service.d.ts.map +0 -1
- package/dist/services/metrics.rpc-service.js +0 -90
- package/dist/services/metrics.rpc-service.js.map +0 -1
- package/dist/services/metrics.service.d.ts +0 -72
- package/dist/services/metrics.service.d.ts.map +0 -1
- package/dist/services/metrics.service.js +0 -185
- package/dist/services/metrics.service.js.map +0 -1
- package/dist/supervisor/omnitron-supervisor.d.ts +0 -21
- package/dist/supervisor/omnitron-supervisor.d.ts.map +0 -1
- package/dist/supervisor/omnitron-supervisor.js +0 -43
- package/dist/supervisor/omnitron-supervisor.js.map +0 -1
- package/dist/webapp/static-server.d.ts +0 -24
- package/dist/webapp/static-server.d.ts.map +0 -1
- package/dist/webapp/static-server.js +0 -152
- package/dist/webapp/static-server.js.map +0 -1
- package/webapp/dist/assets/Badge-D2ZBP5iK.js +0 -1
- package/webapp/dist/assets/Card-vO88g06B.js +0 -1
- package/webapp/dist/assets/CardActions-C9h7Q2wW.js +0 -1
- package/webapp/dist/assets/CardContent-BA_Xmmhk.js +0 -1
- package/webapp/dist/assets/CardHeader-ceIs__6x.js +0 -1
- package/webapp/dist/assets/Chip-Ckk0xUhK.js +0 -1
- package/webapp/dist/assets/DialogActions-BhHM7hov.js +0 -1
- package/webapp/dist/assets/DialogContentText-BT2JQRmK.js +0 -1
- package/webapp/dist/assets/FormControlLabel-CcQByVS8.js +0 -1
- package/webapp/dist/assets/Grid-14PETRQW.js +0 -1
- package/webapp/dist/assets/InputAdornment-B8aHIsQ7.js +0 -1
- package/webapp/dist/assets/Skeleton-B74-Ds6O.js +0 -37
- package/webapp/dist/assets/Switch-DvWD2wh4.js +0 -1
- package/webapp/dist/assets/SwitchBase-CDU4nY8O.js +0 -1
- package/webapp/dist/assets/Tab-DcCOYYp5.js +0 -1
- package/webapp/dist/assets/TableContainer-CzTh4mu-.js +0 -1
- package/webapp/dist/assets/TableRow-BySEreZR.js +0 -2
- package/webapp/dist/assets/TextField-BLf-BHz2.js +0 -1
- package/webapp/dist/assets/alerts-DnRbT41C.js +0 -1
- package/webapp/dist/assets/apps-CdR0VH2d.js +0 -1
- package/webapp/dist/assets/chunk-DtcAfS_W.js +0 -1
- package/webapp/dist/assets/client-DU8I_lDc.js +0 -2
- package/webapp/dist/assets/constants-BgnT-Xdy.js +0 -1
- package/webapp/dist/assets/containers-Dw-rRXV1.js +0 -1
- package/webapp/dist/assets/dashboard-CzgB0uZz.js +0 -1
- package/webapp/dist/assets/dashboard-builder-DsA0yg33.js +0 -1
- package/webapp/dist/assets/deployments-DtQAoIcQ.js +0 -1
- package/webapp/dist/assets/detail-BJR-G7JG.js +0 -1
- package/webapp/dist/assets/detail-nlCeSltl.js +0 -8
- package/webapp/dist/assets/formatters-Do41SRmE.js +0 -1
- package/webapp/dist/assets/index-ByQDwp2r.js +0 -566
- package/webapp/dist/assets/index-CHVXOsTS.css +0 -1
- package/webapp/dist/assets/isMuiElement-DwF2naaF.js +0 -1
- package/webapp/dist/assets/logs-Kn8o4H7k.js +0 -11
- package/webapp/dist/assets/metrics-DN8Zu5wT.js +0 -2
- package/webapp/dist/assets/nodes-Bgch7AtN.js +0 -7
- package/webapp/dist/assets/pipelines-Cry3qm-S.js +0 -4
- package/webapp/dist/assets/popper-BJFSj6rc.js +0 -1
- package/webapp/dist/assets/preload-helper-DSXbuxSR.js +0 -1
- package/webapp/dist/assets/projects-Dym2GI1U.js +0 -1
- package/webapp/dist/assets/react-apexcharts.esm-CSGK5Cxn.js +0 -958
- package/webapp/dist/assets/react-apexcharts.esm-DEAWOwx5.js +0 -1003
- package/webapp/dist/assets/settings-va3zTcow.js +0 -1
- package/webapp/dist/assets/sign-in-ik35umbp.js +0 -1
- package/webapp/dist/assets/stacks-CVFOnxbF.js +0 -1
- package/webapp/dist/assets/system-info-npIXAjX2.js +0 -1
- package/webapp/dist/assets/topology-CHpVij2M.css +0 -1
- package/webapp/dist/assets/topology-bDe70vLs.js +0 -12
- package/webapp/dist/assets/traces-DIIcT8DF.js +0 -1
- package/webapp/dist/assets/use-stack-context-DHLwZv1r.js +0 -1
- /package/webapp/dist/assets/{fs-CgZLtHiQ.js → fs-Ccl3sAcp.js} +0 -0
package/dist/daemon/daemon.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* - RBAC: role-based access on all RPC endpoints (admin/operator/viewer)
|
|
18
18
|
* - Config resolution: secrets + env-aware injection into apps
|
|
19
19
|
*/
|
|
20
|
+
import path from 'node:path';
|
|
20
21
|
import { Application, ShutdownReason, ShutdownPriority, ApplicationEvent } from '@omnitron-dev/titan';
|
|
21
22
|
import { UnixSocketTransport } from '@omnitron-dev/titan/netron/transport/unix';
|
|
22
23
|
import { TcpTransport } from '@omnitron-dev/titan/netron/transport/tcp';
|
|
@@ -43,23 +44,191 @@ import { FileWatcher } from '../orchestrator/file-watcher.js';
|
|
|
43
44
|
import { InfrastructureService } from '../infrastructure/infrastructure.service.js';
|
|
44
45
|
import { DockerHealthIndicator } from '../monitoring/docker-health.indicator.js';
|
|
45
46
|
import { AppHealthIndicator } from '../monitoring/app-health.indicator.js';
|
|
47
|
+
import { EventLoopWatch } from '../monitoring/event-loop-watch.js';
|
|
48
|
+
import { EventLoopStallIndicator } from '../monitoring/event-loop-stall.indicator.js';
|
|
46
49
|
import { registerDaemonJobs } from './daemon-scheduler.js';
|
|
47
50
|
import { METRICS_SERVICE_TOKEN as TITAN_METRICS_TOKEN } from '@omnitron-dev/titan-metrics';
|
|
48
|
-
import { ORCHESTRATOR_TOKEN, LOG_MANAGER_TOKEN, STATE_STORE_TOKEN, OMNITRON_DB_TOKEN, AUTH_SERVICE_TOKEN, LOG_COLLECTOR_TOKEN, FLEET_SERVICE_TOKEN, ALERT_SERVICE_TOKEN, HEALTH_CHECK_SERVICE_TOKEN, DISCOVERY_SERVICE_TOKEN, KUBERNETES_SERVICE_TOKEN, PIPELINE_SERVICE_TOKEN, TRACE_COLLECTOR_TOKEN, BACKUP_SERVICE_TOKEN, SECRETS_SERVICE_TOKEN, TELEMETRY_RELAY_TOKEN, DEPLOY_SERVICE_TOKEN, INFRASTRUCTURE_GATE_TOKEN, PROJECT_SERVICE_TOKEN, SLAVE_STORAGE_TOKEN, } from '../shared/tokens.js';
|
|
51
|
+
import { ORCHESTRATOR_TOKEN, LOG_MANAGER_TOKEN, STATE_STORE_TOKEN, OMNITRON_DB_TOKEN, AUTH_SERVICE_TOKEN, LOG_COLLECTOR_TOKEN, FLEET_SERVICE_TOKEN, ALERT_SERVICE_TOKEN, HEALTH_CHECK_SERVICE_TOKEN, DISCOVERY_SERVICE_TOKEN, KUBERNETES_SERVICE_TOKEN, PIPELINE_SERVICE_TOKEN, TRACE_COLLECTOR_TOKEN, BACKUP_SERVICE_TOKEN, SECRETS_SERVICE_TOKEN, AUDIT_SERVICE_TOKEN, DAEMON_STATE_STORE_TOKEN, TELEMETRY_RELAY_TOKEN, DEPLOY_SERVICE_TOKEN, INFRASTRUCTURE_GATE_TOKEN, PROJECT_SERVICE_TOKEN, SLAVE_STORAGE_TOKEN, } from '../shared/tokens.js';
|
|
49
52
|
import { APP_EVENTS, INFRA_EVENTS, DAEMON_EVENTS, PROJECT_EVENTS, STACK_EVENTS, NODE_EVENTS, } from '../shared/events.js';
|
|
50
53
|
import { JWT_SERVICE_TOKEN } from '@omnitron-dev/titan-auth';
|
|
51
|
-
import { AuthenticationManager } from '@omnitron-dev/titan/netron/auth';
|
|
54
|
+
import { AuthenticationManager, AuthorizationManager, } from '@omnitron-dev/titan/netron/auth';
|
|
52
55
|
import { createAuthContextWrapper } from '../services/auth-context.js';
|
|
56
|
+
import { ROLES } from '../shared/roles.js';
|
|
57
|
+
import { expandPath } from '../shared/paths.js';
|
|
58
|
+
/**
|
|
59
|
+
* Deadline for a request on the daemon's unix socket.
|
|
60
|
+
*
|
|
61
|
+
* Same value as `CLI_REQUEST_TIMEOUT` in `daemon-client.ts`: one number for
|
|
62
|
+
* one socket, stated by both ends rather than inherited from a default meant
|
|
63
|
+
* for wire requests.
|
|
64
|
+
*/
|
|
65
|
+
const DAEMON_SOCKET_REQUEST_TIMEOUT = 60_000;
|
|
66
|
+
/**
|
|
67
|
+
* Where the daemon listens. The default is loopback; anything the operator
|
|
68
|
+
* writes is passed through literally, `0.0.0.0` included.
|
|
69
|
+
*
|
|
70
|
+
* Exported so the two call sites below and the tests agree on one
|
|
71
|
+
* definition. They previously each carried their own copy of
|
|
72
|
+
* `host !== '0.0.0.0' ? host : '127.0.0.1'`, which is how the two of them
|
|
73
|
+
* plus the config default managed to disagree about what the default was.
|
|
74
|
+
*/
|
|
75
|
+
export function resolveBindHost(configured) {
|
|
76
|
+
return configured ?? '127.0.0.1';
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Where a daemon binds its fleet TCP transport.
|
|
80
|
+
*
|
|
81
|
+
* A master follows `daemon.host`, whose default is loopback — the safe answer
|
|
82
|
+
* for the machine an operator is sitting at.
|
|
83
|
+
*
|
|
84
|
+
* A slave cannot use that default, because being reachable is the whole of
|
|
85
|
+
* what a slave is for: the master dials it to check its health and to pull
|
|
86
|
+
* from it. Bound to loopback it is a daemon nobody can see, and the console
|
|
87
|
+
* shows it as offline for ever with no way to tell it from a machine that is
|
|
88
|
+
* genuinely down.
|
|
89
|
+
*
|
|
90
|
+
* It was exactly that, and by a longer route than a wrong default. The
|
|
91
|
+
* generated slave config carried `daemon: { host: '0.0.0.0', … }` — and
|
|
92
|
+
* `IEcosystemConfig`, the schema of the file it was written into, has no
|
|
93
|
+
* `daemon` key; the daemon boots from `~/.omnitron/config.json`, which until
|
|
94
|
+
* now could not carry one either. So the setting was written, ignored, and
|
|
95
|
+
* every provisioned slave would have bound 127.0.0.1.
|
|
96
|
+
*
|
|
97
|
+
* An explicit `host` still wins, for an operator who wants one interface.
|
|
98
|
+
*/
|
|
99
|
+
export function fleetBindHostFor(dc) {
|
|
100
|
+
if (dc.role === 'slave')
|
|
101
|
+
return dc.host ?? '0.0.0.0';
|
|
102
|
+
return resolveBindHost(dc.host);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The bind address a daemon should END UP with, from what was actually
|
|
106
|
+
* configured.
|
|
107
|
+
*
|
|
108
|
+
* `fleetBindHostFor` above takes the daemon's RUNNING config, and by the time
|
|
109
|
+
* anything holds one, `host` has been filled in from `DEFAULT_DAEMON_CONFIG`
|
|
110
|
+
* — so `?? '0.0.0.0'` can never fire and every slave binds loopback. The
|
|
111
|
+
* information it needs is whether an operator SET a host, and only the saved
|
|
112
|
+
* file knows that: absent means "no opinion", `127.0.0.1` means "loopback,
|
|
113
|
+
* deliberately".
|
|
114
|
+
*
|
|
115
|
+
* Measured 2026-09-14 on a provisioned slave, after the rule was written and
|
|
116
|
+
* before this existed:
|
|
117
|
+
*
|
|
118
|
+
* LISTEN 127.0.0.1:9700 ← the fleet port no master can dial
|
|
119
|
+
* LISTEN 127.0.0.1:9801
|
|
120
|
+
* LISTEN 127.0.0.1:9802
|
|
121
|
+
*
|
|
122
|
+
* The rule was right, the value it was given was already decided. This is the
|
|
123
|
+
* same rule applied where the answer is still open.
|
|
124
|
+
*/
|
|
125
|
+
export function effectiveBindHost(saved) {
|
|
126
|
+
if (saved?.host)
|
|
127
|
+
return saved.host;
|
|
128
|
+
if (saved?.role === 'slave')
|
|
129
|
+
return '0.0.0.0';
|
|
130
|
+
return DEFAULT_DAEMON_CONFIG.host;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Where a daemon binds the surfaces that exist to serve a console: the Netron
|
|
134
|
+
* HTTP RPC and the WebSocket.
|
|
135
|
+
*
|
|
136
|
+
* A master follows `daemon.host`, like everything else. A slave does not,
|
|
137
|
+
* because on a slave that knob is published for a different reason: a fleet
|
|
138
|
+
* node has to bind its TCP transport somewhere the master can reach, and a
|
|
139
|
+
* generated slave config therefore says `0.0.0.0`. The same value then
|
|
140
|
+
* published two more surfaces — an authentication endpoint and a WebSocket
|
|
141
|
+
* one that has no rate limit available to it — and a slave serves no console,
|
|
142
|
+
* so nothing dials either. They were cost without benefit, on a machine whose
|
|
143
|
+
* whole point is being somewhere else.
|
|
144
|
+
*/
|
|
145
|
+
export function consoleBindHostFor(dc) {
|
|
146
|
+
return dc.role === 'slave' ? '127.0.0.1' : resolveBindHost(dc.host);
|
|
147
|
+
}
|
|
148
|
+
/** Addresses that reach this host and nowhere else. */
|
|
149
|
+
export function isLoopbackHost(host) {
|
|
150
|
+
if (!host)
|
|
151
|
+
return true; // absent means the loopback default above
|
|
152
|
+
const h = host.trim().toLowerCase();
|
|
153
|
+
return h === '127.0.0.1' || h === 'localhost' || h === '::1' || h === '[::1]' || h.startsWith('127.');
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Is the daemon still accepting the password its own migration seeded?
|
|
157
|
+
*
|
|
158
|
+
* Resolves the auth service lazily and answers `false` on any failure — a
|
|
159
|
+
* daemon that cannot reach its database has a louder problem than this, and
|
|
160
|
+
* a warning that fails the boot would be a worse trade than the risk it
|
|
161
|
+
* describes.
|
|
162
|
+
*/
|
|
163
|
+
async function isSeededAdminPasswordInUse(app, logger) {
|
|
164
|
+
try {
|
|
165
|
+
const auth = await app.container.resolveAsync(AUTH_SERVICE_TOKEN);
|
|
166
|
+
return await auth.isUsingSeededAdminPassword();
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
logger.warn({ err: err.message }, 'Could not check whether the seeded admin password is still in use');
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* The address other fleet nodes should dial to reach this one.
|
|
175
|
+
*
|
|
176
|
+
* `peer.address` is not decoration: `leader-election.ts` calls `requestVote`
|
|
177
|
+
* and `leaderHeartbeat` against it. A node bound to `0.0.0.0` therefore may
|
|
178
|
+
* not advertise `0.0.0.0` (not routable) — and must not advertise
|
|
179
|
+
* `127.0.0.1` either, which is what it did: every other node in the fleet
|
|
180
|
+
* resolves that to itself, so votes and heartbeats meant for the leader go
|
|
181
|
+
* to the sender's own loopback. A wrong answer of the right shape.
|
|
182
|
+
*
|
|
183
|
+
* When the bind address says nothing about reachability, take the first
|
|
184
|
+
* non-internal IPv4 the host has. Loopback remains the honest answer only
|
|
185
|
+
* when there is genuinely nothing else — a single-host deployment, where
|
|
186
|
+
* no other node can reach this one regardless.
|
|
187
|
+
*/
|
|
188
|
+
export function advertisedAddress(bindHost) {
|
|
189
|
+
if (bindHost && bindHost !== '0.0.0.0' && bindHost !== '::')
|
|
190
|
+
return bindHost;
|
|
191
|
+
for (const addrs of Object.values(os.networkInterfaces())) {
|
|
192
|
+
for (const a of addrs ?? []) {
|
|
193
|
+
if (a.family === 'IPv4' && !a.internal)
|
|
194
|
+
return a.address;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return '127.0.0.1';
|
|
198
|
+
}
|
|
53
199
|
export class OmnitronDaemon {
|
|
54
200
|
app = null;
|
|
55
201
|
pidManager = null;
|
|
202
|
+
/** Port this daemon serves `/netron/invoke` on; advertised to fleet peers. */
|
|
203
|
+
rpcHttpPort = null;
|
|
56
204
|
fileWatcher = null;
|
|
57
205
|
infraService = null;
|
|
206
|
+
eventLoopWatch = null;
|
|
58
207
|
eventBroadcaster = null;
|
|
59
208
|
syncService = null;
|
|
60
209
|
nodeManagerService = null;
|
|
210
|
+
slaveConnector = null;
|
|
211
|
+
meshHandle = null;
|
|
61
212
|
nodeManagerRpcService = null;
|
|
213
|
+
/**
|
|
214
|
+
* The live record of release builds this daemon is running.
|
|
215
|
+
*
|
|
216
|
+
* Held on the daemon rather than in the container because it is the state
|
|
217
|
+
* of work in progress: a build that a restart kills leaves a release
|
|
218
|
+
* directory with no manifest, and that — not this — is the durable trace.
|
|
219
|
+
*/
|
|
220
|
+
releaseService = null;
|
|
62
221
|
systemWorkerManager = null;
|
|
222
|
+
/** Everything the health-monitor worker needs to be spawned again. */
|
|
223
|
+
healthWorkerSpawn = null;
|
|
224
|
+
healthWorkerRestartTimer = null;
|
|
225
|
+
healthWorkerRestartAttempts = 0;
|
|
226
|
+
/** The startup budget the worker is given, so a failure can name it. */
|
|
227
|
+
healthWorkerStartupTimeout = 0;
|
|
228
|
+
/** In-daemon check timer, armed only while the worker is down. */
|
|
229
|
+
fallbackNodeCheckTimer = null;
|
|
230
|
+
/** Set by the shutdown task so nothing schedules work on the way out. */
|
|
231
|
+
isShuttingDown = false;
|
|
63
232
|
leaderElection = null;
|
|
64
233
|
configSyncService = null;
|
|
65
234
|
metricsServer = null;
|
|
@@ -69,12 +238,17 @@ export class OmnitronDaemon {
|
|
|
69
238
|
get daemonConfig() { return this.dc; }
|
|
70
239
|
async start(config, options, daemonConfig) {
|
|
71
240
|
this.dc = daemonConfig ?? DEFAULT_DAEMON_CONFIG;
|
|
72
|
-
const pidFile = this.dc.pidFile
|
|
241
|
+
const pidFile = expandPath(this.dc.pidFile);
|
|
73
242
|
this.pidManager = new PidManager(pidFile);
|
|
74
243
|
if (this.pidManager.isRunning()) {
|
|
75
244
|
const existingPid = this.pidManager.getPid();
|
|
76
245
|
throw new Error(`Omnitron daemon already running (PID: ${existingPid})`);
|
|
77
246
|
}
|
|
247
|
+
// Stale file from a previous crash is normal — clean it up so the
|
|
248
|
+
// atomic `O_EXCL` write below succeeds. P1-L: doing this AFTER
|
|
249
|
+
// isRunning() returned false means we only delete known-dead
|
|
250
|
+
// markers; live daemons get the conflict error above.
|
|
251
|
+
this.pidManager.remove();
|
|
78
252
|
this.pidManager.write();
|
|
79
253
|
// 1. Create Titan Application (the daemon itself)
|
|
80
254
|
const DaemonModule = createDaemonModule(config, this.dc);
|
|
@@ -82,6 +256,25 @@ export class OmnitronDaemon {
|
|
|
82
256
|
name: 'omnitron',
|
|
83
257
|
version: CLI_VERSION,
|
|
84
258
|
});
|
|
259
|
+
// P1-M — install our own SIGHUP handler BEFORE Application's
|
|
260
|
+
// default shutdown handlers attach, so `kill -HUP <daemon>`
|
|
261
|
+
// triggers a config reload (the Unix convention for long-running
|
|
262
|
+
// daemons) instead of terminating the supervisor. We don't bind
|
|
263
|
+
// this through the Application's signal manager because that
|
|
264
|
+
// path is wired to `runShutdownTasks()`; we install at the
|
|
265
|
+
// process level and the listener runs first.
|
|
266
|
+
process.on('SIGHUP', () => {
|
|
267
|
+
this.reloadConfigOnHup().catch((err) => {
|
|
268
|
+
// The message already carries which steps applied — printing only
|
|
269
|
+
// `.message` was fine for the load failure and misleading for the
|
|
270
|
+
// apply failure, which is the one that leaves work half-done.
|
|
271
|
+
console.warn(`[omnitron] SIGHUP config reload failed: ${err.message}`);
|
|
272
|
+
const cause = err.cause;
|
|
273
|
+
if (cause) {
|
|
274
|
+
console.warn(`[omnitron] caused by: ${cause.stack ?? String(cause)}`);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
});
|
|
85
278
|
// 2. Register transports (Unix, TCP, HTTP, WebSocket)
|
|
86
279
|
await this.registerTransports(this.dc);
|
|
87
280
|
// 3. Resolve and expose RPC services via Netron
|
|
@@ -90,6 +283,12 @@ export class OmnitronDaemon {
|
|
|
90
283
|
await this.app.start();
|
|
91
284
|
const loggerModule = await this.app.container.resolveAsync(LOGGER_SERVICE_TOKEN);
|
|
92
285
|
const logger = loggerModule.logger;
|
|
286
|
+
// As soon as there is somewhere to say it, so a stall in the boot's own
|
|
287
|
+
// steps — infrastructure, migrations — is seen too. A node whose loop
|
|
288
|
+
// stands still answers nothing, its heartbeat included, and until this
|
|
289
|
+
// nothing on the node could say so. See `monitoring/event-loop-watch.ts`.
|
|
290
|
+
this.eventLoopWatch = new EventLoopWatch(logger);
|
|
291
|
+
this.eventLoopWatch.start();
|
|
93
292
|
logger.info({
|
|
94
293
|
socketPath: this.dc.socketPath,
|
|
95
294
|
port: this.dc.port,
|
|
@@ -108,12 +307,12 @@ export class OmnitronDaemon {
|
|
|
108
307
|
// 7. Register custom health indicators (Docker + apps)
|
|
109
308
|
await this.registerHealthIndicators();
|
|
110
309
|
// 8. File watching (dev mode)
|
|
111
|
-
this.startFileWatcher(config, options, logger);
|
|
310
|
+
await this.startFileWatcher(config, options, logger);
|
|
112
311
|
// 8.5. Wire daemon Netron to orchestrator for native topology routing
|
|
113
312
|
{
|
|
114
313
|
const orchestrator = await this.app.container.resolveAsync(ORCHESTRATOR_TOKEN);
|
|
115
314
|
if (this.app.netron) {
|
|
116
|
-
const socketPath = this.dc.socketPath
|
|
315
|
+
const socketPath = expandPath(this.dc.socketPath);
|
|
117
316
|
orchestrator.setDaemonNetron(this.app.netron, socketPath);
|
|
118
317
|
}
|
|
119
318
|
// 8.6. Wire metrics bridge + start /metrics HTTP endpoint.
|
|
@@ -148,7 +347,24 @@ export class OmnitronDaemon {
|
|
|
148
347
|
if (savedConfig?.webapp) {
|
|
149
348
|
try {
|
|
150
349
|
const { WebappService } = await import('../webapp/webapp.service.js');
|
|
151
|
-
|
|
350
|
+
// Publishing the console while the seeded password is still in
|
|
351
|
+
// place hands the whole control plane — start, stop, restart, logs,
|
|
352
|
+
// config — to anyone who can reach the port and guess a word that
|
|
353
|
+
// is written in the migration. Migration 001 says the password
|
|
354
|
+
// "MUST be changed on first login"; nothing enforced it, and a
|
|
355
|
+
// comment is not a control.
|
|
356
|
+
//
|
|
357
|
+
// So the console falls back to loopback rather than refusing to
|
|
358
|
+
// start: the operator needs it to change the password, and a
|
|
359
|
+
// control plane that will not come up is its own outage. The log
|
|
360
|
+
// line says what to do and that this is not the configured bind.
|
|
361
|
+
let consoleHost = this.dc.consoleBindHost ?? '127.0.0.1';
|
|
362
|
+
if (!isLoopbackHost(consoleHost) && (await isSeededAdminPasswordInUse(this.app, logger))) {
|
|
363
|
+
logger.error({ configured: consoleHost, bound: '127.0.0.1' }, 'REFUSING to publish the Console while the seeded admin password is unchanged — ' +
|
|
364
|
+
'binding loopback instead. Sign in at http://127.0.0.1 and change it, then restart.');
|
|
365
|
+
consoleHost = '127.0.0.1';
|
|
366
|
+
}
|
|
367
|
+
const webapp = new WebappService(logger, process.cwd(), (this.dc.httpPort ?? 9800) + 1, this.dc.httpPort ?? 9800, consoleHost);
|
|
152
368
|
await webapp.start();
|
|
153
369
|
}
|
|
154
370
|
catch (err) {
|
|
@@ -156,14 +372,34 @@ export class OmnitronDaemon {
|
|
|
156
372
|
}
|
|
157
373
|
}
|
|
158
374
|
}
|
|
375
|
+
// 8.9. Fleet monitoring. Started BEFORE managed apps and not awaited.
|
|
376
|
+
//
|
|
377
|
+
// It used to be step 11.5, after `startApps`, `startScheduledTasks` and
|
|
378
|
+
// `startBackgroundServices`. Fleet monitoring is about MACHINES; it has
|
|
379
|
+
// nothing to do with whether this daemon's managed applications start, and
|
|
380
|
+
// gating it behind them means one application that fails its startup
|
|
381
|
+
// leaves the whole fleet unwatched for as long as the supervisor keeps
|
|
382
|
+
// retrying it. Measured on this host: ten minutes after a daemon start,
|
|
383
|
+
// with two applications still cycling through failed starts, not a single
|
|
384
|
+
// node had been checked and nothing had said so.
|
|
385
|
+
//
|
|
386
|
+
// Not awaited, for the same reason in the other direction: spawning the
|
|
387
|
+
// worker has a 30-second startup timeout, and the applications should not
|
|
388
|
+
// wait behind it. The function handles and logs its own failures, and arms
|
|
389
|
+
// the in-daemon fallback checks when the worker cannot run.
|
|
390
|
+
void this.startHealthMonitorWorker(logger).catch((err) => {
|
|
391
|
+
// It handles its own failures; this is the last resort, because an
|
|
392
|
+
// unhandled rejection is a crash of the daemon rather than a lost
|
|
393
|
+
// subsystem.
|
|
394
|
+
logger.error({ error: err.message }, 'Health monitor startup threw');
|
|
395
|
+
});
|
|
159
396
|
// 9. Start managed apps (waits for infra gate if apps have `requires`)
|
|
160
397
|
await this.startApps(config, logger);
|
|
161
398
|
// 10. Start background tasks via titan-scheduler (replaces bare setInterval)
|
|
162
399
|
await this.startScheduledTasks(config, logger);
|
|
163
400
|
// 11. Start remaining background services (telemetry, traces, leader election)
|
|
164
401
|
await this.startBackgroundServices(config, logger);
|
|
165
|
-
//
|
|
166
|
-
await this.startHealthMonitorWorker(logger);
|
|
402
|
+
// (Fleet monitoring is started at 8.5, above — before managed apps.)
|
|
167
403
|
// 12. Wire event broadcasting (orchestrator events → WebSocket push)
|
|
168
404
|
await this.wireEventBroadcasting(logger);
|
|
169
405
|
// 13. Register shutdown tasks — Application handles SIGTERM/SIGINT
|
|
@@ -186,18 +422,87 @@ export class OmnitronDaemon {
|
|
|
186
422
|
this.app.netron.registerTransportServer('unix', {
|
|
187
423
|
name: 'daemon-local',
|
|
188
424
|
options: {
|
|
189
|
-
path: dc.socketPath
|
|
425
|
+
path: expandPath(dc.socketPath),
|
|
190
426
|
force: true,
|
|
191
427
|
mode: 0o600, // Owner-only access for security
|
|
428
|
+
// Every other party on this socket states a deadline and this one
|
|
429
|
+
// did not, so `netron.ts:797` — `serverRequestTimeout ??
|
|
430
|
+
// transportOpts.requestTimeout` — found both undefined and built its
|
|
431
|
+
// accepted-connection peers with netron's 5 s default, which is a
|
|
432
|
+
// deadline for a wire request rather than for management-plane work.
|
|
433
|
+
// The reading of the server option was added deliberately («a
|
|
434
|
+
// `requestTimeout` set on the server was silently ignored»); the
|
|
435
|
+
// value was never supplied. Same number as `CLI_REQUEST_TIMEOUT`,
|
|
436
|
+
// which the daemon's own client uses over this same socket.
|
|
437
|
+
requestTimeout: DAEMON_SOCKET_REQUEST_TIMEOUT,
|
|
438
|
+
// The same bridge the HTTP and WebSocket servers below have: it puts
|
|
439
|
+
// the context the guard admitted a call with — here the implicit
|
|
440
|
+
// `omnitron-local` set just after this — where the services read
|
|
441
|
+
// who is calling. This server had none, so for every CLI call the
|
|
442
|
+
// guard saw `omnitron-local` and the services saw nobody: the audit
|
|
443
|
+
// trail recorded `system` for 171 of the master's 178 rows, and an
|
|
444
|
+
// operator's deployment read exactly like the daemon's own boot
|
|
445
|
+
// autostart. No proxy stands in front of a unix socket, so the
|
|
446
|
+
// wrapper trusts no forwarded address — its default.
|
|
447
|
+
invocationWrapper: createAuthContextWrapper(),
|
|
192
448
|
},
|
|
193
449
|
});
|
|
194
|
-
//
|
|
450
|
+
// Local CLI trust. The Unix socket above is created mode 0600, so any
|
|
451
|
+
// peer that can open it is provably the same OS user that owns this
|
|
452
|
+
// daemon — the OS has already authenticated them. Grant those
|
|
453
|
+
// connections an implicit admin context so the local CLI satisfies the
|
|
454
|
+
// `@Public({ auth: { roles } })` guards on the daemon RPC services
|
|
455
|
+
// without a redundant JWT handshake (the CLI talks over this socket
|
|
456
|
+
// only). Remote transports — TCP (fleet), HTTP/WS (webapp) — are NOT
|
|
457
|
+
// registered here and keep requiring a validated token, so this widens
|
|
458
|
+
// nothing beyond same-user local access that the socket mode already
|
|
459
|
+
// grants.
|
|
460
|
+
this.app.netron.setTransportAuthContext('unix', {
|
|
461
|
+
userId: 'omnitron-local',
|
|
462
|
+
roles: [ROLES.ADMIN],
|
|
463
|
+
permissions: [],
|
|
464
|
+
metadata: { source: 'local-unix-socket' },
|
|
465
|
+
});
|
|
466
|
+
// TCP — remote fleet communication (cross-server). The default is
|
|
467
|
+
// 127.0.0.1 so a single-host deployment never exposes daemon control
|
|
468
|
+
// to the LAN; multi-host fleet operators opt in via `daemon.host`.
|
|
469
|
+
//
|
|
470
|
+
// The default belongs in DEFAULT_DAEMON_CONFIG, not here. It used to be
|
|
471
|
+
// enforced here instead, as `dc.host !== '0.0.0.0' ? dc.host :
|
|
472
|
+
// '127.0.0.1'` over a config default of `'0.0.0.0'` — absence encoded as
|
|
473
|
+
// a value from the domain of valid answers. `0.0.0.0` is not a marker for
|
|
474
|
+
// "unset", it is a bind address with a meaning, and it was the exact
|
|
475
|
+
// value the comment above it told fleet operators to set. Following the
|
|
476
|
+
// documentation produced loopback and no fleet, silently. It also
|
|
477
|
+
// contradicted every neighbouring knob: `consoleBindHost: '0.0.0.0'`
|
|
478
|
+
// publishes, and so does an app's transport host.
|
|
479
|
+
//
|
|
480
|
+
// (The original hazard — pre-fix this defaulted to all-interfaces while
|
|
481
|
+
// the AuthorizationManager below was missing, giving any LAN host an
|
|
482
|
+
// unauthenticated `stopAll({force:true})` — is answered by the default
|
|
483
|
+
// being loopback and by that manager now being wired.)
|
|
484
|
+
const tcpHost = fleetBindHostFor(dc);
|
|
485
|
+
if (!isLoopbackHost(tcpHost)) {
|
|
486
|
+
// Said, not enforced, and the difference is deliberate: silently
|
|
487
|
+
// rebinding a fleet transport to loopback would take a cluster down,
|
|
488
|
+
// and a node that cannot be reached is an outage rather than a
|
|
489
|
+
// hardening. The console above IS rebound, because its whole purpose
|
|
490
|
+
// is a password prompt and loopback still serves it.
|
|
491
|
+
void (async () => {
|
|
492
|
+
const loggerModule = await this.app.container.resolveAsync(LOGGER_SERVICE_TOKEN);
|
|
493
|
+
const log = loggerModule.logger;
|
|
494
|
+
if (await isSeededAdminPasswordInUse(this.app, log)) {
|
|
495
|
+
log.error({ host: tcpHost, port: dc.port }, 'The daemon fleet transport is published and the seeded admin password is unchanged — ' +
|
|
496
|
+
'anyone who can reach this port can sign in and stop every app. Change it now.');
|
|
497
|
+
}
|
|
498
|
+
})().catch(() => undefined);
|
|
499
|
+
}
|
|
195
500
|
this.app.netron.registerTransport('tcp', () => new TcpTransport());
|
|
196
501
|
this.app.netron.registerTransportServer('tcp', {
|
|
197
502
|
name: 'daemon-fleet',
|
|
198
503
|
options: {
|
|
199
504
|
port: dc.port,
|
|
200
|
-
host:
|
|
505
|
+
host: tcpHost,
|
|
201
506
|
},
|
|
202
507
|
});
|
|
203
508
|
// Auth — JWT validation + session check + role extraction
|
|
@@ -246,18 +551,79 @@ export class OmnitronDaemon {
|
|
|
246
551
|
},
|
|
247
552
|
tokenCache: { enabled: true, ttl: 10_000 },
|
|
248
553
|
});
|
|
249
|
-
|
|
250
|
-
|
|
554
|
+
// Wire the AuthorizationManager so the `@Public({ auth: { roles } })`
|
|
555
|
+
// decorators on DaemonRpcService are actually enforced on the wire.
|
|
556
|
+
// Without an authzManager, `remote-peer.ts:enforceMethodAccess`
|
|
557
|
+
// early-returns and every method is reachable by anyone who can
|
|
558
|
+
// mint a valid JWT, regardless of `roles`. The WS origin policy
|
|
559
|
+
// (`allowedOrigins: true` → same-host) closes the cross-origin
|
|
560
|
+
// upgrade attack against cookie-mode auth.
|
|
561
|
+
const authzManager = new AuthorizationManager(authLogger);
|
|
562
|
+
this.app.netron.configureAuth(authManager, authzManager, {
|
|
563
|
+
allowedOrigins: true,
|
|
564
|
+
});
|
|
565
|
+
// `trustProxy` is shared with the rate limiter deliberately: both answer
|
|
566
|
+
// the same question — is there a proxy in front whose forwarded headers
|
|
567
|
+
// we may believe? Two separate switches would eventually disagree.
|
|
568
|
+
const authContextWrapper = createAuthContextWrapper({
|
|
569
|
+
trustProxy: dc.httpRateLimit?.trustProxy === true,
|
|
570
|
+
});
|
|
571
|
+
// HTTP / WS bind also defaults to 127.0.0.1. The webapp talks to
|
|
572
|
+
// these over the same loopback; nginx fronts the public surface.
|
|
573
|
+
// Operators who proxy in from another host opt in via `daemon.host`
|
|
574
|
+
// (same knob that controls TCP, with the same literal meaning).
|
|
575
|
+
//
|
|
576
|
+
// Except on a slave, where that knob has to be published for a different
|
|
577
|
+
// reason and publishing these with it is pure cost. A fleet node must
|
|
578
|
+
// bind its TCP transport somewhere the master can reach — that is what
|
|
579
|
+
// `daemon.host: '0.0.0.0'` in a generated slave config is for — and the
|
|
580
|
+
// same value then published the Netron HTTP RPC and the WebSocket
|
|
581
|
+
// alongside it. A slave serves no console: the operator uses the
|
|
582
|
+
// master's. So the two surfaces it gained are an authentication endpoint
|
|
583
|
+
// it does not need and a WebSocket one that, as the note below records,
|
|
584
|
+
// has no rate limit available to it.
|
|
585
|
+
//
|
|
586
|
+
// Rebound rather than warned about, which is the opposite of the choice
|
|
587
|
+
// made for the TCP transport twenty lines up — and for the opposite
|
|
588
|
+
// reason. Rebinding the fleet port would take a cluster down, because
|
|
589
|
+
// being reachable is that port's whole job. Rebinding these costs a slave
|
|
590
|
+
// nothing, because nothing dials them.
|
|
591
|
+
const localHost = consoleBindHostFor(dc);
|
|
251
592
|
// HTTP — Netron RPC API (internal port, nginx proxies from public port)
|
|
593
|
+
// The public `httpPort` (9800) is nginx in front of the console; the
|
|
594
|
+
// daemon's own Netron HTTP listener sits one above it. Remembered here
|
|
595
|
+
// because the fleet registration below must advertise the port peers can
|
|
596
|
+
// actually POST `/netron/invoke` to — not the TCP port, and not the
|
|
597
|
+
// console's.
|
|
252
598
|
const internalHttpPort = (dc.httpPort ?? 9800) + 1;
|
|
599
|
+
this.rpcHttpPort = internalHttpPort;
|
|
253
600
|
this.app.netron.registerTransport('http', () => new HttpTransport());
|
|
601
|
+
const rl = dc.httpRateLimit ?? {};
|
|
254
602
|
this.app.netron.registerTransportServer('http', {
|
|
255
603
|
name: 'daemon-http',
|
|
256
604
|
options: {
|
|
257
605
|
port: internalHttpPort,
|
|
258
|
-
host:
|
|
606
|
+
host: localHost,
|
|
259
607
|
cors: true,
|
|
260
608
|
invocationWrapper: authContextWrapper,
|
|
609
|
+
// Volume cap on the HTTP RPC surface, and only that one. Password
|
|
610
|
+
// guessing is bounded by the per-account lockout in AuthService.
|
|
611
|
+
//
|
|
612
|
+
// The WebSocket surface below is NOT covered: netron's WebSocket
|
|
613
|
+
// transport has no rate-limit option — `maxPayload` is the only
|
|
614
|
+
// bound it accepts — and the console talks over WebSocket. This
|
|
615
|
+
// comment used to say the limit bounded "everything else, including
|
|
616
|
+
// attempts to flood the daemon into unresponsiveness", which
|
|
617
|
+
// describes a protection that covers one of the two transports an
|
|
618
|
+
// attacker can reach.
|
|
619
|
+
rateLimit: {
|
|
620
|
+
enabled: rl.enabled ?? true,
|
|
621
|
+
windowMs: rl.windowMs ?? 60_000,
|
|
622
|
+
maxRequests: rl.maxRequests ?? 3_000,
|
|
623
|
+
globalMaxRequests: rl.globalMaxRequests ?? 6_000,
|
|
624
|
+
trustProxy: rl.trustProxy ?? false,
|
|
625
|
+
...(rl.whitelist ? { whitelist: rl.whitelist } : {}),
|
|
626
|
+
},
|
|
261
627
|
},
|
|
262
628
|
});
|
|
263
629
|
// WebSocket — real-time event push to webapp clients
|
|
@@ -267,8 +633,18 @@ export class OmnitronDaemon {
|
|
|
267
633
|
name: 'daemon-ws',
|
|
268
634
|
options: {
|
|
269
635
|
port: wsPort,
|
|
270
|
-
host:
|
|
636
|
+
host: localHost,
|
|
637
|
+
// Applied per invocation by `remote-peer.ts`, the dispatcher every
|
|
638
|
+
// socket transport shares — so WS calls get the same request context
|
|
639
|
+
// HTTP calls do. Until recently only the HTTP server read this
|
|
640
|
+
// option and this line did nothing.
|
|
271
641
|
invocationWrapper: authContextWrapper,
|
|
642
|
+
// The only bound this transport accepts. Left unset it inherits
|
|
643
|
+
// `ws`'s 100 MB default, which is a lot of memory to hand a single
|
|
644
|
+
// frame on a control-plane socket that carries RPC arguments and
|
|
645
|
+
// event pushes. 8 MB is well above anything the console sends and
|
|
646
|
+
// well below anything worth allocating for a stranger.
|
|
647
|
+
maxPayload: dc.wsMaxPayload ?? 8 * 1024 * 1024,
|
|
272
648
|
},
|
|
273
649
|
});
|
|
274
650
|
}
|
|
@@ -286,11 +662,20 @@ export class OmnitronDaemon {
|
|
|
286
662
|
const logManager = await container.resolveAsync(LOG_MANAGER_TOKEN);
|
|
287
663
|
const logCollector = await container.resolveAsync(LOG_COLLECTOR_TOKEN);
|
|
288
664
|
const loggerModule = await container.resolveAsync(LOGGER_SERVICE_TOKEN);
|
|
665
|
+
// Table retention. `logging.maxSize` and `maxFiles` bound the rotated
|
|
666
|
+
// files on disk and say nothing about the `logs` table, which had no
|
|
667
|
+
// bound at all — 13 GB on the development host. Off unless configured,
|
|
668
|
+
// and the number comes from the config rather than a default chosen
|
|
669
|
+
// inside the collector, because a wrong default there deletes history.
|
|
670
|
+
logCollector.setRetentionDays(config.logging?.databaseRetentionDays ?? 0, loggerModule.logger.child({ component: 'log-retention' }));
|
|
289
671
|
const rpcService = new DaemonRpcService(orchestrator, titanHealth, logManager, config, this);
|
|
290
672
|
await this.app.netron.peer.exposeService(rpcService);
|
|
291
673
|
// Logs RPC service (works on both master and slave — uses PG or SQLite)
|
|
292
674
|
const logsRpcService = new LogsRpcService(logCollector);
|
|
293
675
|
await this.app.netron.peer.exposeService(logsRpcService);
|
|
676
|
+
// `getLogs` answers an app this daemon does not run from the stored rows —
|
|
677
|
+
// where a node's synced logs are.
|
|
678
|
+
rpcService.setLogStore(logCollector);
|
|
294
679
|
// Metrics RPC service — provided by TitanMetricsModule
|
|
295
680
|
const metricsService = await container.resolveAsync(TITAN_METRICS_TOKEN);
|
|
296
681
|
const { MetricsRpcService: MetricsRpc } = await import('@omnitron-dev/titan-metrics');
|
|
@@ -301,10 +686,29 @@ export class OmnitronDaemon {
|
|
|
301
686
|
const healthCheckService = await container.resolveAsync(HEALTH_CHECK_SERVICE_TOKEN);
|
|
302
687
|
const healthCheckRpcService = new HealthCheckRpc(healthCheckService);
|
|
303
688
|
await this.app.netron.peer.exposeService(healthCheckRpcService);
|
|
689
|
+
// The audit trail. Master-only — its table lives in the omnitron
|
|
690
|
+
// database — and every service that records into it takes it as an
|
|
691
|
+
// optional dependency, so a slave serves the same methods and records
|
|
692
|
+
// nothing rather than refusing them.
|
|
693
|
+
let audit;
|
|
694
|
+
if (!isSlave) {
|
|
695
|
+
try {
|
|
696
|
+
audit = await container.resolveAsync(AUDIT_SERVICE_TOKEN);
|
|
697
|
+
// Revealing an app's secrets is recorded (`revealEnv`).
|
|
698
|
+
rpcService.setAudit(audit);
|
|
699
|
+
const { AuditRpcService } = await import('../services/audit.rpc-service.js');
|
|
700
|
+
await this.app.netron.peer.exposeService(new AuditRpcService(audit));
|
|
701
|
+
}
|
|
702
|
+
catch (err) {
|
|
703
|
+
// A daemon whose database did not come up still runs; it simply
|
|
704
|
+
// records nothing, and says so once rather than at every action.
|
|
705
|
+
loggerModule.logger.warn({ error: err.message }, 'No audit trail on this daemon — actions will not be recorded');
|
|
706
|
+
}
|
|
707
|
+
}
|
|
304
708
|
// Secrets RPC service (file-based, no DB dependency)
|
|
305
709
|
const { SecretsRpcService: SecretsRpc } = await import('../services/secrets.rpc-service.js');
|
|
306
710
|
const secretsService = await container.resolveAsync(SECRETS_SERVICE_TOKEN);
|
|
307
|
-
const secretsRpcService = new SecretsRpc(secretsService);
|
|
711
|
+
const secretsRpcService = new SecretsRpc(secretsService, audit);
|
|
308
712
|
await this.app.netron.peer.exposeService(secretsRpcService);
|
|
309
713
|
// Kubernetes RPC service (no DB dependency)
|
|
310
714
|
const { KubernetesRpcService: K8sRpc } = await import('../services/kubernetes.rpc-service.js');
|
|
@@ -316,14 +720,60 @@ export class OmnitronDaemon {
|
|
|
316
720
|
const backupService = await container.resolveAsync(BACKUP_SERVICE_TOKEN);
|
|
317
721
|
const backupRpcService = new BackupRpc(backupService);
|
|
318
722
|
await this.app.netron.peer.exposeService(backupRpcService);
|
|
723
|
+
// Re-arm any persisted backup schedules so they survive daemon restarts.
|
|
724
|
+
await backupService.restoreSchedules().catch((err) => loggerModule.logger.warn({ err: err.message }, 'Failed to restore backup schedules'));
|
|
319
725
|
// Infrastructure RPC service (reports infra state — slave has no infra)
|
|
320
726
|
const { InfrastructureRpcService: InfraRpc } = await import('../services/infrastructure.rpc-service.js');
|
|
321
|
-
const infraRpcService = new InfraRpc(() => this.infraService
|
|
727
|
+
const infraRpcService = new InfraRpc(() => this.infraService,
|
|
728
|
+
// Only a node hosts a stack's infrastructure on demand. A master
|
|
729
|
+
// provisions its own from its own config at boot, and handing it a
|
|
730
|
+
// second one over RPC would give one machine two reconcilers over one
|
|
731
|
+
// set of containers.
|
|
732
|
+
isSlave
|
|
733
|
+
? (infraConfig, declaredServices, presetRegistry, serviceOverrides) => {
|
|
734
|
+
const service = new InfrastructureService(loggerModule.logger.child({ component: 'infra' }), infraConfig, declaredServices, presetRegistry, serviceOverrides,
|
|
735
|
+
// A node keeps its own state in SQLite. Provisioning a
|
|
736
|
+
// control-plane Postgres for it gives the host a database
|
|
737
|
+
// nobody queries, on default credentials.
|
|
738
|
+
false);
|
|
739
|
+
this.infraService = service;
|
|
740
|
+
return service;
|
|
741
|
+
}
|
|
742
|
+
: undefined,
|
|
743
|
+
// The node's own vault. Generated service credentials are written
|
|
744
|
+
// here and read back on every later provision, which is what makes a
|
|
745
|
+
// generated password usable: a data directory keeps the one it was
|
|
746
|
+
// initialised with.
|
|
747
|
+
// Resolved per call, not captured here: a resolution that fails during
|
|
748
|
+
// startup would otherwise leave credential generation off for the life
|
|
749
|
+
// of this daemon, and the absence reads as "this node needs none".
|
|
750
|
+
isSlave
|
|
751
|
+
? () => {
|
|
752
|
+
try {
|
|
753
|
+
return container.resolve(SECRETS_SERVICE_TOKEN);
|
|
754
|
+
}
|
|
755
|
+
catch {
|
|
756
|
+
return undefined;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
: undefined,
|
|
760
|
+
// The logger, because the one thing this service says on its own — that
|
|
761
|
+
// a deployment is running on a default credential — is said at error
|
|
762
|
+
// level and reaches nobody without it.
|
|
763
|
+
loggerModule.logger.child({ component: 'infra' }));
|
|
322
764
|
await this.app.netron.peer.exposeService(infraRpcService);
|
|
323
765
|
// Project + Stack management RPC service
|
|
324
766
|
const projectService = await container.resolveAsync(PROJECT_SERVICE_TOKEN);
|
|
325
|
-
const projectRpcService = new ProjectRpcService(projectService);
|
|
767
|
+
const projectRpcService = new ProjectRpcService(projectService, audit);
|
|
326
768
|
await this.app.netron.peer.exposeService(projectRpcService);
|
|
769
|
+
// Releases. Master-only, like the builds themselves: a release is built
|
|
770
|
+
// from clean clones of BOTH repositories, and only a master has both.
|
|
771
|
+
if (!isSlave) {
|
|
772
|
+
const { ReleaseService } = await import('../services/release.service.js');
|
|
773
|
+
const { ReleaseRpcService } = await import('../services/release.rpc-service.js');
|
|
774
|
+
this.releaseService = new ReleaseService(loggerModule.logger.child({ component: 'release' }));
|
|
775
|
+
await this.app.netron.peer.exposeService(new ReleaseRpcService(this.releaseService, audit, projectService));
|
|
776
|
+
}
|
|
327
777
|
// Sync service (slave→master data replication)
|
|
328
778
|
const syncNodeId = `${os.hostname()}-${dc.port}`;
|
|
329
779
|
let syncDb;
|
|
@@ -335,6 +785,53 @@ export class OmnitronDaemon {
|
|
|
335
785
|
syncDb = await container.resolveAsync(OMNITRON_DB_TOKEN);
|
|
336
786
|
}
|
|
337
787
|
this.syncService = new SyncService(syncDb, loggerModule.logger.child({ component: 'sync' }), syncNodeId, dc.role, dc.sync);
|
|
788
|
+
// Remote metrics into the store the console actually reads.
|
|
789
|
+
//
|
|
790
|
+
// `ingestMetric` wrote them to `metrics_raw`, and nothing in this
|
|
791
|
+
// repository reads that table — the metrics page queries titan-metrics'
|
|
792
|
+
// own storage. So once the pipeline carried anything, it would have
|
|
793
|
+
// carried it somewhere invisible. Recording through the same service the
|
|
794
|
+
// master uses for its own readings makes a remote node a LABEL on the
|
|
795
|
+
// existing series instead of a second store of the same concept.
|
|
796
|
+
//
|
|
797
|
+
// `node` is a distinct argument in the sink's signature rather than a
|
|
798
|
+
// key a caller may forget to put in `labels`: a sample recorded without
|
|
799
|
+
// it merges with the master's own, and the chart then shows two machines
|
|
800
|
+
// summed under one name.
|
|
801
|
+
if (!isSlave) {
|
|
802
|
+
const syncMetrics = await container.resolveAsync(TITAN_METRICS_TOKEN);
|
|
803
|
+
this.syncService.setMetricsSink((sample) => {
|
|
804
|
+
try {
|
|
805
|
+
syncMetrics.recordTyped('gauge', sample.name, { ...sample.labels, app: sample.app, node: sample.node }, sample.value);
|
|
806
|
+
}
|
|
807
|
+
catch (err) {
|
|
808
|
+
loggerModule.logger.warn({ node: sample.node, name: sample.name, error: err.message }, 'Failed to record a replicated metric');
|
|
809
|
+
}
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
// The producer the replication pipeline never had.
|
|
813
|
+
//
|
|
814
|
+
// `SyncService` buffers, batches, retries with backoff, evicts when over
|
|
815
|
+
// budget, and the master keeps a dedup ledger for what it has taken —
|
|
816
|
+
// all of it built, and `buffer`/`bufferBatch` had ZERO callers. A slave
|
|
817
|
+
// collected its logs into its own SQLite and replicated none of them,
|
|
818
|
+
// and nothing said so: an empty buffer drains successfully every cycle.
|
|
819
|
+
//
|
|
820
|
+
// Wired only for a slave. `bufferBatch` is a no-op for any other role,
|
|
821
|
+
// so this is belt and braces rather than the guard itself — but a master
|
|
822
|
+
// has no master to ship to, and doing the work would be pure cost.
|
|
823
|
+
if (isSlave) {
|
|
824
|
+
const syncService = this.syncService;
|
|
825
|
+
logCollector.setSyncSink((entries) => {
|
|
826
|
+
void syncService
|
|
827
|
+
.bufferBatch(entries.map((e) => ({ category: 'logs', payload: e })))
|
|
828
|
+
.catch(() => {
|
|
829
|
+
// `bufferBatch` logs its own failure. Swallowed here because the
|
|
830
|
+
// lines are already in the local table: losing the replica copy
|
|
831
|
+
// must not cost the flush that succeeded.
|
|
832
|
+
});
|
|
833
|
+
});
|
|
834
|
+
}
|
|
338
835
|
const syncRpcService = new SyncRpcService(this.syncService);
|
|
339
836
|
await this.app.netron.peer.exposeService(syncRpcService);
|
|
340
837
|
// System info service (real-time OS/hardware metrics)
|
|
@@ -343,19 +840,120 @@ export class OmnitronDaemon {
|
|
|
343
840
|
await this.app.netron.peer.exposeService(systemInfoRpcService);
|
|
344
841
|
// Event Broadcaster RPC service (WebSocket subscriptions)
|
|
345
842
|
this.eventBroadcaster = new EventBroadcasterService(loggerModule.logger);
|
|
346
|
-
const eventBroadcasterRpcService = new EventBroadcasterRpcService(this.eventBroadcaster);
|
|
843
|
+
const eventBroadcasterRpcService = new EventBroadcasterRpcService(this.eventBroadcaster, this.app.netron);
|
|
347
844
|
await this.app.netron.peer.exposeService(eventBroadcasterRpcService);
|
|
348
845
|
// Node manager — file-based, no PG (master only — manages infrastructure nodes)
|
|
349
846
|
// Health checks delegated to dedicated system worker (started later after infra is ready)
|
|
350
847
|
if (!isSlave) {
|
|
351
848
|
const { NodeManagerService } = await import('../services/node-manager.service.js');
|
|
352
849
|
const { NodeManagerRpcService } = await import('../services/node-manager.rpc-service.js');
|
|
353
|
-
const
|
|
354
|
-
const
|
|
850
|
+
const { DaemonStateStore: DaemonStateStoreCls } = await import('./daemon-state-store.service.js');
|
|
851
|
+
const daemonStateStore = await container.resolveAsync(DAEMON_STATE_STORE_TOKEN);
|
|
852
|
+
const nodeManager = new NodeManagerService(loggerModule.logger.child({ component: 'nodes' }), daemonStateStore, secretsService);
|
|
355
853
|
this.nodeManagerService = nodeManager;
|
|
356
|
-
const nodeManagerRpcService = new NodeManagerRpcService(nodeManager);
|
|
854
|
+
const nodeManagerRpcService = new NodeManagerRpcService(nodeManager, audit);
|
|
855
|
+
// The deployer reaches nodes through the same SSH implementation as the
|
|
856
|
+
// health checks — the only one that can present a stored password or a
|
|
857
|
+
// key passphrase.
|
|
858
|
+
{
|
|
859
|
+
const { RemoteDeployer } = await import('../services/remote-deployer.service.js');
|
|
860
|
+
const { ExecutionService } = await import('../execution/execution.service.js');
|
|
861
|
+
const deployLogger = loggerModule.logger.child({ component: 'deploy' });
|
|
862
|
+
const remoteDeployer = new RemoteDeployer(deployLogger, new ExecutionService(deployLogger));
|
|
863
|
+
nodeManagerRpcService.setRemoteDeployer(remoteDeployer);
|
|
864
|
+
// Upgrading a node from the console: the same build the CLI makes,
|
|
865
|
+
// made here, then the same two calls. Without this the console could
|
|
866
|
+
// see every node and update none of them.
|
|
867
|
+
const { NodeUpgradeService } = await import('../services/node-upgrade.service.js');
|
|
868
|
+
nodeManagerRpcService.setUpgradeService(new NodeUpgradeService(loggerModule.logger.child({ component: 'node-upgrade' }), {
|
|
869
|
+
getNode: (id) => nodeManager.getNode(id),
|
|
870
|
+
// The same projection the CLI builds for `fleet upgrade`, made
|
|
871
|
+
// here so the console's plan and the terminal's dry run decide
|
|
872
|
+
// from identical inputs. Two places computing «what is this
|
|
873
|
+
// node running» is how they come to disagree.
|
|
874
|
+
listCandidates: () => nodeManager.listNodes().map((n) => ({
|
|
875
|
+
nodeId: n.id,
|
|
876
|
+
name: n.name,
|
|
877
|
+
currentVersion: n.status?.omnitronVersion ?? null,
|
|
878
|
+
isLocal: n.isLocal,
|
|
879
|
+
// SSH, not the daemon port: an upgrade travels over SSH,
|
|
880
|
+
// and a node whose daemon is unreachable is often exactly
|
|
881
|
+
// the one worth upgrading.
|
|
882
|
+
sshReachable: n.status?.sshConnected ?? null,
|
|
883
|
+
// The machine, for telling two registry names for one box
|
|
884
|
+
// apart before both get the bundle.
|
|
885
|
+
address: `${n.host}:${n.sshPort}`,
|
|
886
|
+
})),
|
|
887
|
+
}, (id) => nodeManager.nodeToDeployTarget(id), () => remoteDeployer, audit));
|
|
888
|
+
}
|
|
357
889
|
this.nodeManagerRpcService = nodeManagerRpcService;
|
|
890
|
+
// The local node's own answers, for the three readers that ask every
|
|
891
|
+
// node about itself. A daemon has no mesh connection to itself, so
|
|
892
|
+
// `askNode` needs a local source for each.
|
|
893
|
+
//
|
|
894
|
+
// On the INSTANCE, after it is assigned, and not on `this.…?.` from
|
|
895
|
+
// wherever each dependency happens to be constructed: `setSyncService`
|
|
896
|
+
// was first written next to `new SyncService(...)`, ninety lines above
|
|
897
|
+
// this assignment and inside the same function, where `?.` swallowed it
|
|
898
|
+
// silently and the local node would have reported "not wired" forever.
|
|
899
|
+
// An optional call is only safe where the object is known to exist.
|
|
900
|
+
nodeManagerRpcService.setSyncService(this.syncService);
|
|
358
901
|
await this.app.netron.peer.exposeService(nodeManagerRpcService);
|
|
902
|
+
// The mesh: every registered node, connected and replicating.
|
|
903
|
+
//
|
|
904
|
+
// `SlaveConnector` maintains the connections and pulls each node's
|
|
905
|
+
// write-ahead buffer on connect and on every heartbeat, and all of it
|
|
906
|
+
// worked — but the only caller of `addSlave` was a remote or cluster
|
|
907
|
+
// stack starting. So the master connected to the nodes something had
|
|
908
|
+
// been deployed onto, and to no others. A node added through the
|
|
909
|
+
// console, provisioned, and collecting its own metrics and logs was
|
|
910
|
+
// never dialled, and buffered locally forever: measured at 47,407
|
|
911
|
+
// undelivered entries over eleven hours on the first such node, which
|
|
912
|
+
// reported healthy the whole time.
|
|
913
|
+
//
|
|
914
|
+
// Built here rather than inside ProjectService because reaching a node
|
|
915
|
+
// needs what only this side has — the registry's SSH credentials, for
|
|
916
|
+
// the token the node's daemon demands and for the tunnel a firewalled
|
|
917
|
+
// daemon port needs. ProjectService adopts the same instance: one per
|
|
918
|
+
// master, or two connectors pull the same buffer and race to ack it.
|
|
919
|
+
try {
|
|
920
|
+
const { SlaveConnector } = await import('../cluster/slave-connector.js');
|
|
921
|
+
const { createMeshDialer } = await import('../cluster/mesh-link.js');
|
|
922
|
+
const { startMesh } = await import('../cluster/mesh.js');
|
|
923
|
+
const { ExecutionService: Exec } = await import('../execution/execution.service.js');
|
|
924
|
+
const meshLogger = loggerModule.logger.child({ component: 'mesh' });
|
|
925
|
+
const connector = new SlaveConnector(meshLogger, this.syncService ?? null, {
|
|
926
|
+
dial: createMeshDialer({
|
|
927
|
+
logger: meshLogger,
|
|
928
|
+
execution: new Exec(meshLogger),
|
|
929
|
+
subject: `mesh:${os.hostname()}`,
|
|
930
|
+
sshTargetFor: async ({ host }) => {
|
|
931
|
+
const node = nodeManager.listNodes().find((n) => n.host === host && !n.isLocal);
|
|
932
|
+
return node ? nodeManager.nodeToSshTarget(node) : null;
|
|
933
|
+
},
|
|
934
|
+
}),
|
|
935
|
+
});
|
|
936
|
+
this.slaveConnector = connector;
|
|
937
|
+
projectService.setSlaveConnector(connector);
|
|
938
|
+
// So the console can answer "is this node replicating", which is a
|
|
939
|
+
// different question from "can this master reach it".
|
|
940
|
+
nodeManagerRpcService.setSlaveConnector(connector);
|
|
941
|
+
// A stack names a host; the registry holds the credential for it.
|
|
942
|
+
// Wired here because this is the side that has both — ProjectService
|
|
943
|
+
// reads config files, the node registry keeps its secrets in the
|
|
944
|
+
// daemon's vault.
|
|
945
|
+
projectService.setNodeCredentialResolver(async (host) => {
|
|
946
|
+
const node = nodeManager.listNodes().find((n) => n.host === host && !n.isLocal);
|
|
947
|
+
return node ? nodeManager.nodeToSshTarget(node) : null;
|
|
948
|
+
});
|
|
949
|
+
this.meshHandle = startMesh({ registry: nodeManager, connector, logger: meshLogger });
|
|
950
|
+
}
|
|
951
|
+
catch (err) {
|
|
952
|
+
// A master with no mesh still supervises its own apps, so this does
|
|
953
|
+
// not stop the daemon — but nothing else reports it, and a silent
|
|
954
|
+
// failure here looks exactly like a fleet that has nothing to say.
|
|
955
|
+
loggerModule.logger.error({ error: err.message }, 'Mesh not started — registered nodes will buffer their data locally and replicate nothing');
|
|
956
|
+
}
|
|
359
957
|
}
|
|
360
958
|
// =====================================================================
|
|
361
959
|
// Master-only RPC services (require PostgreSQL)
|
|
@@ -374,6 +972,9 @@ export class OmnitronDaemon {
|
|
|
374
972
|
const { TelemetryRpcService: TelemetryRpc } = await import('../services/telemetry.rpc-service.js');
|
|
375
973
|
const telemetryRelay = await container.resolveAsync(TELEMETRY_RELAY_TOKEN);
|
|
376
974
|
const telemetryRpcService = new TelemetryRpc(telemetryRelay);
|
|
975
|
+
// The console asks every node for its relay, and a daemon has no mesh
|
|
976
|
+
// connection to itself, so the local node's answer comes from here.
|
|
977
|
+
this.nodeManagerRpcService?.setTelemetryRelay(telemetryRelay);
|
|
377
978
|
await this.app.netron.peer.exposeService(telemetryRpcService);
|
|
378
979
|
// Fleet management RPC service
|
|
379
980
|
const { FleetRpcService: FleetRpc } = await import('../services/fleet.rpc-service.js');
|
|
@@ -413,6 +1014,8 @@ export class OmnitronDaemon {
|
|
|
413
1014
|
...(dc.cluster.heartbeatInterval != null && { heartbeatInterval: dc.cluster.heartbeatInterval }),
|
|
414
1015
|
});
|
|
415
1016
|
const clusterRpcService = new ClusterRpc(this.leaderElection);
|
|
1017
|
+
// The local node's own election state, for the cross-node reader.
|
|
1018
|
+
this.nodeManagerRpcService?.setLeaderElection(this.leaderElection);
|
|
416
1019
|
await this.app.netron.peer.exposeService(clusterRpcService);
|
|
417
1020
|
}
|
|
418
1021
|
}
|
|
@@ -448,6 +1051,10 @@ export class OmnitronDaemon {
|
|
|
448
1051
|
if (!this.app)
|
|
449
1052
|
return;
|
|
450
1053
|
const stateStore = await this.app.container.resolveAsync(STATE_STORE_TOKEN);
|
|
1054
|
+
// First-touch init reads from SQLite (and migrates the legacy
|
|
1055
|
+
// JSON snapshot in-place if one exists). Subsequent reads via
|
|
1056
|
+
// `load()` are synchronous from the in-memory cache.
|
|
1057
|
+
await stateStore.init();
|
|
451
1058
|
const previousState = stateStore.load();
|
|
452
1059
|
if (previousState) {
|
|
453
1060
|
const runningApps = previousState.apps.filter((a) => a.status === 'online' || a.status === 'starting');
|
|
@@ -531,7 +1138,7 @@ export class OmnitronDaemon {
|
|
|
531
1138
|
// stack auto-detection upstream); the daemon does not provision it
|
|
532
1139
|
// again here.
|
|
533
1140
|
const { ProjectRegistry } = await import('../project/registry.js');
|
|
534
|
-
const projects =
|
|
1141
|
+
const projects = ProjectRegistry.open().list();
|
|
535
1142
|
const projectModeActive = projects.some((p) => Array.isArray(p.enabledStacks) && p.enabledStacks.length > 0);
|
|
536
1143
|
if (projectModeActive) {
|
|
537
1144
|
logger.info({ projects: projects.length }, 'project mode active — daemon-level infrastructure deferred to stack provision');
|
|
@@ -590,27 +1197,70 @@ export class OmnitronDaemon {
|
|
|
590
1197
|
*/
|
|
591
1198
|
async reconcileOrphanContainers(logger, projects, projectService) {
|
|
592
1199
|
const { listManagedContainers, stopContainer, removeContainer } = await import('../infrastructure/container-runtime.js');
|
|
1200
|
+
const { decideOrphans } = await import('../infrastructure/orphan-containers.js');
|
|
593
1201
|
const managed = await listManagedContainers();
|
|
594
1202
|
if (managed.length === 0)
|
|
595
1203
|
return;
|
|
596
1204
|
// Build set of expected container name prefixes from registered projects/stacks
|
|
597
1205
|
const expectedPrefixes = new Set();
|
|
598
1206
|
const internalNames = new Set(['omnitron-pg', 'omnitron-nginx']);
|
|
1207
|
+
// Load each project's config FIRST. `listStacks` reads the loaded-config
|
|
1208
|
+
// cache and returns [] for a project whose config has not been read —
|
|
1209
|
+
// and this runs before the per-project load loop further down, whose own
|
|
1210
|
+
// comment says loading "populates internal cache used by listStacks".
|
|
1211
|
+
//
|
|
1212
|
+
// So on every boot where projects come from the registry rather than CWD
|
|
1213
|
+
// auto-detection — the normal case — `expectedPrefixes` was EMPTY and
|
|
1214
|
+
// every managed container looked like an orphan. Measured from this
|
|
1215
|
+
// daemon's own log, 2026-09-12 12:46, ten RUNNING containers removed in
|
|
1216
|
+
// fourteen seconds: postgres, redis, bitcoin, monero (daemon and wallet),
|
|
1217
|
+
// nominatim, tor, tiles, minio, gateway — each logged as "not part of any
|
|
1218
|
+
// registered stack" while being part of the registered stack.
|
|
1219
|
+
//
|
|
1220
|
+
// Named volumes survived (`docker rm -f`, no `-v`), so this cost a cold
|
|
1221
|
+
// restart of every service rather than the chain data. That is luck, not
|
|
1222
|
+
// design.
|
|
1223
|
+
let expectationsComplete = true;
|
|
599
1224
|
for (const project of projects) {
|
|
1225
|
+
try {
|
|
1226
|
+
await projectService.loadProjectConfig(project.name);
|
|
1227
|
+
}
|
|
1228
|
+
catch (err) {
|
|
1229
|
+
expectationsComplete = false;
|
|
1230
|
+
logger.warn({ project: project.name, error: err.message }, 'Could not read this project’s stacks — skipping orphan reconciliation rather than guessing');
|
|
1231
|
+
continue;
|
|
1232
|
+
}
|
|
600
1233
|
const stacks = projectService.listStacks(project.name);
|
|
1234
|
+
if (stacks.length === 0)
|
|
1235
|
+
expectationsComplete = false;
|
|
601
1236
|
for (const stack of stacks) {
|
|
602
1237
|
expectedPrefixes.add(`${project.name}-${stack.name}-`);
|
|
603
1238
|
}
|
|
604
1239
|
}
|
|
1240
|
+
// Whether anything may be removed is one decision with several ways of
|
|
1241
|
+
// being wrong, and every way it has been wrong so far was a mistake about
|
|
1242
|
+
// what the inputs MEANT. It lives in `decideOrphans`, where it can be
|
|
1243
|
+
// pinned in a test rather than discovered on a host.
|
|
1244
|
+
const decision = decideOrphans({
|
|
1245
|
+
isSlave: this.dc?.role === 'slave',
|
|
1246
|
+
managed: managed.map((c) => ({
|
|
1247
|
+
name: c.name,
|
|
1248
|
+
status: c.status,
|
|
1249
|
+
project: c.project,
|
|
1250
|
+
stack: c.stack,
|
|
1251
|
+
})),
|
|
1252
|
+
projects: projects.map((p) => p.name),
|
|
1253
|
+
expectedPrefixes: [...expectedPrefixes],
|
|
1254
|
+
expectationsComplete,
|
|
1255
|
+
internalNames: [...internalNames],
|
|
1256
|
+
});
|
|
1257
|
+
if (decision.action === 'skip') {
|
|
1258
|
+
logger.warn({ managed: managed.length, expectedPrefixes: expectedPrefixes.size, because: decision.because }, 'Orphan reconciliation skipped');
|
|
1259
|
+
return;
|
|
1260
|
+
}
|
|
605
1261
|
let orphanCount = 0;
|
|
606
|
-
for (const
|
|
607
|
-
|
|
608
|
-
if (internalNames.has(container.name))
|
|
609
|
-
continue;
|
|
610
|
-
// Keep containers that match a known project/stack prefix
|
|
611
|
-
if ([...expectedPrefixes].some((prefix) => container.name.startsWith(prefix)))
|
|
612
|
-
continue;
|
|
613
|
-
// This container is an orphan — stop and remove it
|
|
1262
|
+
for (const name of decision.containers) {
|
|
1263
|
+
const container = managed.find((c) => c.name === name);
|
|
614
1264
|
logger.info({ container: container.name, status: container.status }, 'Removing orphan container (not part of any registered stack)');
|
|
615
1265
|
try {
|
|
616
1266
|
if (container.status === 'running')
|
|
@@ -626,49 +1276,23 @@ export class OmnitronDaemon {
|
|
|
626
1276
|
logger.info({ removed: orphanCount }, 'Orphan container cleanup complete');
|
|
627
1277
|
}
|
|
628
1278
|
}
|
|
1279
|
+
/**
|
|
1280
|
+
* Apply the internal-database schema.
|
|
1281
|
+
*
|
|
1282
|
+
* Delegates to the shared runner (`database/migration-runner.ts`) so this
|
|
1283
|
+
* path, the infrastructure service and the `migrate` CLI all execute the
|
|
1284
|
+
* same registry through the same engine. A failure here is logged as an
|
|
1285
|
+
* ERROR — the daemon keeps running, but every feature backed by
|
|
1286
|
+
* omnitron-pg (alerts, sessions, logs, metrics, deployments) is degraded
|
|
1287
|
+
* and the operator has to see it.
|
|
1288
|
+
*/
|
|
629
1289
|
async runOmnitronMigrations(logger) {
|
|
1290
|
+
const { runOmnitronMigrations } = await import('../database/migration-runner.js');
|
|
630
1291
|
try {
|
|
631
|
-
|
|
632
|
-
const pg = await import('pg');
|
|
633
|
-
const m001 = await import('../database/migrations/001_initial_schema.js');
|
|
634
|
-
const m002 = await import('../database/migrations/002_metrics_raw.js');
|
|
635
|
-
const m003 = await import('../database/migrations/003_pipelines_traces.js');
|
|
636
|
-
const m004 = await import('../database/migrations/004_sync_buffer.js');
|
|
637
|
-
const m005 = await import('../database/migrations/005_node_health_checks.js');
|
|
638
|
-
const pool = new pg.default.Pool({
|
|
639
|
-
host: 'localhost', port: 5480,
|
|
640
|
-
database: 'omnitron', user: 'omnitron', password: 'omnitron',
|
|
641
|
-
});
|
|
642
|
-
const db = new Kysely({ dialect: new PostgresDialect({ pool }) });
|
|
643
|
-
try {
|
|
644
|
-
const migrator = new Migrator({
|
|
645
|
-
db,
|
|
646
|
-
provider: {
|
|
647
|
-
async getMigrations() {
|
|
648
|
-
return {
|
|
649
|
-
'001_initial_schema': { up: m001.up, down: m001.down },
|
|
650
|
-
'002_metrics_raw': { up: m002.up, down: m002.down },
|
|
651
|
-
'003_pipelines_traces': { up: m003.up, down: m003.down },
|
|
652
|
-
'004_sync_buffer': { up: m004.up, down: m004.down },
|
|
653
|
-
'005_node_health_checks': { up: m005.up, down: m005.down },
|
|
654
|
-
};
|
|
655
|
-
},
|
|
656
|
-
},
|
|
657
|
-
});
|
|
658
|
-
const { results, error } = await migrator.migrateToLatest();
|
|
659
|
-
const applied = results?.filter((r) => r.status === 'Success') ?? [];
|
|
660
|
-
if (applied.length > 0) {
|
|
661
|
-
logger.info({ migrations: applied.map((r) => r.migrationName) }, `Applied ${applied.length} migration(s)`);
|
|
662
|
-
}
|
|
663
|
-
if (error)
|
|
664
|
-
logger.warn({ error: String(error) }, 'Migration warning');
|
|
665
|
-
}
|
|
666
|
-
finally {
|
|
667
|
-
await db.destroy();
|
|
668
|
-
}
|
|
1292
|
+
await runOmnitronMigrations(logger);
|
|
669
1293
|
}
|
|
670
1294
|
catch (err) {
|
|
671
|
-
logger.
|
|
1295
|
+
logger.error({ error: err.message }, 'Omnitron database migrations FAILED — alerts, sessions, logs and metrics will not work until this is resolved');
|
|
672
1296
|
}
|
|
673
1297
|
}
|
|
674
1298
|
// ============================================================================
|
|
@@ -684,6 +1308,15 @@ export class OmnitronDaemon {
|
|
|
684
1308
|
titanHealth.registerIndicator(new DockerHealthIndicator(() => this.infraService));
|
|
685
1309
|
// Managed apps health indicator
|
|
686
1310
|
titanHealth.registerIndicator(new AppHealthIndicator(orchestrator));
|
|
1311
|
+
// How long the loop has stood still, and when — the number the console
|
|
1312
|
+
// reads for a node that went quiet.
|
|
1313
|
+
if (this.eventLoopWatch)
|
|
1314
|
+
titanHealth.registerIndicator(new EventLoopStallIndicator(this.eventLoopWatch));
|
|
1315
|
+
// The console asks every node for its own indicators, and a daemon has
|
|
1316
|
+
// no mesh connection to itself — so the local node's answer comes from
|
|
1317
|
+
// here. Registered beside the indicators rather than in the wiring
|
|
1318
|
+
// above, because this is the object that has just been given them.
|
|
1319
|
+
this.nodeManagerRpcService?.setTitanHealth(titanHealth);
|
|
687
1320
|
}
|
|
688
1321
|
catch {
|
|
689
1322
|
// Health module may not be available — non-critical
|
|
@@ -692,18 +1325,17 @@ export class OmnitronDaemon {
|
|
|
692
1325
|
// ============================================================================
|
|
693
1326
|
// File Watching (dev mode)
|
|
694
1327
|
// ============================================================================
|
|
695
|
-
startFileWatcher(config, options, logger) {
|
|
696
|
-
if (!
|
|
1328
|
+
async startFileWatcher(config, options, logger) {
|
|
1329
|
+
if (!this.app)
|
|
697
1330
|
return;
|
|
698
|
-
this.app.container.resolveAsync(ORCHESTRATOR_TOKEN)
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
});
|
|
1331
|
+
const orchestrator = await this.app.container.resolveAsync(ORCHESTRATOR_TOKEN);
|
|
1332
|
+
const enabled = !!options?.watch && !options?.noWatch;
|
|
1333
|
+
orchestrator.devMode = enabled;
|
|
1334
|
+
await orchestrator.setWatchMode(enabled, options?.watchApps);
|
|
1335
|
+
if (!enabled)
|
|
1336
|
+
return;
|
|
1337
|
+
this.fileWatcher = new FileWatcher(logger, orchestrator, config, process.cwd());
|
|
1338
|
+
this.fileWatcher.start(options?.watchApps);
|
|
707
1339
|
}
|
|
708
1340
|
// ============================================================================
|
|
709
1341
|
// Start Managed Apps
|
|
@@ -743,6 +1375,31 @@ export class OmnitronDaemon {
|
|
|
743
1375
|
logger.info('No projects registered. Use `omnitron project add <name> <path>` or run from a directory with omnitron.config.ts');
|
|
744
1376
|
return;
|
|
745
1377
|
}
|
|
1378
|
+
// When there are enabled stacks to resume, wait for Docker first. Under
|
|
1379
|
+
// OS-service supervision the daemon boots at login, seconds before
|
|
1380
|
+
// OrbStack/dockerd finishes starting — on 2026-07-11 the one-shot resume
|
|
1381
|
+
// fired into "Docker is not available" and the platform stayed appless
|
|
1382
|
+
// for days. Bounded wait; on timeout we proceed and the enabled-stacks
|
|
1383
|
+
// reconciler keeps retrying with backoff.
|
|
1384
|
+
const hasEnabledStacks = allProjects.some((p) => (p.enabledStacks?.length ?? 0) > 0);
|
|
1385
|
+
if (hasEnabledStacks) {
|
|
1386
|
+
const { isDockerAvailable } = await import('../infrastructure/container-runtime.js');
|
|
1387
|
+
const deadline = Date.now() + 120_000;
|
|
1388
|
+
let waited = false;
|
|
1389
|
+
while (!(await isDockerAvailable())) {
|
|
1390
|
+
if (Date.now() > deadline) {
|
|
1391
|
+
logger.warn('Docker still unavailable after 120s — proceeding; reconciler will retry enabled stacks');
|
|
1392
|
+
break;
|
|
1393
|
+
}
|
|
1394
|
+
if (!waited) {
|
|
1395
|
+
logger.info('Docker not available yet (host still booting?) — waiting before stack resume');
|
|
1396
|
+
waited = true;
|
|
1397
|
+
}
|
|
1398
|
+
await new Promise((r) => setTimeout(r, 3_000));
|
|
1399
|
+
}
|
|
1400
|
+
if (waited)
|
|
1401
|
+
logger.info('Docker is available — continuing stack resume');
|
|
1402
|
+
}
|
|
746
1403
|
// Reconcile orphan containers: stop/remove any omnitron.managed containers
|
|
747
1404
|
// that don't belong to current registered projects/stacks (e.g. leftovers from
|
|
748
1405
|
// a previous session or auto-restarted by Docker after a system reboot).
|
|
@@ -777,7 +1434,7 @@ export class OmnitronDaemon {
|
|
|
777
1434
|
// Start each enabled stack
|
|
778
1435
|
for (const stackName of enabledStacks) {
|
|
779
1436
|
try {
|
|
780
|
-
await projectService.startStack(project.name, stackName);
|
|
1437
|
+
await projectService.startStack(project.name, stackName, { source: 'boot' });
|
|
781
1438
|
totalStacks++;
|
|
782
1439
|
logger.info({ project: project.name, stack: stackName }, 'Stack started');
|
|
783
1440
|
}
|
|
@@ -787,6 +1444,10 @@ export class OmnitronDaemon {
|
|
|
787
1444
|
}
|
|
788
1445
|
}
|
|
789
1446
|
logger.info({ projects: allProjects.length, stacks: totalStacks }, 'All projects and stacks initialized');
|
|
1447
|
+
// Keep converging after boot: retry failed resumes (with backoff) and
|
|
1448
|
+
// re-start enabled stacks that later fall over. One-shot boot resume is
|
|
1449
|
+
// not enough — see the 2026-07-11 Docker-race incident.
|
|
1450
|
+
projectService.startEnabledStacksReconciler();
|
|
790
1451
|
}
|
|
791
1452
|
// ============================================================================
|
|
792
1453
|
// Scheduled Tasks (Phase 2: titan-scheduler replaces bare setInterval)
|
|
@@ -803,7 +1464,8 @@ export class OmnitronDaemon {
|
|
|
803
1464
|
const logManager = await container.resolveAsync(LOG_MANAGER_TOKEN);
|
|
804
1465
|
// Master-only services (require PG)
|
|
805
1466
|
const authService = !isSlave ? await container.resolveAsync(AUTH_SERVICE_TOKEN) : null;
|
|
806
|
-
|
|
1467
|
+
// Both roles: a node evaluates its own alarms on its SQLite (daemon.module.ts).
|
|
1468
|
+
const alertService = await container.resolveAsync(ALERT_SERVICE_TOKEN);
|
|
807
1469
|
const fleetService = !isSlave ? await container.resolveAsync(FLEET_SERVICE_TOKEN) : null;
|
|
808
1470
|
registerDaemonJobs(scheduler, {
|
|
809
1471
|
logger,
|
|
@@ -814,6 +1476,10 @@ export class OmnitronDaemon {
|
|
|
814
1476
|
fleetService,
|
|
815
1477
|
logManager,
|
|
816
1478
|
infraService: this.infraService,
|
|
1479
|
+
// Only a slave replicates. `bufferBatch` is itself a no-op for any
|
|
1480
|
+
// other role, but passing null keeps the job from registering at all
|
|
1481
|
+
// and makes the scheduler's own "skipped, because" line say so.
|
|
1482
|
+
syncService: isSlave ? this.syncService : null,
|
|
817
1483
|
metricsInterval: config.monitoring.metrics.interval,
|
|
818
1484
|
healthCheckInterval: config.monitoring.healthCheck.interval,
|
|
819
1485
|
});
|
|
@@ -844,16 +1510,18 @@ export class OmnitronDaemon {
|
|
|
844
1510
|
logger.warn({ error: err.message }, 'Telemetry relay failed to start');
|
|
845
1511
|
}
|
|
846
1512
|
}
|
|
847
|
-
// Register self in fleet (master only — requires PG)
|
|
1513
|
+
// Register self in fleet (master only — requires PG). `registerSelf`, so
|
|
1514
|
+
// the service remembers which row is this daemon's: the fleet-heartbeat
|
|
1515
|
+
// job beats that row, and had only the literal 'self' before.
|
|
848
1516
|
if (!isSlave) {
|
|
849
1517
|
try {
|
|
850
1518
|
const fleetService = await container.resolveAsync(FLEET_SERVICE_TOKEN);
|
|
851
|
-
await fleetService.
|
|
1519
|
+
await fleetService.registerSelf({
|
|
852
1520
|
hostname: os.hostname(),
|
|
853
|
-
address: this.dc.host
|
|
1521
|
+
address: advertisedAddress(this.dc.host),
|
|
854
1522
|
port: this.dc.port,
|
|
855
1523
|
role: 'leader',
|
|
856
|
-
metadata: { pid: process.pid, version: CLI_VERSION, httpPort: this.dc.httpPort },
|
|
1524
|
+
metadata: { pid: process.pid, version: CLI_VERSION, httpPort: this.dc.httpPort, rpcPort: this.rpcHttpPort },
|
|
857
1525
|
});
|
|
858
1526
|
}
|
|
859
1527
|
catch {
|
|
@@ -898,31 +1566,50 @@ export class OmnitronDaemon {
|
|
|
898
1566
|
// ============================================================================
|
|
899
1567
|
// Health Monitor System Worker
|
|
900
1568
|
// ============================================================================
|
|
1569
|
+
/**
|
|
1570
|
+
* Start the health-monitor system worker, and keep it started.
|
|
1571
|
+
*
|
|
1572
|
+
* Three things were wrong with the previous version, and they compounded
|
|
1573
|
+
* into one outage:
|
|
1574
|
+
*
|
|
1575
|
+
* - It returned SILENTLY when a precondition failed, so a daemon that
|
|
1576
|
+
* never checked a single node looked exactly like one that checked them
|
|
1577
|
+
* all. Each branch now says which precondition it was.
|
|
1578
|
+
* - Nothing watched the worker's process. When it died, the master kept
|
|
1579
|
+
* the proxy, and every fleet check — the console's Refresh, the Check
|
|
1580
|
+
* button, `omnitron node check` — answered
|
|
1581
|
+
* `TitanError: Service with id HealthMonitor@1.0.0 not found`. Observed
|
|
1582
|
+
* live: a fleet frozen at the worker's last report for two days, with
|
|
1583
|
+
* the console rendering it as current.
|
|
1584
|
+
* - The fallback timer existed only inside the catch for a FAILED SPAWN,
|
|
1585
|
+
* so a worker that started and later crashed had no fallback at all.
|
|
1586
|
+
*
|
|
1587
|
+
* The worker is now respawned with backoff, the proxy is dropped the moment
|
|
1588
|
+
* its process ends, and the daemon runs the checks itself in the meantime.
|
|
1589
|
+
*/
|
|
901
1590
|
async startHealthMonitorWorker(logger) {
|
|
902
|
-
if (
|
|
1591
|
+
if (this.dc.role === 'slave')
|
|
1592
|
+
return; // By design: slaves do not manage a fleet.
|
|
1593
|
+
if (!this.app) {
|
|
1594
|
+
logger.warn({}, 'Health monitor not started — application is not available');
|
|
903
1595
|
return;
|
|
1596
|
+
}
|
|
1597
|
+
if (!this.nodeManagerService) {
|
|
1598
|
+
logger.warn({}, 'Health monitor not started — node manager was not constructed');
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
const nodeManager = this.nodeManagerService;
|
|
904
1602
|
try {
|
|
905
1603
|
const titanPm = await import('@omnitron-dev/titan-pm');
|
|
906
1604
|
const { SystemWorkerManager } = await import('../workers/system-worker-manager.js');
|
|
907
1605
|
const { fileURLToPath } = await import('node:url');
|
|
908
1606
|
const nodePath = await import('node:path');
|
|
1607
|
+
const { omnitronPgConnectionString } = await import('../database/connection.js');
|
|
909
1608
|
// Resolve PM from DI
|
|
910
1609
|
const pm = await this.app.container.resolveAsync(titanPm.PM_MANAGER_TOKEN);
|
|
911
1610
|
const loggerModule = await this.app.container.resolveAsync(LOGGER_SERVICE_TOKEN);
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
const hmDefaults = this.dc.healthMonitor ?? {};
|
|
915
|
-
const healthConfig = {
|
|
916
|
-
intervalMs: hmDefaults.intervalMs ?? 30_000,
|
|
917
|
-
concurrency: hmDefaults.concurrency ?? 20,
|
|
918
|
-
offlineTimeoutMs: hmDefaults.offlineTimeoutMs ?? 90_000,
|
|
919
|
-
pingTimeout: hmDefaults.pingTimeout ?? 5_000,
|
|
920
|
-
sshTimeout: hmDefaults.sshTimeout ?? 10_000,
|
|
921
|
-
omnitronCheckTimeout: hmDefaults.omnitronCheckTimeout ?? 15_000,
|
|
922
|
-
pingEnabled: hmDefaults.pingEnabled ?? true,
|
|
923
|
-
retentionDays: hmDefaults.retentionDays ?? 7,
|
|
924
|
-
dbUrl: 'postgresql://omnitron:omnitron@localhost:5480/omnitron',
|
|
925
|
-
};
|
|
1611
|
+
const workerManager = new SystemWorkerManager(pm, loggerModule.logger.child({ component: 'system-workers' }));
|
|
1612
|
+
this.systemWorkerManager = workerManager;
|
|
926
1613
|
// Get worker process path. The naive heuristic of "tsx in execArgv → .ts"
|
|
927
1614
|
// is wrong: the daemon binary itself is loaded with `--import tsx/esm`
|
|
928
1615
|
// (so transpilation works for any .ts in the tree), but the *daemon
|
|
@@ -932,52 +1619,114 @@ export class OmnitronDaemon {
|
|
|
932
1619
|
const workersDir = nodePath.resolve(thisDir, '..', 'workers');
|
|
933
1620
|
const tsPath = nodePath.join(workersDir, 'health-monitor-process.ts');
|
|
934
1621
|
const jsPath = nodePath.join(workersDir, 'health-monitor-process.js');
|
|
935
|
-
const
|
|
1622
|
+
const fsMod = await import('node:fs');
|
|
1623
|
+
const workerPath = fsMod.existsSync(jsPath)
|
|
936
1624
|
? jsPath
|
|
937
|
-
:
|
|
1625
|
+
: fsMod.existsSync(tsPath)
|
|
938
1626
|
? tsPath
|
|
939
1627
|
: jsPath; // fall through to .js — error will be clear if missing
|
|
940
|
-
// Convert nodes to check targets
|
|
941
|
-
const nodesJson = JSON.stringify(await this.nodeManagerService.getNodeCheckTargets());
|
|
942
|
-
const configJson = JSON.stringify(healthConfig);
|
|
943
1628
|
const spawnOpts = {};
|
|
944
1629
|
if (process.execArgv.some((a) => a.includes('tsx'))) {
|
|
945
1630
|
spawnOpts.execArgv = ['--import', 'tsx/esm'];
|
|
946
1631
|
}
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
//
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1632
|
+
// What the worker has to do before it can report ready is create a
|
|
1633
|
+
// Titan application — a DI container, a module graph and a PG pool.
|
|
1634
|
+
// Managed applications get two to five minutes for that; this was
|
|
1635
|
+
// thirty seconds, and on a loaded host it expired on every attempt.
|
|
1636
|
+
// A deadline shorter than the work turns a healthy subsystem into one
|
|
1637
|
+
// that is started and killed for ever, which is what was observed:
|
|
1638
|
+
// fifty minutes of restart attempts, none of which could have finished.
|
|
1639
|
+
spawnOpts.startupTimeout =
|
|
1640
|
+
this.dc.healthMonitor?.startupTimeoutMs
|
|
1641
|
+
?? DEFAULT_DAEMON_CONFIG.healthMonitor?.startupTimeoutMs
|
|
1642
|
+
?? 120_000;
|
|
1643
|
+
this.healthWorkerStartupTimeout = spawnOpts.startupTimeout;
|
|
1644
|
+
/**
|
|
1645
|
+
* The worker's configuration.
|
|
1646
|
+
*
|
|
1647
|
+
* Read at every spawn, not once: the operator's check settings live in
|
|
1648
|
+
* the node manager and change at runtime. The fallbacks come from
|
|
1649
|
+
* `DEFAULT_DAEMON_CONFIG` rather than being written out again here —
|
|
1650
|
+
* the inline copies said 30 s and 7 days while the declared defaults
|
|
1651
|
+
* said 60 s and 90 days, so which numbers a deployment got depended on
|
|
1652
|
+
* whether its config file happened to mention `healthMonitor` at all.
|
|
1653
|
+
*/
|
|
1654
|
+
const buildConfig = () => {
|
|
1655
|
+
const declared = DEFAULT_DAEMON_CONFIG.healthMonitor ?? {};
|
|
1656
|
+
const configured = this.dc.healthMonitor ?? {};
|
|
1657
|
+
const operator = nodeManager.getCheckConfig();
|
|
1658
|
+
return {
|
|
1659
|
+
intervalMs: configured.intervalMs ?? declared.intervalMs ?? 60_000,
|
|
1660
|
+
concurrency: operator.concurrency,
|
|
1661
|
+
offlineTimeoutMs: configured.offlineTimeoutMs ?? declared.offlineTimeoutMs ?? 90_000,
|
|
1662
|
+
pingTimeout: operator.pingTimeout,
|
|
1663
|
+
sshTimeout: operator.sshTimeout,
|
|
1664
|
+
omnitronCheckTimeout: operator.omnitronCheckTimeout,
|
|
1665
|
+
pingEnabled: operator.pingEnabled,
|
|
1666
|
+
retentionDays: configured.retentionDays ?? declared.retentionDays ?? 90,
|
|
1667
|
+
// Was a hard-coded DSN, password included, in this file — the sixth
|
|
1668
|
+
// copy of literals `database/connection.ts` exists to be the only
|
|
1669
|
+
// copy of. A daemon pointed elsewhere by OMNITRON_DATABASE_URL wrote
|
|
1670
|
+
// its check history to a database nothing else used.
|
|
1671
|
+
dbUrl: omnitronPgConnectionString(),
|
|
1672
|
+
};
|
|
1673
|
+
};
|
|
1674
|
+
this.healthWorkerSpawn = async () => {
|
|
1675
|
+
const healthConfig = buildConfig();
|
|
1676
|
+
const nodesJson = JSON.stringify(await nodeManager.getNodeCheckTargets());
|
|
1677
|
+
const proxy = await workerManager.spawn('health-monitor', workerPath, { configJson: JSON.stringify(healthConfig), nodesJson }, spawnOpts);
|
|
1678
|
+
// Wire IPC: worker → master status cache updates via PM's public API
|
|
1679
|
+
workerManager.onMessage('health-monitor', (msg) => {
|
|
1680
|
+
if (msg?.type === 'health:status_batch' && Array.isArray(msg.summaries)) {
|
|
1681
|
+
nodeManager.updateStatusCacheFromWorker(msg.summaries);
|
|
1682
|
+
this.broadcastNodeCheckCompleted(msg.summaries);
|
|
966
1683
|
}
|
|
1684
|
+
});
|
|
1685
|
+
if (this.nodeManagerRpcService) {
|
|
1686
|
+
this.nodeManagerRpcService.setHealthWorkerProxy(proxy);
|
|
967
1687
|
}
|
|
1688
|
+
this.healthWorkerRestartAttempts = 0;
|
|
1689
|
+
this.stopFallbackNodeChecks();
|
|
1690
|
+
logger.info({ intervalMs: healthConfig.intervalMs }, 'Health monitor system worker started');
|
|
1691
|
+
};
|
|
1692
|
+
// A worker that ends — crash or deliberate stop — must take its proxy
|
|
1693
|
+
// with it. `expected` is true only while the daemon is shutting down,
|
|
1694
|
+
// which is also when a respawn would be wrong.
|
|
1695
|
+
workerManager.onExit('health-monitor', (exit) => {
|
|
1696
|
+
this.nodeManagerRpcService?.setHealthWorkerProxy(null);
|
|
1697
|
+
if (exit.expected || this.isShuttingDown)
|
|
1698
|
+
return;
|
|
1699
|
+
this.startFallbackNodeChecks(logger);
|
|
1700
|
+
this.scheduleHealthMonitorRestart(logger);
|
|
1701
|
+
});
|
|
1702
|
+
// Operator changes to the check settings have to reach the process that
|
|
1703
|
+
// performs the checks. They reached a field on the node manager that
|
|
1704
|
+
// only the daemon's own fallback path read, so turning ping off in the
|
|
1705
|
+
// console turned nothing off.
|
|
1706
|
+
nodeManager.on('checkConfig:changed', () => {
|
|
1707
|
+
void callWorkerMethod(workerManager, 'updateConfig', JSON.stringify(buildConfig())).catch((err) => {
|
|
1708
|
+
logger.warn({ error: err.message }, 'Failed to push check config to health monitor');
|
|
1709
|
+
});
|
|
968
1710
|
});
|
|
969
1711
|
// Wire node CRUD events → sync to worker
|
|
970
1712
|
const syncNodesToWorker = async () => {
|
|
1713
|
+
if (!workerManager.get('health-monitor'))
|
|
1714
|
+
return;
|
|
971
1715
|
const targets = await nodeManager.getNodeCheckTargets();
|
|
972
|
-
|
|
1716
|
+
await callWorkerMethod(workerManager, 'updateNodes', JSON.stringify(targets)).catch((err) => {
|
|
1717
|
+
logger.warn({ error: err.message }, 'Failed to sync node list to health monitor');
|
|
1718
|
+
});
|
|
973
1719
|
};
|
|
974
1720
|
nodeManager.on('node:added', syncNodesToWorker);
|
|
975
1721
|
nodeManager.on('node:updated', syncNodesToWorker);
|
|
976
1722
|
nodeManager.on('node:removed', syncNodesToWorker);
|
|
977
|
-
//
|
|
1723
|
+
// A node changing state is the event the console subscribes to. Four of
|
|
1724
|
+
// the five NODE_EVENTS channels were declared and never emitted.
|
|
1725
|
+
nodeManager.on('node:health', (t) => {
|
|
1726
|
+
this.broadcastNodeTransition(t);
|
|
1727
|
+
});
|
|
1728
|
+
// Wire PG repository for direct history reads (bypasses worker)
|
|
978
1729
|
if (this.nodeManagerRpcService) {
|
|
979
|
-
this.nodeManagerRpcService.setHealthWorkerProxy(proxy);
|
|
980
|
-
// Wire PG repository for direct history reads (bypasses worker)
|
|
981
1730
|
try {
|
|
982
1731
|
const db = await this.app.container.resolveAsync(OMNITRON_DB_TOKEN);
|
|
983
1732
|
const { NodeHealthRepository } = await import('../services/node-health.repository.js');
|
|
@@ -987,20 +1736,102 @@ export class OmnitronDaemon {
|
|
|
987
1736
|
logger.warn({}, 'Could not wire health repository — PG may not be ready');
|
|
988
1737
|
}
|
|
989
1738
|
}
|
|
990
|
-
|
|
1739
|
+
// The console needs these to size its uptime bars against history that
|
|
1740
|
+
// actually exists.
|
|
1741
|
+
const bootConfig = buildConfig();
|
|
1742
|
+
nodeManager.setHistoryConfig({
|
|
1743
|
+
uptimeIntervalMs: this.dc.healthMonitor?.uptimeIntervalMs
|
|
1744
|
+
?? DEFAULT_DAEMON_CONFIG.healthMonitor?.uptimeIntervalMs
|
|
1745
|
+
?? 86_400_000,
|
|
1746
|
+
retentionDays: bootConfig.retentionDays,
|
|
1747
|
+
});
|
|
1748
|
+
await this.healthWorkerSpawn();
|
|
991
1749
|
}
|
|
992
1750
|
catch (err) {
|
|
993
1751
|
logger.warn({ error: err.message }, 'Health monitor worker failed to start — falling back to direct checks');
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
const intervalMs = this.dc.healthMonitor?.intervalMs ?? 30_000;
|
|
998
|
-
const timer = setInterval(() => void this.nodeManagerService?.checkAllNodes(), intervalMs);
|
|
999
|
-
timer.unref();
|
|
1000
|
-
void this.nodeManagerService.checkAllNodes();
|
|
1001
|
-
}
|
|
1752
|
+
this.startFallbackNodeChecks(logger);
|
|
1753
|
+
if (this.healthWorkerSpawn)
|
|
1754
|
+
this.scheduleHealthMonitorRestart(logger);
|
|
1002
1755
|
}
|
|
1003
1756
|
}
|
|
1757
|
+
/**
|
|
1758
|
+
* Try the health-monitor worker again, backing off.
|
|
1759
|
+
*
|
|
1760
|
+
* Capped at a minute: the worker is cheap to start and the fleet view is
|
|
1761
|
+
* blind without it, but a worker that cannot start (a missing file, a bad
|
|
1762
|
+
* runtime) must not be respawned in a tight loop for the life of the daemon.
|
|
1763
|
+
*/
|
|
1764
|
+
scheduleHealthMonitorRestart(logger) {
|
|
1765
|
+
if (this.healthWorkerRestartTimer || this.isShuttingDown || !this.healthWorkerSpawn)
|
|
1766
|
+
return;
|
|
1767
|
+
const attempt = ++this.healthWorkerRestartAttempts;
|
|
1768
|
+
const delay = Math.min(60_000, 2_000 * 2 ** Math.min(attempt - 1, 5));
|
|
1769
|
+
logger.warn({ attempt, delayMs: delay }, 'Health monitor worker is down — restarting');
|
|
1770
|
+
this.healthWorkerRestartTimer = setTimeout(() => {
|
|
1771
|
+
this.healthWorkerRestartTimer = null;
|
|
1772
|
+
if (this.isShuttingDown || !this.healthWorkerSpawn)
|
|
1773
|
+
return;
|
|
1774
|
+
this.healthWorkerSpawn().catch((err) => {
|
|
1775
|
+
logger.warn({ attempt, startupTimeoutMs: this.healthWorkerStartupTimeout, error: err.message }, 'Health monitor worker restart failed');
|
|
1776
|
+
this.scheduleHealthMonitorRestart(logger);
|
|
1777
|
+
});
|
|
1778
|
+
}, delay);
|
|
1779
|
+
this.healthWorkerRestartTimer.unref();
|
|
1780
|
+
}
|
|
1781
|
+
/**
|
|
1782
|
+
* Run node checks in the daemon while the worker is unavailable.
|
|
1783
|
+
*
|
|
1784
|
+
* Idempotent, and stopped as soon as the worker is back — two check loops
|
|
1785
|
+
* against the same fleet would double every remote host's load and write
|
|
1786
|
+
* two rows per interval.
|
|
1787
|
+
*/
|
|
1788
|
+
startFallbackNodeChecks(logger) {
|
|
1789
|
+
if (this.fallbackNodeCheckTimer || !this.nodeManagerService)
|
|
1790
|
+
return;
|
|
1791
|
+
const declared = DEFAULT_DAEMON_CONFIG.healthMonitor ?? {};
|
|
1792
|
+
const intervalMs = this.dc.healthMonitor?.intervalMs ?? declared.intervalMs ?? 60_000;
|
|
1793
|
+
logger.warn({ intervalMs }, 'Checking nodes from the daemon until the health monitor returns');
|
|
1794
|
+
this.fallbackNodeCheckTimer = setInterval(() => {
|
|
1795
|
+
void this.nodeManagerService?.checkAllNodes();
|
|
1796
|
+
}, intervalMs);
|
|
1797
|
+
this.fallbackNodeCheckTimer.unref();
|
|
1798
|
+
void this.nodeManagerService.checkAllNodes();
|
|
1799
|
+
}
|
|
1800
|
+
stopFallbackNodeChecks() {
|
|
1801
|
+
if (!this.fallbackNodeCheckTimer)
|
|
1802
|
+
return;
|
|
1803
|
+
clearInterval(this.fallbackNodeCheckTimer);
|
|
1804
|
+
this.fallbackNodeCheckTimer = null;
|
|
1805
|
+
}
|
|
1806
|
+
/** Aggregate counts from a worker batch → one console event. */
|
|
1807
|
+
broadcastNodeCheckCompleted(summaries) {
|
|
1808
|
+
if (!this.eventBroadcaster)
|
|
1809
|
+
return;
|
|
1810
|
+
const count = (s) => summaries.filter((x) => x.status === s).length;
|
|
1811
|
+
this.eventBroadcaster.broadcast(NODE_EVENTS.CHECK_COMPLETED, {
|
|
1812
|
+
nodeCount: summaries.length,
|
|
1813
|
+
onlineCount: count('online'),
|
|
1814
|
+
degradedCount: count('degraded'),
|
|
1815
|
+
offlineCount: count('offline'),
|
|
1816
|
+
});
|
|
1817
|
+
}
|
|
1818
|
+
/** One node's health changing → the channel named after the new state. */
|
|
1819
|
+
broadcastNodeTransition(transition) {
|
|
1820
|
+
if (!this.eventBroadcaster)
|
|
1821
|
+
return;
|
|
1822
|
+
const payload = {
|
|
1823
|
+
nodeId: transition.nodeId,
|
|
1824
|
+
status: transition.status,
|
|
1825
|
+
...(transition.previousStatus ? { previousStatus: transition.previousStatus } : {}),
|
|
1826
|
+
};
|
|
1827
|
+
this.eventBroadcaster.broadcast(NODE_EVENTS.STATUS_UPDATED, payload);
|
|
1828
|
+
const channel = transition.status === 'online' ? NODE_EVENTS.WENT_ONLINE
|
|
1829
|
+
: transition.status === 'offline' ? NODE_EVENTS.WENT_OFFLINE
|
|
1830
|
+
: transition.status === 'degraded' ? NODE_EVENTS.WENT_DEGRADED
|
|
1831
|
+
: null;
|
|
1832
|
+
if (channel)
|
|
1833
|
+
this.eventBroadcaster.broadcast(channel, payload);
|
|
1834
|
+
}
|
|
1004
1835
|
// ============================================================================
|
|
1005
1836
|
// Event Broadcasting (Phase 3: orchestrator events → WebSocket push)
|
|
1006
1837
|
// ============================================================================
|
|
@@ -1093,19 +1924,60 @@ export class OmnitronDaemon {
|
|
|
1093
1924
|
}
|
|
1094
1925
|
const config = await this.getConfig();
|
|
1095
1926
|
this.fileWatcher = new FileWatcher(loggerModule.logger, orchestrator, config, process.cwd());
|
|
1927
|
+
orchestrator.devMode = true;
|
|
1928
|
+
await orchestrator.setWatchMode(true, apps);
|
|
1096
1929
|
this.fileWatcher.start(apps);
|
|
1097
|
-
return this.fileWatcher.getWatchedApps();
|
|
1930
|
+
return [...this.fileWatcher.getWatchedApps(), ...orchestrator.getBuildWatchedApps()];
|
|
1098
1931
|
}
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1932
|
+
/**
|
|
1933
|
+
* Point the file watcher at a reloaded config, if one is running.
|
|
1934
|
+
*
|
|
1935
|
+
* Public because `DaemonRpcService.reloadConfig` is the other half of the
|
|
1936
|
+
* same reload — the RPC and the SIGHUP handler must not diverge on what a
|
|
1937
|
+
* reload updates, which is exactly how the watcher came to be left out of
|
|
1938
|
+
* both.
|
|
1939
|
+
*/
|
|
1940
|
+
async applyWatchConfig(config) {
|
|
1941
|
+
this.fileWatcher?.applyConfig(config);
|
|
1942
|
+
if (!this.app)
|
|
1943
|
+
return;
|
|
1944
|
+
const orchestrator = await this.app.container.resolveAsync(ORCHESTRATOR_TOKEN);
|
|
1945
|
+
for (const entry of config.apps) {
|
|
1946
|
+
const handle = orchestrator.getHandle(entry.name);
|
|
1947
|
+
// A bare name may resolve to a different registered project's app.
|
|
1948
|
+
// Only the same entry point may update that handle's watch policy.
|
|
1949
|
+
const source = entry.bootstrap ?? entry.script;
|
|
1950
|
+
const running = handle?.entry.bootstrap ?? handle?.entry.script;
|
|
1951
|
+
if (!handle || !source || !running ||
|
|
1952
|
+
path.resolve(entry.cwd ?? process.cwd(), source) !== path.resolve(handle.entry.cwd ?? process.cwd(), running))
|
|
1953
|
+
continue;
|
|
1954
|
+
const next = { ...handle.entry };
|
|
1955
|
+
if (entry.watch === undefined)
|
|
1956
|
+
delete next.watch;
|
|
1957
|
+
else
|
|
1958
|
+
next.watch = entry.watch;
|
|
1959
|
+
await orchestrator.redefineApp(handle.name, next);
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
async disableWatch() {
|
|
1963
|
+
this.fileWatcher?.stop();
|
|
1964
|
+
this.fileWatcher = null;
|
|
1965
|
+
if (this.app) {
|
|
1966
|
+
const orchestrator = await this.app.container.resolveAsync(ORCHESTRATOR_TOKEN);
|
|
1967
|
+
await orchestrator.setWatchMode(false);
|
|
1103
1968
|
}
|
|
1104
1969
|
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1970
|
+
/** Reports both watcher engines, including registered bootstrap projects. */
|
|
1971
|
+
async getWatchStatus() {
|
|
1972
|
+
const orchestrator = this.app
|
|
1973
|
+
? await this.app.container.resolveAsync(ORCHESTRATOR_TOKEN) : null;
|
|
1974
|
+
const apps = [...(this.fileWatcher?.getWatchedApps() ?? []), ...(orchestrator?.getBuildWatchedApps() ?? [])];
|
|
1975
|
+
return {
|
|
1976
|
+
enabled: !!this.fileWatcher,
|
|
1977
|
+
watching: apps.length > 0,
|
|
1978
|
+
...(apps.length ? {} : { reason: this.fileWatcher ? 'no enabled app matches the watch policy' : 'watching is disabled' }),
|
|
1979
|
+
apps,
|
|
1980
|
+
};
|
|
1109
1981
|
}
|
|
1110
1982
|
async getConfig() {
|
|
1111
1983
|
const { loadEcosystemConfig } = await import('../config/loader.js');
|
|
@@ -1116,7 +1988,7 @@ export class OmnitronDaemon {
|
|
|
1116
1988
|
// ============================================================================
|
|
1117
1989
|
/**
|
|
1118
1990
|
* Trigger graceful shutdown via Application's lifecycle system.
|
|
1119
|
-
* Called by DaemonRpcService.shutdown() for the `omnitron
|
|
1991
|
+
* Called by DaemonRpcService.shutdown() for the `omnitron down` CLI command.
|
|
1120
1992
|
*/
|
|
1121
1993
|
async stop() {
|
|
1122
1994
|
if (!this.app)
|
|
@@ -1125,6 +1997,65 @@ export class OmnitronDaemon {
|
|
|
1125
1997
|
// Application doesn't process.exit() for Manual reason — do it explicitly
|
|
1126
1998
|
process.exit(0);
|
|
1127
1999
|
}
|
|
2000
|
+
/**
|
|
2001
|
+
* SIGHUP handler — reload the ecosystem config without taking the
|
|
2002
|
+
* daemon down. Follows the Unix convention (`man 7 signal`: "many
|
|
2003
|
+
* daemons interpret SIGHUP as a request to reread their configs").
|
|
2004
|
+
* Reloads via the same code path the `reloadConfig` RPC uses so
|
|
2005
|
+
* orchestrator + RPC service both pick up the new entries.
|
|
2006
|
+
*/
|
|
2007
|
+
async reloadConfigOnHup() {
|
|
2008
|
+
if (!this.app)
|
|
2009
|
+
return;
|
|
2010
|
+
// Loading first, on its own: a malformed file must be rejected before
|
|
2011
|
+
// anything is touched, and that failure genuinely means "the daemon is as
|
|
2012
|
+
// it was".
|
|
2013
|
+
const { loadEcosystemConfig } = await import('../config/loader.js');
|
|
2014
|
+
const newConfig = await loadEcosystemConfig();
|
|
2015
|
+
// Applying is the other half, and it has no such guarantee — each
|
|
2016
|
+
// destination takes the config in turn, so a failure in the middle leaves
|
|
2017
|
+
// the daemon split. `applyReloadedConfig` names what applied and what did
|
|
2018
|
+
// not, because "reload failed" reads as "nothing changed" and that is the
|
|
2019
|
+
// wrong reading exactly when it matters.
|
|
2020
|
+
//
|
|
2021
|
+
// The handler used to end in `catch (err) { throw err; }`, which did
|
|
2022
|
+
// nothing whatever. Removing it is trivial; what it was standing in front
|
|
2023
|
+
// of is not.
|
|
2024
|
+
const { applyReloadedConfig } = await import('./config-reload.js');
|
|
2025
|
+
await applyReloadedConfig(newConfig, [
|
|
2026
|
+
{
|
|
2027
|
+
name: 'orchestrator',
|
|
2028
|
+
apply: async (cfg) => {
|
|
2029
|
+
const orchestrator = await this.app.container.resolveAsync(ORCHESTRATOR_TOKEN);
|
|
2030
|
+
orchestrator.setConfig(cfg);
|
|
2031
|
+
},
|
|
2032
|
+
},
|
|
2033
|
+
{
|
|
2034
|
+
name: 'file watcher',
|
|
2035
|
+
// The watcher holds its own copy of the app list. Left out, a reload
|
|
2036
|
+
// updated who gets restarted but not who is watched: an app added to
|
|
2037
|
+
// the config was never watched, and one removed from it kept its
|
|
2038
|
+
// watchers and went on triggering restarts.
|
|
2039
|
+
apply: (cfg) => this.applyWatchConfig(cfg),
|
|
2040
|
+
},
|
|
2041
|
+
{
|
|
2042
|
+
name: 'RPC snapshot',
|
|
2043
|
+
// Exposed under DAEMON_SERVICE_ID; the reloadConfig RPC path mutates
|
|
2044
|
+
// `this.config` directly, so we mirror the same write. Unresolvable is
|
|
2045
|
+
// not a failure here — the service may not be exposed yet.
|
|
2046
|
+
apply: async (cfg) => {
|
|
2047
|
+
const { DAEMON_SERVICE_ID } = await import('../config/defaults.js');
|
|
2048
|
+
const daemonRpc = await this.app.container
|
|
2049
|
+
.resolveAsync(DAEMON_SERVICE_ID)
|
|
2050
|
+
.catch(() => null);
|
|
2051
|
+
if (daemonRpc) {
|
|
2052
|
+
daemonRpc.config = cfg;
|
|
2053
|
+
}
|
|
2054
|
+
},
|
|
2055
|
+
},
|
|
2056
|
+
]);
|
|
2057
|
+
console.info('[omnitron] SIGHUP — config reloaded');
|
|
2058
|
+
}
|
|
1128
2059
|
/**
|
|
1129
2060
|
* Register all daemon shutdown tasks with Application's lifecycle system.
|
|
1130
2061
|
*
|
|
@@ -1199,6 +2130,20 @@ export class OmnitronDaemon {
|
|
|
1199
2130
|
}
|
|
1200
2131
|
catch { /* non-critical */ }
|
|
1201
2132
|
}, ShutdownPriority.First);
|
|
2133
|
+
// A release build outlives its daemon otherwise.
|
|
2134
|
+
//
|
|
2135
|
+
// Every step runs in its own process group, detached, so `pnpm install`
|
|
2136
|
+
// and the gate suite carry on after the daemon that started them is
|
|
2137
|
+
// gone — holding ports, writing into a release directory nothing will
|
|
2138
|
+
// ever finish, and for a quarter of an hour. Stopped first, with the
|
|
2139
|
+
// file watcher, because ending them is instant and everything after
|
|
2140
|
+
// this is slower.
|
|
2141
|
+
app.registerShutdownTask('stop-release-builds', () => {
|
|
2142
|
+
// It says what it stopped through its own logger; a shutdown task that
|
|
2143
|
+
// resolved the logger module to say one line would be one more thing
|
|
2144
|
+
// that can fail while the daemon is going down.
|
|
2145
|
+
this.releaseService?.stopAll();
|
|
2146
|
+
}, ShutdownPriority.First);
|
|
1202
2147
|
// --- Priority: VeryHigh (10) — Stop managed apps (fast — 5s per app max) ---
|
|
1203
2148
|
app.registerShutdownTask('stop-managed-apps', async () => {
|
|
1204
2149
|
const orchestrator = await container.resolveAsync(ORCHESTRATOR_TOKEN);
|
|
@@ -1216,11 +2161,6 @@ export class OmnitronDaemon {
|
|
|
1216
2161
|
await mc.stop();
|
|
1217
2162
|
}
|
|
1218
2163
|
catch { /* non-critical */ }
|
|
1219
|
-
try {
|
|
1220
|
-
const alert = await container.resolveAsync(ALERT_SERVICE_TOKEN);
|
|
1221
|
-
alert.stop();
|
|
1222
|
-
}
|
|
1223
|
-
catch { /* non-critical */ }
|
|
1224
2164
|
try {
|
|
1225
2165
|
const fleet = await container.resolveAsync(FLEET_SERVICE_TOKEN);
|
|
1226
2166
|
fleet.stopHeartbeatSweep();
|
|
@@ -1234,6 +2174,22 @@ export class OmnitronDaemon {
|
|
|
1234
2174
|
}, ShutdownPriority.High);
|
|
1235
2175
|
// --- Priority: Normal (50) — System workers, node manager, sync, cluster ---
|
|
1236
2176
|
app.registerShutdownTask('stop-system-services', async () => {
|
|
2177
|
+
// The mesh first: stop following the registry, then drop the
|
|
2178
|
+
// connections. Each one may hold an SSH tunnel, and a tunnel that
|
|
2179
|
+
// outlives its daemon holds a socket and a remote session open with
|
|
2180
|
+
// nothing left to notice.
|
|
2181
|
+
try {
|
|
2182
|
+
this.meshHandle?.stop();
|
|
2183
|
+
}
|
|
2184
|
+
catch { /* non-critical */ }
|
|
2185
|
+
this.meshHandle = null;
|
|
2186
|
+
if (this.slaveConnector) {
|
|
2187
|
+
try {
|
|
2188
|
+
await this.slaveConnector.dispose();
|
|
2189
|
+
}
|
|
2190
|
+
catch { /* non-critical */ }
|
|
2191
|
+
this.slaveConnector = null;
|
|
2192
|
+
}
|
|
1237
2193
|
if (this.syncService) {
|
|
1238
2194
|
try {
|
|
1239
2195
|
await this.syncService.stop();
|
|
@@ -1251,6 +2207,15 @@ export class OmnitronDaemon {
|
|
|
1251
2207
|
this.configSyncService.stopPeriodicSync();
|
|
1252
2208
|
}
|
|
1253
2209
|
catch { /* non-critical */ }
|
|
2210
|
+
// Before stopping the workers: a worker exiting on the way out must not
|
|
2211
|
+
// be read as a crash and rescheduled.
|
|
2212
|
+
this.isShuttingDown = true;
|
|
2213
|
+
this.healthWorkerSpawn = null;
|
|
2214
|
+
if (this.healthWorkerRestartTimer) {
|
|
2215
|
+
clearTimeout(this.healthWorkerRestartTimer);
|
|
2216
|
+
this.healthWorkerRestartTimer = null;
|
|
2217
|
+
}
|
|
2218
|
+
this.stopFallbackNodeChecks();
|
|
1254
2219
|
if (this.systemWorkerManager) {
|
|
1255
2220
|
try {
|
|
1256
2221
|
await this.systemWorkerManager.stopAll();
|
|
@@ -1297,10 +2262,30 @@ export class OmnitronDaemon {
|
|
|
1297
2262
|
}
|
|
1298
2263
|
catch { /* non-critical */ }
|
|
1299
2264
|
if (this.infraService) {
|
|
1300
|
-
|
|
1301
|
-
|
|
2265
|
+
// A node's infrastructure outlives its daemon.
|
|
2266
|
+
//
|
|
2267
|
+
// `teardown()` is `docker rm`, not `docker stop`, and this task runs
|
|
2268
|
+
// on every shutdown — so on a node, restarting the daemon would
|
|
2269
|
+
// remove the stack's Postgres, Redis and MinIO. `omnitron fleet
|
|
2270
|
+
// upgrade` restarts every node's daemon, which would have made a
|
|
2271
|
+
// routine upgrade take the test environment down with it.
|
|
2272
|
+
//
|
|
2273
|
+
// The daemon is the supervisor, not the owner of the data plane's
|
|
2274
|
+
// lifetime. Locally it still tears down — `omnitron down` there means
|
|
2275
|
+
// "I am done for the day" — and on either, `omnitron infra down` is
|
|
2276
|
+
// the command that removes containers on purpose.
|
|
2277
|
+
if (this.dc.role === 'slave') {
|
|
2278
|
+
// Said on the way out, because the absence of a teardown is
|
|
2279
|
+
// otherwise indistinguishable from a teardown that failed.
|
|
2280
|
+
this.infraService.dispose();
|
|
2281
|
+
console.info('[omnitron] leaving this node\'s infrastructure running — the daemon does not own its lifetime');
|
|
2282
|
+
}
|
|
2283
|
+
else {
|
|
2284
|
+
try {
|
|
2285
|
+
await this.infraService.teardown();
|
|
2286
|
+
}
|
|
2287
|
+
catch { /* best-effort */ }
|
|
1302
2288
|
}
|
|
1303
|
-
catch { /* best-effort */ }
|
|
1304
2289
|
this.infraService = null;
|
|
1305
2290
|
}
|
|
1306
2291
|
}, ShutdownPriority.VeryLow);
|
|
@@ -1310,4 +2295,22 @@ export class OmnitronDaemon {
|
|
|
1310
2295
|
}, ShutdownPriority.Last);
|
|
1311
2296
|
}
|
|
1312
2297
|
}
|
|
2298
|
+
/**
|
|
2299
|
+
* Call a method on a system worker's proxy.
|
|
2300
|
+
*
|
|
2301
|
+
* `ServiceProxy` is typed with an index signature whose values may be an
|
|
2302
|
+
* async iterable as well as a function, so a direct `worker.updateConfig(…)`
|
|
2303
|
+
* does not type-check. Resolving through one place keeps the cast in one
|
|
2304
|
+
* place, and returns without throwing when the worker is not running — the
|
|
2305
|
+
* only correct answer for "tell the health monitor" when there is none.
|
|
2306
|
+
*/
|
|
2307
|
+
async function callWorkerMethod(manager, method, ...args) {
|
|
2308
|
+
const worker = manager.get('health-monitor');
|
|
2309
|
+
if (!worker)
|
|
2310
|
+
return undefined;
|
|
2311
|
+
const fn = worker[method];
|
|
2312
|
+
if (typeof fn !== 'function')
|
|
2313
|
+
return undefined;
|
|
2314
|
+
return fn.apply(worker, args);
|
|
2315
|
+
}
|
|
1313
2316
|
//# sourceMappingURL=daemon.js.map
|