KollectInventory¶
Scope: Namespace · Reconciled: Yes · Short name: kinv
Payload location
Full export payloads live in sinks — status holds counts, conditions, and metadata refs only
(ADR-0103). Query Postgres or Git for the authoritative snapshot.
What it is for¶
A KollectInventory aggregates all collected rows from KollectTarget objects in the same
namespace and exports the marshalled JSON payload to one or more family sink backends
(KollectSnapshotSink, KollectDatabaseSink, KollectEventSink). The
in-memory store updates immediately on every watch event; sink writes coalesce per sink ref —
each backend may use a different effective exportMinInterval
(ADR-0413).
Postgres and Kafka are the primary portal integration path; Git suits small single-cluster
installs. Full payloads live in sinks; status holds counts, conditions, and export metadata only
(ADR-0103).
How it fits the pipeline¶
flowchart LR
Target[KollectTarget]
Store[(Collect store)]
Inv[KollectInventory]
Scope[KollectScope]
Snap[KollectSnapshotSink]
Db[KollectDatabaseSink]
Ev[KollectEventSink]
Target --> Store
Store --> Inv
Scope -.->|sink allow-list| Inv
Inv -->|debounced export| Snap
Inv --> Db
Inv --> Ev
| Relationship | Rule |
|---|---|
| Targets | All active targets in namespace contribute rows |
| Sinks | spec.snapshotSinkRefs, spec.databaseSinkRefs, spec.eventSinkRefs — names in same namespace |
| Scope | When present, every sink must appear in the matching family list on KollectScope |
Debouncing state machine: DATA-FLOWS.md §1.
Effective interval precedence
For each family ref: ref override → family sink spec.exportMinInterval →
spec.exportMinInterval (default 30s) → clamped to KollectScope.spec.minExportInterval
floor when scope exists. Material checksum or metadata.generation changes bypass debounce per
sink. See ADR-0413.
Interval semantics — debounce, not rate limit
exportMinInterval only throttles re-export of an identical payload. Material changes
(payload checksum or generation bump) export immediately, regardless of the interval —
distinct payloads are never delayed or rate-limited. 0s is valid and means material-change
only: instant export on change, no periodic re-export (a 30s status watchdog still requeues
without exporting). Sub-second values (e.g. 500ms) are accepted up to the 24h cap, but
requeue wake-ups floor at 1s — prefer 0s, which event sinks (Kafka/NATS) typically use.
Full semantics: DATA-FLOWS §1.
Spec fields¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
spec.snapshotSinkRefs[] |
list | No | — | Snapshot sink names (string) or { name, exportMinInterval? } |
spec.databaseSinkRefs[] |
list | No | — | Database sink refs (same shape) |
spec.eventSinkRefs[] |
list | No | — | Event sink refs (same shape); combined max 20 refs |
spec.exportMinInterval |
duration | No | 30s | Debounce for identical payloads per ref without override; material changes always export immediately; 0s = material-change only |
spec.maxExportBytes |
int64 | No | global cap | Max marshalled payload size |
spec.suspend |
bool | No | false | Pause reconciliation |
spec.httpEndpoint.enabled |
bool | No | false | Per-CR HTTP debug (operator gate also required) |
spec.httpEndpoint.port |
int32 | No | 8082 | Listen port when HTTP enabled |
Example¶
A dual-cadence inventory: export to Postgres every 30s for portals, and to a Git audit repo
hourly (config/samples/kollect_v1alpha1_kollectinventory.yaml):
apiVersion: kollect.dev/v1alpha1
kind: KollectInventory
metadata:
name: team-inventory
namespace: default
spec:
exportMinInterval: 30s # default cadence for refs without an override
databaseSinkRefs:
- postgres-inventory-demo
snapshotSinkRefs:
- name: git-inventory-demo # per-ref override: audit trail at a slower cadence
exportMinInterval: 1h
suspend: false
See config/samples/kollect_v1alpha1_kollectinventory_sharded.yaml
for a large-profile sharded variant.
Sample usage¶
# Prerequisites: profile, target, sink in default namespace
kubectl apply -f config/samples/kollect_v1alpha1_kollectprofile.yaml
kubectl apply -f config/samples/kollect_v1alpha1_kollectdatabasesink.yaml
kubectl apply -f config/samples/kollect_v1alpha1_kollecttarget.yaml
kubectl apply -f config/samples/kollect_v1alpha1_kollectinventory.yaml
kubectl get kinv -n default team-inventory -w
kubectl describe kinv team-inventory -n default
Git-backed walkthrough (swap postgres sink for git sample):
kubectl apply -k config/samples/
kubectl get kinv,ktgt,ksnap,kdb -A
Force faster export after spec change (generation bump):
kubectl patch kinv team-inventory -n default --type=merge \
-p '{"spec":{"exportMinInterval":"10s"}}'
Status conditions¶
| Type | When set | Meaning | Remediation |
|---|---|---|---|
Ready=True |
Healthy | Aggregating and exporting | None |
Synced=True |
Export OK | All sinks exported on last reconcile (or debounced with no failures) | Check status.lastExportTime |
Synced=False PartiallySynced |
Mixed cadence | Some sinks exported; others debounced on identical payload | Normal for dual-cadence fan-out — inspect status.sinkExports[] |
Synced=False |
Transient export error | reason: Progressing |
Wait for retry/backoff |
Degraded=True |
Hard block | Scope, size, or terminal export | See reasons below |
SinkReachable=True/False |
Pre/post export | Sink probe or last export outcome | Fix family sink CR |
Per-sink status (status.sinkExports[])¶
When family sink refs are configured, each entry mirrors export observation:
| Field | Meaning |
|---|---|
name |
Sink key family/name (e.g. database/warehouse) |
lastExportTime |
Last successful export to this sink |
lastChecksum |
Payload fingerprint from last export |
conditions[] |
Per-sink Synced — reason=Debounced when interval not elapsed |
Aggregate status.lastExportTime is the max of per-sink times (backward compatible). Read API
/status prefers sinkExports when present (ADR-0413).
Common Degraded reasons¶
| Reason | Cause | Fix |
|---|---|---|
ScopeSinkDenied |
Sink not in scope | Add to matching family list on KollectScope |
ScopeLookupFailed |
Cannot read scope | RBAC / API error |
SinkNotFound |
Bad sinkRefs entry |
Correct sink name |
SinkUnreachable |
ConnectionVerified=False |
Fix sink credentials / network |
PayloadTooLarge |
Exceeds maxExportBytes |
Split targets, raise cap within global limit, or trim attributes |
ExportTerminal |
Non-retryable sink error | Fix sink config; check operator logs |
Progressing |
Transient network/429 | Usually self-heals; inspect kollect_sink_errors_total |
RBAC¶
| Actor | Verbs | Resource | Notes |
|---|---|---|---|
| Team admins | create, update, patch, delete |
kollectinventories |
Configure export |
| Developers | get, list, watch |
kollectinventories |
Read status / counts |
| Operator | get, list, watch |
family sink CRs, kollectscopes |
Aggregate + export |
| Operator | get, list, watch |
secrets |
Sink credential resolution |
| Operator | update, patch |
kollectinventories/status |
Conditions and export metadata |
HTTP inventory read path (when enabled) requires caller SAR get on kollectinventories —
ADR-0404.
Common failure modes¶
| Symptom | Likely cause | Fix |
|---|---|---|
itemCount 0 |
No matching targets or suspended targets | Check ktgt status; deploy matching workloads |
| Exports every 30s identical payload | Debounce working as designed | Lower exportMinInterval only if needed |
| No export for minutes | Debounced identical checksum | Change inventory material (deploy patch) or wait interval |
| Postgres empty table | Export not implemented / sink error | kubectl logs -n kollect-system deploy/kollect-controller-manager |
RequeueAfter in logs |
Debounce wait | Normal — see DATA-FLOWS timing example |
| HTTP endpoint unreachable | Feature gate off | Enable Helm featureGates.inventoryHttp and spec.httpEndpoint.enabled |