@kici-dev/orchestrator 0.0.0 → 0.1.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/LICENSE +661 -0
- package/README.md +1 -6
- package/dist/__test-helpers__/mock-db.d.ts +103 -0
- package/dist/__test-helpers__/mock-ws.d.ts +13 -0
- package/dist/agent/dispatcher.d.ts +231 -0
- package/dist/agent/ownership-tracker.d.ts +46 -0
- package/dist/agent/registry.d.ts +255 -0
- package/dist/agent/token-store.d.ts +96 -0
- package/dist/app.d.ts +234 -0
- package/dist/audit/access-log.d.ts +92 -0
- package/dist/audit/sampling-rate-limiter.d.ts +41 -0
- package/dist/cache/build-coordinator.d.ts +42 -0
- package/dist/cache/dep-cache.d.ts +51 -0
- package/dist/cache/index.d.ts +16 -0
- package/dist/cache/pending-builds.d.ts +14 -0
- package/dist/cache/pending-dynamics.d.ts +15 -0
- package/dist/cache/pending-inits.d.ts +19 -0
- package/dist/cache/pending-tracker.d.ts +65 -0
- package/dist/cache/source-cache.d.ts +30 -0
- package/dist/cli/api-client.d.ts +411 -0
- package/dist/cli/commands/access-log.d.ts +30 -0
- package/dist/cli/commands/agent-service/index.d.ts +15 -0
- package/dist/cli/commands/agent-service/install.d.ts +9 -0
- package/dist/cli/commands/agent-service/logs.d.ts +9 -0
- package/dist/cli/commands/agent-service/restart.d.ts +8 -0
- package/dist/cli/commands/agent-service/start.d.ts +8 -0
- package/dist/cli/commands/agent-service/status.d.ts +10 -0
- package/dist/cli/commands/agent-service/stop.d.ts +8 -0
- package/dist/cli/commands/agent-service/uninstall.d.ts +9 -0
- package/dist/cli/commands/agent-service/upgrade.d.ts +11 -0
- package/dist/cli/commands/agent.d.ts +10 -0
- package/dist/cli/commands/api-key.d.ts +12 -0
- package/dist/cli/commands/audit.d.ts +9 -0
- package/dist/cli/commands/backend.d.ts +17 -0
- package/dist/cli/commands/cold-store-impl.d.ts +101 -0
- package/dist/cli/commands/cold-store.d.ts +30 -0
- package/dist/cli/commands/config.d.ts +16 -0
- package/dist/cli/commands/db.d.ts +19 -0
- package/dist/cli/commands/debug-bundle.d.ts +16 -0
- package/dist/cli/commands/diagnose.d.ts +15 -0
- package/dist/cli/commands/environment.d.ts +24 -0
- package/dist/cli/commands/event-dlq.d.ts +19 -0
- package/dist/cli/commands/event-log.d.ts +27 -0
- package/dist/cli/commands/event.d.ts +4 -0
- package/dist/cli/commands/execution.d.ts +17 -0
- package/dist/cli/commands/inspect-bundle.d.ts +16 -0
- package/dist/cli/commands/maintenance.d.ts +4 -0
- package/dist/cli/commands/orchestrator-service/index.d.ts +12 -0
- package/dist/cli/commands/orchestrator-service/install.d.ts +10 -0
- package/dist/cli/commands/orchestrator-service/logs.d.ts +10 -0
- package/dist/cli/commands/orchestrator-service/restart.d.ts +8 -0
- package/dist/cli/commands/orchestrator-service/start.d.ts +8 -0
- package/dist/cli/commands/orchestrator-service/status.d.ts +10 -0
- package/dist/cli/commands/orchestrator-service/stop.d.ts +8 -0
- package/dist/cli/commands/orchestrator-service/uninstall.d.ts +9 -0
- package/dist/cli/commands/orchestrator-service/upgrade.d.ts +12 -0
- package/dist/cli/commands/org-settings.d.ts +17 -0
- package/dist/cli/commands/peer.d.ts +13 -0
- package/dist/cli/commands/queue.d.ts +16 -0
- package/dist/cli/commands/registration.d.ts +18 -0
- package/dist/cli/commands/rotate.d.ts +9 -0
- package/dist/cli/commands/runs.d.ts +34 -0
- package/dist/cli/commands/secret.d.ts +12 -0
- package/dist/cli/commands/shared/db.d.ts +16 -0
- package/dist/cli/commands/shared/versioned-upgrade.d.ts +38 -0
- package/dist/cli/commands/source.d.ts +24 -0
- package/dist/cli/commands/token.d.ts +10 -0
- package/dist/cli/commands/workflow.d.ts +31 -0
- package/dist/cli/join.d.ts +14 -0
- package/dist/cli/kici-admin.d.ts +13 -0
- package/dist/cli/lazy-deps/cache.d.ts +17 -0
- package/dist/cli/lazy-deps/downloader.d.ts +33 -0
- package/dist/cli/lazy-deps/registry.d.ts +43 -0
- package/dist/cli/service/compose.d.ts +25 -0
- package/dist/cli/service/index.d.ts +24 -0
- package/dist/cli/service/launchd.d.ts +34 -0
- package/dist/cli/service/platform-detect.d.ts +59 -0
- package/dist/cli/service/systemd.d.ts +41 -0
- package/dist/cli/service/types.d.ts +91 -0
- package/dist/cli/service/windows.d.ts +20 -0
- package/dist/cli/wizard/agent-wizard.d.ts +24 -0
- package/dist/cli/wizard/orchestrator-wizard.d.ts +38 -0
- package/dist/cli/wizard/prompts.d.ts +23 -0
- package/dist/cli.js +11435 -0
- package/dist/cluster/cluster-identity.d.ts +59 -0
- package/dist/cluster/coordinator.d.ts +204 -0
- package/dist/cluster/health-api.d.ts +30 -0
- package/dist/cluster/index.d.ts +24 -0
- package/dist/cluster/join-client.d.ts +75 -0
- package/dist/cluster/join-handler.d.ts +58 -0
- package/dist/cluster/join-token.d.ts +94 -0
- package/dist/cluster/orphan-recovery.d.ts +67 -0
- package/dist/cluster/peer-client.d.ts +190 -0
- package/dist/cluster/peer-credentials.d.ts +108 -0
- package/dist/cluster/peer-crypto.d.ts +57 -0
- package/dist/cluster/peer-handler.d.ts +97 -0
- package/dist/cluster/peer-registry.d.ts +186 -0
- package/dist/cluster/raft-state.d.ts +36 -0
- package/dist/cluster/raft.d.ts +140 -0
- package/dist/cold-store/load-access-log-range.d.ts +73 -0
- package/dist/cold-store/load-event-log-range.d.ts +62 -0
- package/dist/cold-store/load-secret-audit-log-range.d.ts +38 -0
- package/dist/cold-store/orchestrator-cold-store.d.ts +58 -0
- package/dist/cold-store/tables/access-log.d.ts +80 -0
- package/dist/cold-store/tables/event-log.d.ts +70 -0
- package/dist/cold-store/tables/execution-jobs.d.ts +63 -0
- package/dist/cold-store/tables/execution-runs.d.ts +81 -0
- package/dist/cold-store/tables/execution-steps.d.ts +65 -0
- package/dist/cold-store/tables/secret-audit-log.d.ts +77 -0
- package/dist/concurrency/dispatch-next-queued.d.ts +63 -0
- package/dist/concurrency/group-tracker.d.ts +51 -0
- package/dist/concurrency/index.d.ts +3 -0
- package/dist/concurrency/queue-manager.d.ts +68 -0
- package/dist/concurrency/waiters.d.ts +58 -0
- package/dist/config/encryption.d.ts +82 -0
- package/dist/config/env-overlay.d.ts +45 -0
- package/dist/config/index.d.ts +16 -0
- package/dist/config/loader.d.ts +26 -0
- package/dist/config/reload.d.ts +113 -0
- package/dist/config/resolver.d.ts +47 -0
- package/dist/config/schema.d.ts +210 -0
- package/dist/config/shared-store.d.ts +142 -0
- package/dist/config/types.d.ts +218 -0
- package/dist/config.d.ts +249 -0
- package/dist/cron/cron-scheduler.d.ts +78 -0
- package/dist/cron/cron-store.d.ts +38 -0
- package/dist/dashboard/handler.d.ts +243 -0
- package/dist/db/client.d.ts +13 -0
- package/dist/db/migration-provider.d.ts +9 -0
- package/dist/db/migrations/001_initial.d.ts +8 -0
- package/dist/db/migrations/002_config_versions_key_version.d.ts +16 -0
- package/dist/db/migrations/003_access_log.d.ts +26 -0
- package/dist/db/migrations/004_rename_bundle_to_source.d.ts +19 -0
- package/dist/db/migrations/005_cold_store_chunk_counter.d.ts +19 -0
- package/dist/db/migrations/006_runs_jobs_steps_archived_at.d.ts +38 -0
- package/dist/db/migrations/007_audit_logs_archived_at.d.ts +42 -0
- package/dist/db/migrations/008_event_log_archived_at.d.ts +40 -0
- package/dist/db/migrations/009_access_log_trigram.d.ts +15 -0
- package/dist/db/migrations/010_cold_store_chunks.d.ts +34 -0
- package/dist/db/migrations/011_drop_source_secrets_notify.d.ts +21 -0
- package/dist/db/migrations/012_peer_credentials_active_uniq.d.ts +28 -0
- package/dist/db/migrations/013_execution_log_bytes.d.ts +21 -0
- package/dist/db/migrations/014_kici_events_lease_retry.d.ts +36 -0
- package/dist/db/migrations/015_org_settings_customer_scoped.d.ts +30 -0
- package/dist/db/migrations/016_org_settings_allow_http_npm.d.ts +15 -0
- package/dist/db/migrations/017_org_id_widen.d.ts +4 -0
- package/dist/db/migrations/018_org_id_prefix_backfill.d.ts +4 -0
- package/dist/db/migrator.d.ts +32 -0
- package/dist/db/types.d.ts +1266 -0
- package/dist/diagnostics/bundle-reader.d.ts +48 -0
- package/dist/diagnostics/bundle-writer.d.ts +57 -0
- package/dist/diagnostics/checks/agents.d.ts +10 -0
- package/dist/diagnostics/checks/certs.d.ts +9 -0
- package/dist/diagnostics/checks/config.d.ts +10 -0
- package/dist/diagnostics/checks/db.d.ts +9 -0
- package/dist/diagnostics/checks/disk.d.ts +9 -0
- package/dist/diagnostics/checks/index.d.ts +17 -0
- package/dist/diagnostics/checks/ws.d.ts +9 -0
- package/dist/diagnostics/index.d.ts +13 -0
- package/dist/diagnostics/runner.d.ts +23 -0
- package/dist/diagnostics/types.d.ts +38 -0
- package/dist/entry-helpers.d.ts +93 -0
- package/dist/environments/binding-store.d.ts +27 -0
- package/dist/environments/environment-store.d.ts +74 -0
- package/dist/environments/held-runs.d.ts +64 -0
- package/dist/environments/index.d.ts +10 -0
- package/dist/environments/protection/branch-gate.d.ts +5 -0
- package/dist/environments/protection/concurrency-gate.d.ts +7 -0
- package/dist/environments/protection/pipeline.d.ts +18 -0
- package/dist/environments/protection/reviewer-gate.d.ts +7 -0
- package/dist/environments/protection/trust-gate.d.ts +7 -0
- package/dist/environments/protection/wait-timer-gate.d.ts +7 -0
- package/dist/environments/variable-store.d.ts +39 -0
- package/dist/events/circuit-breaker.d.ts +33 -0
- package/dist/events/event-emitter.d.ts +55 -0
- package/dist/events/event-retry-scanner.d.ts +52 -0
- package/dist/events/event-router.d.ts +183 -0
- package/dist/events/event-store.d.ts +157 -0
- package/dist/events/trust-store.d.ts +54 -0
- package/dist/events/types.d.ts +61 -0
- package/dist/helpers/ip-extraction.d.ts +29 -0
- package/dist/helpers/rate-limiter.d.ts +23 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +772 -0
- package/dist/lockfile-cache.d.ts +39 -0
- package/dist/metrics/agent-metrics-aggregator.d.ts +116 -0
- package/dist/metrics/metrics-reporter.d.ts +40 -0
- package/dist/metrics/prometheus.d.ts +261 -0
- package/dist/metrics/scheduled-jobs.d.ts +20 -0
- package/dist/orchestrator-core.d.ts +193 -0
- package/dist/pipeline/dispatch-matched-workflow.d.ts +102 -0
- package/dist/pipeline/inline-eval.d.ts +28 -0
- package/dist/pipeline/install-secrets-resolver.d.ts +73 -0
- package/dist/pipeline/manual-schedule.d.ts +21 -0
- package/dist/pipeline/needs-scheduler.d.ts +85 -0
- package/dist/pipeline/process-webhook.d.ts +38 -0
- package/dist/pipeline/processor.d.ts +326 -0
- package/dist/pipeline/rerun.d.ts +79 -0
- package/dist/pipeline/test-pipeline.d.ts +110 -0
- package/dist/provider-registry.d.ts +122 -0
- package/dist/providers/generic/index.d.ts +23 -0
- package/dist/providers/generic/normalizer.d.ts +112 -0
- package/dist/providers/generic/verification.d.ts +47 -0
- package/dist/providers/github/auth.d.ts +60 -0
- package/dist/providers/github/changed-files.d.ts +51 -0
- package/dist/providers/github/check-status-poster.d.ts +35 -0
- package/dist/providers/github/contributor-resolver.d.ts +30 -0
- package/dist/providers/github/index.d.ts +20 -0
- package/dist/providers/github/lock-file.d.ts +32 -0
- package/dist/providers/github/normalizer.d.ts +103 -0
- package/dist/providers/github/repo-url.d.ts +35 -0
- package/dist/providers/internal/index.d.ts +32 -0
- package/dist/providers/internal/lock-file-fetcher.d.ts +34 -0
- package/dist/providers/internal/normalizer.d.ts +89 -0
- package/dist/providers/internal/repo-url-builder.d.ts +42 -0
- package/dist/providers/universal-git/changed-files.d.ts +42 -0
- package/dist/providers/universal-git/clone-token.d.ts +83 -0
- package/dist/providers/universal-git/config.d.ts +192 -0
- package/dist/providers/universal-git/index.d.ts +55 -0
- package/dist/providers/universal-git/lock-file.d.ts +71 -0
- package/dist/providers/universal-git/normalizer.d.ts +90 -0
- package/dist/providers/universal-git/repo-url.d.ts +50 -0
- package/dist/providers/universal-git/ssh-auth.d.ts +94 -0
- package/dist/queue/bootstrap.d.ts +50 -0
- package/dist/queue/cleanup.d.ts +41 -0
- package/dist/queue/depth-refresher.d.ts +65 -0
- package/dist/queue/job-queue.d.ts +343 -0
- package/dist/queue/scheduled-job.d.ts +91 -0
- package/dist/registration/extractor.d.ts +44 -0
- package/dist/registration/registration-index.d.ts +162 -0
- package/dist/registration/registration-store.d.ts +111 -0
- package/dist/reporting/check-run-summary.d.ts +102 -0
- package/dist/reporting/commit-status.d.ts +382 -0
- package/dist/reporting/execution-tracker.d.ts +538 -0
- package/dist/reporting/fs-log-storage.d.ts +41 -0
- package/dist/reporting/log-pull-handler.d.ts +35 -0
- package/dist/reporting/log-storage.d.ts +70 -0
- package/dist/reporting/log-writer.d.ts +45 -0
- package/dist/reporting/s3-log-storage.d.ts +42 -0
- package/dist/reporting/step-log-buffer.d.ts +57 -0
- package/dist/routes/admin-access-log.d.ts +34 -0
- package/dist/routes/admin-backends.d.ts +28 -0
- package/dist/routes/admin-config.d.ts +57 -0
- package/dist/routes/admin-db.d.ts +20 -0
- package/dist/routes/admin-environments.d.ts +42 -0
- package/dist/routes/admin-errors.d.ts +4 -0
- package/dist/routes/admin-event-dlq.d.ts +39 -0
- package/dist/routes/admin-event-log.d.ts +42 -0
- package/dist/routes/admin-events.d.ts +46 -0
- package/dist/routes/admin-maintenance.d.ts +22 -0
- package/dist/routes/admin-org-settings.d.ts +29 -0
- package/dist/routes/admin-queue-execution.d.ts +27 -0
- package/dist/routes/admin-registrations.d.ts +37 -0
- package/dist/routes/admin-runs.d.ts +57 -0
- package/dist/routes/admin-scheduled-jobs.d.ts +36 -0
- package/dist/routes/admin-sources.d.ts +18 -0
- package/dist/routes/admin.d.ts +103 -0
- package/dist/routes/capabilities.d.ts +24 -0
- package/dist/routes/diagnostics.d.ts +16 -0
- package/dist/routes/health.d.ts +20 -0
- package/dist/routes/test-trigger.d.ts +41 -0
- package/dist/routes/uploads.d.ts +38 -0
- package/dist/routes/webhooks.d.ts +36 -0
- package/dist/scaler/bare-metal-backend.d.ts +107 -0
- package/dist/scaler/config.d.ts +303 -0
- package/dist/scaler/container-backend.d.ts +125 -0
- package/dist/scaler/file-tail.d.ts +23 -0
- package/dist/scaler/firecracker-api.d.ts +100 -0
- package/dist/scaler/firecracker-backend.d.ts +263 -0
- package/dist/scaler/index.d.ts +24 -0
- package/dist/scaler/ip-allocator.d.ts +177 -0
- package/dist/scaler/label-matcher.d.ts +73 -0
- package/dist/scaler/log-forwarder.d.ts +54 -0
- package/dist/scaler/machine-ledger.d.ts +160 -0
- package/dist/scaler/manager.d.ts +338 -0
- package/dist/scaler/nftables.d.ts +85 -0
- package/dist/scaler/types.d.ts +388 -0
- package/dist/scaler/warm-pool.d.ts +81 -0
- package/dist/secrets/audit-logger.d.ts +65 -0
- package/dist/secrets/backend-health.d.ts +60 -0
- package/dist/secrets/backend-registry.d.ts +68 -0
- package/dist/secrets/backend-sync.d.ts +40 -0
- package/dist/secrets/cleanup.d.ts +40 -0
- package/dist/secrets/config.d.ts +51 -0
- package/dist/secrets/crypto.d.ts +49 -0
- package/dist/secrets/ephemeral-keys.d.ts +49 -0
- package/dist/secrets/index.d.ts +17 -0
- package/dist/secrets/pg-secret-store.d.ts +105 -0
- package/dist/secrets/rbac.d.ts +47 -0
- package/dist/secrets/secret-output-store.d.ts +46 -0
- package/dist/secrets/secret-resolver.d.ts +137 -0
- package/dist/secrets/source-credentials.d.ts +61 -0
- package/dist/secrets/token-manager.d.ts +63 -0
- package/dist/secrets/vault-secret-store.d.ts +85 -0
- package/dist/security/comment-handler.d.ts +67 -0
- package/dist/security/contributor-cache.d.ts +75 -0
- package/dist/security/global-workflow-policy.d.ts +72 -0
- package/dist/security/lock-source.d.ts +34 -0
- package/dist/security/trust-resolver.d.ts +108 -0
- package/dist/security/workflow-diff.d.ts +26 -0
- package/dist/server.d.ts +17 -0
- package/dist/server.js +48055 -0
- package/dist/sources/index.d.ts +10 -0
- package/dist/sources/source-manager.d.ts +63 -0
- package/dist/sources/source-store.d.ts +79 -0
- package/dist/sources/source-validator.d.ts +16 -0
- package/dist/stale-detector/stale-run-detector.d.ts +109 -0
- package/dist/standalone.d.ts +20 -0
- package/dist/standalone.js +41546 -0
- package/dist/storage/blob-routes.d.ts +20 -0
- package/dist/storage/filesystem.d.ts +60 -0
- package/dist/storage/index.d.ts +20 -0
- package/dist/storage/s3.d.ts +68 -0
- package/dist/storage/sign-url.d.ts +45 -0
- package/dist/storage/types.d.ts +98 -0
- package/dist/webhook/dedup.d.ts +44 -0
- package/dist/webhook/event-log.d.ts +83 -0
- package/dist/webhook/generic-sources.d.ts +169 -0
- package/dist/webhook/handler.d.ts +23 -0
- package/dist/webhook/relay-buffer.d.ts +96 -0
- package/dist/webhook/verify-inbound.d.ts +78 -0
- package/dist/worker/in-memory-execution-tracker.d.ts +94 -0
- package/dist/worker/in-memory-job-queue.d.ts +74 -0
- package/dist/worker/static-agent-token-store.d.ts +58 -0
- package/dist/worker/worker-status.d.ts +36 -0
- package/dist/worker-core.d.ts +74 -0
- package/dist/ws/agent-api-registry.d.ts +49 -0
- package/dist/ws/agent-handler.d.ts +176 -0
- package/dist/ws/agent-heartbeat.d.ts +45 -0
- package/dist/ws/dashboard-backends-handler.d.ts +51 -0
- package/dist/ws/dashboard-diagnostics-handler.d.ts +56 -0
- package/dist/ws/dashboard-env-handler.d.ts +107 -0
- package/dist/ws/dashboard-global-workflows-handler.d.ts +72 -0
- package/dist/ws/dashboard-registrations-handler.d.ts +84 -0
- package/dist/ws/event-buffer.d.ts +16 -0
- package/dist/ws/observer-handler.d.ts +42 -0
- package/dist/ws/observer-registry.d.ts +88 -0
- package/dist/ws/platform-client.d.ts +270 -0
- package/dist/ws/server-options.d.ts +15 -0
- package/package.json +87 -6
- package/sbom.spdx.json +14370 -0
- package/index.js +0 -3
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-backed, cross-process resource ledger for named machine pools.
|
|
3
|
+
*
|
|
4
|
+
* Multiple orchestrators on the same host that reference the same `machinePool`
|
|
5
|
+
* name share a JSON file under `KICI_MACHINE_LEDGER_DIR ?? /var/lib/kici/scaler-ledger`.
|
|
6
|
+
* Each scaler reservation appends a row; releases delete the matching row;
|
|
7
|
+
* and a periodic reaper prunes rows whose `(pid, bootId)` no longer exists.
|
|
8
|
+
*
|
|
9
|
+
* ## Concurrency
|
|
10
|
+
*
|
|
11
|
+
* Every read-modify-write goes through `withLock(poolName, fn)`, which uses
|
|
12
|
+
* an atomic POSIX `mkdir` on a sibling lockdir as the cross-process mutex.
|
|
13
|
+
* `mkdir` succeeds for exactly one caller when the directory does not exist,
|
|
14
|
+
* so it works as a portable `flock` substitute without any native dependency.
|
|
15
|
+
*
|
|
16
|
+
* The plan considered `proper-lockfile` and `fs-ext` first; neither is a
|
|
17
|
+
* transitive dep today (`pnpm why proper-lockfile` and `pnpm why fs-ext`
|
|
18
|
+
* both empty), so we use the documented `mkdir` fallback. This avoids
|
|
19
|
+
* adding a native binding for the sake of a single locking primitive.
|
|
20
|
+
*
|
|
21
|
+
* ## Crash safety
|
|
22
|
+
*
|
|
23
|
+
* Reservations carry `{ pid, bootId, instanceId, agentId, cpus, memBytes }`.
|
|
24
|
+
* `bootId` is read once at orchestrator startup from
|
|
25
|
+
* `/proc/sys/kernel/random/boot_id`; combined with `pid`, it lets the reaper
|
|
26
|
+
* detect "this PID is dead AND was on a previous boot" reliably:
|
|
27
|
+
*
|
|
28
|
+
* - Same boot: `process.kill(pid, 0)` answers liveness.
|
|
29
|
+
* - Different boot: any pre-reboot row is unconditionally stale.
|
|
30
|
+
*
|
|
31
|
+
* If an orchestrator dies without releasing, the next reservation request
|
|
32
|
+
* from any orchestrator on the host calls `reapStale()` first, so there's
|
|
33
|
+
* no leak window beyond the next spawn attempt.
|
|
34
|
+
*/
|
|
35
|
+
import type { ResourceCap } from './types.js';
|
|
36
|
+
/** Wire format for the per-pool ledger JSON file. */
|
|
37
|
+
export interface LedgerFile {
|
|
38
|
+
version: number;
|
|
39
|
+
cap: ResourceCap;
|
|
40
|
+
reservations: ReservationRow[];
|
|
41
|
+
}
|
|
42
|
+
/** A single reservation row in the ledger. */
|
|
43
|
+
export interface ReservationRow {
|
|
44
|
+
/** Orchestrator instance id (from `KICI_CLUSTER_INSTANCE_ID` or generated). */
|
|
45
|
+
instanceId: string;
|
|
46
|
+
/** Process id that owns this reservation. */
|
|
47
|
+
pid: number;
|
|
48
|
+
/** Linux boot id at the time the row was created. */
|
|
49
|
+
bootId: string;
|
|
50
|
+
/** Agent id this reservation is associated with. */
|
|
51
|
+
agentId: string;
|
|
52
|
+
/** Reserved cpus (cores). */
|
|
53
|
+
cpus: number;
|
|
54
|
+
/** Reserved memory in bytes. */
|
|
55
|
+
memBytes: number;
|
|
56
|
+
/** When the row was inserted (epoch ms). */
|
|
57
|
+
reservedAt: number;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* File-backed machine pool ledger.
|
|
61
|
+
*
|
|
62
|
+
* One instance is shared across all scaler entries that reference any pool
|
|
63
|
+
* (the pool name is passed per-call). The ledger does not cache the JSON:
|
|
64
|
+
* every operation goes through the lock, reads the file, applies the
|
|
65
|
+
* mutation, and writes it back — keeping the wire format the only source
|
|
66
|
+
* of truth across processes.
|
|
67
|
+
*/
|
|
68
|
+
export declare class MachineLedger {
|
|
69
|
+
private readonly bootId;
|
|
70
|
+
private dirPath;
|
|
71
|
+
private readonly explicitDir;
|
|
72
|
+
private readonly instanceId;
|
|
73
|
+
/** Per-process knownCaps cache; the on-disk file's `cap` must match the caller's expectation. */
|
|
74
|
+
private readonly expectedCaps;
|
|
75
|
+
/** Reaper interval handle. */
|
|
76
|
+
private reaperTimer;
|
|
77
|
+
constructor(opts: {
|
|
78
|
+
explicitDir?: string;
|
|
79
|
+
instanceId: string;
|
|
80
|
+
});
|
|
81
|
+
/**
|
|
82
|
+
* Lazy directory resolution so construction stays synchronous. Called from
|
|
83
|
+
* every operation; resolves once and caches.
|
|
84
|
+
*/
|
|
85
|
+
private ensureDir;
|
|
86
|
+
/** Register the expected cap for a pool. The on-disk file's cap must match. */
|
|
87
|
+
registerPool(name: string, cap: ResourceCap): void;
|
|
88
|
+
/**
|
|
89
|
+
* Path to the JSON file for `poolName`. Sibling lockdir is `<file>.lock`.
|
|
90
|
+
*/
|
|
91
|
+
private pathFor;
|
|
92
|
+
/**
|
|
93
|
+
* Atomic mkdir-based lock. Held for the duration of `fn`.
|
|
94
|
+
*/
|
|
95
|
+
private withLock;
|
|
96
|
+
/**
|
|
97
|
+
* If the lock directory has been held for more than 30 seconds, assume the
|
|
98
|
+
* holder is dead and release it. Without this, an orchestrator that gets
|
|
99
|
+
* SIGKILL'd while holding the lock would leave it stuck forever.
|
|
100
|
+
*/
|
|
101
|
+
private maybeReleaseStaleLock;
|
|
102
|
+
/**
|
|
103
|
+
* Read the ledger file (or initialize an empty one when missing).
|
|
104
|
+
*/
|
|
105
|
+
private readLedger;
|
|
106
|
+
/** Atomic write via temp-file + rename. */
|
|
107
|
+
private writeLedger;
|
|
108
|
+
/**
|
|
109
|
+
* Try to add a reservation. Returns true if the cap allowed it (and the row
|
|
110
|
+
* was persisted), false if any cap would be exceeded after summing.
|
|
111
|
+
*
|
|
112
|
+
* Reaps stale rows from dead processes before checking the cap so an
|
|
113
|
+
* orphaned reservation doesn't permanently squat capacity.
|
|
114
|
+
*/
|
|
115
|
+
tryReserve(poolName: string, agentId: string, cpus: number, memBytes: number): Promise<boolean>;
|
|
116
|
+
/**
|
|
117
|
+
* Release the reservation for `agentId`. Idempotent.
|
|
118
|
+
*/
|
|
119
|
+
release(poolName: string, agentId: string): Promise<void>;
|
|
120
|
+
/**
|
|
121
|
+
* Reap stale (dead-process) rows for the given pool. Called periodically.
|
|
122
|
+
*/
|
|
123
|
+
reapStale(poolName: string): Promise<void>;
|
|
124
|
+
/**
|
|
125
|
+
* Mutates `ledger.reservations` in place to drop rows that point at dead
|
|
126
|
+
* processes. Live-pid heuristic:
|
|
127
|
+
* - Different bootId → unconditionally dead (host rebooted since).
|
|
128
|
+
* - Same bootId, OWN instance: probe via `process.kill(pid, 0)` (always
|
|
129
|
+
* works inside this process's PID namespace).
|
|
130
|
+
* - Same bootId, OTHER instance: keep the row. We cannot safely
|
|
131
|
+
* `process.kill(pid, 0)` against a peer orchestrator's PID — when the
|
|
132
|
+
* two orchestrators share a host but live in different PID namespaces
|
|
133
|
+
* (e.g. one runs natively and the other in a container), `kill` returns
|
|
134
|
+
* ESRCH for any peer pid and the reservation would be falsely reaped,
|
|
135
|
+
* silently breaking the cross-process cap. Peer cleanup happens via
|
|
136
|
+
* `releaseAllForInstance()` on graceful shutdown; SIGKILL'd peers leave
|
|
137
|
+
* their rows in place until the host reboots (which the bootId check
|
|
138
|
+
* then reaps unconditionally).
|
|
139
|
+
*/
|
|
140
|
+
private dropDeadReservations;
|
|
141
|
+
/** Return current usage (sum of `requests` across all live rows). */
|
|
142
|
+
getUsage(poolName: string): Promise<{
|
|
143
|
+
cpus: number;
|
|
144
|
+
memBytes: number;
|
|
145
|
+
}>;
|
|
146
|
+
/**
|
|
147
|
+
* Start the periodic reaper. Idempotent. The reaper iterates every
|
|
148
|
+
* registered pool every 30s.
|
|
149
|
+
*/
|
|
150
|
+
start(intervalMs?: number): void;
|
|
151
|
+
/** Stop the periodic reaper. */
|
|
152
|
+
stop(): void;
|
|
153
|
+
private reapAllPools;
|
|
154
|
+
/**
|
|
155
|
+
* Best-effort: release every reservation owned by this instance across all
|
|
156
|
+
* registered pools. Called on graceful shutdown.
|
|
157
|
+
*/
|
|
158
|
+
releaseAllForInstance(): Promise<void>;
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=machine-ledger.d.ts.map
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ScalerManager: central coordinator for all scaler backends.
|
|
3
|
+
*
|
|
4
|
+
* Sits between the orchestrator's Dispatcher and individual scaler backends.
|
|
5
|
+
* Receives "no agent available" signals, routes to the correct backend,
|
|
6
|
+
* enforces global limits, tracks spawning agents to prevent over-provisioning,
|
|
7
|
+
* and manages the agent lifecycle from spawn to destroy.
|
|
8
|
+
*/
|
|
9
|
+
import type { ResourceRequest } from '@kici-dev/engine';
|
|
10
|
+
import type { ScalerBackend, ScalerConfig, ScaleResult, ScalerEvent, ResourceCap, ValidationResult } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Resolved per-job resource amounts (cpus + bytes) for both `requests` and
|
|
13
|
+
* `limits`. The scaler manager produces this from the job's declared resources
|
|
14
|
+
* combined with the scaler's `defaults.resources`, applying the request<->limit
|
|
15
|
+
* mirroring rule. Caps aggregate `requests`; backends use `limits`.
|
|
16
|
+
*/
|
|
17
|
+
export interface ResolvedResources {
|
|
18
|
+
requests: {
|
|
19
|
+
cpus: number;
|
|
20
|
+
memBytes: number;
|
|
21
|
+
};
|
|
22
|
+
limits: {
|
|
23
|
+
cpus: number;
|
|
24
|
+
memBytes: number;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Status summary for metrics and health endpoints.
|
|
29
|
+
*/
|
|
30
|
+
export interface ScalerStatus {
|
|
31
|
+
globalMaxAgents: number;
|
|
32
|
+
globalActiveCount: number;
|
|
33
|
+
spawningCount: number;
|
|
34
|
+
warmPoolCount: number;
|
|
35
|
+
/** Sum of `requests.cpus` / `requests.memBytes` reserved across all scalers. */
|
|
36
|
+
globalUsage: {
|
|
37
|
+
cpus: number;
|
|
38
|
+
memBytes: number;
|
|
39
|
+
};
|
|
40
|
+
/** Per-orchestrator resource cap, if configured. */
|
|
41
|
+
globalResourceCap?: ResourceCap;
|
|
42
|
+
backends: Array<{
|
|
43
|
+
name: string;
|
|
44
|
+
type: string;
|
|
45
|
+
activeCount: number;
|
|
46
|
+
maxAgents: number;
|
|
47
|
+
/** Label sets this backend can provision (each entry is a string[] of labels) */
|
|
48
|
+
labelSets: string[][];
|
|
49
|
+
/** Sum of `requests` reserved by this scaler's active agents. */
|
|
50
|
+
usage: {
|
|
51
|
+
cpus: number;
|
|
52
|
+
memBytes: number;
|
|
53
|
+
};
|
|
54
|
+
/** Per-scaler resource cap, if configured. */
|
|
55
|
+
resourceCap?: ResourceCap;
|
|
56
|
+
/** Machine-pool reference, if any. */
|
|
57
|
+
machinePool?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Labels a job MUST declare in `runsOn` to be allowed on this backend.
|
|
60
|
+
* Empty array = no gate. Surfaced in heartbeat-side scaler capacity
|
|
61
|
+
* summaries so cross-peer routing applies the same gate.
|
|
62
|
+
*/
|
|
63
|
+
mandatoryLabels: string[];
|
|
64
|
+
}>;
|
|
65
|
+
}
|
|
66
|
+
export declare class ScalerManager {
|
|
67
|
+
private readonly backends;
|
|
68
|
+
private readonly backendRoles;
|
|
69
|
+
private globalMaxAgents;
|
|
70
|
+
/** Per-scaler resource caps (`{ maxCpu, maxMemoryBytes }`), keyed by scaler name. */
|
|
71
|
+
private readonly resourceCaps;
|
|
72
|
+
/** Per-scaler default resources (used when neither job nor label-set declares them). */
|
|
73
|
+
private readonly scalerDefaults;
|
|
74
|
+
/** Per-scaler usage counters (sum of `requests` for active + spawning agents). */
|
|
75
|
+
private readonly perScalerUsage;
|
|
76
|
+
/** Orchestrator-wide cap on summed `requests`. */
|
|
77
|
+
private globalResourceCap;
|
|
78
|
+
/** Orchestrator-wide usage counter. */
|
|
79
|
+
private readonly globalUsage;
|
|
80
|
+
/** Per-scaler machine-pool name (set when scalers reference a pool). */
|
|
81
|
+
private readonly scalerMachinePools;
|
|
82
|
+
/** Outstanding reservations keyed by agentId; used to release on disconnect. */
|
|
83
|
+
private readonly reservations;
|
|
84
|
+
/**
|
|
85
|
+
* Serialization queue for the check+reserve critical section. A simple
|
|
86
|
+
* promise chain is sufficient because every reservation runs on the same
|
|
87
|
+
* Node.js event loop and the work inside the critical section is purely
|
|
88
|
+
* synchronous (`tryReserveAll`).
|
|
89
|
+
*/
|
|
90
|
+
private reservationLock;
|
|
91
|
+
/**
|
|
92
|
+
* File-backed cross-process ledger for named machine pools (optional).
|
|
93
|
+
* Lazily initialized in the constructor when at least one scaler entry
|
|
94
|
+
* references a pool.
|
|
95
|
+
*/
|
|
96
|
+
private readonly machineLedger;
|
|
97
|
+
/** Per-scaler URL overrides from config, keyed by scaler name */
|
|
98
|
+
private readonly scalerUrls;
|
|
99
|
+
/**
|
|
100
|
+
* Tracks agents being spawned but not yet registered via WS.
|
|
101
|
+
* Keyed by pre-generated agentId.
|
|
102
|
+
*/
|
|
103
|
+
private readonly spawningAgents;
|
|
104
|
+
/**
|
|
105
|
+
* Maps registered agentId to backendName for lifecycle events.
|
|
106
|
+
*/
|
|
107
|
+
private readonly managedAgentIndex;
|
|
108
|
+
/**
|
|
109
|
+
* Active log forwarders for scaler-managed agents (container/bare-metal).
|
|
110
|
+
* Keyed by agentId. Each forwarder consumes a LogCapture stream.
|
|
111
|
+
*/
|
|
112
|
+
private readonly logForwarders;
|
|
113
|
+
/**
|
|
114
|
+
* Correlation map: agentId -> { runId, jobId }.
|
|
115
|
+
* Populated by correlateAgentToJob() after job dispatch to a scaler-managed agent.
|
|
116
|
+
*/
|
|
117
|
+
private readonly agentJobCorrelation;
|
|
118
|
+
/**
|
|
119
|
+
* Buffer for scaler events emitted before job correlation is established.
|
|
120
|
+
* Keyed by agentId. Flushed when correlateAgentToJob() is called.
|
|
121
|
+
*/
|
|
122
|
+
private readonly eventBuffer;
|
|
123
|
+
/**
|
|
124
|
+
* External callback for relaying correlated scaler events (e.g. to execution tracker).
|
|
125
|
+
*/
|
|
126
|
+
private readonly onScalerEvent?;
|
|
127
|
+
private readonly warmPool;
|
|
128
|
+
constructor(deps: {
|
|
129
|
+
config: ScalerConfig;
|
|
130
|
+
backends: Array<{
|
|
131
|
+
name: string;
|
|
132
|
+
backend: ScalerBackend;
|
|
133
|
+
}>;
|
|
134
|
+
/** Callback for relaying scaler events with runId/jobId context. */
|
|
135
|
+
onScalerEvent?: (runId: string, jobId: string, event: ScalerEvent) => void;
|
|
136
|
+
/**
|
|
137
|
+
* Optional machine-ledger options. When `machinePools` are configured,
|
|
138
|
+
* the manager initializes a `MachineLedger` keyed off this directory and
|
|
139
|
+
* the orchestrator's instance id; reservations sum across orchestrators
|
|
140
|
+
* on the same host.
|
|
141
|
+
*/
|
|
142
|
+
machineLedger?: {
|
|
143
|
+
/** Override the on-disk ledger directory. Falls back to `KICI_MACHINE_LEDGER_DIR`. */
|
|
144
|
+
dir?: string;
|
|
145
|
+
/** Orchestrator instance id (used in ledger rows for ownership). */
|
|
146
|
+
instanceId: string;
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
/** Per-scaler mandatoryLabels (taint-style opt-in gate). */
|
|
150
|
+
private readonly scalerMandatoryLabels;
|
|
151
|
+
/**
|
|
152
|
+
* Build enriched scaler entries with auto-labels injected into each label set.
|
|
153
|
+
* This ensures label matching accounts for auto-injected labels (kici:role:*,
|
|
154
|
+
* kici:os:*, kici:arch:*, kici:agent:*, kici:scaler:*) that agents receive
|
|
155
|
+
* at spawn time.
|
|
156
|
+
*
|
|
157
|
+
* Mandatory labels are surfaced unchanged from the per-scaler config so the
|
|
158
|
+
* label matcher can apply the gate alongside subset matching.
|
|
159
|
+
*/
|
|
160
|
+
private getEnrichedScalerEntries;
|
|
161
|
+
/**
|
|
162
|
+
* Main entry point: called by the Dispatcher when no agent is available.
|
|
163
|
+
*
|
|
164
|
+
* `resources` is the per-job request/limit declaration (or `undefined` to fall
|
|
165
|
+
* back to scaler defaults). Used by per-scaler / per-orchestrator / per-machine
|
|
166
|
+
* resource caps; the cap math is wired up by ScalerManager itself.
|
|
167
|
+
*/
|
|
168
|
+
requestScale(labels: string[], jobId: string, excludeLabels?: string[], resources?: ResourceRequest): Promise<ScaleResult>;
|
|
169
|
+
/**
|
|
170
|
+
* Run a critical section under the reservation lock. Serializes concurrent
|
|
171
|
+
* `requestScale()` calls so the check+reserve sequence is atomic.
|
|
172
|
+
*/
|
|
173
|
+
private runWithReservationLock;
|
|
174
|
+
/**
|
|
175
|
+
* Resolve the effective `{ requests, limits }` for a job at this scaler.
|
|
176
|
+
*
|
|
177
|
+
* Layered defaults (highest priority first):
|
|
178
|
+
* 1. Job's own `resources` (after request<->limit mirroring).
|
|
179
|
+
* 2. Label-set's `resources`.
|
|
180
|
+
* 3. Scaler's `defaults.resources` (already merged from global defaults at construction).
|
|
181
|
+
* 4. Zero (`{ cpus: 0, memBytes: 0 }`).
|
|
182
|
+
*
|
|
183
|
+
* Returns both sides fully resolved as numeric `{ cpus, memBytes }` pairs.
|
|
184
|
+
*/
|
|
185
|
+
private resolveEffective;
|
|
186
|
+
/**
|
|
187
|
+
* Attempt to reserve `requests` against the per-scaler and per-orchestrator
|
|
188
|
+
* caps. Returns false (no state change) if any cap would be exceeded.
|
|
189
|
+
*
|
|
190
|
+
* Caller must hold the reservation lock.
|
|
191
|
+
*/
|
|
192
|
+
private tryReserveAll;
|
|
193
|
+
/**
|
|
194
|
+
* Push the current `perScalerUsage` and `globalUsage` snapshot into the
|
|
195
|
+
* Prometheus observable gauges. Called on every successful reservation /
|
|
196
|
+
* release so the gauge callback always reflects the latest state without
|
|
197
|
+
* doing any work itself (gauge callbacks are synchronous and MUST NOT
|
|
198
|
+
* touch this map directly — they just read whatever was last published).
|
|
199
|
+
*
|
|
200
|
+
* Note: pool-level usage is intentionally not emitted here. The on-disk
|
|
201
|
+
* machine-pool ledger requires async I/O + a file lock to read accurately,
|
|
202
|
+
* and OTel observable-gauge callbacks must be synchronous. Operators
|
|
203
|
+
* dashboarding pool utilization can derive a lower bound from the sum of
|
|
204
|
+
* `kici_orch_scaler_cpus_used` rows whose scaler belongs to the pool.
|
|
205
|
+
*/
|
|
206
|
+
private publishUsageMetrics;
|
|
207
|
+
/**
|
|
208
|
+
* Release the reservation tracked for an agent. Idempotent. Also releases
|
|
209
|
+
* the cross-process pool reservation (best-effort) when the scaler
|
|
210
|
+
* references a pool.
|
|
211
|
+
*/
|
|
212
|
+
private releaseAll;
|
|
213
|
+
/**
|
|
214
|
+
* Subtract the given `requests` from the per-scaler and global in-memory
|
|
215
|
+
* counters. Used both by `releaseAll()` and by the rollback path when a
|
|
216
|
+
* machine-pool reservation refuses after the in-memory reservation
|
|
217
|
+
* already succeeded.
|
|
218
|
+
*/
|
|
219
|
+
private releaseInMemory;
|
|
220
|
+
/**
|
|
221
|
+
* Resolve the scaler-level default resources, merging the global
|
|
222
|
+
* `defaults.resources` underneath any scaler-specific override.
|
|
223
|
+
*
|
|
224
|
+
* Currently scaler entries themselves do not carry their own `defaults` (the
|
|
225
|
+
* label-set level does). The merged result is stored per-scaler so that
|
|
226
|
+
* future scaler-level defaults can be added without touching the resolver.
|
|
227
|
+
*/
|
|
228
|
+
private resolveScalerDefaults;
|
|
229
|
+
/**
|
|
230
|
+
* Called from agent-handler.ts when an agent registers via WS.
|
|
231
|
+
* Correlates the registered agent to a spawned tracking entry.
|
|
232
|
+
*
|
|
233
|
+
* Returns:
|
|
234
|
+
* - `boundJobId` (optional): the queued jobId this agent was spawned for.
|
|
235
|
+
* Used by the caller to eagerly dispatch the bound job before the
|
|
236
|
+
* agent's idle timer fires, skipping the generic queue drain race.
|
|
237
|
+
* - `mandatoryLabels` (always populated for scaler-managed agents): the
|
|
238
|
+
* spawning scaler's `mandatoryLabels` gate. Threaded into the
|
|
239
|
+
* AgentRegistry so the queue-drain path (`onAgentAvailable` →
|
|
240
|
+
* `dequeueForLabels`) and the eager-dispatch path
|
|
241
|
+
* (`dispatchBoundJob` → `dequeueById`) both reject queued jobs whose
|
|
242
|
+
* `runsOn` does not include every gate label.
|
|
243
|
+
*
|
|
244
|
+
* Returns `null` for static agents and warm-pool replenishment spawns
|
|
245
|
+
* (no spawning entry exists).
|
|
246
|
+
*/
|
|
247
|
+
onAgentRegistered(agentId: string, labels: string[]): {
|
|
248
|
+
boundJobId?: string;
|
|
249
|
+
mandatoryLabels: string[];
|
|
250
|
+
} | null;
|
|
251
|
+
/**
|
|
252
|
+
* Called from agent-handler.ts when an agent disconnects.
|
|
253
|
+
*/
|
|
254
|
+
onAgentDisconnected(agentId: string): void;
|
|
255
|
+
/**
|
|
256
|
+
* Look up the scaler backend name (e.g. `container`, `firecracker`,
|
|
257
|
+
* `bare-metal`) for a registered agent. Returns null if the agent is
|
|
258
|
+
* not scaler-managed (i.e. a static / stateful agent).
|
|
259
|
+
*
|
|
260
|
+
* Used by AgentMetricsAggregator to inject a `scaler` label on each
|
|
261
|
+
* `kici_agent_*` series so dashboards can split per-scaler instead of
|
|
262
|
+
* per-agent_id (which is too high-cardinality and doesn't tell the
|
|
263
|
+
* operator which pool is loaded).
|
|
264
|
+
*/
|
|
265
|
+
getBackendName(agentId: string): string | null;
|
|
266
|
+
/**
|
|
267
|
+
* Called from agent-handler.ts when an agent sends config.ack.
|
|
268
|
+
* For Firecracker agents, clears MMDS data (belt-and-suspenders with in-VM iptables).
|
|
269
|
+
* For non-Firecracker agents, this is a no-op.
|
|
270
|
+
*/
|
|
271
|
+
onConfigAck(agentId: string): void;
|
|
272
|
+
/**
|
|
273
|
+
* Called when a scaler-managed agent completes a job.
|
|
274
|
+
*/
|
|
275
|
+
onJobComplete(agentId: string): void;
|
|
276
|
+
/**
|
|
277
|
+
* Correlate an agentId to a runId/jobId after the dispatcher assigns a job
|
|
278
|
+
* to a scaler-managed agent. Flushes any buffered pre-dispatch events.
|
|
279
|
+
*/
|
|
280
|
+
correlateAgentToJob(agentId: string, runId: string, jobId: string): void;
|
|
281
|
+
/**
|
|
282
|
+
* Sum of all backends' active count + spawning agents.
|
|
283
|
+
*/
|
|
284
|
+
getGlobalActiveCount(): number;
|
|
285
|
+
/**
|
|
286
|
+
* Stop warm pool, shutdown all backends, clear tracking maps.
|
|
287
|
+
*/
|
|
288
|
+
shutdownAll(): Promise<void>;
|
|
289
|
+
/**
|
|
290
|
+
* Validate and reload configuration.
|
|
291
|
+
*/
|
|
292
|
+
reload(newConfig: ScalerConfig): Promise<ValidationResult>;
|
|
293
|
+
/**
|
|
294
|
+
* Return status summary for metrics and health endpoints.
|
|
295
|
+
*/
|
|
296
|
+
getStatus(): ScalerStatus;
|
|
297
|
+
/**
|
|
298
|
+
* Get the backend name managing a specific agent.
|
|
299
|
+
* Returns null if the agent is not scaler-managed (standalone).
|
|
300
|
+
*/
|
|
301
|
+
getBackendForAgent(agentId: string): string | null;
|
|
302
|
+
/**
|
|
303
|
+
* Get scaler-specific configuration metadata for a managed agent.
|
|
304
|
+
* Returns undefined for non-scaler-managed (static) agents.
|
|
305
|
+
* Used to enrich job.context before forwarding to Platform.
|
|
306
|
+
*/
|
|
307
|
+
getScalerContextForAgent(agentId: string): Record<string, unknown> | undefined;
|
|
308
|
+
/**
|
|
309
|
+
* Start the warm pool idle check interval and the machine-pool ledger reaper.
|
|
310
|
+
*/
|
|
311
|
+
start(): void;
|
|
312
|
+
/**
|
|
313
|
+
* Remove spawning entries older than 5 minutes.
|
|
314
|
+
* These represent agents that were spawned but never registered via WS
|
|
315
|
+
* (e.g., process/container crashed on startup). Without cleanup, these
|
|
316
|
+
* entries would leak in spawningAgents forever.
|
|
317
|
+
*/
|
|
318
|
+
private pruneStaleSpawningEntries;
|
|
319
|
+
private generateAgentId;
|
|
320
|
+
/**
|
|
321
|
+
* Start log forwarding for a scaler-managed agent if its backend supports LogCapture.
|
|
322
|
+
* Fire-and-forget: the forward() promise runs for the agent's lifetime.
|
|
323
|
+
*/
|
|
324
|
+
private startLogForwarding;
|
|
325
|
+
private getOrchestratorUrl;
|
|
326
|
+
/**
|
|
327
|
+
* Create a per-agent event emitter closure to pass to backend.spawn().
|
|
328
|
+
* The closure captures agentId and routes events through handleScalerEvent().
|
|
329
|
+
*/
|
|
330
|
+
private createEventEmitter;
|
|
331
|
+
/**
|
|
332
|
+
* Handle a scaler event from a backend.
|
|
333
|
+
* If the agent is correlated to a job, relay immediately.
|
|
334
|
+
* Otherwise, buffer until correlation is established.
|
|
335
|
+
*/
|
|
336
|
+
private handleScalerEvent;
|
|
337
|
+
}
|
|
338
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Programmatic nftables rule management for agent network isolation.
|
|
3
|
+
*
|
|
4
|
+
* Manages RFC1918 + cloud metadata blocking rules per-interface (Firecracker/container)
|
|
5
|
+
* or per-UID (bare-metal). All operations use `nft` CLI via child_process.execFile.
|
|
6
|
+
*
|
|
7
|
+
* Table layout:
|
|
8
|
+
* table ip kici {
|
|
9
|
+
* chain forward { type filter hook forward priority 0; policy accept; }
|
|
10
|
+
* chain output { type filter hook output priority 0; policy accept; }
|
|
11
|
+
* }
|
|
12
|
+
*/
|
|
13
|
+
import type { NetworkPolicy } from './types.js';
|
|
14
|
+
/**
|
|
15
|
+
* Match mode for nftables isolation rules.
|
|
16
|
+
* - 'iifname': Match on input interface name (Firecracker TAP devices)
|
|
17
|
+
* - 'saddr': Match on source IP address (container backends)
|
|
18
|
+
*/
|
|
19
|
+
export type NftMatchMode = 'iifname' | 'saddr';
|
|
20
|
+
/**
|
|
21
|
+
* Options for nft command execution.
|
|
22
|
+
*/
|
|
23
|
+
interface NftOptions {
|
|
24
|
+
/**
|
|
25
|
+
* Wrap the `nft` invocation with `sudo -n` so non-root orchestrators (e.g.
|
|
26
|
+
* Pi user-mode systemd) can manage rules. Operators must have a NOPASSWD
|
|
27
|
+
* sudoers entry for /usr/sbin/nft. Default false.
|
|
28
|
+
*/
|
|
29
|
+
requireSudo?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Validate that nftables is available and the process has NET_ADMIN capability.
|
|
33
|
+
* Attempts `nft list tables` -- if it fails:
|
|
34
|
+
* - ENOENT: nft binary not installed
|
|
35
|
+
* - EPERM: nft binary present but NET_ADMIN capability missing
|
|
36
|
+
* Throws with a clear error message in both cases.
|
|
37
|
+
*/
|
|
38
|
+
export declare function validateNftablesAvailability(opts?: NftOptions): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Ensure the `kici` nftables table and required chains exist.
|
|
41
|
+
* Idempotent -- safe to call multiple times.
|
|
42
|
+
*/
|
|
43
|
+
export declare function ensureKiciTable(opts?: NftOptions): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Add network isolation rules for a specific network interface.
|
|
46
|
+
* Used by Firecracker and container backends.
|
|
47
|
+
*
|
|
48
|
+
* Rule order (top to bottom):
|
|
49
|
+
* 1. Accept gateway traffic (MUST be first -- inserted, not appended)
|
|
50
|
+
* 2. Accept allowlisted CIDRs (if any)
|
|
51
|
+
* 3. Drop RFC1918 ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
|
|
52
|
+
* 4. Drop cloud metadata (169.254.0.0/16)
|
|
53
|
+
* 5. Drop all remaining traffic (only if denyAll is true)
|
|
54
|
+
*
|
|
55
|
+
* @param identifier - Network interface name or source IP to match (e.g., "veth-abc123" or "172.30.0.5")
|
|
56
|
+
* @param gatewayIp - Gateway IP that must remain accessible (e.g., "10.0.0.1")
|
|
57
|
+
* @param networkPolicy - Optional policy with allowlist and denyAll settings
|
|
58
|
+
* @param matchMode - How to match traffic: 'iifname' for interface name (default), 'saddr' for source IP
|
|
59
|
+
*/
|
|
60
|
+
export declare function addIsolationRules(identifier: string, gatewayIp: string, networkPolicy?: NetworkPolicy, matchMode?: NftMatchMode, opts?: NftOptions): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Remove all isolation rules matching a specific interface from the kici forward chain.
|
|
63
|
+
* Called during agent cleanup/destruction.
|
|
64
|
+
*
|
|
65
|
+
* Lists all rules with handles, finds those matching the interface name, and deletes them.
|
|
66
|
+
* Best-effort: logs errors but does not throw (cleanup should not block destruction).
|
|
67
|
+
*
|
|
68
|
+
* @param interfaceName - Network interface whose rules should be removed
|
|
69
|
+
*/
|
|
70
|
+
export declare function removeIsolationRules(interfaceName: string, opts?: NftOptions): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Re-export NftOptions type for use by callers (Firecracker / container backends)
|
|
73
|
+
* that need to pass the requireSudo flag through to these functions.
|
|
74
|
+
*/
|
|
75
|
+
export type { NftOptions };
|
|
76
|
+
/**
|
|
77
|
+
* Parse nft rule listing output and extract handles for rules matching a given identifier.
|
|
78
|
+
* Handles lines like: ` iifname "veth-abc" ip daddr 10.0.0.0/8 drop # handle 42`
|
|
79
|
+
*
|
|
80
|
+
* @param nftOutput - Raw output from `nft -a list chain ip kici <chain>`
|
|
81
|
+
* @param identifier - String to search for in each rule line (interface name or UID)
|
|
82
|
+
* @returns Array of numeric rule handles
|
|
83
|
+
*/
|
|
84
|
+
export declare function parseRuleHandles(nftOutput: string, identifier: string): number[];
|
|
85
|
+
//# sourceMappingURL=nftables.d.ts.map
|