Accountant: Inventar, where, Checkmk, Abrechnung

This commit is contained in:
br committed 2026-10-18 17:08:58 +02:00
1 parent 9f16148cde
commit dd93277750
59 files changed
+7522 -113

No files matched your search

+53 -1
View File
@@ -24,6 +24,7 @@ import (
"sultan/pkg/crypto"
"sultan/pkg/docker"
"sultan/pkg/license"
"sultan/pkg/registry"
"sultan/pkg/server"
"sultan/pkg/store"
"sultan/pkg/stream"
@@ -179,11 +180,18 @@ func newFakeDocker(t *testing.T, containers ...docker.Container) *fakeDocker {
key := fmt.Sprintf("%d/%s", p.PrivatePort, p.Type)
bindings[key] = append(bindings[key], map[string]string{"HostIp": p.IP, "HostPort": fmt.Sprint(p.PublicPort)})
}
json.NewEncoder(w).Encode(map[string]any{"Id": c.ID, "HostConfig": map[string]any{"PortBindings": bindings}})
state := map[string]any{"Status": c.State, "StartedAt": c.StartedAt}
if c.Health != "" {
state["Health"] = map[string]string{"Status": c.Health}
}
json.NewEncoder(w).Encode(map[string]any{"Id": c.ID, "State": state, "HostConfig": map[string]any{"PortBindings": bindings}})
return
}
http.Error(w, `{"message":"No such container"}`, http.StatusNotFound)
})
mux.HandleFunc("/info", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`{"Name":"webdocker11","OperatingSystem":"Debian GNU/Linux 13 (trixie)","ServerVersion":"29.8.2"}`))
})
mux.HandleFunc("/events", func(w http.ResponseWriter, r *http.Request) {
ch := make(chan docker.Event, 8)
f.mu.Lock()
@@ -872,3 +880,47 @@ func TestServerCandidates(t *testing.T) {
t.Errorf("ohne Override: %v", got)
}
}
// Zusatzdaten für Inventar und Störfall kommen automatisch beim Server an:
// Compose-Projekt/-Verzeichnis, Startzeit, Health je Container; FQDN,
// Betriebssystem (des Hosts) und Docker-Version je Knoten. Ein Wechsel des
// Health-Status wird nachgemeldet.
func TestRun_ReportsMetadata(t *testing.T) {
s := startServer(t, "", "")
started := time.Date(2026, 10, 16, 8, 15, 30, 0, time.UTC)
wp := wordpress()
wp.Labels["com.docker.compose.project"] = "kunde-a"
wp.Labels["com.docker.compose.service"] = "wordpress"
wp.Labels["com.docker.compose.project.working_dir"] = "/srv/kunde-a"
wp.StartedAt = started
wp.Health = "healthy"
dock := newFakeDocker(t, wp)
cfg := testConfig(t, filepath.Join(t.TempDir(), "suldata"), s, s.invite(t, "kunde"), dock.socket)
cfg.FQDN = "webdocker11.lan.r25dc.de"
runAgent(t, cfg)
var st registry.NodeState
eventually(t, "Zustand mit Zusatzdaten", func() bool {
var ok bool
st, ok = s.NodeState("node-1")
return ok && len(st.Workloads) == 1 && st.Host != nil
})
wantMeta := &registry.WorkloadMeta{
ComposeProject: "kunde-a", ComposeService: "wordpress", ComposeDir: "/srv/kunde-a",
State: "running", StartedAt: started, Health: "healthy",
}
if !reflect.DeepEqual(st.Workloads[0].Meta, wantMeta) {
t.Errorf("Meta = %+v, erwartet %+v", st.Workloads[0].Meta, wantMeta)
}
if h := st.Host; h.FQDN != "webdocker11.lan.r25dc.de" || h.OS != "Debian GNU/Linux 13 (trixie)" || h.DockerVersion != "29.8.2" {
t.Errorf("Host = %+v", h)
}
sick := wp
sick.Health = "unhealthy"
dock.set("health_status: unhealthy", sick)
eventually(t, "Health-Wechsel nachgemeldet", func() bool {
st, ok := s.NodeState("node-1")
return ok && len(st.Workloads) == 1 && st.Workloads[0].Meta != nil && st.Workloads[0].Meta.Health == "unhealthy"
})
}