package cluster import ( "encoding/json" "errors" "net/http" "strconv" "time" "github.com/go-chi/chi/v5" "github.com/jackc/pgx/v5" "github.com/example/remote-access-platform/backend/internal/platform/authority" "github.com/example/remote-access-platform/backend/internal/platform/httpx" "github.com/example/remote-access-platform/backend/internal/platform/module" "github.com/example/remote-access-platform/backend/internal/platform/secrets" ) type Module struct { service *Service } func NewModule(deps module.Dependencies, verifiers ...*authority.Verifier) *Module { store := NewPostgresStore(deps.Infra.DB, verifiers...) if deps.Config.Secret.EncryptionKeyBase64 != "" { if encryptor, err := secrets.NewEncryptor(deps.Config.Secret.EncryptionKeyBase64, deps.Config.Secret.EncryptionKeyID); err == nil { store.WithClusterKeyEncryptor(encryptor) } } return &Module{service: NewService(store)} } func (m *Module) Name() string { return "cluster" } func (m *Module) RegisterRoutes(router chi.Router) { router.Route("/clusters", func(r chi.Router) { r.Get("/", m.listClusters) r.Post("/", m.createCluster) r.Get("/{clusterID}", m.getCluster) r.Put("/{clusterID}", m.updateCluster) r.Get("/{clusterID}/nodes", m.listClusterNodes) r.Get("/{clusterID}/node-groups", m.listNodeGroups) r.Post("/{clusterID}/node-groups", m.createNodeGroup) r.Get("/{clusterID}/join-requests", m.listJoinRequests) r.Post("/{clusterID}/join-requests", m.createJoinRequest) r.Post("/{clusterID}/join-requests/{requestID}/approve", m.approveJoinRequest) r.Post("/{clusterID}/join-requests/{requestID}/reject", m.rejectJoinRequest) r.Post("/{clusterID}/join-tokens", m.createJoinToken) r.Post("/{clusterID}/join-tokens/{tokenID}/revoke", m.revokeJoinToken) r.Get("/{clusterID}/nodes/{nodeID}/roles", m.listNodeRoles) r.Post("/{clusterID}/nodes/{nodeID}/roles", m.assignNodeRole) r.Post("/{clusterID}/nodes/{nodeID}/heartbeats", m.recordHeartbeat) r.Get("/{clusterID}/nodes/{nodeID}/heartbeats", m.listNodeHeartbeats) r.Get("/{clusterID}/nodes/{nodeID}/testing-flags", m.getEffectiveNodeTestingFlags) r.Get("/{clusterID}/nodes/{nodeID}/mesh/synthetic-config", m.getNodeSyntheticMeshConfig) r.Post("/{clusterID}/nodes/{nodeID}/telemetry", m.recordNodeTelemetry) r.Get("/{clusterID}/nodes/{nodeID}/telemetry", m.listNodeTelemetry) r.Post("/{clusterID}/nodes/{nodeID}/membership/attach", m.attachExistingNodeToCluster) r.Put("/{clusterID}/nodes/{nodeID}/group", m.assignNodeGroup) r.Post("/{clusterID}/nodes/{nodeID}/identity/revoke", m.revokeNodeIdentity) r.Post("/{clusterID}/nodes/{nodeID}/membership/disable", m.disableMembership) r.Get("/{clusterID}/nodes/{nodeID}/workloads/desired", m.listDesiredWorkloads) r.Put("/{clusterID}/nodes/{nodeID}/workloads/{serviceType}/desired", m.setDesiredWorkload) r.Post("/{clusterID}/nodes/{nodeID}/workloads/{serviceType}/status", m.reportWorkloadStatus) r.Get("/{clusterID}/nodes/{nodeID}/workloads/status", m.listWorkloadStatuses) r.Get("/{clusterID}/mesh/links", m.listMeshLinks) r.Post("/{clusterID}/mesh/links", m.reportMeshLink) r.Get("/{clusterID}/mesh/route-intents", m.listRouteIntents) r.Post("/{clusterID}/mesh/route-intents", m.createRouteIntent) r.Get("/{clusterID}/mesh/qos-policies", m.listQoSPolicies) r.Get("/{clusterID}/fabric/entry-points", m.listFabricEntryPoints) r.Post("/{clusterID}/fabric/entry-points", m.createFabricEntryPoint) r.Get("/{clusterID}/fabric/entry-points/{entryPointID}/nodes", m.listFabricEntryPointNodes) r.Put("/{clusterID}/fabric/entry-points/{entryPointID}/nodes/{nodeID}", m.setFabricEntryPointNode) r.Get("/{clusterID}/fabric/egress-pools", m.listFabricEgressPools) r.Post("/{clusterID}/fabric/egress-pools", m.createFabricEgressPool) r.Get("/{clusterID}/fabric/egress-pools/{egressPoolID}/nodes", m.listFabricEgressPoolNodes) r.Put("/{clusterID}/fabric/egress-pools/{egressPoolID}/nodes/{nodeID}", m.setFabricEgressPoolNode) r.Post("/{clusterID}/vpn-connection-leases/expire-stale", m.expireStaleVPNConnectionLeases) r.Get("/{clusterID}/vpn-connections", m.listVPNConnections) r.Post("/{clusterID}/vpn-connections", m.createVPNConnection) r.Get("/{clusterID}/vpn-connections/{vpnConnectionID}", m.getVPNConnection) r.Put("/{clusterID}/vpn-connections/{vpnConnectionID}/desired-state", m.updateVPNConnectionDesiredState) r.Get("/{clusterID}/vpn-connections/{vpnConnectionID}/allowed-nodes", m.listVPNConnectionAllowedNodes) r.Put("/{clusterID}/vpn-connections/{vpnConnectionID}/allowed-nodes", m.setVPNConnectionAllowedNodes) r.Get("/{clusterID}/vpn-connections/{vpnConnectionID}/route-policies", m.listVPNConnectionRoutePolicies) r.Post("/{clusterID}/vpn-connections/{vpnConnectionID}/route-policies", m.upsertVPNConnectionRoutePolicy) r.Get("/{clusterID}/vpn-connections/{vpnConnectionID}/leases/active", m.getActiveVPNConnectionLease) r.Post("/{clusterID}/vpn-connections/{vpnConnectionID}/leases/acquire", m.acquireVPNConnectionLease) r.Post("/{clusterID}/vpn-connections/{vpnConnectionID}/leases/{leaseID}/renew", m.renewVPNConnectionLease) r.Post("/{clusterID}/vpn-connections/{vpnConnectionID}/leases/{leaseID}/release", m.releaseVPNConnectionLease) r.Post("/{clusterID}/vpn-connections/{vpnConnectionID}/leases/{leaseID}/fence", m.fenceVPNConnectionLease) r.Get("/{clusterID}/authority", m.getClusterAuthority) r.Put("/{clusterID}/authority", m.updateClusterAuthority) r.Get("/{clusterID}/audit", m.listAuditEvents) }) router.Get("/cluster-admin-summaries", m.listClusterAdminSummaries) router.Get("/fabric/testing-flags", m.listFabricTestingFlags) router.Put("/fabric/testing-flags", m.upsertFabricTestingFlag) } func (m *Module) listClusters(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListClusters(r.Context(), r.URL.Query().Get("actor_user_id")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"clusters": items}) } func (m *Module) getCluster(w http.ResponseWriter, r *http.Request) { item, err := m.service.GetCluster(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"cluster": item}) } func (m *Module) createCluster(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` Slug string `json:"slug"` Name string `json:"name"` Region *string `json:"region"` Metadata json.RawMessage `json:"metadata"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid cluster payload") return } item, err := m.service.CreateCluster(r.Context(), CreateClusterInput{ ActorUserID: payload.ActorUserID, Slug: payload.Slug, Name: payload.Name, Region: payload.Region, Metadata: payload.Metadata, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusCreated, map[string]any{"cluster": item}) } func (m *Module) updateCluster(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` Name string `json:"name"` Status string `json:"status"` Region *string `json:"region"` Metadata json.RawMessage `json:"metadata"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid cluster payload") return } item, err := m.service.UpdateCluster(r.Context(), UpdateClusterInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), Name: payload.Name, Status: payload.Status, Region: payload.Region, Metadata: payload.Metadata, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"cluster": item}) } func (m *Module) listClusterNodes(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListClusterNodes(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"nodes": items}) } func (m *Module) listNodeGroups(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListNodeGroups(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"node_groups": items}) } func (m *Module) createNodeGroup(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` ParentGroupID *string `json:"parent_group_id"` Name string `json:"name"` Description *string `json:"description"` SortOrder int `json:"sort_order"` Metadata json.RawMessage `json:"metadata"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid node group payload") return } item, err := m.service.CreateNodeGroup(r.Context(), CreateNodeGroupInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), ParentGroupID: payload.ParentGroupID, Name: payload.Name, Description: payload.Description, SortOrder: payload.SortOrder, Metadata: payload.Metadata, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusCreated, map[string]any{"node_group": item}) } func (m *Module) createJoinToken(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` Scope json.RawMessage `json:"scope"` ExpiresAt *time.Time `json:"expires_at"` MaxUses int `json:"max_uses"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid join token payload") return } expiresAt := time.Time{} if payload.ExpiresAt != nil { expiresAt = *payload.ExpiresAt } item, err := m.service.CreateJoinToken(r.Context(), CreateJoinTokenInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), Scope: payload.Scope, ExpiresAt: expiresAt, MaxUses: payload.MaxUses, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusCreated, map[string]any{"join_token": item}) } func (m *Module) createJoinRequest(w http.ResponseWriter, r *http.Request) { var payload struct { JoinToken string `json:"join_token"` NodeName string `json:"node_name"` NodeFingerprint string `json:"node_fingerprint"` PublicKey string `json:"public_key"` ReportedCapabilities json.RawMessage `json:"reported_capabilities"` ReportedFacts json.RawMessage `json:"reported_facts"` RequestedRoles json.RawMessage `json:"requested_roles"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid join request payload") return } item, err := m.service.CreateJoinRequest(r.Context(), CreateJoinRequestInput{ ClusterID: chi.URLParam(r, "clusterID"), JoinToken: payload.JoinToken, NodeName: payload.NodeName, NodeFingerprint: payload.NodeFingerprint, PublicKey: payload.PublicKey, ReportedCapabilities: payload.ReportedCapabilities, ReportedFacts: payload.ReportedFacts, RequestedRoles: payload.RequestedRoles, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusCreated, map[string]any{"join_request": item}) } func (m *Module) listJoinRequests(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListJoinRequests(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"join_requests": items}) } func (m *Module) approveJoinRequest(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` NodeKey string `json:"node_key"` OwnershipType string `json:"ownership_type"` OwnerOrganizationID *string `json:"owner_organization_id"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid join request approval payload") return } item, err := m.service.ApproveJoinRequest(r.Context(), ApproveJoinRequestInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), JoinRequestID: chi.URLParam(r, "requestID"), NodeKey: payload.NodeKey, OwnershipType: payload.OwnershipType, OwnerOrganizationID: payload.OwnerOrganizationID, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, item) } func (m *Module) rejectJoinRequest(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` Reason string `json:"reason"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid join request rejection payload") return } item, err := m.service.RejectJoinRequest(r.Context(), RejectJoinRequestInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), JoinRequestID: chi.URLParam(r, "requestID"), Reason: payload.Reason, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"join_request": item}) } func (m *Module) revokeJoinToken(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid join token revoke payload") return } item, err := m.service.RevokeJoinToken(r.Context(), RevokeJoinTokenInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), TokenID: chi.URLParam(r, "tokenID"), }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"join_token": item}) } func (m *Module) assignNodeRole(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` OrganizationID *string `json:"organization_id"` Role string `json:"role"` Status string `json:"status"` Policy json.RawMessage `json:"policy"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid node role payload") return } item, err := m.service.AssignNodeRole(r.Context(), AssignNodeRoleInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), NodeID: chi.URLParam(r, "nodeID"), OrganizationID: payload.OrganizationID, Role: payload.Role, Status: payload.Status, Policy: payload.Policy, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusCreated, map[string]any{"role_assignment": item}) } func (m *Module) listNodeRoles(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListNodeRoleAssignments(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID"), chi.URLParam(r, "nodeID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"role_assignments": items}) } func (m *Module) recordHeartbeat(w http.ResponseWriter, r *http.Request) { var payload struct { HealthStatus string `json:"health_status"` ReportedVersion *string `json:"reported_version"` Capabilities json.RawMessage `json:"capabilities"` ServiceStates json.RawMessage `json:"service_states"` Metadata json.RawMessage `json:"metadata"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid node heartbeat payload") return } item, err := m.service.RecordHeartbeat(r.Context(), RecordHeartbeatInput{ ClusterID: chi.URLParam(r, "clusterID"), NodeID: chi.URLParam(r, "nodeID"), HealthStatus: payload.HealthStatus, ReportedVersion: payload.ReportedVersion, Capabilities: payload.Capabilities, ServiceStates: payload.ServiceStates, Metadata: payload.Metadata, }) if writeServiceError(w, err) { return } flags, _ := m.service.GetEffectiveNodeTestingFlags(r.Context(), chi.URLParam(r, "clusterID"), chi.URLParam(r, "nodeID")) httpx.WriteJSON(w, http.StatusAccepted, map[string]any{"heartbeat": item, "testing_flags": flags}) } func (m *Module) listNodeHeartbeats(w http.ResponseWriter, r *http.Request) { limit, _ := strconv.Atoi(r.URL.Query().Get("limit")) items, err := m.service.ListNodeHeartbeats(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID"), chi.URLParam(r, "nodeID"), limit) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"heartbeats": items}) } func (m *Module) getEffectiveNodeTestingFlags(w http.ResponseWriter, r *http.Request) { item, err := m.service.GetEffectiveNodeTestingFlags(r.Context(), chi.URLParam(r, "clusterID"), chi.URLParam(r, "nodeID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"testing_flags": item}) } func (m *Module) getNodeSyntheticMeshConfig(w http.ResponseWriter, r *http.Request) { item, err := m.service.GetNodeSyntheticMeshConfig(r.Context(), GetNodeSyntheticMeshConfigInput{ ClusterID: chi.URLParam(r, "clusterID"), NodeID: chi.URLParam(r, "nodeID"), }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"synthetic_mesh_config": item}) } func (m *Module) recordNodeTelemetry(w http.ResponseWriter, r *http.Request) { var payload struct { CPUPercent *float64 `json:"cpu_percent"` MemoryUsedBytes *int64 `json:"memory_used_bytes"` MemoryTotalBytes *int64 `json:"memory_total_bytes"` DiskUsedBytes *int64 `json:"disk_used_bytes"` DiskTotalBytes *int64 `json:"disk_total_bytes"` NetworkRxBytes *int64 `json:"network_rx_bytes"` NetworkTxBytes *int64 `json:"network_tx_bytes"` ProcessCount *int `json:"process_count"` Payload json.RawMessage `json:"payload"` ObservedAt *time.Time `json:"observed_at"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid node telemetry payload") return } observedAt := time.Time{} if payload.ObservedAt != nil { observedAt = *payload.ObservedAt } item, err := m.service.RecordNodeTelemetry(r.Context(), RecordNodeTelemetryInput{ ClusterID: chi.URLParam(r, "clusterID"), NodeID: chi.URLParam(r, "nodeID"), CPUPercent: payload.CPUPercent, MemoryUsedBytes: payload.MemoryUsedBytes, MemoryTotalBytes: payload.MemoryTotalBytes, DiskUsedBytes: payload.DiskUsedBytes, DiskTotalBytes: payload.DiskTotalBytes, NetworkRxBytes: payload.NetworkRxBytes, NetworkTxBytes: payload.NetworkTxBytes, ProcessCount: payload.ProcessCount, Payload: payload.Payload, ObservedAt: observedAt, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusAccepted, map[string]any{"telemetry": item}) } func (m *Module) listNodeTelemetry(w http.ResponseWriter, r *http.Request) { limit, _ := strconv.Atoi(r.URL.Query().Get("limit")) items, err := m.service.ListNodeTelemetry(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID"), chi.URLParam(r, "nodeID"), limit) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"telemetry": items}) } func (m *Module) attachExistingNodeToCluster(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` Roles []string `json:"roles"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid membership attach payload") return } item, err := m.service.AttachExistingNodeToCluster(r.Context(), AttachExistingNodeInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), NodeID: chi.URLParam(r, "nodeID"), Roles: payload.Roles, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"node": item}) } func (m *Module) assignNodeGroup(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` GroupID *string `json:"group_id"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid node group assignment payload") return } item, err := m.service.AssignNodeToGroup(r.Context(), AssignNodeGroupInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), NodeID: chi.URLParam(r, "nodeID"), GroupID: payload.GroupID, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"node": item}) } func (m *Module) revokeNodeIdentity(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` Reason string `json:"reason"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid node identity revoke payload") return } err := m.service.RevokeNodeIdentity(r.Context(), RevokeNodeIdentityInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), NodeID: chi.URLParam(r, "nodeID"), Reason: payload.Reason, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusAccepted, map[string]any{"status": "accepted"}) } func (m *Module) disableMembership(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` Reason string `json:"reason"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid membership disable payload") return } err := m.service.DisableClusterMembership(r.Context(), DisableMembershipInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), NodeID: chi.URLParam(r, "nodeID"), Reason: payload.Reason, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusAccepted, map[string]any{"status": "accepted"}) } func (m *Module) setDesiredWorkload(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` DesiredState string `json:"desired_state"` Version *string `json:"version"` RuntimeMode string `json:"runtime_mode"` ArtifactRef *string `json:"artifact_ref"` Config json.RawMessage `json:"config"` Environment json.RawMessage `json:"environment"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid desired workload payload") return } item, err := m.service.SetDesiredWorkload(r.Context(), SetDesiredWorkloadInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), NodeID: chi.URLParam(r, "nodeID"), ServiceType: chi.URLParam(r, "serviceType"), DesiredState: payload.DesiredState, Version: payload.Version, RuntimeMode: payload.RuntimeMode, ArtifactRef: payload.ArtifactRef, Config: payload.Config, Environment: payload.Environment, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"desired_workload": item}) } func (m *Module) listDesiredWorkloads(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListDesiredWorkloads(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID"), chi.URLParam(r, "nodeID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"desired_workloads": items}) } func (m *Module) reportWorkloadStatus(w http.ResponseWriter, r *http.Request) { var payload struct { ReportedState string `json:"reported_state"` RuntimeMode string `json:"runtime_mode"` Version *string `json:"version"` StatusPayload json.RawMessage `json:"status_payload"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid workload status payload") return } item, err := m.service.ReportWorkloadStatus(r.Context(), ReportWorkloadStatusInput{ ClusterID: chi.URLParam(r, "clusterID"), NodeID: chi.URLParam(r, "nodeID"), ServiceType: chi.URLParam(r, "serviceType"), ReportedState: payload.ReportedState, RuntimeMode: payload.RuntimeMode, Version: payload.Version, StatusPayload: payload.StatusPayload, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusAccepted, map[string]any{"workload_status": item}) } func (m *Module) listWorkloadStatuses(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListLatestWorkloadStatuses(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID"), chi.URLParam(r, "nodeID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"workload_statuses": items}) } func (m *Module) reportMeshLink(w http.ResponseWriter, r *http.Request) { var payload struct { SourceNodeID string `json:"source_node_id"` TargetNodeID string `json:"target_node_id"` LinkStatus string `json:"link_status"` LatencyMs *int `json:"latency_ms"` QualityScore *int `json:"quality_score"` Metadata json.RawMessage `json:"metadata"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid mesh link payload") return } item, err := m.service.ReportMeshLink(r.Context(), ReportMeshLinkInput{ ClusterID: chi.URLParam(r, "clusterID"), SourceNodeID: payload.SourceNodeID, TargetNodeID: payload.TargetNodeID, LinkStatus: payload.LinkStatus, LatencyMs: payload.LatencyMs, QualityScore: payload.QualityScore, Metadata: payload.Metadata, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusAccepted, map[string]any{"mesh_link": item}) } func (m *Module) listMeshLinks(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListMeshLinks(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"mesh_links": items}) } func (m *Module) createRouteIntent(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` SourceSelector json.RawMessage `json:"source_selector"` DestinationSelector json.RawMessage `json:"destination_selector"` ServiceClass string `json:"service_class"` Priority int `json:"priority"` Policy json.RawMessage `json:"policy"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid route intent payload") return } item, err := m.service.CreateRouteIntent(r.Context(), CreateRouteIntentInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), SourceSelector: payload.SourceSelector, DestinationSelector: payload.DestinationSelector, ServiceClass: payload.ServiceClass, Priority: payload.Priority, Policy: payload.Policy, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusCreated, map[string]any{"route_intent": item}) } func (m *Module) listRouteIntents(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListRouteIntents(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"route_intents": items}) } func (m *Module) listQoSPolicies(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListQoSPolicies(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"qos_policies": items}) } func (m *Module) listFabricEntryPoints(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListFabricEntryPoints(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"entry_points": items}) } func (m *Module) createFabricEntryPoint(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` Name string `json:"name"` Status string `json:"status"` EndpointType string `json:"endpoint_type"` PublicEndpoint *string `json:"public_endpoint"` Policy json.RawMessage `json:"policy"` Metadata json.RawMessage `json:"metadata"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid fabric entry point payload") return } item, err := m.service.CreateFabricEntryPoint(r.Context(), CreateFabricEntryPointInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), Name: payload.Name, Status: payload.Status, EndpointType: payload.EndpointType, PublicEndpoint: payload.PublicEndpoint, Policy: payload.Policy, Metadata: payload.Metadata, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusCreated, map[string]any{"entry_point": item}) } func (m *Module) setFabricEntryPointNode(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` Status string `json:"status"` Priority int `json:"priority"` Metadata json.RawMessage `json:"metadata"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid fabric entry point node payload") return } item, err := m.service.SetFabricEntryPointNode(r.Context(), SetFabricEntryPointNodeInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), EntryPointID: chi.URLParam(r, "entryPointID"), NodeID: chi.URLParam(r, "nodeID"), Status: payload.Status, Priority: payload.Priority, Metadata: payload.Metadata, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"entry_point_node": item}) } func (m *Module) listFabricEntryPointNodes(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListFabricEntryPointNodes( r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID"), chi.URLParam(r, "entryPointID"), ) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"entry_point_nodes": items}) } func (m *Module) listFabricEgressPools(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListFabricEgressPools(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"egress_pools": items}) } func (m *Module) createFabricEgressPool(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` Name string `json:"name"` Status string `json:"status"` Description *string `json:"description"` RouteScope json.RawMessage `json:"route_scope"` Policy json.RawMessage `json:"policy"` Metadata json.RawMessage `json:"metadata"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid fabric egress pool payload") return } item, err := m.service.CreateFabricEgressPool(r.Context(), CreateFabricEgressPoolInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), Name: payload.Name, Status: payload.Status, Description: payload.Description, RouteScope: payload.RouteScope, Policy: payload.Policy, Metadata: payload.Metadata, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusCreated, map[string]any{"egress_pool": item}) } func (m *Module) setFabricEgressPoolNode(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` Status string `json:"status"` Priority int `json:"priority"` Metadata json.RawMessage `json:"metadata"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid fabric egress pool node payload") return } item, err := m.service.SetFabricEgressPoolNode(r.Context(), SetFabricEgressPoolNodeInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), EgressPoolID: chi.URLParam(r, "egressPoolID"), NodeID: chi.URLParam(r, "nodeID"), Status: payload.Status, Priority: payload.Priority, Metadata: payload.Metadata, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"egress_pool_node": item}) } func (m *Module) listFabricEgressPoolNodes(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListFabricEgressPoolNodes( r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID"), chi.URLParam(r, "egressPoolID"), ) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"egress_pool_nodes": items}) } func (m *Module) createVPNConnection(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` OrganizationID string `json:"organization_id"` Name string `json:"name"` TargetEndpoint json.RawMessage `json:"target_endpoint"` ProtocolFamily string `json:"protocol_family"` CredentialRef *string `json:"credential_ref"` Mode string `json:"mode"` DesiredState string `json:"desired_state"` AllowedNodePolicy json.RawMessage `json:"allowed_node_policy"` RoutingUsage json.RawMessage `json:"routing_usage"` RoutePolicy json.RawMessage `json:"route_policy"` QoSPolicy json.RawMessage `json:"qos_policy"` PlacementPolicy json.RawMessage `json:"placement_policy"` Metadata json.RawMessage `json:"metadata"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid vpn connection payload") return } item, err := m.service.CreateVPNConnection(r.Context(), CreateVPNConnectionInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), OrganizationID: payload.OrganizationID, Name: payload.Name, TargetEndpoint: payload.TargetEndpoint, ProtocolFamily: payload.ProtocolFamily, CredentialRef: payload.CredentialRef, Mode: payload.Mode, DesiredState: payload.DesiredState, AllowedNodePolicy: payload.AllowedNodePolicy, RoutingUsage: payload.RoutingUsage, RoutePolicy: payload.RoutePolicy, QoSPolicy: payload.QoSPolicy, PlacementPolicy: payload.PlacementPolicy, Metadata: payload.Metadata, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusCreated, map[string]any{"vpn_connection": item}) } func (m *Module) listVPNConnections(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListVPNConnections(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"vpn_connections": items}) } func (m *Module) getVPNConnection(w http.ResponseWriter, r *http.Request) { item, err := m.service.GetVPNConnection(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID"), chi.URLParam(r, "vpnConnectionID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"vpn_connection": item}) } func (m *Module) updateVPNConnectionDesiredState(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` DesiredState string `json:"desired_state"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid vpn connection desired state payload") return } item, err := m.service.UpdateVPNConnectionDesiredState(r.Context(), UpdateVPNConnectionDesiredStateInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), VPNConnectionID: chi.URLParam(r, "vpnConnectionID"), DesiredState: payload.DesiredState, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"vpn_connection": item}) } func (m *Module) upsertVPNConnectionRoutePolicy(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` RouteType string `json:"route_type"` Destination string `json:"destination"` Action string `json:"action"` ServiceType *string `json:"service_type"` Priority int `json:"priority"` Policy json.RawMessage `json:"policy"` Status string `json:"status"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid vpn route policy payload") return } item, err := m.service.UpsertVPNConnectionRoutePolicy(r.Context(), UpsertVPNConnectionRoutePolicyInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), VPNConnectionID: chi.URLParam(r, "vpnConnectionID"), RouteType: payload.RouteType, Destination: payload.Destination, Action: payload.Action, ServiceType: payload.ServiceType, Priority: payload.Priority, Policy: payload.Policy, Status: payload.Status, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusCreated, map[string]any{"route_policy": item}) } func (m *Module) listVPNConnectionRoutePolicies(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListVPNConnectionRoutePolicies(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID"), chi.URLParam(r, "vpnConnectionID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"route_policies": items}) } func (m *Module) setVPNConnectionAllowedNodes(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` NodeIDs []string `json:"node_ids"` RolePreference string `json:"role_preference"` Metadata json.RawMessage `json:"metadata"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid vpn allowed nodes payload") return } items, err := m.service.SetVPNConnectionAllowedNodes(r.Context(), SetVPNConnectionAllowedNodesInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), VPNConnectionID: chi.URLParam(r, "vpnConnectionID"), NodeIDs: payload.NodeIDs, RolePreference: payload.RolePreference, Metadata: payload.Metadata, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"allowed_nodes": items}) } func (m *Module) listVPNConnectionAllowedNodes(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListVPNConnectionAllowedNodes(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID"), chi.URLParam(r, "vpnConnectionID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"allowed_nodes": items}) } func (m *Module) acquireVPNConnectionLease(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` OwnerNodeID string `json:"owner_node_id"` TTLSeconds int `json:"ttl_seconds"` Metadata json.RawMessage `json:"metadata"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid vpn lease acquire payload") return } item, err := m.service.AcquireVPNConnectionLease(r.Context(), AcquireVPNConnectionLeaseInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), VPNConnectionID: chi.URLParam(r, "vpnConnectionID"), OwnerNodeID: payload.OwnerNodeID, TTL: time.Duration(payload.TTLSeconds) * time.Second, Metadata: payload.Metadata, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusCreated, map[string]any{"lease": item}) } func (m *Module) renewVPNConnectionLease(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` OwnerNodeID string `json:"owner_node_id"` FencingToken string `json:"fencing_token"` TTLSeconds int `json:"ttl_seconds"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid vpn lease renew payload") return } item, err := m.service.RenewVPNConnectionLease(r.Context(), RenewVPNConnectionLeaseInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), VPNConnectionID: chi.URLParam(r, "vpnConnectionID"), LeaseID: chi.URLParam(r, "leaseID"), OwnerNodeID: payload.OwnerNodeID, FencingToken: payload.FencingToken, TTL: time.Duration(payload.TTLSeconds) * time.Second, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"lease": item}) } func (m *Module) releaseVPNConnectionLease(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` OwnerNodeID string `json:"owner_node_id"` FencingToken string `json:"fencing_token"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid vpn lease release payload") return } item, err := m.service.ReleaseVPNConnectionLease(r.Context(), ReleaseVPNConnectionLeaseInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), VPNConnectionID: chi.URLParam(r, "vpnConnectionID"), LeaseID: chi.URLParam(r, "leaseID"), OwnerNodeID: payload.OwnerNodeID, FencingToken: payload.FencingToken, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"lease": item}) } func (m *Module) fenceVPNConnectionLease(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` Reason string `json:"reason"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid vpn lease fence payload") return } item, err := m.service.FenceVPNConnectionLease(r.Context(), FenceVPNConnectionLeaseInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), VPNConnectionID: chi.URLParam(r, "vpnConnectionID"), LeaseID: chi.URLParam(r, "leaseID"), Reason: payload.Reason, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"lease": item}) } func (m *Module) getActiveVPNConnectionLease(w http.ResponseWriter, r *http.Request) { item, err := m.service.GetActiveVPNConnectionLease(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID"), chi.URLParam(r, "vpnConnectionID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"lease": item}) } func (m *Module) expireStaleVPNConnectionLeases(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid vpn stale lease payload") return } items, err := m.service.ExpireStaleVPNConnectionLeases(r.Context(), ExpireStaleVPNConnectionLeasesInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"expired_leases": items}) } func (m *Module) getClusterAuthority(w http.ResponseWriter, r *http.Request) { item, err := m.service.GetClusterAuthorityState(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"authority_state": item}) } func (m *Module) updateClusterAuthority(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` AuthorityState string `json:"authority_state"` MutationMode string `json:"mutation_mode"` Notes *string `json:"notes"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid cluster authority payload") return } item, err := m.service.UpdateClusterAuthorityState(r.Context(), UpdateClusterAuthorityInput{ ActorUserID: payload.ActorUserID, ClusterID: chi.URLParam(r, "clusterID"), AuthorityState: payload.AuthorityState, MutationMode: payload.MutationMode, Notes: payload.Notes, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"authority_state": item}) } func (m *Module) listClusterAdminSummaries(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListClusterAdminSummaries(r.Context(), r.URL.Query().Get("actor_user_id")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"cluster_summaries": items}) } func (m *Module) listFabricTestingFlags(w http.ResponseWriter, r *http.Request) { items, err := m.service.ListFabricTestingFlags(r.Context(), r.URL.Query().Get("actor_user_id")) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"testing_flags": items}) } func (m *Module) upsertFabricTestingFlag(w http.ResponseWriter, r *http.Request) { var payload struct { ActorUserID string `json:"actor_user_id"` ScopeType string `json:"scope_type"` ScopeID *string `json:"scope_id"` ClusterID *string `json:"cluster_id"` Enabled bool `json:"enabled"` TelemetryEnabled bool `json:"telemetry_enabled"` SyntheticLinksEnabled bool `json:"synthetic_links_enabled"` HistoryRetentionHours int `json:"history_retention_hours"` Metadata json.RawMessage `json:"metadata"` } if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { httpx.WriteError(w, http.StatusBadRequest, "invalid testing flag payload") return } item, err := m.service.UpsertFabricTestingFlag(r.Context(), UpsertFabricTestingFlagInput{ ActorUserID: payload.ActorUserID, ScopeType: payload.ScopeType, ScopeID: payload.ScopeID, ClusterID: payload.ClusterID, Enabled: payload.Enabled, TelemetryEnabled: payload.TelemetryEnabled, SyntheticLinksEnabled: payload.SyntheticLinksEnabled, HistoryRetentionHours: payload.HistoryRetentionHours, Metadata: payload.Metadata, }) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"testing_flag": item}) } func (m *Module) listAuditEvents(w http.ResponseWriter, r *http.Request) { limit, _ := strconv.Atoi(r.URL.Query().Get("limit")) items, err := m.service.ListAuditEvents(r.Context(), r.URL.Query().Get("actor_user_id"), chi.URLParam(r, "clusterID"), limit) if writeServiceError(w, err) { return } httpx.WriteJSON(w, http.StatusOK, map[string]any{"audit_events": items}) } func writeServiceError(w http.ResponseWriter, err error) bool { if err == nil { return false } switch { case errors.Is(err, ErrAccessDenied): httpx.WriteError(w, http.StatusForbidden, err.Error()) case errors.Is(err, ErrVPNLeaseOwnerNotAllowed), errors.Is(err, ErrVPNLeaseOwnerRoleRequired): httpx.WriteError(w, http.StatusForbidden, err.Error()) case errors.Is(err, ErrClusterReadOnly): httpx.WriteError(w, http.StatusConflict, err.Error()) case errors.Is(err, ErrVPNLeaseAlreadyActive): httpx.WriteError(w, http.StatusConflict, err.Error()) case errors.Is(err, ErrInvalidPayload), errors.Is(err, ErrInvalidJoinToken), errors.Is(err, ErrInvalidNodeRole): httpx.WriteError(w, http.StatusBadRequest, err.Error()) case errors.Is(err, ErrInvalidCluster), errors.Is(err, ErrInvalidJoinRequest), errors.Is(err, ErrInvalidVPNConnection), errors.Is(err, ErrInvalidVPNLease), errors.Is(err, pgx.ErrNoRows): httpx.WriteError(w, http.StatusNotFound, err.Error()) default: httpx.WriteError(w, http.StatusInternalServerError, err.Error()) } return true }