@kici-dev/orchestrator 0.5.0 → 0.6.0
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/dist/__test-helpers__/fake-scaler-state-store.d.ts +24 -0
- package/dist/__test-helpers__/mock-db-query.d.ts +130 -0
- package/dist/__test-helpers__/mock-db.d.ts +23 -0
- package/dist/agent/dispatcher.d.ts +81 -13
- package/dist/agent/host-roster.d.ts +37 -5
- package/dist/agent/registry.d.ts +2 -0
- package/dist/app.d.ts +33 -6
- package/dist/approvals/apply-decision.d.ts +67 -19
- package/dist/approvals/held-run-release-wiring.d.ts +45 -0
- package/dist/approvals/independent-wiring.d.ts +55 -0
- package/dist/approvals/resume-router.d.ts +9 -0
- package/dist/approvals/triggerer-subject.d.ts +37 -0
- package/dist/cache/dep-cache.d.ts +54 -10
- package/dist/cache/global-eval-round-cache.d.ts +7 -0
- package/dist/cli/api-client.d.ts +18 -0
- package/dist/cli/commands/cluster-settings.d.ts +11 -0
- package/dist/cli/commands/diagnose.d.ts +6 -0
- package/dist/cli/commands/held-run.d.ts +58 -0
- package/dist/cli/commands/trust-policy.d.ts +117 -12
- package/dist/cli/kici-admin.d.ts +10 -0
- package/dist/cli.js +2272 -1025
- package/dist/cluster/cluster-identity.d.ts +3 -3
- package/dist/cluster/cluster-settings-reader.d.ts +7 -1
- package/dist/cluster/coordinator.d.ts +44 -0
- package/dist/cluster/index.d.ts +4 -0
- package/dist/cluster/peer-handler.d.ts +19 -0
- package/dist/cluster/peer-registry.d.ts +17 -0
- package/dist/cluster/plan-headroom-store.d.ts +26 -0
- package/dist/cluster/worker-eviction.d.ts +69 -0
- package/dist/cold-store/load-event-log-range.d.ts +10 -3
- package/dist/cold-store/load-secret-audit-log-range.d.ts +4 -3
- package/dist/cold-store/tables/secret-audit-log.d.ts +4 -3
- package/dist/config.d.ts +21 -21
- package/dist/contexts/held-runs.d.ts +123 -16
- package/dist/contexts/protection/aggregate.d.ts +3 -2
- package/dist/contexts/protection/branch-gate.d.ts +15 -0
- package/dist/contexts/protection/concurrency-gate.d.ts +8 -2
- package/dist/contexts/protection/pipeline.d.ts +18 -0
- package/dist/contexts/release-queued-holds.d.ts +35 -0
- package/dist/dashboard/attestation-filters.d.ts +8 -0
- package/dist/dashboard/handler.d.ts +6 -24
- package/dist/db/migrations/116_org_plan_headroom.d.ts +4 -0
- package/dist/db/migrations/117_invoke_gate_proxy_jobs.d.ts +4 -0
- package/dist/db/migrations/118_invoke_gate_scheduling.d.ts +4 -0
- package/dist/db/migrations/119_scaler_ha_ownership.d.ts +4 -0
- package/dist/db/migrations/120_cluster_settings_scaler_reaper.d.ts +4 -0
- package/dist/db/migrations/121_org_settings_allow_untrusted_dockerfile_builds.d.ts +19 -0
- package/dist/db/migrations/122_host_roster_scaler_managed.d.ts +25 -0
- package/dist/db/migrations/123_workflow_registrations_default_branch.d.ts +24 -0
- package/dist/db/migrations/124_cluster_settings_provision_backoff.d.ts +4 -0
- package/dist/db/migrations/125_org_trust_directory.d.ts +30 -0
- package/dist/db/migrations/126_held_runs_posted_pending_check.d.ts +28 -0
- package/dist/db/migrations/127_org_trust_policy_approval_expiry_seconds.d.ts +26 -0
- package/dist/db/migrations/128_execution_runs_global_eval_round.d.ts +23 -0
- package/dist/db/migrations/129_execution_runs_dispatch_routing_key.d.ts +24 -0
- package/dist/db/migrations/130_scaler_provision_outcomes.d.ts +32 -0
- package/dist/db/types.d.ts +368 -10
- package/dist/entry-helpers.d.ts +28 -0
- package/dist/events/event-emitter.d.ts +22 -0
- package/dist/events/event-router.d.ts +87 -1
- package/dist/events/types.d.ts +2 -23
- package/dist/git/credential-broker.d.ts +94 -0
- package/dist/git/inherited-secret.d.ts +24 -0
- package/dist/git/installation-token.d.ts +38 -0
- package/dist/git/job-context.d.ts +13 -0
- package/dist/index.js +324 -84
- package/dist/metrics/agent-metrics-aggregator.d.ts +2 -2
- package/dist/metrics/prometheus.d.ts +111 -3
- package/dist/oidc/oidc-mint-registration.d.ts +7 -3
- package/dist/orchestrator-core.d.ts +79 -23
- package/dist/pipeline/direct-ingress-deps.d.ts +100 -0
- package/dist/pipeline/dispatch-matched-workflow.d.ts +302 -31
- package/dist/pipeline/global-eval-round.d.ts +14 -0
- package/dist/pipeline/internal-event-pipeline.d.ts +140 -0
- package/dist/pipeline/invoke-gate.d.ts +164 -0
- package/dist/pipeline/needs-scheduler.d.ts +13 -0
- package/dist/pipeline/process-webhook.d.ts +119 -31
- package/dist/pipeline/processor.d.ts +226 -21
- package/dist/pipeline/rerun.d.ts +21 -0
- package/dist/pipeline/resume-workflow.d.ts +40 -7
- package/dist/pipeline/route-or-dispatch-jobs.d.ts +9 -0
- package/dist/pipeline/security-hold-check.d.ts +217 -0
- package/dist/pipeline/undispatched-hold-checks.d.ts +23 -0
- package/dist/policy/dashboard-write-policy-listener.d.ts +62 -0
- package/dist/policy/dashboard-write-policy.d.ts +14 -0
- package/dist/provider-registry.d.ts +10 -2
- package/dist/providers/github/check-status-poster.d.ts +11 -0
- package/dist/providers/github/index.d.ts +0 -2
- package/dist/providers/github/normalizer.d.ts +3 -2
- package/dist/providers/local/normalizer.d.ts +3 -5
- package/dist/providers/universal-git/index.d.ts +11 -2
- package/dist/queue/job-queue.d.ts +43 -1
- package/dist/registration/extractor.d.ts +3 -3
- package/dist/registration/registration-index.d.ts +7 -0
- package/dist/registration/registration-store.d.ts +22 -0
- package/dist/reporting/check-run-reporter.d.ts +94 -1
- package/dist/reporting/check-run-summary.d.ts +25 -1
- package/dist/reporting/execution-tracker.d.ts +207 -2
- package/dist/reporting/run-aggregator.d.ts +4 -14
- package/dist/reporting/step-display-order.d.ts +43 -0
- package/dist/routes/admin-held-runs.d.ts +142 -0
- package/dist/routes/admin-trust-policy.d.ts +34 -6
- package/dist/routes/admin.d.ts +9 -0
- package/dist/scaler/backend-factory.d.ts +55 -0
- package/dist/scaler/bare-metal-backend.d.ts +43 -5
- package/dist/scaler/claim-store.d.ts +119 -0
- package/dist/scaler/config.d.ts +4 -0
- package/dist/scaler/container-backend.d.ts +18 -4
- package/dist/scaler/container-routing.d.ts +23 -0
- package/dist/scaler/container-spawn.d.ts +28 -0
- package/dist/scaler/event-backend.d.ts +124 -0
- package/dist/scaler/event-provision-reaper.d.ts +350 -0
- package/dist/scaler/failure-tracker.d.ts +1 -1
- package/dist/scaler/firecracker-backend.d.ts +33 -6
- package/dist/scaler/index.d.ts +11 -1
- package/dist/scaler/label-matcher.d.ts +4 -3
- package/dist/scaler/manager.d.ts +899 -72
- package/dist/scaler/resolve-container-auth.d.ts +45 -0
- package/dist/scaler/scaler-events.d.ts +11 -0
- package/dist/scaler/scaler-state-store.d.ts +294 -10
- package/dist/scaler/types.d.ts +131 -13
- package/dist/scaler/warm-pool.d.ts +132 -29
- package/dist/security/comment-handler.d.ts +50 -11
- package/dist/security/identity-link.d.ts +60 -0
- package/dist/security/lock-source.d.ts +11 -13
- package/dist/security/reduced-privilege-note.d.ts +59 -0
- package/dist/security/trust-directory-store.d.ts +233 -0
- package/dist/security/trust-policy-gate.d.ts +94 -59
- package/dist/security/trust-policy-store.d.ts +3 -0
- package/dist/security/trust-resolver.d.ts +14 -98
- package/dist/server.d.ts +11 -1
- package/dist/server.js +17671 -7350
- package/dist/stale-detector/gate-deadline-detector.d.ts +52 -0
- package/dist/stale-detector/stale-run-detector.d.ts +61 -3
- package/dist/standalone.js +24238 -13822
- package/dist/worker/in-memory-job-queue.d.ts +1 -1
- package/dist/ws/agent-handler.d.ts +28 -4
- package/dist/ws/dashboard-context-handler.d.ts +28 -4
- package/dist/ws/dashboard-global-workflows-handler.d.ts +6 -0
- package/dist/ws/failure-messages.d.ts +2 -0
- package/dist/ws/git-credential-relay.d.ts +39 -0
- package/dist/ws/oidc-token-relay.d.ts +6 -11
- package/dist/ws/platform-client.d.ts +54 -9
- package/installer-image-digests.json +3 -3
- package/package.json +24 -19
- package/sbom.spdx.json +864 -822
- package/dist/approvals/team-membership-lookup.d.ts +0 -13
- package/dist/providers/github/contributor-resolver.d.ts +0 -30
- package/dist/security/contributor-cache.d.ts +0 -83
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event scaler backend — workflow-driven autoscaling.
|
|
3
|
+
*
|
|
4
|
+
* Unlike the local backends (container / bare-metal / firecracker), this backend
|
|
5
|
+
* performs NO local compute. Its `spawn()` emits a `kici.scaler.scale-up` event
|
|
6
|
+
* and its `destroy()` emits a `kici.scaler.scale-down` event; a customer-authored
|
|
7
|
+
* provisioning / teardown workflow (subscribed via `kiciEvent()`) consumes those
|
|
8
|
+
* events to boot and tear down an ephemeral cloud instance. The provisioned
|
|
9
|
+
* instance's agent registers back with the scaler-chosen `agentId` and the
|
|
10
|
+
* existing bound-job dispatch runs the pending job — reusing the whole scaling
|
|
11
|
+
* engine (demand detection, caps, reservations, spawn timeout, teardown).
|
|
12
|
+
*/
|
|
13
|
+
import type { EffectiveLimits, LabelSetConfig, ManagedAgent, ScalerBackend, ScalerDestroyContext, ScalerEntry, ScalerEventCallback, SpawnContext, ValidationResult } from './types.js';
|
|
14
|
+
import type { ClaimStore } from './claim-store.js';
|
|
15
|
+
import type { ScalerScaleUpPayload, ScalerScaleDownPayload } from './scaler-events.js';
|
|
16
|
+
/**
|
|
17
|
+
* Subset of `EventEmitter` the backend needs. Injected so the backend is unit
|
|
18
|
+
* testable without a real event router.
|
|
19
|
+
*/
|
|
20
|
+
export interface ScalerEventEmitterLike {
|
|
21
|
+
emitScalerScaleUp(payload: ScalerScaleUpPayload, targets: string[]): Promise<string>;
|
|
22
|
+
emitScalerScaleDown(payload: ScalerScaleDownPayload, targets: string[]): Promise<string>;
|
|
23
|
+
}
|
|
24
|
+
export interface EventScalerBackendOptions {
|
|
25
|
+
/** The parsed scaler entry (`type: 'event'`). */
|
|
26
|
+
entry: ScalerEntry;
|
|
27
|
+
/** Emits the reserved scale-up / scale-down events. */
|
|
28
|
+
emitter: ScalerEventEmitterLike;
|
|
29
|
+
/** Mints ephemeral credentials when a claim code is redeemed — normally by
|
|
30
|
+
* the provisioned agent self-bootstrapping, or by a provisioning workflow. */
|
|
31
|
+
claimStore: ClaimStore;
|
|
32
|
+
/** Correlation-id generator for scale-up / scale-down requests. */
|
|
33
|
+
requestId: () => string;
|
|
34
|
+
}
|
|
35
|
+
export declare class EventScalerBackend implements ScalerBackend {
|
|
36
|
+
readonly type: "event";
|
|
37
|
+
readonly spawnsOnLocalHost = false;
|
|
38
|
+
readonly logsSource = "event";
|
|
39
|
+
labelSets: LabelSetConfig[];
|
|
40
|
+
maxAgents: number;
|
|
41
|
+
/** Exposed so the composition root can wire `onClaimCredentials` to it. */
|
|
42
|
+
readonly claimStore: ClaimStore;
|
|
43
|
+
private entry;
|
|
44
|
+
private readonly emitter;
|
|
45
|
+
private readonly requestId;
|
|
46
|
+
private readonly agents;
|
|
47
|
+
constructor(opts: EventScalerBackendOptions);
|
|
48
|
+
/** The entry this backend is serving; the reload rollback restores it. */
|
|
49
|
+
get currentEntry(): ScalerEntry;
|
|
50
|
+
getActiveCount(): number;
|
|
51
|
+
/**
|
|
52
|
+
* Register a pending claim, emit a scale-up event to the provisioning targets,
|
|
53
|
+
* and track the agent as provisioning. Performs no local compute.
|
|
54
|
+
*/
|
|
55
|
+
spawn(labelSet: string[], agentId: string, orchestratorUrl: string, _onEvent?: ScalerEventCallback, effectiveLimits?: EffectiveLimits, spawnContext?: SpawnContext, signal?: AbortSignal): Promise<ManagedAgent>;
|
|
56
|
+
/**
|
|
57
|
+
* Drop the tracked agent, emit a scale-down event (carrying the teardown
|
|
58
|
+
* reason), then invalidate the pending claim. Idempotent: a repeat destroy of
|
|
59
|
+
* an already-torn-down agent is a no-op (no duplicate scale-down).
|
|
60
|
+
*
|
|
61
|
+
* The tracking entry is dropped before the first `await` so a concurrent
|
|
62
|
+
* destroy of the same agent returns at the guard above and cannot emit a
|
|
63
|
+
* second scale-down.
|
|
64
|
+
*
|
|
65
|
+
* The claim invalidation is last and fails open. It is a DB delete, and the
|
|
66
|
+
* scale-down is the only thing that tears down the customer's cloud instance:
|
|
67
|
+
* running the delete first lets a DB error suppress the teardown for good,
|
|
68
|
+
* because the agent is already out of `this.agents` and a retried destroy
|
|
69
|
+
* returns at the guard. A claim left behind instead is inert — the row is
|
|
70
|
+
* single-use and TTL-bounded, so it can mint at most one token for an agent
|
|
71
|
+
* id that is being torn down.
|
|
72
|
+
*/
|
|
73
|
+
destroy(managedId: string, context?: ScalerDestroyContext): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Drop the tracked agent without emitting anything.
|
|
76
|
+
*
|
|
77
|
+
* The counterpart to `adopt()` on the other side of a cross-instance
|
|
78
|
+
* registration: the spawning coordinator is never told that a peer adopted
|
|
79
|
+
* its provision, so its entry would otherwise live until the process exits —
|
|
80
|
+
* inflating `getActiveCount()` against the global cap forever, and handing
|
|
81
|
+
* `shutdownAll()` a peer's live agent to tear down. Forgetting says "this
|
|
82
|
+
* coordinator no longer tracks the provision", which is exactly true and says
|
|
83
|
+
* nothing about whether the customer's instance is still running; the adopter
|
|
84
|
+
* emits the teardown, and the leader-gated reaper is the backstop.
|
|
85
|
+
*/
|
|
86
|
+
forget(agentId: string): void;
|
|
87
|
+
/**
|
|
88
|
+
* Take over bookkeeping for an agent another instance spawned. Seeds the same
|
|
89
|
+
* entry `spawn()` would have, so `destroy()` emits its teardown instead of
|
|
90
|
+
* no-opping on an unknown id.
|
|
91
|
+
*/
|
|
92
|
+
adopt(agentId: string, labelSet: string[]): void;
|
|
93
|
+
/** Mark a provisioned agent active once its instance registers over WS. */
|
|
94
|
+
markActive(agentId: string): void;
|
|
95
|
+
/** Delegate a credential claim to the backend's claim store. */
|
|
96
|
+
claim(code: string): Promise<import("./claim-store.js").ClaimedCredentials>;
|
|
97
|
+
/**
|
|
98
|
+
* Emits nothing. An event provision is a customer cloud instance whose
|
|
99
|
+
* lifetime spans the cluster, not this process: the coordinator holding the
|
|
100
|
+
* agent emits its teardown from the WS-close path, and the leader-gated
|
|
101
|
+
* reaper is the backstop for one that reaches nobody. This map also carries
|
|
102
|
+
* provisions a peer has already adopted — the spawning coordinator is never
|
|
103
|
+
* told — so emitting here would make a routine restart tear down a peer's
|
|
104
|
+
* running agents.
|
|
105
|
+
*
|
|
106
|
+
* The map is deliberately left intact rather than cleared: a WS close landing
|
|
107
|
+
* during the remaining shutdown steps then still emits its own teardown.
|
|
108
|
+
*/
|
|
109
|
+
shutdownAll(): Promise<void>;
|
|
110
|
+
/**
|
|
111
|
+
* Apply the new config. The backend reads `roles`, `mandatoryLabels`,
|
|
112
|
+
* `agentTokenTtlSeconds` and `provisioningTargets` off its entry at every
|
|
113
|
+
* spawn, so the entry is replaced here — otherwise a reload that retargets
|
|
114
|
+
* the provisioning workflow, or changes the scaler's roles, would keep
|
|
115
|
+
* emitting scale-up events to the old workflow refs and minting agent labels
|
|
116
|
+
* from the old roles, while the manager's own routing gate used the new ones.
|
|
117
|
+
*/
|
|
118
|
+
reload(labelSets: LabelSetConfig[], opts?: {
|
|
119
|
+
maxAgents?: number;
|
|
120
|
+
entry?: ScalerEntry;
|
|
121
|
+
}): ValidationResult;
|
|
122
|
+
private provisioningTargets;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=event-backend.d.ts.map
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { ScaleDownReason } from './scaler-events.js';
|
|
2
|
+
import type { ReapCandidate } from './scaler-state-store.js';
|
|
3
|
+
/**
|
|
4
|
+
* How long a provision outcome is kept once its spawn row is gone.
|
|
5
|
+
*
|
|
6
|
+
* Deliberately a constant rather than a `cluster_settings` knob: unlike the
|
|
7
|
+
* claim retention beside it, there is no operational decision here. The only
|
|
8
|
+
* reader is the stale-spawn prune, and the interval the row must survive is
|
|
9
|
+
* derived from windows the reaper already resolves — so a knob would be surface
|
|
10
|
+
* with nothing behind it. The purge floors this against twice the spawn
|
|
11
|
+
* deadline, so raising `KICI_SCALER_SPAWN_TIMEOUT_MS` for a slow cloud widens
|
|
12
|
+
* the retention with it.
|
|
13
|
+
*/
|
|
14
|
+
export declare const PROVISION_OUTCOME_RETENTION_MS = 86400000;
|
|
15
|
+
/**
|
|
16
|
+
* The live values one sweep runs against. Read together at the top of each tick
|
|
17
|
+
* so a sweep is internally consistent even if an operator changes a knob
|
|
18
|
+
* halfway through.
|
|
19
|
+
*/
|
|
20
|
+
export interface ReaperWindows {
|
|
21
|
+
/** How often the leader sweeps. A change reschedules the timer after this tick. */
|
|
22
|
+
intervalMs: number;
|
|
23
|
+
/** How long an unadopted provision may stay unregistered before teardown. */
|
|
24
|
+
spawnTimeoutMs: number;
|
|
25
|
+
/** How long an adopted provision may stay unseen before teardown. */
|
|
26
|
+
strandedTimeoutMs: number;
|
|
27
|
+
/**
|
|
28
|
+
* How long a peer disconnection, or an agent's absence, must persist before
|
|
29
|
+
* it counts as real rather than as a reconnect in progress. Shared with the
|
|
30
|
+
* rerouted-job guard (`reroute_flap_grace_ms`) because it answers the same
|
|
31
|
+
* question for the same reason.
|
|
32
|
+
*/
|
|
33
|
+
flapGraceMs: number;
|
|
34
|
+
/** How long before a candidate whose teardown did not clear it is retried. */
|
|
35
|
+
reattemptIntervalMs: number;
|
|
36
|
+
/** How long an expired provisioning claim is kept before it is purged. */
|
|
37
|
+
claimRetentionMs: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The flap grace the reaper actually runs on.
|
|
41
|
+
*
|
|
42
|
+
* `reroute_flap_grace_ms` is shared with the rerouted-job guard, and the two
|
|
43
|
+
* consumers do not carry the same risk: the reroute guard force-fails a run it
|
|
44
|
+
* could have waited for, while this one deletes a customer's running instance.
|
|
45
|
+
* An operator lowering the knob for reroute reasons must not silently collapse
|
|
46
|
+
* that protection to two consecutive sweeps.
|
|
47
|
+
*
|
|
48
|
+
* The floor is two peer-stale-timeout windows — the very derivation the knob's
|
|
49
|
+
* own default (`DEFAULT_REROUTE_FLAP_GRACE_MS`) comes from, applied as a floor
|
|
50
|
+
* rather than a default. It has to cover the worst honest gap between an agent
|
|
51
|
+
* being alive and being visible here: an agent reconnect backing off to its cap
|
|
52
|
+
* (60s), plus the peer heartbeat interval (30s) during which a freshly
|
|
53
|
+
* reconnected peer advertises no agents at all. Two stale windows (120s at the
|
|
54
|
+
* defaults) covers that 90s; one (60s) would not.
|
|
55
|
+
*
|
|
56
|
+
* A raised knob is honoured as-is: the floor only ever raises.
|
|
57
|
+
*/
|
|
58
|
+
export declare function reaperFlapGraceMs(flapGraceMs: number, peerStaleTimeoutMs: number): number;
|
|
59
|
+
/** The slice of the peer registry the cluster-view guard reads. */
|
|
60
|
+
export interface ReaperPeerView {
|
|
61
|
+
/** Every coordinator peer this instance knows, connected or not. */
|
|
62
|
+
getCoordinatorPeers(): readonly unknown[];
|
|
63
|
+
/** How many of those are connected right now. */
|
|
64
|
+
getConnectedCoordinatorPeerCount(): number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The reaper's `canReap` predicate, over static config plus the live peer
|
|
68
|
+
* registry.
|
|
69
|
+
*
|
|
70
|
+
* Extracted and exported so the wiring itself is testable. The bug this closes
|
|
71
|
+
* lived in exactly this expression — `clusterViewSufficient` was unit-tested
|
|
72
|
+
* throughout, while the call site that fed it the wrong count was not, so the
|
|
73
|
+
* guard read permissive on a Platform-mode HA pair through two review rounds.
|
|
74
|
+
* A component whose false positive deletes a customer's running instances
|
|
75
|
+
* cannot have an untested load-bearing line.
|
|
76
|
+
*
|
|
77
|
+
* The peer count is the max of the two sources because neither alone covers
|
|
78
|
+
* both modes: `KICI_CLUSTER_PEERS` is set only in independent mode, while a
|
|
79
|
+
* Platform-mode cluster learns its peers from the matchmaker and leaves that
|
|
80
|
+
* array empty. `getCoordinatorPeers()` filters on role, not on connectivity, so
|
|
81
|
+
* a peer lost to a partition stays counted and the guard stays armed.
|
|
82
|
+
*/
|
|
83
|
+
export declare function canReapForCluster(configuredPeerCount: number, peers: ReaperPeerView): boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Whether an adopting coordinator should still be treated as live.
|
|
86
|
+
*
|
|
87
|
+
* Mirrors `shouldDeferReroutedJob`, and for the same reason: `PeerRegistry`
|
|
88
|
+
* flips `connected` the instant a peer WS closes, with no grace of its own, so
|
|
89
|
+
* sampling it alone cannot tell a link blip between two healthy processes from
|
|
90
|
+
* a dead coordinator — while the agent is still attached to that peer running a
|
|
91
|
+
* customer job. A peer we have never heard of is genuinely gone.
|
|
92
|
+
*/
|
|
93
|
+
export declare function adopterIsLive(peer: {
|
|
94
|
+
connected: boolean;
|
|
95
|
+
lastHeartbeatAt: number;
|
|
96
|
+
} | undefined, nowMs: number, flapGraceMs: number): boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Whether this coordinator sees enough of its cluster to tear down provisions
|
|
99
|
+
* on the cluster's behalf.
|
|
100
|
+
*
|
|
101
|
+
* Raft self-elects a coordinator that has zero connected coordinator peers, so
|
|
102
|
+
* both halves of a partitioned pair become leader on their own side. Each then
|
|
103
|
+
* reads every agent the other side holds as registered nowhere, and roughly one
|
|
104
|
+
* flap grace later both emit teardowns for the other's live instances —
|
|
105
|
+
* symmetric destruction of a running fleet. Standing down costs a delayed
|
|
106
|
+
* backstop; not standing down costs the customer their fleet.
|
|
107
|
+
*
|
|
108
|
+
* `knownCoordinatorPeerCount` must count peers this coordinator has *ever*
|
|
109
|
+
* handshaken with, not the ones named in static config. `KICI_CLUSTER_PEERS` is
|
|
110
|
+
* set only in multi-orchestrator independent mode: the documented HA-pair recipe
|
|
111
|
+
* runs Platform mode and joins by token, so peers arrive through the Platform
|
|
112
|
+
* matchmaker and the static array stays empty. Keying on it left the guard inert
|
|
113
|
+
* on precisely the topology it exists to protect. A known peer survives a
|
|
114
|
+
* partition because `evictStalePeers` only marks it disconnected, so the guard
|
|
115
|
+
* stays armed for as long as the partition lasts.
|
|
116
|
+
*
|
|
117
|
+
* A coordinator that has never met a peer is a single-coordinator deployment,
|
|
118
|
+
* not a partitioned one, so it is never blocked.
|
|
119
|
+
*/
|
|
120
|
+
export declare function clusterViewSufficient(knownCoordinatorPeerCount: number, connectedCoordinatorPeerCount: number): boolean;
|
|
121
|
+
export interface EventProvisionReaperOptions {
|
|
122
|
+
/** Event rows that are either adopted, or past the spawn deadline unadopted. */
|
|
123
|
+
listCandidates: (spawnCutoff: Date) => Promise<ReapCandidate[]>;
|
|
124
|
+
/**
|
|
125
|
+
* Whether an instance id is still a live cluster member (self counts as live).
|
|
126
|
+
* `flapGraceMs` is passed in so the implementation can treat a peer that
|
|
127
|
+
* disconnected moments ago as live — `peer.connected` alone flips on WS close
|
|
128
|
+
* with no grace at all.
|
|
129
|
+
*/
|
|
130
|
+
isPeerLive: (instanceId: string, flapGraceMs: number) => boolean;
|
|
131
|
+
/** Whether an agent id is registered anywhere in the cluster we can see. */
|
|
132
|
+
isAgentRegistered: (agentId: string) => boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Whether this coordinator can see enough of the cluster to act on its
|
|
135
|
+
* behalf. False on a node that *knows* coordinator peers but is connected to
|
|
136
|
+
* none of them, which is exactly the shape a network partition produces.
|
|
137
|
+
*
|
|
138
|
+
* "Knows" spans both modes: peers named in static config, plus peers this
|
|
139
|
+
* instance has handshaken with. Keying on static config alone is what left
|
|
140
|
+
* this guard inert on a Platform-mode HA pair, which configures none.
|
|
141
|
+
*/
|
|
142
|
+
canReap: () => boolean;
|
|
143
|
+
/** Emit the teardown and drop the row. */
|
|
144
|
+
emitScaleDown: (candidate: ReapCandidate, reason: ScaleDownReason) => Promise<void>;
|
|
145
|
+
/** Delete pending claims that expired before the cutoff; returns rows deleted. */
|
|
146
|
+
purgeExpiredClaims: (cutoff: Date) => Promise<number>;
|
|
147
|
+
/**
|
|
148
|
+
* Delete provision outcomes older than the cutoff whose spawn row is gone;
|
|
149
|
+
* returns rows deleted. Runs on the same leader-gated sweep as the claim
|
|
150
|
+
* purge, which is the orchestrator's one precedent for a timer-driven purge
|
|
151
|
+
* of scaler bookkeeping.
|
|
152
|
+
*/
|
|
153
|
+
purgeProvisionOutcomes: (cutoff: Date) => Promise<number>;
|
|
154
|
+
/**
|
|
155
|
+
* Read the live windows for one sweep. Backed by `cluster_settings`, so an
|
|
156
|
+
* operator retunes the reaper on a running cluster; each read falls back to
|
|
157
|
+
* the orchestrator's configured default when the column is NULL.
|
|
158
|
+
*/
|
|
159
|
+
resolveWindows: () => Promise<ReaperWindows>;
|
|
160
|
+
/**
|
|
161
|
+
* Interval used for the very first schedule, before any knob has been read.
|
|
162
|
+
* `onBecomeLeader` is synchronous (it is a Raft callback), so the timer starts
|
|
163
|
+
* at the configured default and the first tick reconciles it to the live value.
|
|
164
|
+
*/
|
|
165
|
+
bootIntervalMs: number;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Leader-gated teardown backstop for event-scaler provisions.
|
|
169
|
+
*
|
|
170
|
+
* An event scaler emits a scale-up and then has no further local handle on the
|
|
171
|
+
* instance a customer workflow booted. `spawn()` returns as soon as the event
|
|
172
|
+
* is emitted, so the spawn-call deadline says nothing about whether the VM ever
|
|
173
|
+
* appeared, and nothing else tears the provision down: an agent that never
|
|
174
|
+
* registers — a cloud API 500, a cancelled run, a denied quota — leaves a
|
|
175
|
+
* permanent row holding a `maxAgents` slot and no `kici.scaler.scale-down` is
|
|
176
|
+
* ever emitted. Two more shapes strand a provision on a cluster: the spawning
|
|
177
|
+
* coordinator dies before the agent registers, and the adopting coordinator
|
|
178
|
+
* dies mid-job.
|
|
179
|
+
*
|
|
180
|
+
* The same pass purges pending provisioning claims past their expiry. A claim
|
|
181
|
+
* row outlives its agent whenever a registration unwinds after the claim was
|
|
182
|
+
* written, or whenever the coordinator that would have invalidated it crashed
|
|
183
|
+
* first, and nothing else deletes one on a timer.
|
|
184
|
+
*
|
|
185
|
+
* Every teardown deletes a customer's cloud instance, so the whole design is
|
|
186
|
+
* biased towards leaving a doubtful row alone:
|
|
187
|
+
*
|
|
188
|
+
* - **Nothing is ever condemned on one sample.** "The agent is registered
|
|
189
|
+
* nowhere" is an observation that flips false for a live agent on routine
|
|
190
|
+
* events — a local WS reconnect, or the ~30s after any peer reconnect during
|
|
191
|
+
* which that peer's advertised agent list is empty. So the reaper times how
|
|
192
|
+
* long the observation has *persisted* (leader-local, never a database
|
|
193
|
+
* column a re-adopt could refresh) and requires it to hold for at least the
|
|
194
|
+
* flap grace before any arm can fire.
|
|
195
|
+
* - **A peer disconnection gets the same grace.** `peer.connected` flips on WS
|
|
196
|
+
* close with no grace of its own, so the adopter-liveness question is asked
|
|
197
|
+
* the way `shouldDeferReroutedJob` asks it: connected, or last heard from
|
|
198
|
+
* inside the flap window.
|
|
199
|
+
* - **A node that cannot see its cluster does not act for it.** A coordinator
|
|
200
|
+
* isolated by a partition self-elects after ~60s with zero connected peers;
|
|
201
|
+
* without a guard its first sweep would read every adopter as dead and
|
|
202
|
+
* condemn every adopted provision in the cluster, including the ones the
|
|
203
|
+
* majority side is still running. The guard counts *known* peers — static
|
|
204
|
+
* config plus everyone handshaken with — never static config alone.
|
|
205
|
+
*
|
|
206
|
+
* Modelled on `PendingScaleSweeper` / `HostRosterReaper`: one timer, started and
|
|
207
|
+
* stopped by the Raft leadership callbacks, so several coordinators never each
|
|
208
|
+
* tear the same provision down. Unlike those two, every window it runs on is a
|
|
209
|
+
* live `cluster_settings` knob re-read per sweep — including the interval, which
|
|
210
|
+
* reschedules the timer at the end of the sweep that observed the change.
|
|
211
|
+
*/
|
|
212
|
+
export declare class EventProvisionReaper {
|
|
213
|
+
private readonly opts;
|
|
214
|
+
private timer;
|
|
215
|
+
private isLeader;
|
|
216
|
+
/** The interval the live timer was created with, so a change is detectable. */
|
|
217
|
+
private scheduledIntervalMs;
|
|
218
|
+
/** Whether the previous sweep was blocked, so the log fires on the edge only. */
|
|
219
|
+
private reapBlocked;
|
|
220
|
+
/**
|
|
221
|
+
* agentId → when this reaper last emitted a teardown for it. A candidate that
|
|
222
|
+
* comes back means the emit did not clear the row — most often because
|
|
223
|
+
* neither the row nor the leader's config names a provisioning target, which
|
|
224
|
+
* `ScalerManager.emitScaleDownForSpec` deliberately answers by keeping the
|
|
225
|
+
* row and logging. Without this throttle that row would be re-emitted and
|
|
226
|
+
* re-logged at error level on every single tick, forever.
|
|
227
|
+
*/
|
|
228
|
+
private readonly lastAttemptAt;
|
|
229
|
+
/**
|
|
230
|
+
* agentId → when this reaper first observed the agent registered nowhere.
|
|
231
|
+
*
|
|
232
|
+
* This is the debounce that makes "unseen" mean sustained absence rather than
|
|
233
|
+
* one unlucky sample. It is leader-local observation, deliberately not a
|
|
234
|
+
* database column: `adopted_at` is refreshed by a coordinator re-adopting its
|
|
235
|
+
* own agent, so a restart loop on the adopter would keep resetting the clock
|
|
236
|
+
* on its own stranded provision.
|
|
237
|
+
*/
|
|
238
|
+
private readonly strandedSince;
|
|
239
|
+
/**
|
|
240
|
+
* How many entries of `strandedSince` the last sweep found absent for at
|
|
241
|
+
* least the flap grace.
|
|
242
|
+
*
|
|
243
|
+
* The gauge publishes this rather than `strandedSince.size`, because the two
|
|
244
|
+
* answer different questions. `size` counts every agent currently observed
|
|
245
|
+
* absent, and an agent transits that set on every ordinary reconnect — a 30s
|
|
246
|
+
* peer heartbeat against a 60s sweep, and `PeerRegistry` emptying a peer's
|
|
247
|
+
* agent list on any disconnect, mean one flap enrols every peer-adopted agent
|
|
248
|
+
* at once. So `size` is routinely non-zero on a healthy cluster, while
|
|
249
|
+
* `verdict()` refuses to act on anything below the flap grace. Publishing the
|
|
250
|
+
* past-grace count makes the gauge measure the same thing the reaper does.
|
|
251
|
+
*/
|
|
252
|
+
private unseenPastGrace;
|
|
253
|
+
/**
|
|
254
|
+
* agentIds already reported as having an unknown owner, so the warning fires
|
|
255
|
+
* once per row rather than once per sweep. Pruned with the other per-agent
|
|
256
|
+
* maps when the row leaves the candidate set.
|
|
257
|
+
*/
|
|
258
|
+
private readonly unknownOwnerLogged;
|
|
259
|
+
constructor(opts: EventProvisionReaperOptions);
|
|
260
|
+
onBecomeLeader(): void;
|
|
261
|
+
onLoseLeadership(): void;
|
|
262
|
+
stop(): void;
|
|
263
|
+
/**
|
|
264
|
+
* The interval the timer currently runs at, or null when no timer is armed.
|
|
265
|
+
* Public so a caller can observe that a live knob change actually took.
|
|
266
|
+
*/
|
|
267
|
+
currentIntervalMs(): number | null;
|
|
268
|
+
/** One sweep pass. Public for tests. Never throws (logs and keeps ticking). */
|
|
269
|
+
tick(): Promise<void>;
|
|
270
|
+
/** Tear down every candidate the verdict condemns. */
|
|
271
|
+
private reapProvisions;
|
|
272
|
+
/** The candidate half of one sweep, once the blocked check has passed. */
|
|
273
|
+
private sweepCandidates;
|
|
274
|
+
/** How many absence clocks have run for at least the flap grace. */
|
|
275
|
+
private countUnseenPastGrace;
|
|
276
|
+
/** Emit a teardown for every candidate the verdict condemns. */
|
|
277
|
+
private condemnCandidates;
|
|
278
|
+
/**
|
|
279
|
+
* Publish what this sweep observed.
|
|
280
|
+
*
|
|
281
|
+
* The unseen count is the only outward sign of the one failure this design
|
|
282
|
+
* cannot fix on its own: the absence clock is leader-local, so a cluster with
|
|
283
|
+
* enough leader churn — or a peer link flapping faster than the stranded
|
|
284
|
+
* window — restarts it before it can ever expire, and a genuinely stranded
|
|
285
|
+
* provision bills forever with no log line to show for it.
|
|
286
|
+
*/
|
|
287
|
+
private publishGauges;
|
|
288
|
+
/** Delete pending claims past their expiry plus the retention grace. */
|
|
289
|
+
private purgeClaims;
|
|
290
|
+
/**
|
|
291
|
+
* Delete provision outcomes nothing can ask about any more.
|
|
292
|
+
*
|
|
293
|
+
* The retention is floored against twice the spawn deadline because that
|
|
294
|
+
* deadline also floors the stale-spawn prune window: recovery rehydrates a
|
|
295
|
+
* spawning entry from the spawn row, and that entry asks about its provision
|
|
296
|
+
* one prune later. The store's own `NOT EXISTS` predicate is what makes the
|
|
297
|
+
* purge safe while the spawn row is still there; this floor covers the window
|
|
298
|
+
* after it goes.
|
|
299
|
+
*
|
|
300
|
+
* `spawnTimeoutMs` needs no finiteness guard the way `reconcileInterval`'s
|
|
301
|
+
* period does: `config.scalerSpawnTimeoutMs` is parsed as an integer of at
|
|
302
|
+
* least 1000, and this is the one window `resolveWindows` takes straight from
|
|
303
|
+
* config rather than from a `cluster_settings` column.
|
|
304
|
+
*/
|
|
305
|
+
private purgeOutcomes;
|
|
306
|
+
/**
|
|
307
|
+
* Adopt a changed sweep interval by rebuilding the timer.
|
|
308
|
+
*
|
|
309
|
+
* Re-read every sweep rather than only at a leadership transition: a knob an
|
|
310
|
+
* operator can set but that is silently ignored until the next election is
|
|
311
|
+
* worse than no knob at all. A value that is not a usable interval is ignored
|
|
312
|
+
* — a zero or negative `setInterval` period would spin the sweep as fast as
|
|
313
|
+
* the event loop allows.
|
|
314
|
+
*/
|
|
315
|
+
private reconcileInterval;
|
|
316
|
+
/** Replace the timer with one running at `intervalMs`. */
|
|
317
|
+
private schedule;
|
|
318
|
+
/**
|
|
319
|
+
* Drop per-agent tracking for rows that are gone, so a long-lived leader's
|
|
320
|
+
* maps cannot grow without bound.
|
|
321
|
+
*/
|
|
322
|
+
private pruneTracking;
|
|
323
|
+
/**
|
|
324
|
+
* `null` means leave it alone.
|
|
325
|
+
*
|
|
326
|
+
* A registered agent is always spared, and seeing it registered resets its
|
|
327
|
+
* stranded clock: that is the one signal saying the provision is genuinely
|
|
328
|
+
* alive, and it outranks every other test.
|
|
329
|
+
*
|
|
330
|
+
* Otherwise the agent is unseen, and every arm below needs that observation
|
|
331
|
+
* to have held for at least the flap grace — one sample proves nothing, since
|
|
332
|
+
* a live agent reads unseen during its own WS reconnect and during the window
|
|
333
|
+
* after a peer reconnect in which that peer advertises no agents yet.
|
|
334
|
+
*
|
|
335
|
+
* An adopted row means the agent reached some coordinator at least once, so
|
|
336
|
+
* its disappearance is a lost heartbeat rather than a spawn that never
|
|
337
|
+
* landed — both adopted shapes emit the same reason, and which coordinator
|
|
338
|
+
* the agent happened to reach stays invisible to the customer's teardown
|
|
339
|
+
* workflow. They differ only in how much sustained absence they need: a dead
|
|
340
|
+
* adopter is strong corroboration that the provision is orphaned (its agent's
|
|
341
|
+
* WS died with it), so the flap grace alone suffices; a live adopter is no
|
|
342
|
+
* evidence either way, so that arm waits out the full stranded window.
|
|
343
|
+
*
|
|
344
|
+
* A row with neither an owner nor an adopter predates migration 119 —
|
|
345
|
+
* `owner_instance_id IS NULL` reads as "unknown owner", never as "not mine",
|
|
346
|
+
* so it is left for a human rather than reaped during a rolling upgrade.
|
|
347
|
+
*/
|
|
348
|
+
private verdict;
|
|
349
|
+
}
|
|
350
|
+
//# sourceMappingURL=event-provision-reaper.d.ts.map
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
export interface ScalerFailureRecord {
|
|
12
12
|
/** Scaler instance name (the configured scaler `name`); the diagnose row key. */
|
|
13
13
|
backendName: string;
|
|
14
|
-
/** Backend type: 'container' | 'bare-metal' | 'firecracker' | 'unknown'. */
|
|
14
|
+
/** Backend type: 'container' | 'bare-metal' | 'firecracker' | 'event' | 'unknown'. */
|
|
15
15
|
backendType: string;
|
|
16
16
|
/** True when the failed spawn was bound to a queued job (a run was affected). */
|
|
17
17
|
bound: boolean;
|
|
@@ -20,7 +20,7 @@ import { type ToolRequirement } from '@kici-dev/shared';
|
|
|
20
20
|
import type { IpAllocator, IpAllocationResult } from './ip-allocator.js';
|
|
21
21
|
import type { AgentTokenStore } from '../agent/token-store.js';
|
|
22
22
|
import { type FirecrackerBridgeConfig, type BridgeHealth, type ExecOptions } from '../firecracker/host-network.js';
|
|
23
|
-
import type { ScalerBackend, ScalerEntry, ManagedAgent, LabelSetConfig, ScalerEventCallback, ValidationResult, EffectiveLimits, SpawnContext } from './types.js';
|
|
23
|
+
import type { ScalerBackend, ScalerDestroyContext, ScalerEntry, ManagedAgent, LabelSetConfig, ScalerEventCallback, ValidationResult, EffectiveLimits, SpawnContext } from './types.js';
|
|
24
24
|
/**
|
|
25
25
|
* Infrastructure interfaces that share the `kici-` prefix but must NEVER be
|
|
26
26
|
* deleted by the orphan sweep. Bridges (kici-br0/kici-br1) carry all VM
|
|
@@ -104,7 +104,7 @@ export interface FirecrackerScalerBackendOptions {
|
|
|
104
104
|
export declare class FirecrackerScalerBackend implements ScalerBackend {
|
|
105
105
|
readonly type: "firecracker";
|
|
106
106
|
readonly spawnsOnLocalHost = true;
|
|
107
|
-
|
|
107
|
+
maxAgents: number;
|
|
108
108
|
readonly logsSource = "firecracker-serial";
|
|
109
109
|
/** AbortControllers for file tailing per managed VM (keyed by agent ID) */
|
|
110
110
|
private readonly tailAbortControllers;
|
|
@@ -145,7 +145,7 @@ export declare class FirecrackerScalerBackend implements ScalerBackend {
|
|
|
145
145
|
static getRequiredTools(entry: ScalerEntry): ToolRequirement[];
|
|
146
146
|
get labelSets(): LabelSetConfig[];
|
|
147
147
|
getActiveCount(): number;
|
|
148
|
-
spawn(labelSet: string[], agentId: string, orchestratorUrl: string, onEvent?: ScalerEventCallback, effectiveLimits?: EffectiveLimits,
|
|
148
|
+
spawn(labelSet: string[], agentId: string, orchestratorUrl: string, onEvent?: ScalerEventCallback, effectiveLimits?: EffectiveLimits, spawnContext?: SpawnContext, _signal?: AbortSignal): Promise<ManagedAgent>;
|
|
149
149
|
getScalerContext(agentId: string): Record<string, unknown> | undefined;
|
|
150
150
|
/**
|
|
151
151
|
* Bridge config for host-network diagnostics (read-only snapshot).
|
|
@@ -165,19 +165,46 @@ export declare class FirecrackerScalerBackend implements ScalerBackend {
|
|
|
165
165
|
* ScalerManager.ensureHostsReady catches per-backend and degrades this scaler.
|
|
166
166
|
*/
|
|
167
167
|
ensureHostReady(): Promise<void>;
|
|
168
|
-
destroy(managedId: string): Promise<void>;
|
|
168
|
+
destroy(managedId: string, _context?: ScalerDestroyContext): Promise<void>;
|
|
169
|
+
/**
|
|
170
|
+
* Force-reclaim a VM this backend no longer tracks in memory.
|
|
171
|
+
*
|
|
172
|
+
* `destroy()` opens with `if (!managed) return`, so after an orchestrator
|
|
173
|
+
* restart it silently no-ops while the VM keeps running, holding its RAM and
|
|
174
|
+
* its IP. `cleanupOrphans()` cannot recover that VM either: every one of its
|
|
175
|
+
* three passes skips an id whose jailer process is alive, deliberately, since
|
|
176
|
+
* a live process is the only thing that distinguishes a healthy VM from a
|
|
177
|
+
* leaked one when you are sweeping blind.
|
|
178
|
+
*
|
|
179
|
+
* This is the same reclaim addressed to ONE id whose orphan status the caller
|
|
180
|
+
* already established, so the liveness check is exactly what must not apply.
|
|
181
|
+
* See `ScalerBackend.reapUnowned` for the two properties the caller relies on;
|
|
182
|
+
* the host-local half is enforced here by refusing to act unless the jailer
|
|
183
|
+
* chroot for `managedId` exists on THIS host. That directory is the only
|
|
184
|
+
* host-local artifact a VM leaves: an `ip_allocations` row is not one, because
|
|
185
|
+
* an HA pair is "two identical orchestrators sharing the same PostgreSQL,
|
|
186
|
+
* scalers, and routing key" (`docs/operator/orchestrator/clustering.md`), so a
|
|
187
|
+
* peer's live VM has a row naming this very scaler. The row is read only to
|
|
188
|
+
* finish a reclaim the chroot already authorized.
|
|
189
|
+
*/
|
|
190
|
+
reapUnowned(managedId: string): Promise<boolean>;
|
|
169
191
|
shutdownAll(): Promise<void>;
|
|
170
192
|
/**
|
|
171
193
|
* Clear MMDS data for an agent after receiving config.ack via WS.
|
|
172
194
|
* Belt-and-suspenders: even though MMDS only contains orchestrator URL,
|
|
173
195
|
* clearing it reduces the attack surface to zero post-startup.
|
|
174
196
|
*
|
|
175
|
-
*
|
|
197
|
+
* Called by `ScalerManager.onConfigAck`, which reaches it structurally
|
|
198
|
+
* (`'clearAgentMmds' in backend`) rather than through `ScalerBackend` — no
|
|
199
|
+
* other backend has an MMDS to clear.
|
|
176
200
|
*
|
|
177
201
|
* @param agentId - The agent ID whose VM MMDS should be cleared
|
|
178
202
|
*/
|
|
179
203
|
clearAgentMmds(agentId: string): Promise<void>;
|
|
180
|
-
reload(labelSets: LabelSetConfig[]
|
|
204
|
+
reload(labelSets: LabelSetConfig[], opts?: {
|
|
205
|
+
maxAgents?: number;
|
|
206
|
+
entry?: ScalerEntry;
|
|
207
|
+
}): ValidationResult;
|
|
181
208
|
/**
|
|
182
209
|
* Clean up orphaned VMs.
|
|
183
210
|
*
|
package/dist/scaler/index.d.ts
CHANGED
|
@@ -14,9 +14,19 @@ export { BareMetalScalerBackend } from './bare-metal-backend.js';
|
|
|
14
14
|
export type { BareMetalScalerBackendOptions } from './bare-metal-backend.js';
|
|
15
15
|
export { FirecrackerScalerBackend } from './firecracker-backend.js';
|
|
16
16
|
export type { FirecrackerScalerBackendOptions, FirecrackerManagedAgent, } from './firecracker-backend.js';
|
|
17
|
+
export { createScalerBackend, requiredToolsFor } from './backend-factory.js';
|
|
18
|
+
export type { BackendFactoryContext, IpAllocatorParams } from './backend-factory.js';
|
|
19
|
+
export { EventScalerBackend } from './event-backend.js';
|
|
20
|
+
export type { EventScalerBackendOptions, ScalerEventEmitterLike } from './event-backend.js';
|
|
21
|
+
export { ClaimStore, DEFAULT_CLAIM_TTL_SECONDS } from './claim-store.js';
|
|
22
|
+
export type { ClaimSpec, ClaimedCredentials, ClaimStoreOptions, CreateEphemeralToken, } from './claim-store.js';
|
|
23
|
+
export { SCALER_EVENT_NAMES, ScaleDownReason, ScalerScaleUpPayload, ScalerScaleDownPayload, KICI_EVENT_NAME_PREFIX, } from './scaler-events.js';
|
|
24
|
+
export type { ScalerDestroyContext } from './types.js';
|
|
17
25
|
export { FirecrackerApi, FirecrackerApiError } from './firecracker-api.js';
|
|
18
26
|
export { ScalerManager } from './manager.js';
|
|
19
|
-
export type { ScalerStatus } from './manager.js';
|
|
27
|
+
export type { ScalerStatus, ScalerManagerDeps } from './manager.js';
|
|
28
|
+
export { EventProvisionReaper } from './event-provision-reaper.js';
|
|
29
|
+
export type { EventProvisionReaperOptions, ReaperWindows } from './event-provision-reaper.js';
|
|
20
30
|
export { WarmPoolManager } from './warm-pool.js';
|
|
21
31
|
export type { WarmPoolCallbacks } from './warm-pool.js';
|
|
22
32
|
export { DbIpAllocator, InMemoryIpAllocator, parseCidr, ipToNumber, numberToIp, generateMac, generateTapName, } from './ip-allocator.js';
|
|
@@ -52,10 +52,10 @@ export declare function detectLabelSetOverlaps(scalers: Array<{
|
|
|
52
52
|
* ['macos'] matches ['macos', 'darwin', 'bare-metal']. This is consistent
|
|
53
53
|
* with peer routing (findPeersWithCapacity) which uses the same semantics.
|
|
54
54
|
*
|
|
55
|
-
* In addition, every label
|
|
55
|
+
* In addition, every label in the gate for the matched label set must be
|
|
56
56
|
* present in the job's `runsOn`. This is the Kubernetes-taint-style opt-in
|
|
57
|
-
* gate: a
|
|
58
|
-
*
|
|
57
|
+
* gate: a label set gated on `['gpu']` only accepts jobs that explicitly
|
|
58
|
+
* include `gpu` in `runsOn`.
|
|
59
59
|
*
|
|
60
60
|
* When multiple backends match, the one with the smallest label set wins
|
|
61
61
|
* (most specific match).
|
|
@@ -66,6 +66,7 @@ export declare function findBackendForLabels(labels: string[], scalers: Array<{
|
|
|
66
66
|
labels: string[];
|
|
67
67
|
}>;
|
|
68
68
|
mandatoryLabels?: string[];
|
|
69
|
+
labelSetMandatoryLabels?: string[][];
|
|
69
70
|
}>, excludeLabels?: string[]): {
|
|
70
71
|
scalerName: string;
|
|
71
72
|
labelSetIndex: number;
|