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.
80 lines
2.4 KiB
Go
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
|
|
} |