Files
oikos/internal/httpapi/fleet_health.go
dtoro 75c0848a6f
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
0.29.0 — code-quality refactor (plan E1–E5): file splits, sqlc migration, SSH unification, test coverage
E1: split monolithic files — cmd/nomos (main.go → server.go + mcp.go + workers.go),
    internal/mcp/tools.go → entity_tools/ops_tools/knowledge_tools/analysis_tools,
    internal/httpapi/impl.go → domain files (entities, events, signals, ontology,
    fleet_health, client_context, client_lifecycle, entity_mutations, query_audit).
E2: migrate raw pool.Exec queries to sqlc (entities/relationships queries + generated).
E3: unify SSH — consolidate crypto/ssh dial into actuator/client.go (+client_test).
E4/E5: add tests — db/lifecycle, checkdefaults/build, ontology/preconditions, policy/risk.
2026-08-08 22:47:06 +02:00

80 lines
2.4 KiB
Go

package httpapi
import (
"context"
"time"
"github.com/dtoro/oikos/internal/db"
"github.com/dtoro/oikos/internal/httpapi/gen"
)
func (s *Server) GetFleetHealth(ctx context.Context, req gen.GetFleetHealthRequestObject) (gen.GetFleetHealthResponseObject, error) {
resp := gen.GetFleetHealth200JSONResponse{}
resp.Entities = []struct {
Health gen.HealthSummaryEntitiesHealth `json:"health"`
LastCheckAt *time.Time `json:"last_check_at"`
Slug string `json:"slug"`
Trend *gen.HealthSummaryEntitiesTrend `json:"trend"`
Type string `json:"type"`
}{}
// Exclude 'check' entities (internal probes) — only entities actually
// being monitored should count toward fleet health.
rows, err := s.pool.Query(ctx, `
SELECT e.slug, e.type, st.health, st.last_check_at
FROM entity_status st JOIN entities e ON e.id = st.entity_id
WHERE e.type <> 'check'
ORDER BY e.slug`)
if err != nil {
return nil, err
}
defer rows.Close()
stale := 0
for rows.Next() {
var slug, typ, health string
var lastCheck *time.Time
if err := rows.Scan(&slug, &typ, &health, &lastCheck); err != nil {
return nil, err
}
switch health {
case "healthy":
resp.Summary.Healthy++
case "degraded":
resp.Summary.Degraded++
case "down":
resp.Summary.Down++
case "stale":
stale++
default:
resp.Summary.Unknown++
}
resp.Entities = append(resp.Entities, struct {
Health gen.HealthSummaryEntitiesHealth `json:"health"`
LastCheckAt *time.Time `json:"last_check_at"`
Slug string `json:"slug"`
Trend *gen.HealthSummaryEntitiesTrend `json:"trend"`
Type string `json:"type"`
}{
Health: gen.HealthSummaryEntitiesHealth(health),
LastCheckAt: lastCheck,
Slug: slug,
Type: typ,
})
}
if stale > 0 {
resp.Summary.Stale = &stale
}
return resp, rows.Err()
}
func (s *Server) ExportSeeds(ctx context.Context, req gen.ExportSeedsRequestObject) (gen.ExportSeedsResponseObject, error) {
exports, err := db.ExportToYAML(ctx, s.pool)
if err != nil {
return nil, err
}
return gen.ExportSeeds200JSONResponse{
Ontology: string(exports["ontology.yaml"]),
Inventory: string(exports["inventory.yaml"]),
Policy: string(exports["policy.yaml"]),
}, nil
}