← Changelog
v0.16.0July 28, 2026

Domain plugins, starting with Carina CSI

This release introduces domain plugins — a way for zapkube to teach itself about ecosystem-specific CRDs — and ships the first pack: Carina CSI local-storage awareness, wired all the way into the schedulability simulator.

🔌 Domain plugins

  • New plugin core: a data-shaped plugin contract with declarative feeds (watched resources), composite join keys, and per-feed targets
  • Feeds are activated per surface, not globally — a plugin only watches what the visible views actually need
  • Plugins can contribute list columns, detail sections, and scheduling predicates without touching core resource modules

💾 Carina CSI (first plugin)

  • NodeStorageResource and LogicVolume resource modules, pinned to the confirmed v1 schema
  • Local Storage column on the Nodes list — total and available device capacity, styled like the CPU/Mem cells
  • Local Storage section on the Node overview, with per-device capacity breakdown
  • Pinned Volumes on the Node overview: which local volumes are anchored to this node, for drain safety
  • PVC cross-link — a local PVC now surfaces the node its volume actually lives on

🧮 Schedulability simulator

  • Carina storage predicate: the simulator now accounts for local-volume capacity when deciding whether a pod fits a node
  • "Where could this move?" — a relocation entry point that asks the simulator where an existing pod could be rescheduled
  • StatefulSet volumeClaimTemplates are read into the simulated subject
  • Three-state claim toggle — keep / re-provision / ignore — for reasoning about existing volumes
  • Plugin predicates get their own column and a third "unknown" state instead of being forced into pass/fail

🐛 Fixes

  • Node conditions default to healthy-when-False, read Not… names in both directions, and the Conditions column is coloured by its worst tone
  • Conditions are ordered by severity, kubelet first; healthy kubelet conditions rank above purely informational ones
  • Carina syncTime is a last-change stamp, not a heartbeat — staleness warnings derived from it were wrong and have been removed
  • Pods: long image references stay inside the container card

🧹 Misc / Chore

  • Condition tone vocabulary extracted (4-state tone + binaryTone) and shared across nodes and columns
  • Plugin columns are rebuilt on set changes instead of on every watch event; each Carina storage report is parsed once, keyed on object identity
  • One activation hook shared by all three plugin consumers, one cluster-scoped key helper, dead code dropped