v0.5.0-rc1: slice 5 Phase A — storage observe/report + watchdog (read-only, live)

Fill the slice-3 storage_targets stub and add the fast-poll storage watchdog.
Read-only this phase; the host-root surface (mounts/SMART/grow/destructive gate)
is Phase B. Hub-owned desired manifest is slice 10, so reconcile against it is
built-but-unfed.

- internal/storage: StorageTarget wire contract, durable_id derivation per type,
  HostReader seam (procfs/sysfs, root-free), Observer (storage_targets from
  ListStorage/NodeStorage + host reads, lvmthin thin-pool fill), and the watchdog
  (third daemon goroutine; debounced out-of-band report on a known target's
  attach/disconnect transition).
- proxmox.Storage: additive parse-only config fields (durable_id sources).
- collector StorageObserver seam; Loop.SetTrigger out-of-band report; daemon runs
  the watchdog as a third goroutine; StorageConfig knobs.
- cross-repo golden kept byte-identical with felhom.eu/hub; bidirectional key-set test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-09 09:59:05 +02:00
parent 1af21a6cac
commit 27b68f043b
22 changed files with 2129 additions and 103 deletions
+28
View File
@@ -17,6 +17,7 @@ import (
"os"
"strconv"
"strings"
"time"
)
// Config is the agent configuration.
@@ -25,9 +26,36 @@ type Config struct {
Privileged PrivilegedConfig `json:"privileged"`
Authz AuthzConfig `json:"authz"`
Hub HubConfig `json:"hub"`
Storage StorageConfig `json:"storage"`
LogLevel string `json:"log_level"` // debug|info|warn|error (default info)
}
// StorageConfig tunes the storage watchdog (slice 5). All optional — zero values fall back
// to the storage package defaults via the accessor methods. The watchdog poll is FAST
// (seconds) to catch a USB drop quickly; the debounce keeps a flapping drive from storming
// the hub; the known-set refresh bounds how often the watchdog re-derives the target set
// from the Proxmox API (liveness is probed every poll regardless).
type StorageConfig struct {
WatchdogIntervalSeconds int `json:"watchdog_interval_seconds"`
WatchdogDebounceSeconds int `json:"watchdog_debounce_seconds"`
KnownRefreshSeconds int `json:"known_refresh_seconds"`
}
// WatchdogInterval returns the configured poll interval (0 = package default).
func (s StorageConfig) WatchdogInterval() time.Duration {
return time.Duration(s.WatchdogIntervalSeconds) * time.Second
}
// WatchdogDebounce returns the configured debounce window (0 = package default).
func (s StorageConfig) WatchdogDebounce() time.Duration {
return time.Duration(s.WatchdogDebounceSeconds) * time.Second
}
// KnownRefresh returns the configured known-set refresh TTL (0 = package default).
func (s StorageConfig) KnownRefresh() time.Duration {
return time.Duration(s.KnownRefreshSeconds) * time.Second
}
// HubConfig configures the outbound hub client + daemon poll loop (internal/hub).
// The hub serves a real cert (hub.felhom.eu, cert-manager) — this is standard TLS
// (system roots), NOT the Proxmox fingerprint-pinning path.