feat(checks): per-entity monitoring override; service:haos opts out
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
ci / web (push) Has been cancelled
Desktop App / Build Linux (amd64) (push) Has been cancelled
Desktop App / Attach to Release (push) Has been cancelled

A `monitoring` attribute on an entity now overrides its type's declaration:
"none" opts out, a list overrides the kinds. service:haos uses it to opt out —
haos blocks SSH (no process probe can reach it) and the VM is already covered
by vm:haos's vm-status check, so the redundant process check only ever reported
false-down. vm:haos -> service:haos via provides confirms the coverage.
This commit is contained in:
2026-07-29 23:47:43 +02:00
parent eb16796bf0
commit c9a00a9532
2 changed files with 35 additions and 1 deletions

View File

@@ -110,6 +110,18 @@ func Ensure(ctx context.Context, tx pgx.Tx, tree *ontology.TypeTree, t Target) (
attrs = map[string]any{}
}
// Per-entity override: an explicit `monitoring` attribute wins over the
// type declaration. A single entity can opt out (monitoring: none) or pick
// different kinds without introducing a new type — e.g. service:haos opts
// out because its VM is already covered by a vm-status check and the
// service can't be SSH-probed (haos blocks SSH).
if mo, ok := attrs["monitoring"]; ok {
mon = resolveMonitoringAttr(mo, mon)
if mon.None() {
return res, nil
}
}
// A service has no address of its own — it lives on the container that
// provides it. Fall back to the graph before giving up.
host := resolveHost(attrs)
@@ -148,6 +160,27 @@ func Ensure(ctx context.Context, tx pgx.Tx, tree *ontology.TypeTree, t Target) (
return res, nil
}
// resolveMonitoringAttr turns an entity's `monitoring` attribute into a
// MonitoringResolution that overrides the type's declaration. Accepts the
// scalar "none" (or empty) to opt out, or a list of kind strings to override.
func resolveMonitoringAttr(v any, fallback ontology.MonitoringResolution) ontology.MonitoringResolution {
switch vv := v.(type) {
case string:
if vv == "none" || vv == "" {
return ontology.MonitoringResolution{Declared: true, Source: "attribute"}
}
case []any:
kinds := make([]string, 0, len(vv))
for _, k := range vv {
if s, ok := k.(string); ok && s != "" {
kinds = append(kinds, s)
}
}
return ontology.MonitoringResolution{Declared: true, Kinds: kinds, Source: "attribute"}
}
return fallback
}
// buildKind turns one declared semantic kind into concrete check_defs, or
// returns the reason it could not.
func buildKind(kind string, t Target, attrs map[string]any, host, user string, port int) ([]checkDef, string) {

View File

@@ -265,7 +265,8 @@ entities:
attributes: {url: "https://zimaos.hubris.network",
doc_page: knowledge/wiki/vms/100-zimaos.md}}
- {slug: "service:haos", type: service, name: haos,
attributes: {doc_page: knowledge/wiki/vms/108-haos.md}}
attributes: {doc_page: knowledge/wiki/vms/108-haos.md,
monitoring: none}} # redundant: vm:haos covers liveness via vm-status; haos blocks SSH so a process check can't reach it
- {slug: "service:teddycloud", type: service, name: teddycloud,
attributes: {url: "https://teddy.hubris.network",
doc_page: knowledge/wiki/containers/131-teddycloud.md,