package main import ( "embed" "flag" "io/fs" "log" "net/http" "os" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/cors" "github.com/will/k8s-agent-dashboard/internal/api" "github.com/will/k8s-agent-dashboard/internal/store" ) //go:embed all:web var webFS embed.FS func main() { port := flag.String("port", "8080", "Server port") dataDir := flag.String("data", "/data", "Data directory for state") flag.Parse() // Initialize store s, err := store.New(*dataDir) if err != nil { log.Fatalf("Failed to initialize store: %v", err) } // Create router r := chi.NewRouter() // Middleware r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Use(middleware.Compress(5)) r.Use(cors.Handler(cors.Options{ AllowedOrigins: []string{"*"}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"Accept", "Content-Type"}, ExposedHeaders: []string{"Link"}, AllowCredentials: false, MaxAge: 300, })) // API routes r.Route("/api", func(r chi.Router) { r.Get("/health", api.HealthCheck) r.Get("/status", api.GetClusterStatus(s)) r.Get("/pending", api.GetPendingActions(s)) r.Post("/pending/{id}/approve", api.ApproveAction(s)) r.Post("/pending/{id}/reject", api.RejectAction(s)) r.Get("/history", api.GetActionHistory(s)) r.Get("/workflows", api.GetWorkflows(s)) r.Post("/workflows/{name}/run", api.RunWorkflow(s)) r.Post("/workflows/{name}/complete", api.CompleteWorkflow(s)) // Webhook endpoints r.Post("/webhooks/alertmanager", api.AlertmanagerWebhook(s)) }) // Static files webContent, err := fs.Sub(webFS, "web") if err != nil { log.Fatalf("Failed to get web content: %v", err) } fileServer := http.FileServer(http.FS(webContent)) r.Handle("/*", fileServer) // Start server addr := ":" + *port if envPort := os.Getenv("PORT"); envPort != "" { addr = ":" + envPort } log.Printf("Starting server on %s", addr) log.Printf("Data directory: %s", *dataDir) if err := http.ListenAndServe(addr, r); err != nil { log.Fatalf("Server failed: %v", err) } }