Files
josh f58ab9fab3
build-and-push / test (push) Successful in 35s
build-and-push / build-and-push (push) Successful in 1m20s
Add automated PXE installation via ISO GRUB modification and auto-answer endpoint
Modifies uploaded ISO's GRUB config in-place to set timeout=0 and inject
proxmox-start-auto-installer + answer-url kernel params, enabling fully
hands-off installation. Adds /api/boot/auto-answer endpoint that identifies
hosts by ARP-resolving the requester's IP to MAC address.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-14 14:28:10 -04:00

84 lines
2.3 KiB
Go

package httpserver
import (
"io/fs"
"net/http"
"provisioning/internal/api"
"provisioning/internal/events"
"provisioning/internal/web"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
type Deps struct {
HostAPI *api.HostAPI
BootAPI *api.BootAPI
ImageAPI *api.ImageAPI
UI *api.UI
Hub *events.Hub
ImageDir string
}
func NewRouter(d Deps) http.Handler {
r := chi.NewRouter()
r.Use(middleware.RealIP)
r.Use(middleware.Recoverer)
r.Use(middleware.Logger)
// Static files
staticFS, _ := fs.Sub(web.Static, "static")
r.Handle("/static/*", http.StripPrefix("/static/", http.FileServer(http.FS(staticFS))))
// Boot image files (kernel/initrd served from disk)
r.Handle("/images/boot/*", http.StripPrefix("/images/boot/",
http.FileServer(http.Dir(d.ImageDir))))
// SSE
r.Get("/events", d.Hub.ServeSSE)
// Dashboard UI
r.Get("/", d.UI.Dashboard)
r.Get("/hosts/new", d.UI.NewHostForm)
r.Post("/hosts", d.UI.CreateHost)
r.Get("/hosts/{id}", d.UI.HostDetail)
r.Post("/hosts/{id}/rebuild", d.UI.TriggerRebuild)
r.Post("/hosts/{id}/delete", d.UI.DeleteHost)
r.Get("/ops/{id}", d.UI.OperationDetail)
r.Post("/ops/{id}/cancel", d.UI.CancelOperation)
r.Get("/images", d.UI.ImagesPage)
r.Get("/images/new", d.UI.NewImageForm)
r.Post("/images/upload", d.UI.UploadImage)
r.Post("/images/{id}/default", d.UI.SetDefaultImage)
r.Post("/images/{id}/delete", d.UI.DeleteImage)
// Host JSON API
r.Route("/api/hosts", func(r chi.Router) {
r.Get("/", d.HostAPI.List)
r.Post("/", d.HostAPI.Create)
r.Get("/{id}", d.HostAPI.Get)
r.Delete("/{id}", d.HostAPI.Delete)
r.Post("/{id}/rebuild", d.HostAPI.Rebuild)
})
// Image JSON API
r.Route("/api/images", func(r chi.Router) {
r.Get("/", d.ImageAPI.List)
r.Post("/", d.ImageAPI.Upload)
r.Get("/{id}", d.ImageAPI.Get)
r.Delete("/{id}", d.ImageAPI.Delete)
r.Post("/{id}/default", d.ImageAPI.SetDefault)
})
// Boot / PXE endpoints
r.Get("/ipxe/{mac}", d.BootAPI.IPXEScript)
r.Get("/api/boot/auto-answer", d.BootAPI.AutoAnswer)
r.Post("/api/boot/answer", d.BootAPI.AnswerFile)
r.Post("/api/hosts/{id}/installed", d.BootAPI.InstallComplete)
r.Get("/api/hosts/{id}/first-boot-script", d.BootAPI.FirstBootScript)
r.Post("/api/hosts/{id}/phone-home", d.BootAPI.PhoneHome)
return r
}