feat: Add service registration API

Add the service registration abstraction — the key contract between
Central and its consumers (Wild Cloud, Wild Works). Services register
with Central to get DNS, gateway routing, TLS, and public exposure.

- internal/services/manager.go: CRUD for service registrations stored
  as YAML files, with reach model (off/internal/public), backend types
  (tcp-passthrough/http/static), and TLS modes
- internal/api/v1/handlers_services.go: HTTP endpoints
  POST/GET/PATCH/DELETE /api/v1/services
- Full test coverage for registration, update, deregister, validation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-08 23:33:30 +00:00
parent beb643f76f
commit e936102eab
4 changed files with 517 additions and 1 deletions

View File

@@ -24,6 +24,7 @@ import (
"github.com/wild-cloud/wild-central/internal/network"
"github.com/wild-cloud/wild-central/internal/nftables"
"github.com/wild-cloud/wild-central/internal/secrets"
"github.com/wild-cloud/wild-central/internal/services"
"github.com/wild-cloud/wild-central/internal/sse"
"github.com/wild-cloud/wild-central/internal/storage"
"github.com/wild-cloud/wild-central/internal/wireguard"
@@ -44,7 +45,8 @@ type API struct {
crowdsec *crowdsec.Manager
vpn *wireguard.Manager
certbot *certbot.Manager
sseManager *sse.Manager // SSE manager for real-time events
services *services.Manager // Service registration manager
sseManager *sse.Manager // SSE manager for real-time events
}
// NewAPI creates a new Central API handler with all dependencies
@@ -76,6 +78,7 @@ func NewAPI(dataDir, version string, allowedOrigins []string) (*API, error) {
crowdsec: crowdsec.NewManager(),
vpn: wireguard.NewManager(dataDir, vpnConfigPath),
certbot: certbot.NewManager(""),
services: services.NewManager(dataDir),
sseManager: sseManager,
}
@@ -205,6 +208,13 @@ func (api *API) RegisterRoutes(r *mux.Router) {
r.HandleFunc("/api/v1/crowdsec/bouncers", api.CrowdSecGetBouncers).Methods("GET")
r.HandleFunc("/api/v1/crowdsec/bouncers/{name}", api.CrowdSecDeleteBouncer).Methods("DELETE")
// Service registration
r.HandleFunc("/api/v1/services", api.ServicesListAll).Methods("GET")
r.HandleFunc("/api/v1/services", api.ServicesRegister).Methods("POST")
r.HandleFunc("/api/v1/services/{name}", api.ServicesGet).Methods("GET")
r.HandleFunc("/api/v1/services/{name}", api.ServicesUpdate).Methods("PATCH")
r.HandleFunc("/api/v1/services/{name}", api.ServicesDeregister).Methods("DELETE")
// SSE events
r.HandleFunc("/api/v1/events", api.GlobalEventStream).Methods("GET")
}