Skip to main content

Module kv

Module kv 

Source
Expand description

NATS KV bucket name + key helpers (spec §2.3.2).

NATS KV bucket names must be domain-safe ASCII (a-z, A-Z, 0-9, _, -), so the spec’s dotted names (script.current, script.status) are flattened to underscore form here.

Constants§

ALL_KV_BUCKETS
Every KV bucket ensure_jetstream_resources creates. The *_yaml source-of-truth buckets and the operator-managed singletons (fleet_config, group_contacts) are included — they’re part of the bootstrap contract, so a missing one is a genuine degradation. Lazily- created buckets that bootstrap does NOT guarantee (e.g. views, scheduler_dispatch) are deliberately excluded so a fresh fleet that never used them doesn’t read as degraded.
ALL_OBJECT_STORES
Every Object Store ensure_jetstream_resources creates. The status probe used to list only agent_releases, which is why the dashboard’s “Object stores” column looked suspiciously empty.
ALL_STREAMS
Canonical list of every JetStream resource crate::bootstrap::ensure_jetstream_resources creates. The health rollup (/api/health/fleet) and the status snapshot (/api/jetstream/status) both iterate these so the dashboard reports the complete resource set — previously each kept its own hand- maintained subset that drifted behind bootstrap (e.g. only 1 of the 5 object stores showed up). Keep in lockstep with bootstrap.rs: a new stream / bucket / store added there must be appended here too. The canonical_resource_lists_are_sane test below guards the easy mistakes (dots, dupes, empties); keeping the set aligned with bootstrap stays a manual discipline (bootstrap needs per-resource config, so it can’t be derived from a name list alone).
BUCKET_AGENTS_STATE
BUCKET_AGENT_CONFIG
BUCKET_AGENT_GROUPS
BUCKET_FLEET_CONFIG
Fleet-wide singleton settings that aren’t per-agent (so they don’t belong in agent_config’s layered scopes) and aren’t per-schedule (so they don’t belong in schedules). First and only key so far is KEY_FREEZE (#418 Phase 5 global change-freeze). One small bucket both the backend scheduler and every agent’s local scheduler watch.
BUCKET_GROUP_CONTACTS
group_contacts — per-group notification email addresses, keyed by group name, value JSON GroupContacts. Operator-managed via the SPA Groups page. Distinct from agent_groups (per-PC membership) and agent_config’s groups.* scopes (agent config pushed to machines): this is operator contact info, read backend-side to fan a compliance alert out to email.
BUCKET_JOBS
Job catalog (v0.15) — operator-registered Manifests, keyed by manifest.id. Schedules and ad-hoc kanade run --job-id ... look jobs up here; the wire never round-trips an inline Manifest body through a Schedule again. Editing a job in-place retroactively changes what future schedule fires deploy.
BUCKET_JOBS_YAML
Parallel “operator source-of-truth YAML” stores keyed identically to BUCKET_JOBS / BUCKET_SCHEDULES. The agent / scheduler / projector all keep reading the JSON KVs above — these buckets exist only so the SPA’s YAML editor can round-trip operator comments + script indentation + block-scalar style exactly.
BUCKET_NOTIFICATIONS_READ
notifications_read — per-user read/ack state for end-user notifications (SPEC §2.3.2 / Phase E). Key shape {pc_id}.{user_sid}.{notification_id}, value JSON {"acked_at": ..., "acked_by": "<sid>"}. The agent writes a row when it handles a KLP notifications.ack, stamping the connecting user’s OS-derived SID — so a shared PC tracks each user’s reads independently. The {pc_id}.{user_sid}. prefix lets notifications.list fetch one user’s read set with a single prefix walk. history: 1 — only the latest ack per key matters.
BUCKET_SCHEDULER_DISPATCH
KV bucket holding per-(schedule, pc) last-dispatch marks for the backend scheduler’s in-flight suppression.
BUCKET_SCHEDULES
BUCKET_SCHEDULES_YAML
BUCKET_SCRIPT_CURRENT
BUCKET_SCRIPT_STATUS
BUCKET_SERVER_SETTINGS
Backend-side, operator-editable server settings that aren’t per-agent (so they don’t belong in agent_config’s layered scopes) and aren’t a fleet-wide switch every agent watches (so they don’t belong in fleet_config). A single JSON document under KEY_SERVER_SETTINGS holding crate::wire::ServerSettings, managed via the SPA Settings page’s “server settings” tab. Deliberately generic: future server-side knobs join the same document rather than spawning a bucket each. First consumer is the cleanup task’s dead-agent prune window (ServerSettings::agent_prune_days). history: 1 — only the current state matters; nothing replays its history.
BUCKET_VIEWS
View catalog (#743) — operator-registered View resources, keyed by view.id. A view is a pure, declarative read/aggregation over stored fleet data (obs_events, …) for the Analytics page — no execute, no schedule. The backend reads these at query time and merges their widgets with the co-located aggregate: hints on jobs. Distinct from BUCKET_JOBS so a cross-cutting dashboard doesn’t need a noop job carrier.
BUCKET_VIEWS_YAML
Operator source-of-truth YAML mirror for BUCKET_VIEWS (same role as BUCKET_JOBS_YAML): keeps comments/formatting for the SPA editor.
KEY_AGENT_CONFIG_GLOBAL
Sprint 6 layered-config keys inside BUCKET_AGENT_CONFIG:
KEY_AGENT_TARGET_VERSION
Key inside BUCKET_AGENT_CONFIG carrying the broadcast target version. Agents watch this key and self-update when their running version drifts.
KEY_FREEZE
Singleton key in BUCKET_FLEET_CONFIG holding the JSON-encoded crate::manifest::Freeze. Key absent ⇒ not frozen (clearing the freeze is a KV delete), so readers treat a missing key as “fire normally” and only evaluate Freeze::is_active when the key exists.
KEY_SERVER_SETTINGS
Singleton key in BUCKET_SERVER_SETTINGS holding the JSON-encoded crate::wire::ServerSettings. Key absent ⇒ all-default settings (e.g. agent_prune_days = 0, pruning disabled), so a fresh deployment behaves exactly as it did before the bucket existed.
OBJECT_AGENT_RELEASES
Object Store bucket holding raw agent binaries (one object per version, e.g. 0.2.0 → file bytes).
OBJECT_APP_PACKAGES
Object Store holding generic application packages — anything the agent / kitting scripts pull down + install on endpoints. First consumer is the kanade-client app, but the bucket is intentionally generic: third-party installers (Webex, Teams, custom MSI bundles), upgrade scripts, configuration archives, etc. all live here.
OBJECT_COLLECTIONS
Object Store holding collected file bundles (#219). A job carrying a collect: manifest hint prints a JSON list of file paths on stdout; the agent zips them and uploads the archive here, recording the key in crate::wire::ExecResult::collect_object. The SPA Collect page lists / downloads bundles straight from this bucket. Object keys follow <pc_id>/<job_id>/<rfc3339>.zip, or <pc_id>/<job_id>/<label>__<rfc3339>.zip when a run emits multiple labeled bundles (e.g. one zip per day), so a listing groups by host then job. Per-bucket retention is 30 days (bundles are debugging/audit artifacts, not curated config like app_packages / scripts, so they auto-expire) — see kanade-shared::bootstrap.
OBJECT_RESULT_OUTPUT
Object Store holding overflow stdout / stderr blobs for the ExecResult wire kind (#227). The default NATS max_payload is 1 MB; a result whose stdout / stderr exceeds it would reject the publish and pin the agent’s outbox in a reconnect loop. The agent uploads any stdout / stderr larger than STDOUT_INLINE_THRESHOLD (256 KB, picked at 1/4 of the default max_payload so the rest of the ExecResult fields fit alongside) into this bucket and replaces the inline field with crate::wire::ExecResult::stdout_object / stderr_object pointers. Backend’s results projector derefs the pointers before INSERT so downstream consumers (SQLite, SPA Activity, inventory projector) see the full text the same way they always have.
OBJECT_SCRIPTS
Object Store holding manifest script bodies referenced by Execute::script_object (SPEC §2.4.1’s alternative to inline script: / repo-local script_file:). Per yukimemi/kanade issue #210, this is the “Plan B 4-bucket layout” sibling of app_packages — separated because scripts have a different lifecycle than installer binaries:
PREFIX_AGENT_CONFIG_GROUPS
PREFIX_AGENT_CONFIG_PCS
SCRIPT_STATUS_ACTIVE
SCRIPT_STATUS_REVOKED
STDOUT_INLINE_THRESHOLD
Inline threshold for ExecResult.stdout / .stderr. Larger payloads overflow into OBJECT_RESULT_OUTPUT. 256 KB = 1/4 of the NATS default max_payload (1 MB) so the rest of the ExecResult JSON (request_id, exec_id, etc.) easily fits below the publish-reject ceiling.
STREAM_AUDIT
STREAM_EVENTS
STREAM_EXEC
STREAM_INVENTORY
STREAM_NOTIFICATIONS
JetStream stream retaining end-user notification history (SPEC §2.3.1 / Phase E). Catches every notifications.{all|group.X|pc.Y} publish the backend fans out, so a Client App that connects after a notification was sent can still fetch it via KLP notifications.list. 90-day window — long enough for “what did I miss while on leave” without unbounded growth. Unlike EXEC, retains all messages per subject (no max_messages_per_subject): each notification is its own history entry, not a latest-only state.
STREAM_OBS_EVENTS
JetStream stream backing the per-PC observability event pipeline (Issue #246). Distinct from STREAM_EVENTS (in-flight script lifecycle) — STREAM_OBS_EVENTS carries the timeline data the SPA’s Events page consumes: sign-in/out, power on/off, sleep/ resume, agent milestones, diagnostic bundle pointers. The agent publishes on obs.<pc_id> (see crate::subject::obs) and this stream catches everything matching crate::subject::OBS_FILTER so a backend that boots after the agent doesn’t miss any already-emitted events.
STREAM_RESULTS

Functions§

agent_config_group_key
agent_config_pc_key
dispatch_mark_pc_key
Per-pc dispatch-mark key (OncePerPc).
dispatch_mark_target_key
Whole-target dispatch-mark key (OncePerTarget). One key per schedule — a per-target fire dispatches the whole target at once, so there’s nothing per-pc to record. Length-prefixed for symmetry with dispatch_mark_pc_key.
notifications_read_key
KV key in BUCKET_NOTIFICATIONS_READ for one user’s ack of one notification: {pc_id}.{user_sid}.{notification_id} (SPEC §2.3.2).
notifications_read_prefix
Prefix selecting every ack row for one (pc_id, user_sid) in BUCKET_NOTIFICATIONS_READ{pc_id}.{user_sid}.. notifications.list walks the bucket keys and keeps those carrying this prefix to compute the caller’s unread set. Pairs with notifications_read_key.
parse_agent_config_group_key
Inverse of agent_config_group_key — returns the bare group name if key carries the groups-scope prefix, else None.
parse_agent_config_pc_key
Inverse of agent_config_pc_key.