diff --git a/spindle/server.go b/spindle/server.go index 7bc64c80..dde9549c 100644 --- a/spindle/server.go +++ b/spindle/server.go @@ -9,6 +9,7 @@ import ( "encoding/json" "errors" "fmt" + "io" "log/slog" "maps" "net/http" @@ -702,6 +703,10 @@ func (s *Spindle) Router() http.Handler { mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write(s.GetMotdContent()) }) + mux.Get("/_health", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + _, _ = io.WriteString(w, "{\"status\":\"ok\"}\n") + }) if s.cfg.Role != config.RoleExecutor { mux.HandleFunc("/events", s.Events) mux.HandleFunc("/logs/{knot}/{rkey}/{name}", s.Logs) diff --git a/spindle/server_test.go b/spindle/server_test.go index 07c62542..f9fbd832 100644 --- a/spindle/server_test.go +++ b/spindle/server_test.go @@ -96,6 +96,18 @@ func TestExecutorRoleBuildsMinimalSpindle(t *testing.T) { if rr.Code != http.StatusOK { t.Fatalf("root status = %d, want %d", rr.Code, http.StatusOK) } + rr = httptest.NewRecorder() + req = httptest.NewRequest(http.MethodGet, "/_health", nil) + s.Router().ServeHTTP(rr, req) + if rr.Code != http.StatusOK { + t.Fatalf("health status = %d, want %d", rr.Code, http.StatusOK) + } + if got := rr.Header().Get("Content-Type"); got != "application/json" { + t.Fatalf("health content type = %q, want application/json", got) + } + if got := rr.Body.String(); got != "{\"status\":\"ok\"}\n" { + t.Fatalf("health response = %q, want JSON ok status", got) + } rr = httptest.NewRecorder() req = httptest.NewRequest(http.MethodGet, "/xrpc/_health", nil)