Post-repair hardware validation pipeline for Proxmox cluster hosts. Go orchestrator + in-image agent + mkosi live image + bundled dnsmasq PXE + SQLite + HTMX/SSE UI + notify registry + janitor + full docs.
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
// Package httpserver assembles the chi router. It lives in its own
|
||||
// package because it depends on both `api` and `orchestrator`, and
|
||||
// those two packages must stay import-independent.
|
||||
package httpserver
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
|
||||
"vetting/internal/api"
|
||||
"vetting/internal/auth"
|
||||
"vetting/internal/web"
|
||||
)
|
||||
|
||||
type Deps struct {
|
||||
Auth *auth.Manager
|
||||
UI *api.UI
|
||||
Agent *api.Agent
|
||||
LiveDir string // directory containing vmlinuz + initrd.img; "" disables /live
|
||||
}
|
||||
|
||||
func NewRouter(d Deps) http.Handler {
|
||||
r := chi.NewRouter()
|
||||
r.Use(middleware.RealIP)
|
||||
r.Use(middleware.Recoverer)
|
||||
r.Use(middleware.Logger)
|
||||
|
||||
staticFS, err := fs.Sub(web.Static, "static")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
r.Handle("/static/*", http.StripPrefix("/static/", http.FileServer(http.FS(staticFS))))
|
||||
|
||||
if d.LiveDir != "" {
|
||||
r.Handle("/live/*", http.StripPrefix("/live/", http.FileServer(http.Dir(d.LiveDir))))
|
||||
}
|
||||
|
||||
// Public (no session required) endpoints.
|
||||
r.Get("/login", d.UI.LoginForm)
|
||||
r.Post("/login", d.UI.LoginSubmit)
|
||||
r.Post("/logout", d.UI.Logout)
|
||||
|
||||
// Agent / PXE endpoints — authenticated per-request by bearer token
|
||||
// or by the unforgeable MAC path parameter, never by the UI session.
|
||||
r.Get("/ipxe/{mac}", d.Agent.IPXEScript)
|
||||
r.Route("/api/v1/runs/{id}", func(r chi.Router) {
|
||||
r.Post("/hello", d.Agent.Hello)
|
||||
r.Post("/claim", d.Agent.Claim)
|
||||
r.Post("/heartbeat", d.Agent.Heartbeat)
|
||||
r.Post("/log", d.Agent.Log)
|
||||
r.Post("/result", d.Agent.Result)
|
||||
r.Post("/hold", d.Agent.Hold)
|
||||
r.Post("/sensor", d.Agent.Sensor)
|
||||
})
|
||||
|
||||
// Session-gated browser UI.
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(d.Auth.RequireSession)
|
||||
|
||||
r.Get("/", d.UI.Dashboard)
|
||||
r.Get("/hosts/new", d.UI.NewHostForm)
|
||||
r.Post("/hosts", d.UI.CreateHost)
|
||||
r.Post("/hosts/{id}/delete", d.UI.DeleteHost)
|
||||
r.Post("/hosts/{id}/start", d.UI.StartRun)
|
||||
r.Post("/hosts/{id}/override-wipe", d.UI.OverrideWipeStorage)
|
||||
r.Get("/reports/{runID}", d.UI.Report)
|
||||
|
||||
r.Get("/events", d.UI.SSE)
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
Reference in New Issue
Block a user