mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-22 11:45:52 +00:00
367 lines
19 KiB
Go
367 lines
19 KiB
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/config"
|
|
)
|
|
|
|
func (r *Router) registerMonitoringResourceRoutes(
|
|
guestMetadataHandler *GuestMetadataHandler,
|
|
dockerMetadataHandler *DockerMetadataHandler,
|
|
hostMetadataHandler *HostMetadataHandler,
|
|
infraUpdateHandlers *UpdateDetectionHandlers,
|
|
) {
|
|
r.mux.HandleFunc("/api/monitoring/scheduler/health", RequireAuth(r.config, r.handleSchedulerHealth))
|
|
r.mux.HandleFunc("/api/storage/", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.handleStorage)))
|
|
r.mux.HandleFunc("/api/storage-charts", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.handleStorageCharts)))
|
|
r.mux.HandleFunc("/api/charts", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.handleCharts)))
|
|
r.mux.HandleFunc("/api/charts/workloads", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.handleWorkloadCharts)))
|
|
r.mux.HandleFunc("/api/charts/infrastructure", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.handleInfrastructureCharts)))
|
|
r.mux.HandleFunc("/api/charts/storage-summary", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.handleStorageSummaryCharts)))
|
|
r.mux.HandleFunc("/api/charts/workloads-summary", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.handleWorkloadsSummaryCharts)))
|
|
r.mux.HandleFunc("/api/metrics-store/stats", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.handleMetricsStoreStats)))
|
|
r.mux.HandleFunc("/api/metrics-store/history", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.handleMetricsHistory)))
|
|
r.mux.HandleFunc("/api/recovery/points", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.recoveryHandlers.HandleListPoints)))
|
|
r.mux.HandleFunc("/api/recovery/series", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.recoveryHandlers.HandleListSeries)))
|
|
r.mux.HandleFunc("/api/recovery/facets", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.recoveryHandlers.HandleListFacets)))
|
|
r.mux.HandleFunc("/api/recovery/rollups", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.recoveryHandlers.HandleListRollups)))
|
|
r.registerReplicationRoutes()
|
|
r.registerPVEBackupsRoutes()
|
|
r.registerPMGRoutes()
|
|
|
|
// Unified resources API
|
|
r.mux.HandleFunc("/api/resources", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.resourceHandlers.HandleListResources)))
|
|
r.mux.HandleFunc("/api/resources/storage-incidents", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.resourceHandlers.HandleStorageIncidents)))
|
|
r.mux.HandleFunc("/api/resources/storage-summary", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.resourceHandlers.HandleStorageSummary)))
|
|
r.mux.HandleFunc("/api/resources/stats", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.resourceHandlers.HandleStats)))
|
|
r.mux.HandleFunc("/api/resources/k8s/namespaces", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.resourceHandlers.HandleK8sNamespaces)))
|
|
r.mux.HandleFunc("/api/resources/{id}/facets", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.resourceHandlers.HandleGetResourceFacets)))
|
|
r.mux.HandleFunc("/api/resources/{id}/timeline", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.resourceHandlers.HandleGetResourceTimeline)))
|
|
// Per-resource operator-set state. GET is read; PUT/DELETE are
|
|
// governance-shaping writes (suppress findings, refuse remediation,
|
|
// schedule maintenance) so they require the write scope. Method-keyed
|
|
// scope wrap mirrors the guests-metadata and docker-metadata pattern
|
|
// elsewhere in this file.
|
|
r.mux.HandleFunc("/api/resources/{id}/operator-state", RequireAuth(r.config, func(w http.ResponseWriter, req *http.Request) {
|
|
switch req.Method {
|
|
case http.MethodGet:
|
|
if !ensureScope(w, req, config.ScopeMonitoringRead) {
|
|
return
|
|
}
|
|
case http.MethodPut, http.MethodDelete:
|
|
if !ensureScope(w, req, config.ScopeMonitoringWrite) {
|
|
return
|
|
}
|
|
default:
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
r.resourceHandlers.HandleResourceOperatorState(w, req)
|
|
}))
|
|
// Per-resource Maintenance Verification Reports. Listing and reading
|
|
// are monitoring-read; rerun is monitoring-write because it produces
|
|
// a new persisted record. Review (mark-reviewed) is monitoring-write
|
|
// for the same reason. Wired before the broad `/api/resources/`
|
|
// catch-all so the more specific paths route here.
|
|
if r.maintenanceVerificationHandlers != nil {
|
|
r.mux.HandleFunc("/api/resources/{id}/maintenance-verifications", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.maintenanceVerificationHandlers.HandleListForResource)))
|
|
r.mux.HandleFunc("POST /api/resources/{id}/maintenance-verifications/rerun", RequireAuth(r.config, RequireScope(config.ScopeMonitoringWrite, r.maintenanceVerificationHandlers.HandleRerun)))
|
|
r.mux.HandleFunc("/api/maintenance-verifications/{reportId}", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.maintenanceVerificationHandlers.HandleGet)))
|
|
r.mux.HandleFunc("POST /api/maintenance-verifications/{reportId}/review", RequireAuth(r.config, RequireScope(config.ScopeMonitoringWrite, r.maintenanceVerificationHandlers.HandleReview)))
|
|
}
|
|
r.mux.HandleFunc("/api/resources/", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.resourceHandlers.HandleResourceRoutes)))
|
|
// Agent-consumable bundled context — substrate for any LLM agent
|
|
// (in-process Patrol/Assistant or external) that needs the full
|
|
// situated picture of a resource in one read instead of chaining
|
|
// resource + operator-state + findings + audit calls.
|
|
r.mux.HandleFunc("/api/agent/resource-context/{id}", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.agentContextHandler.HandleResourceContext)))
|
|
// Agent-consumable fleet triage view — thin per-resource rollups
|
|
// across the org so an agent can pick a focus in one read instead
|
|
// of walking every resource id and bundling each. Companion to the
|
|
// per-resource context endpoint: this is "where do I look?", that
|
|
// is "tell me everything about this one."
|
|
r.mux.HandleFunc("/api/agent/fleet-context", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.agentContextHandler.HandleFleetContext)))
|
|
// Agent capabilities manifest — discovery document. Unauthenticated
|
|
// because it only describes the agent surface; the capabilities
|
|
// themselves keep their own auth scopes. Agents fetch this once at
|
|
// startup to learn what's available.
|
|
r.mux.HandleFunc("/api/agent/capabilities", HandleAgentCapabilitiesManifest)
|
|
// Agent SSE event stream — agents subscribe once and receive
|
|
// real-time notifications instead of polling. Auth at
|
|
// monitoring:read because the stream surfaces the same
|
|
// information already available via the read endpoints.
|
|
if r.agentEventBroadcaster != nil {
|
|
r.mux.HandleFunc("/api/agent/events", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.agentEventBroadcaster.HandleAgentEvents)))
|
|
}
|
|
r.mux.HandleFunc("POST /api/actions/plan", RequireAuth(r.config, RequireScope(config.ScopeAIExecute, r.resourceHandlers.HandlePlanAction)))
|
|
r.mux.HandleFunc("POST /api/actions/{id}/decision", RequireAuth(r.config, RequireScope(config.ScopeAIExecute, r.resourceHandlers.HandleDecideAction)))
|
|
r.mux.HandleFunc("POST /api/actions/{id}/execute", RequireAuth(r.config, RequireScope(config.ScopeAIExecute, r.resourceHandlers.HandleExecuteAction)))
|
|
// Guest metadata routes
|
|
r.mux.HandleFunc("/api/guests/metadata", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, guestMetadataHandler.HandleGetMetadata)))
|
|
r.mux.HandleFunc("/api/guests/metadata/", RequireAuth(r.config, func(w http.ResponseWriter, req *http.Request) {
|
|
switch req.Method {
|
|
case http.MethodGet:
|
|
if !ensureScope(w, req, config.ScopeMonitoringRead) {
|
|
return
|
|
}
|
|
guestMetadataHandler.HandleGetMetadata(w, req)
|
|
case http.MethodPut, http.MethodPost:
|
|
if !ensureScope(w, req, config.ScopeMonitoringWrite) {
|
|
return
|
|
}
|
|
guestMetadataHandler.HandleUpdateMetadata(w, req)
|
|
case http.MethodDelete:
|
|
if !ensureScope(w, req, config.ScopeMonitoringWrite) {
|
|
return
|
|
}
|
|
guestMetadataHandler.HandleDeleteMetadata(w, req)
|
|
default:
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
}
|
|
}))
|
|
|
|
// Docker metadata routes
|
|
r.mux.HandleFunc("/api/docker/metadata", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, dockerMetadataHandler.HandleGetMetadata)))
|
|
r.mux.HandleFunc("/api/docker/metadata/", RequireAuth(r.config, func(w http.ResponseWriter, req *http.Request) {
|
|
switch req.Method {
|
|
case http.MethodGet:
|
|
if !ensureScope(w, req, config.ScopeMonitoringRead) {
|
|
return
|
|
}
|
|
dockerMetadataHandler.HandleGetMetadata(w, req)
|
|
case http.MethodPut, http.MethodPost:
|
|
if !ensureScope(w, req, config.ScopeMonitoringWrite) {
|
|
return
|
|
}
|
|
dockerMetadataHandler.HandleUpdateMetadata(w, req)
|
|
case http.MethodDelete:
|
|
if !ensureScope(w, req, config.ScopeMonitoringWrite) {
|
|
return
|
|
}
|
|
dockerMetadataHandler.HandleDeleteMetadata(w, req)
|
|
default:
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
}
|
|
}))
|
|
|
|
// Docker runtime metadata routes (for custom display names, URLs, notes).
|
|
r.mux.HandleFunc("/api/docker/runtimes/metadata", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, dockerMetadataHandler.HandleGetRuntimeMetadata)))
|
|
r.mux.HandleFunc("/api/docker/runtimes/metadata/", RequireAuth(r.config, func(w http.ResponseWriter, req *http.Request) {
|
|
switch req.Method {
|
|
case http.MethodGet:
|
|
if !ensureScope(w, req, config.ScopeMonitoringRead) {
|
|
return
|
|
}
|
|
dockerMetadataHandler.HandleGetRuntimeMetadata(w, req)
|
|
case http.MethodPut, http.MethodPost:
|
|
if !ensureScope(w, req, config.ScopeMonitoringWrite) {
|
|
return
|
|
}
|
|
dockerMetadataHandler.HandleUpdateRuntimeMetadata(w, req)
|
|
case http.MethodDelete:
|
|
if !ensureScope(w, req, config.ScopeMonitoringWrite) {
|
|
return
|
|
}
|
|
dockerMetadataHandler.HandleDeleteRuntimeMetadata(w, req)
|
|
default:
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
}
|
|
}))
|
|
|
|
// Agent metadata routes (v6 canonical naming).
|
|
handleAgentMetadataWriteRoute := func(w http.ResponseWriter, req *http.Request) {
|
|
switch req.Method {
|
|
case http.MethodGet:
|
|
if !ensureScope(w, req, config.ScopeMonitoringRead) {
|
|
return
|
|
}
|
|
hostMetadataHandler.HandleGetMetadata(w, req)
|
|
case http.MethodPut, http.MethodPost:
|
|
if !ensureScope(w, req, config.ScopeMonitoringWrite) {
|
|
return
|
|
}
|
|
hostMetadataHandler.HandleUpdateMetadata(w, req)
|
|
case http.MethodDelete:
|
|
if !ensureScope(w, req, config.ScopeMonitoringWrite) {
|
|
return
|
|
}
|
|
hostMetadataHandler.HandleDeleteMetadata(w, req)
|
|
default:
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
}
|
|
}
|
|
r.mux.HandleFunc("/api/agents/metadata", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, hostMetadataHandler.HandleGetMetadata)))
|
|
r.mux.HandleFunc("/api/agents/metadata/", RequireAuth(r.config, handleAgentMetadataWriteRoute))
|
|
|
|
// Infrastructure update detection routes (Docker containers, packages, etc.)
|
|
r.mux.HandleFunc("/api/infra-updates", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, infraUpdateHandlers.HandleGetInfraUpdates)))
|
|
r.mux.HandleFunc("/api/infra-updates/summary", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, infraUpdateHandlers.HandleGetInfraUpdatesSummary)))
|
|
r.mux.HandleFunc("/api/infra-updates/check", RequireAuth(r.config, RequireScope(config.ScopeMonitoringWrite, infraUpdateHandlers.HandleTriggerInfraUpdateCheck)))
|
|
r.mux.HandleFunc("/api/infra-updates/agent/", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, func(w http.ResponseWriter, req *http.Request) {
|
|
// Extract agent ID from path: /api/infra-updates/agent/{agentId}
|
|
agentID := strings.TrimPrefix(req.URL.Path, "/api/infra-updates/agent/")
|
|
agentID = strings.TrimSuffix(agentID, "/")
|
|
if agentID == "" {
|
|
writeErrorResponse(w, http.StatusBadRequest, "missing_agent_id", "Agent ID is required", nil)
|
|
return
|
|
}
|
|
infraUpdateHandlers.HandleGetInfraUpdatesForAgent(w, req, agentID)
|
|
})))
|
|
r.mux.HandleFunc("/api/infra-updates/", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, func(w http.ResponseWriter, req *http.Request) {
|
|
// Extract resource ID from path: /api/infra-updates/{resourceId}
|
|
resourceID := strings.TrimPrefix(req.URL.Path, "/api/infra-updates/")
|
|
resourceID = strings.TrimSuffix(resourceID, "/")
|
|
if resourceID == "" || resourceID == "summary" || resourceID == "check" || strings.HasPrefix(resourceID, "agent/") {
|
|
// Let specific handlers deal with these
|
|
http.NotFound(w, req)
|
|
return
|
|
}
|
|
infraUpdateHandlers.HandleGetInfraUpdateForResource(w, req, resourceID)
|
|
})))
|
|
r.mux.HandleFunc("/api/discover", RequireAdmin(r.config, RequireScope(config.ScopeSettingsWrite, r.configHandlers.HandleDiscoverServers)))
|
|
// Alert routes enforce read/write scopes inside HandleAlerts per endpoint method.
|
|
r.mux.HandleFunc("/api/alerts/", RequireAuth(r.config, r.alertHandlers.HandleAlerts))
|
|
|
|
// Notification routes
|
|
r.mux.HandleFunc("/api/notifications/", RequireAdmin(r.config, r.notificationHandlers.HandleNotifications))
|
|
|
|
// Notification queue/DLQ routes
|
|
// Security tokens are handled later in the setup with RBAC
|
|
// SECURITY: DLQ endpoints require settings:read/write scope because DLQ entries may contain
|
|
// notification configs with webhook URLs, SMTP credentials, or other sensitive data
|
|
r.mux.HandleFunc("/api/notifications/dlq", RequireAdmin(r.config, RequireScope(config.ScopeSettingsRead, func(w http.ResponseWriter, req *http.Request) {
|
|
if req.Method == http.MethodGet {
|
|
r.notificationQueueHandlers.GetDLQ(w, req)
|
|
} else {
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
}
|
|
})))
|
|
r.mux.HandleFunc("/api/notifications/queue/stats", RequireAdmin(r.config, RequireScope(config.ScopeSettingsRead, func(w http.ResponseWriter, req *http.Request) {
|
|
if req.Method == http.MethodGet {
|
|
r.notificationQueueHandlers.GetQueueStats(w, req)
|
|
} else {
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
}
|
|
})))
|
|
r.mux.HandleFunc("/api/notifications/dlq/retry", RequireAdmin(r.config, RequireScope(config.ScopeSettingsWrite, func(w http.ResponseWriter, req *http.Request) {
|
|
if req.Method == http.MethodPost {
|
|
r.notificationQueueHandlers.RetryDLQItem(w, req)
|
|
} else {
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
}
|
|
})))
|
|
r.mux.HandleFunc("/api/notifications/dlq/delete", RequireAdmin(r.config, RequireScope(config.ScopeSettingsWrite, func(w http.ResponseWriter, req *http.Request) {
|
|
if req.Method == http.MethodPost || req.Method == http.MethodDelete {
|
|
r.notificationQueueHandlers.DeleteDLQItem(w, req)
|
|
} else {
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
}
|
|
})))
|
|
// AI-powered infrastructure discovery endpoints
|
|
r.mux.HandleFunc("/api/discovery", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.discoveryHandlers.HandleListDiscoveries)))
|
|
r.mux.HandleFunc("/api/discovery/status", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.discoveryHandlers.HandleGetStatus)))
|
|
r.mux.HandleFunc("/api/discovery/run", RequireAuth(r.config, RequireScope(config.ScopeSettingsWrite, func(w http.ResponseWriter, req *http.Request) {
|
|
if req.Method == http.MethodPost {
|
|
r.discoveryHandlers.HandleRunDiscovery(w, req)
|
|
} else {
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
}
|
|
})))
|
|
r.mux.HandleFunc("/api/discovery/settings", RequireAuth(r.config, RequireScope(config.ScopeSettingsWrite, r.discoveryHandlers.HandleUpdateSettings)))
|
|
r.mux.HandleFunc("/api/discovery/info/", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.discoveryHandlers.HandleGetInfo)))
|
|
r.mux.HandleFunc("/api/discovery/type/", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.discoveryHandlers.HandleListByType)))
|
|
handleDiscoveryAgentRoute := func(pathPrefix string) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, req *http.Request) {
|
|
// Route based on method and path depth:
|
|
// GET /api/discovery/agent/{agentId} → list discoveries for an agent
|
|
// GET /api/discovery/agent/{agentId}/{resourceId} → get specific discovery
|
|
// GET /api/discovery/agent/{agentId}/{resourceId}/progress → get scan progress
|
|
// POST /api/discovery/agent/{agentId}/{resourceId} → trigger discovery
|
|
// PUT /api/discovery/agent/{agentId}/{resourceId}/notes → update notes
|
|
// DELETE /api/discovery/agent/{agentId}/{resourceId} → delete discovery
|
|
path := strings.TrimPrefix(req.URL.Path, pathPrefix)
|
|
pathParts := strings.Split(strings.TrimSuffix(path, "/"), "/")
|
|
|
|
switch req.Method {
|
|
case http.MethodGet:
|
|
if !ensureScope(w, req, config.ScopeMonitoringRead) {
|
|
return
|
|
}
|
|
if len(pathParts) == 1 && pathParts[0] != "" {
|
|
// GET /api/discovery/agent/{id} → list by agent
|
|
r.discoveryHandlers.HandleListByAgent(w, req)
|
|
} else if len(pathParts) >= 2 {
|
|
if strings.HasSuffix(req.URL.Path, "/progress") {
|
|
r.discoveryHandlers.HandleGetProgress(w, req)
|
|
} else {
|
|
// GET /api/discovery/agent/{agentId}/{resourceId} → get specific discovery
|
|
r.discoveryHandlers.HandleGetDiscovery(w, req)
|
|
}
|
|
} else {
|
|
http.Error(w, "Invalid path", http.StatusBadRequest)
|
|
}
|
|
case http.MethodPost:
|
|
if !ensureScope(w, req, config.ScopeSettingsWrite) {
|
|
return
|
|
}
|
|
// POST /api/discovery/agent/{agentId}/{resourceId} → trigger discovery
|
|
r.discoveryHandlers.HandleTriggerDiscovery(w, req)
|
|
case http.MethodPut:
|
|
if !ensureScope(w, req, config.ScopeMonitoringWrite) {
|
|
return
|
|
}
|
|
if strings.HasSuffix(req.URL.Path, "/notes") {
|
|
r.discoveryHandlers.HandleUpdateNotes(w, req)
|
|
} else {
|
|
http.Error(w, "Not found", http.StatusNotFound)
|
|
}
|
|
case http.MethodDelete:
|
|
if !ensureScope(w, req, config.ScopeMonitoringWrite) {
|
|
return
|
|
}
|
|
r.discoveryHandlers.HandleDeleteDiscovery(w, req)
|
|
default:
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
}
|
|
}
|
|
}
|
|
r.mux.HandleFunc("/api/discovery/agent/", RequireAuth(r.config, handleDiscoveryAgentRoute("/api/discovery/agent/")))
|
|
r.mux.HandleFunc("/api/discovery/", RequireAuth(r.config, func(w http.ResponseWriter, req *http.Request) {
|
|
path := req.URL.Path
|
|
switch req.Method {
|
|
case http.MethodGet:
|
|
if !ensureScope(w, req, config.ScopeMonitoringRead) {
|
|
return
|
|
}
|
|
if strings.HasSuffix(path, "/progress") {
|
|
r.discoveryHandlers.HandleGetProgress(w, req)
|
|
} else {
|
|
r.discoveryHandlers.HandleGetDiscovery(w, req)
|
|
}
|
|
case http.MethodPost:
|
|
if !ensureScope(w, req, config.ScopeSettingsWrite) {
|
|
return
|
|
}
|
|
r.discoveryHandlers.HandleTriggerDiscovery(w, req)
|
|
case http.MethodPut:
|
|
if !ensureScope(w, req, config.ScopeMonitoringWrite) {
|
|
return
|
|
}
|
|
if strings.HasSuffix(path, "/notes") {
|
|
r.discoveryHandlers.HandleUpdateNotes(w, req)
|
|
} else {
|
|
http.Error(w, "Not found", http.StatusNotFound)
|
|
}
|
|
case http.MethodDelete:
|
|
if !ensureScope(w, req, config.ScopeMonitoringWrite) {
|
|
return
|
|
}
|
|
r.discoveryHandlers.HandleDeleteDiscovery(w, req)
|
|
default:
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
}
|
|
}))
|
|
}
|