1
16
17
18 package stats
19
20 import (
21 "context"
22 "fmt"
23 "net/http"
24
25 restful "github.com/emicklei/go-restful/v3"
26 cadvisorapi "github.com/google/cadvisor/info/v1"
27 cadvisorv2 "github.com/google/cadvisor/info/v2"
28 "k8s.io/klog/v2"
29
30 v1 "k8s.io/api/core/v1"
31 "k8s.io/apimachinery/pkg/types"
32 statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
33 "k8s.io/kubernetes/pkg/kubelet/cm"
34 kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
35 "k8s.io/kubernetes/pkg/volume"
36 )
37
38
39 type Provider interface {
40
41
42
43 ListPodStats(ctx context.Context) ([]statsapi.PodStats, error)
44
45
46 ListPodCPUAndMemoryStats(ctx context.Context) ([]statsapi.PodStats, error)
47
48
49
50
51
52 ListPodStatsAndUpdateCPUNanoCoreUsage(ctx context.Context) ([]statsapi.PodStats, error)
53
54
55
56
57
58
59
60 ImageFsStats(ctx context.Context) (imageFs *statsapi.FsStats, containerFs *statsapi.FsStats, callErr error)
61
62
63
64
65 GetCgroupStats(cgroupName string, updateStats bool) (*statsapi.ContainerStats, *statsapi.NetworkStats, error)
66
67 GetCgroupCPUAndMemoryStats(cgroupName string, updateStats bool) (*statsapi.ContainerStats, error)
68
69
70 RootFsStats() (*statsapi.FsStats, error)
71
72
73
74 GetRequestedContainersInfo(containerName string, options cadvisorv2.RequestOptions) (map[string]*cadvisorapi.ContainerInfo, error)
75
76
77
78
79
80 GetPodByName(namespace, name string) (*v1.Pod, bool)
81
82 GetNode() (*v1.Node, error)
83
84 GetNodeConfig() cm.NodeConfig
85
86
87 ListVolumesForPod(podUID types.UID) (map[string]volume.Volume, bool)
88
89
90 ListBlockVolumesForPod(podUID types.UID) (map[string]volume.BlockVolume, bool)
91
92 GetPods() []*v1.Pod
93
94
95 RlimitStats() (*statsapi.RlimitStats, error)
96
97
98 GetPodCgroupRoot() string
99
100
101
102 GetPodByCgroupfs(cgroupfs string) (*v1.Pod, bool)
103 }
104
105 type handler struct {
106 provider Provider
107 summaryProvider SummaryProvider
108 }
109
110
111 func CreateHandlers(rootPath string, provider Provider, summaryProvider SummaryProvider) *restful.WebService {
112 h := &handler{provider, summaryProvider}
113
114 ws := &restful.WebService{}
115 ws.Path(rootPath).
116 Produces(restful.MIME_JSON)
117
118 endpoints := []struct {
119 path string
120 handler restful.RouteFunction
121 }{
122 {"/summary", h.handleSummary},
123 }
124
125 for _, e := range endpoints {
126 for _, method := range []string{"GET", "POST"} {
127 ws.Route(ws.
128 Method(method).
129 Path(e.path).
130 To(e.handler))
131 }
132 }
133
134 return ws
135 }
136
137
138
139 func (h *handler) handleSummary(request *restful.Request, response *restful.Response) {
140 ctx := request.Request.Context()
141 onlyCPUAndMemory := false
142 err := request.Request.ParseForm()
143 if err != nil {
144 handleError(response, "/stats/summary", fmt.Errorf("parse form failed: %w", err))
145 return
146 }
147 if onlyCluAndMemoryParam, found := request.Request.Form["only_cpu_and_memory"]; found &&
148 len(onlyCluAndMemoryParam) == 1 && onlyCluAndMemoryParam[0] == "true" {
149 onlyCPUAndMemory = true
150 }
151 var summary *statsapi.Summary
152 if onlyCPUAndMemory {
153 summary, err = h.summaryProvider.GetCPUAndMemoryStats(ctx)
154 } else {
155
156 forceStatsUpdate := false
157 summary, err = h.summaryProvider.Get(ctx, forceStatsUpdate)
158 }
159 if err != nil {
160 handleError(response, "/stats/summary", err)
161 } else {
162 writeResponse(response, summary)
163 }
164 }
165
166 func writeResponse(response *restful.Response, stats interface{}) {
167 if err := response.WriteAsJson(stats); err != nil {
168 klog.ErrorS(err, "Error writing response")
169 }
170 }
171
172
173
174 func handleError(response *restful.Response, request string, err error) {
175 switch err {
176 case kubecontainer.ErrContainerNotFound:
177 response.WriteError(http.StatusNotFound, err)
178 default:
179 msg := fmt.Sprintf("Internal Error: %v", err)
180 klog.ErrorS(err, "HTTP InternalServerError serving", "request", request)
181 response.WriteErrorString(http.StatusInternalServerError, msg)
182 }
183 }
184
View as plain text