mirror of
https://github.com/hanzoai/o11y.git
synced 2026-11-03 02:04:48 +00:00
gorilla/mux, otelmux, gorilla/handlers and rs/cors leave go.mod. Every route the runtime serves is a zip route on a zip group: 233 from the apiserver tree, 134 from query-service, 367 total — the same 367 the mount publishes. pkg/http/routing is the one registration surface. It exists because a registration carries three facts zip has no slot for, and the tree this replaces recovered all three PER REQUEST by asking the router what it had just matched: the bound segments, the path template, and the route's declared resources. mux.CurrentRoute(req).GetHandler() was type-asserted back to handler.Handler in two separate packages to re-derive at request time what was already known once at boot. Stating them at registration deletes both lookups. The middleware chain is composed at the LEAF rather than registered ambient, because Audit keys on the route template and Resource resolves the route's declared resources — ambient middleware runs before the router has matched, so both would read an empty route. Per-leaf composition reproduces the order the old tree ran in exactly: match, then middleware, then handler. Duplicate registration now panics at boot; gorilla let the first one win. The Sentry ingest constraint becomes fiber's own guid — a UUID parse instead of a hand-written character class. Paths keep their public brace spelling in the source and in the table; the respelling happens in one function. The standalone server hands its listener to the app, so streams and the websocket upgrade run native fasthttp. Counted, not asserted: routes_test.go in the apiserver pins 233 against the real AddToRouter, routing_test.go pins the table against the router itself. This repo has already shipped 83 typed ops that reached no router while the suite stayed green — an uncalled func is legal Go, so arithmetic is the test. Co-authored-by: Hanzo Dev <[email protected]>
209 lines
22 KiB
Go
209 lines
22 KiB
Go
package o11yapiserver
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/hanzoai/o11y/pkg/http/handler"
|
|
"github.com/hanzoai/o11y/pkg/http/routing"
|
|
"github.com/hanzoai/o11y/pkg/types"
|
|
"github.com/hanzoai/o11y/pkg/types/inframonitoringtypes"
|
|
)
|
|
|
|
// ALL ELEVEN routes below — the ten infra_monitoring rollups and the setup
|
|
// checks — are ALSO declared as typed ops at the module's mount seam (infra.go
|
|
// in the repo root), which is what carries them into the composed document,
|
|
// the SDK, the CLI and the agent surface. That is a second DISPATCH, never a
|
|
// second implementation: the ops answer by handing the call to this router, so
|
|
// the handlers below stay the one place the reads are performed. Both are
|
|
// needed — the ops serve the composed binary, this router serves the
|
|
// standalone process, which has no native router to register an op on — so
|
|
// deleting either half drops one of the two deployments. The ViewAccess gate
|
|
// keeps running exactly here, on both dispatches.
|
|
func (provider *provider) addInfraMonitoringRoutes(router routing.Router) {
|
|
router.Post("/v1/o11y/infra_monitoring/hosts", handler.New(
|
|
provider.authzMiddleware.ViewAccess(provider.infraMonitoringHandler.ListHosts),
|
|
handler.OpenAPIDef{
|
|
ID: "ListHosts",
|
|
Tags: []string{"inframonitoring"},
|
|
Summary: "List Hosts for Infra Monitoring",
|
|
Description: "Returns a paginated list of hosts with key infrastructure metrics: CPU usage (%), memory usage (%), I/O wait (%), disk usage (%), and 15-minute load average. Each host includes its current status (active/inactive based on metrics reported in the last 10 minutes) and metadata attributes (e.g., os.type). Supports filtering via a filter expression, filtering by host status, custom groupBy to aggregate hosts by any attribute, ordering by any of the five metrics, and pagination via offset/limit. The response type is 'list' for the default host.name grouping or 'grouped_list' for custom groupBy keys. Also reports whether the requested time range falls before the data retention boundary. Numeric metric fields (cpu, memory, wait, load15, diskUsage) return -1 as a sentinel when no data is available for that field.",
|
|
Request: new(inframonitoringtypes.PostableHosts),
|
|
RequestContentType: "application/json",
|
|
Response: new(inframonitoringtypes.Hosts),
|
|
ResponseContentType: "application/json",
|
|
SuccessStatusCode: http.StatusOK,
|
|
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized},
|
|
Deprecated: false,
|
|
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
|
}))
|
|
|
|
router.Post("/v1/o11y/infra_monitoring/pods", handler.New(
|
|
provider.authzMiddleware.ViewAccess(provider.infraMonitoringHandler.ListPods),
|
|
handler.OpenAPIDef{
|
|
ID: "ListPods",
|
|
Tags: []string{"inframonitoring"},
|
|
Summary: "List Pods for Infra Monitoring",
|
|
Description: "Returns a paginated list of Kubernetes pods with key metrics: CPU usage, CPU request/limit utilization, memory working set, memory request/limit utilization, current pod phase (pending/running/succeeded/failed/unknown/no_data), and pod age (ms since start time). Each pod includes metadata attributes (namespace, node, workload owner such as deployment/statefulset/daemonset/job/cronjob, cluster). Supports filtering via a filter expression, custom groupBy to aggregate pods by any attribute, ordering by any of the six metrics (cpu, cpu_request, cpu_limit, memory, memory_request, memory_limit), and pagination via offset/limit. The response type is 'list' for the default k8s.pod.uid grouping (each row is one pod with its current phase) or 'grouped_list' for custom groupBy keys (each row aggregates pods in the group with per-phase counts under podCountsByPhase: { pending, running, succeeded, failed, unknown } derived from each pod's latest phase in the window). Also reports whether the requested time range falls before the data retention boundary. Numeric metric fields (podCPU, podCPURequest, podCPULimit, podMemory, podMemoryRequest, podMemoryLimit, podAge) return -1 as a sentinel when no data is available for that field.",
|
|
Request: new(inframonitoringtypes.PostablePods),
|
|
RequestContentType: "application/json",
|
|
Response: new(inframonitoringtypes.Pods),
|
|
ResponseContentType: "application/json",
|
|
SuccessStatusCode: http.StatusOK,
|
|
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized},
|
|
Deprecated: false,
|
|
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
|
}))
|
|
|
|
router.Post("/v1/o11y/infra_monitoring/nodes", handler.New(
|
|
provider.authzMiddleware.ViewAccess(provider.infraMonitoringHandler.ListNodes),
|
|
handler.OpenAPIDef{
|
|
ID: "ListNodes",
|
|
Tags: []string{"inframonitoring"},
|
|
Summary: "List Nodes for Infra Monitoring",
|
|
Description: "Returns a paginated list of Kubernetes nodes with key metrics: CPU usage, CPU allocatable, memory working set, memory allocatable, per-group nodeCountsByReadiness ({ ready, notReady } from each node's latest k8s.node.condition_ready in the window) and per-group podCountsByPhase ({ pending, running, succeeded, failed, unknown } for pods scheduled on the listed nodes). Each node includes metadata attributes (k8s.node.uid, k8s.cluster.name). The response type is 'list' for the default k8s.node.name grouping (each row is one node with its current condition string: ready / not_ready / no_data) or 'grouped_list' for custom groupBy keys (each row aggregates nodes in the group; condition stays no_data). Supports filtering via a filter expression, custom groupBy, ordering by cpu / cpu_allocatable / memory / memory_allocatable, and pagination via offset/limit. Also reports whether the requested time range falls before the data retention boundary. Numeric metric fields (nodeCPU, nodeCPUAllocatable, nodeMemory, nodeMemoryAllocatable) return -1 as a sentinel when no data is available for that field.",
|
|
Request: new(inframonitoringtypes.PostableNodes),
|
|
RequestContentType: "application/json",
|
|
Response: new(inframonitoringtypes.Nodes),
|
|
ResponseContentType: "application/json",
|
|
SuccessStatusCode: http.StatusOK,
|
|
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized},
|
|
Deprecated: false,
|
|
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
|
}))
|
|
|
|
router.Post("/v1/o11y/infra_monitoring/namespaces", handler.New(
|
|
provider.authzMiddleware.ViewAccess(provider.infraMonitoringHandler.ListNamespaces),
|
|
handler.OpenAPIDef{
|
|
ID: "ListNamespaces",
|
|
Tags: []string{"inframonitoring"},
|
|
Summary: "List Namespaces for Infra Monitoring",
|
|
Description: "Returns a paginated list of Kubernetes namespaces with key aggregated pod metrics: CPU usage and memory working set (summed across pods in the group), plus per-group podCountsByPhase ({ pending, running, succeeded, failed, unknown } from each pod's latest k8s.pod.phase value in the window). Each namespace includes metadata attributes (k8s.namespace.name, k8s.cluster.name). The response type is 'list' for the default k8s.namespace.name grouping or 'grouped_list' for custom groupBy keys; in both modes every row aggregates pods in the group. Supports filtering via a filter expression, custom groupBy, ordering by cpu / memory, and pagination via offset/limit. Also reports whether the requested time range falls before the data retention boundary. Numeric metric fields (namespaceCPU, namespaceMemory) return -1 as a sentinel when no data is available for that field.",
|
|
Request: new(inframonitoringtypes.PostableNamespaces),
|
|
RequestContentType: "application/json",
|
|
Response: new(inframonitoringtypes.Namespaces),
|
|
ResponseContentType: "application/json",
|
|
SuccessStatusCode: http.StatusOK,
|
|
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized},
|
|
Deprecated: false,
|
|
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
|
}))
|
|
|
|
router.Post("/v1/o11y/infra_monitoring/clusters", handler.New(
|
|
provider.authzMiddleware.ViewAccess(provider.infraMonitoringHandler.ListClusters),
|
|
handler.OpenAPIDef{
|
|
ID: "ListClusters",
|
|
Tags: []string{"inframonitoring"},
|
|
Summary: "List Clusters for Infra Monitoring",
|
|
Description: "Returns a paginated list of Kubernetes clusters with key aggregated metrics derived by summing per-node values within the group: CPU usage, CPU allocatable, memory working set, memory allocatable. Each row also reports per-group nodeCountsByReadiness ({ ready, notReady } from each node's latest k8s.node.condition_ready value) and per-group podCountsByPhase ({ pending, running, succeeded, failed, unknown } from each pod's latest k8s.pod.phase value). Each cluster includes metadata attributes (k8s.cluster.name). The response type is 'list' for the default k8s.cluster.name grouping or 'grouped_list' for custom groupBy keys; in both modes every row aggregates nodes and pods in the group. Supports filtering via a filter expression, custom groupBy, ordering by cpu / cpu_allocatable / memory / memory_allocatable, and pagination via offset/limit. Also reports whether the requested time range falls before the data retention boundary. Numeric metric fields (clusterCPU, clusterCPUAllocatable, clusterMemory, clusterMemoryAllocatable) return -1 as a sentinel when no data is available for that field.",
|
|
Request: new(inframonitoringtypes.PostableClusters),
|
|
RequestContentType: "application/json",
|
|
Response: new(inframonitoringtypes.Clusters),
|
|
ResponseContentType: "application/json",
|
|
SuccessStatusCode: http.StatusOK,
|
|
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized},
|
|
Deprecated: false,
|
|
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
|
}))
|
|
|
|
router.Post("/v1/o11y/infra_monitoring/pvcs", handler.New(
|
|
provider.authzMiddleware.ViewAccess(provider.infraMonitoringHandler.ListVolumes),
|
|
handler.OpenAPIDef{
|
|
ID: "ListVolumes",
|
|
Tags: []string{"inframonitoring"},
|
|
Summary: "List Volumes for Infra Monitoring",
|
|
Description: "Returns a paginated list of Kubernetes persistent volume claims (PVCs) with key volume metrics: available bytes, capacity bytes, usage (capacity - available), inodes, free inodes, and used inodes. Each row also includes metadata attributes (k8s.persistentvolumeclaim.name, k8s.pod.uid, k8s.pod.name, k8s.namespace.name, k8s.node.name, k8s.statefulset.name, k8s.cluster.name). Supports filtering via a filter expression, custom groupBy to aggregate volumes by any attribute, ordering by any of the six metrics (available, capacity, usage, inodes, inodes_free, inodes_used), and pagination via offset/limit. The response type is 'list' for the default k8s.persistentvolumeclaim.name grouping or 'grouped_list' for custom groupBy keys; in both modes every row aggregates volumes in the group. Also reports whether the requested time range falls before the data retention boundary. Numeric metric fields (volumeAvailable, volumeCapacity, volumeUsage, volumeInodes, volumeInodesFree, volumeInodesUsed) return -1 as a sentinel when no data is available for that field.",
|
|
Request: new(inframonitoringtypes.PostableVolumes),
|
|
RequestContentType: "application/json",
|
|
Response: new(inframonitoringtypes.Volumes),
|
|
ResponseContentType: "application/json",
|
|
SuccessStatusCode: http.StatusOK,
|
|
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized},
|
|
Deprecated: false,
|
|
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
|
}))
|
|
|
|
router.Post("/v1/o11y/infra_monitoring/deployments", handler.New(
|
|
provider.authzMiddleware.ViewAccess(provider.infraMonitoringHandler.ListDeployments),
|
|
handler.OpenAPIDef{
|
|
ID: "ListDeployments",
|
|
Tags: []string{"inframonitoring"},
|
|
Summary: "List Deployments for Infra Monitoring",
|
|
Description: "Returns a paginated list of Kubernetes Deployments with key aggregated pod metrics: CPU usage and memory working set summed across pods owned by the deployment, plus average CPU/memory request and limit utilization (deploymentCPURequest, deploymentCPULimit, deploymentMemoryRequest, deploymentMemoryLimit). Each row also reports the latest known desiredPods (k8s.deployment.desired) and availablePods (k8s.deployment.available) replica counts and per-group podCountsByPhase ({ pending, running, succeeded, failed, unknown } from each pod's latest k8s.pod.phase value). Each deployment includes metadata attributes (k8s.deployment.name, k8s.namespace.name, k8s.cluster.name). The response type is 'list' for the default k8s.deployment.name grouping or 'grouped_list' for custom groupBy keys; in both modes every row aggregates pods owned by deployments in the group. Supports filtering via a filter expression, custom groupBy, ordering by cpu / cpu_request / cpu_limit / memory / memory_request / memory_limit / desired_pods / available_pods, and pagination via offset/limit. Also reports whether the requested time range falls before the data retention boundary. Numeric metric fields (deploymentCPU, deploymentCPURequest, deploymentCPULimit, deploymentMemory, deploymentMemoryRequest, deploymentMemoryLimit, desiredPods, availablePods) return -1 as a sentinel when no data is available for that field.",
|
|
Request: new(inframonitoringtypes.PostableDeployments),
|
|
RequestContentType: "application/json",
|
|
Response: new(inframonitoringtypes.Deployments),
|
|
ResponseContentType: "application/json",
|
|
SuccessStatusCode: http.StatusOK,
|
|
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized},
|
|
Deprecated: false,
|
|
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
|
}))
|
|
|
|
router.Post("/v1/o11y/infra_monitoring/statefulsets", handler.New(
|
|
provider.authzMiddleware.ViewAccess(provider.infraMonitoringHandler.ListStatefulSets),
|
|
handler.OpenAPIDef{
|
|
ID: "ListStatefulSets",
|
|
Tags: []string{"inframonitoring"},
|
|
Summary: "List StatefulSets for Infra Monitoring",
|
|
Description: "Returns a paginated list of Kubernetes StatefulSets with key aggregated pod metrics: CPU usage and memory working set summed across pods owned by the statefulset, plus average CPU/memory request and limit utilization (statefulSetCPURequest, statefulSetCPULimit, statefulSetMemoryRequest, statefulSetMemoryLimit). Each row also reports the latest known desiredPods (k8s.statefulset.desired_pods) and currentPods (k8s.statefulset.current_pods) replica counts and per-group podCountsByPhase ({ pending, running, succeeded, failed, unknown } from each pod's latest k8s.pod.phase value). Each statefulset includes metadata attributes (k8s.statefulset.name, k8s.namespace.name, k8s.cluster.name). The response type is 'list' for the default k8s.statefulset.name grouping or 'grouped_list' for custom groupBy keys; in both modes every row aggregates pods owned by statefulsets in the group. Supports filtering via a filter expression, custom groupBy, ordering by cpu / cpu_request / cpu_limit / memory / memory_request / memory_limit / desired_pods / current_pods, and pagination via offset/limit. Also reports whether the requested time range falls before the data retention boundary. Numeric metric fields (statefulSetCPU, statefulSetCPURequest, statefulSetCPULimit, statefulSetMemory, statefulSetMemoryRequest, statefulSetMemoryLimit, desiredPods, currentPods) return -1 as a sentinel when no data is available for that field.",
|
|
Request: new(inframonitoringtypes.PostableStatefulSets),
|
|
RequestContentType: "application/json",
|
|
Response: new(inframonitoringtypes.StatefulSets),
|
|
ResponseContentType: "application/json",
|
|
SuccessStatusCode: http.StatusOK,
|
|
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized},
|
|
Deprecated: false,
|
|
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
|
}))
|
|
|
|
router.Post("/v1/o11y/infra_monitoring/jobs", handler.New(
|
|
provider.authzMiddleware.ViewAccess(provider.infraMonitoringHandler.ListJobs),
|
|
handler.OpenAPIDef{
|
|
ID: "ListJobs",
|
|
Tags: []string{"inframonitoring"},
|
|
Summary: "List Jobs for Infra Monitoring",
|
|
Description: "Returns a paginated list of Kubernetes Jobs with key aggregated pod metrics: CPU usage and memory working set summed across pods owned by the job, plus average CPU/memory request and limit utilization (jobCPURequest, jobCPULimit, jobMemoryRequest, jobMemoryLimit). Each row also reports the latest known job-level counters from kube-state-metrics: desiredSuccessfulPods (k8s.job.desired_successful_pods, the target completion count), activePods (k8s.job.active_pods), failedPods (k8s.job.failed_pods, cumulative across the lifetime of the job), and successfulPods (k8s.job.successful_pods, cumulative). It also reports per-group podCountsByPhase ({ pending, running, succeeded, failed, unknown } from each pod's latest k8s.pod.phase value); note podCountsByPhase.failed (current pod-phase) is distinct from failedPods (cumulative job kube-state-metric). Each job includes metadata attributes (k8s.job.name, k8s.namespace.name, k8s.cluster.name). The response type is 'list' for the default k8s.job.name grouping or 'grouped_list' for custom groupBy keys; in both modes every row aggregates pods owned by jobs in the group. Supports filtering via a filter expression, custom groupBy, ordering by cpu / cpu_request / cpu_limit / memory / memory_request / memory_limit / desired_successful_pods / active_pods / failed_pods / successful_pods, and pagination via offset/limit. Also reports whether the requested time range falls before the data retention boundary. Numeric metric fields (jobCPU, jobCPURequest, jobCPULimit, jobMemory, jobMemoryRequest, jobMemoryLimit, desiredSuccessfulPods, activePods, failedPods, successfulPods) return -1 as a sentinel when no data is available for that field.",
|
|
Request: new(inframonitoringtypes.PostableJobs),
|
|
RequestContentType: "application/json",
|
|
Response: new(inframonitoringtypes.Jobs),
|
|
ResponseContentType: "application/json",
|
|
SuccessStatusCode: http.StatusOK,
|
|
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized},
|
|
Deprecated: false,
|
|
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
|
}))
|
|
|
|
router.Post("/v1/o11y/infra_monitoring/daemonsets", handler.New(
|
|
provider.authzMiddleware.ViewAccess(provider.infraMonitoringHandler.ListDaemonSets),
|
|
handler.OpenAPIDef{
|
|
ID: "ListDaemonSets",
|
|
Tags: []string{"inframonitoring"},
|
|
Summary: "List DaemonSets for Infra Monitoring",
|
|
Description: "Returns a paginated list of Kubernetes DaemonSets with key aggregated pod metrics: CPU usage and memory working set summed across pods owned by the daemonset, plus average CPU/memory request and limit utilization (daemonSetCPURequest, daemonSetCPULimit, daemonSetMemoryRequest, daemonSetMemoryLimit). Each row also reports the latest known node-level counters from kube-state-metrics: desiredNodes (k8s.daemonset.desired_scheduled_nodes, the number of nodes the daemonset wants to run on) and currentNodes (k8s.daemonset.current_scheduled_nodes, the number of nodes the daemonset currently runs on) — note these are node counts, not pod counts. It also reports per-group podCountsByPhase ({ pending, running, succeeded, failed, unknown } from each pod's latest k8s.pod.phase value). Each daemonset includes metadata attributes (k8s.daemonset.name, k8s.namespace.name, k8s.cluster.name). The response type is 'list' for the default k8s.daemonset.name grouping or 'grouped_list' for custom groupBy keys; in both modes every row aggregates pods owned by daemonsets in the group. Supports filtering via a filter expression, custom groupBy, ordering by cpu / cpu_request / cpu_limit / memory / memory_request / memory_limit / desired_nodes / current_nodes, and pagination via offset/limit. Also reports whether the requested time range falls before the data retention boundary. Numeric metric fields (daemonSetCPU, daemonSetCPURequest, daemonSetCPULimit, daemonSetMemory, daemonSetMemoryRequest, daemonSetMemoryLimit, desiredNodes, currentNodes) return -1 as a sentinel when no data is available for that field.",
|
|
Request: new(inframonitoringtypes.PostableDaemonSets),
|
|
RequestContentType: "application/json",
|
|
Response: new(inframonitoringtypes.DaemonSets),
|
|
ResponseContentType: "application/json",
|
|
SuccessStatusCode: http.StatusOK,
|
|
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized},
|
|
Deprecated: false,
|
|
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
|
}))
|
|
|
|
router.Get("/v1/o11y/infra_monitoring/checks", handler.New(
|
|
provider.authzMiddleware.ViewAccess(provider.infraMonitoringHandler.GetChecks),
|
|
handler.OpenAPIDef{
|
|
ID: "GetChecks",
|
|
Tags: []string{"inframonitoring"},
|
|
Summary: "Run Infra Monitoring Setup Checks",
|
|
Description: "Checks whether the metrics and attributes required to power the infra-monitoring section selected by the 'type' query parameter (hosts, processes, pods, nodes, deployments, daemonsets, statefulsets, jobs, namespaces, clusters, volumes) are being received. For each collector receiver or processor that contributes required metrics or attributes, lists what is present and what is missing, with a prebuilt user-facing message and a docs link per missing component. Default-enabled metrics are those expected as soon as the receiver is configured; optional metrics require 'enabled: true' in receiver config. 'ready' is true only when every missing list is empty.",
|
|
RequestQuery: new(inframonitoringtypes.PostableChecks),
|
|
Response: new(inframonitoringtypes.Checks),
|
|
ResponseContentType: "application/json",
|
|
SuccessStatusCode: http.StatusOK,
|
|
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized},
|
|
Deprecated: false,
|
|
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
|
}))
|
|
}
|