package api import ( "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "jagacloud/node-agent/pkg/compute/libvirt" "jagacloud/node-agent/pkg/config" "jagacloud/node-agent/pkg/containers/lxc" "jagacloud/node-agent/pkg/containers/podman" "jagacloud/node-agent/pkg/state" "jagacloud/node-agent/pkg/tasks" ) // Services bundles runtime services passed to handlers. type Services struct { Tasks *tasks.Registry Libvirt libvirtClient LXC lxcManager Podman podmanClient Store *state.Store Validator ResourceValidator } // StoreLock returns an unlock function for the given ID; no-op if store is nil. func (s Services) StoreLock(id string) func() { if s.Store == nil { return func() {} } return s.Store.Lock(id) } // ResourceValidator validates network/storage resources before actions. type ResourceValidator interface { ValidateVM(libvirt.VMSpec) error ValidateCT(lxc.Spec) error } // Interfaces narrowed for injection/testing. type libvirtClient interface { ListVMs() ([]libvirt.VM, error) CreateVM(libvirt.VMSpec) (libvirt.VM, error) StartVM(id string) error StopVM(id string) error RebootVM(id string) error DeleteVM(id string) error } type lxcManager interface { List() ([]lxc.Container, error) Create(lxc.Spec) (lxc.Container, error) Start(id string) error Stop(id string) error Delete(id string) error } type podmanClient interface { List(ctID string) ([]podman.OCIContainer, error) Create(ctID string, spec podman.CreateSpec) (podman.OCIContainer, error) Start(ctID, cid string) error Stop(ctID, cid string) error Delete(ctID, cid string) error } // RegisterRoutes wires HTTP routes. func RegisterRoutes(r *chi.Mux, cfg config.Config, svc Services) { r.Use(middleware.RequestID) r.Use(middleware.Logger) if cfg.AuthToken != "" { r.Use(authMiddleware(cfg.AuthToken)) } r.Get("/api/v1/node", handleNodeInfo(cfg, svc)) r.Route("/api/v1/vms", func(r chi.Router) { r.Get("/", handleListVMs(cfg, svc)) r.Post("/", handleCreateVM(cfg, svc)) r.Route("/{id}", func(r chi.Router) { r.Get("/", handleGetVM(cfg, svc)) r.Post("/start", handleStartVM(cfg, svc)) r.Post("/stop", handleStopVM(cfg, svc)) r.Post("/reboot", handleRebootVM(cfg, svc)) r.Post("/delete", handleDeleteVM(cfg, svc)) }) }) r.Route("/api/v1/containers", func(r chi.Router) { r.Get("/", handleListCT(cfg, svc)) r.Post("/", handleCreateCT(cfg, svc)) r.Route("/{id}", func(r chi.Router) { r.Get("/", handleGetCT(cfg, svc)) r.Post("/start", handleStartCT(cfg, svc)) r.Post("/stop", handleStopCT(cfg, svc)) r.Post("/delete", handleDeleteCT(cfg, svc)) r.Route("/oci", func(r chi.Router) { r.Get("/", handleListOCI(cfg, svc)) r.Post("/", handleCreateOCI(cfg, svc)) r.Route("/{cid}", func(r chi.Router) { r.Get("/", handleGetOCI(cfg, svc)) r.Post("/start", handleStartOCI(cfg, svc)) r.Post("/stop", handleStopOCI(cfg, svc)) r.Post("/delete", handleDeleteOCI(cfg, svc)) }) }) }) }) r.Route("/api/v1/tasks", func(r chi.Router) { r.Get("/{id}", handleGetTask(cfg, svc)) }) }