k8s.io/kubernetes@v1.29.3/pkg/kubelet/server/stats/handler.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 //go:generate mockgen -source=handler.go -destination=testing/mock_stats_provider.go -package=testing Provider 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 // Provider hosts methods required by stats handlers. 39 type Provider interface { 40 // The following stats are provided by either CRI or cAdvisor. 41 // 42 // ListPodStats returns the stats of all the containers managed by pods. 43 ListPodStats(ctx context.Context) ([]statsapi.PodStats, error) 44 // ListPodStatsAndUpdateCPUNanoCoreUsage updates the cpu nano core usage for 45 // the containers and returns the stats for all the pod-managed containers. 46 ListPodCPUAndMemoryStats(ctx context.Context) ([]statsapi.PodStats, error) 47 // ListPodStatsAndUpdateCPUNanoCoreUsage returns the stats of all the 48 // containers managed by pods and force update the cpu usageNanoCores. 49 // This is a workaround for CRI runtimes that do not integrate with 50 // cadvisor. See https://github.com/kubernetes/kubernetes/issues/72788 51 // for more details. 52 ListPodStatsAndUpdateCPUNanoCoreUsage(ctx context.Context) ([]statsapi.PodStats, error) 53 // ImageFsStats returns the stats of the image filesystem. 54 // Kubelet allows three options for container filesystems 55 // Everything is on node fs (so no image filesystem) 56 // Container storage is on a dedicated disk (imageFs is separate from root) 57 // Container Filesystem is on root and Images are stored on ImageFs 58 // First return parameter is the image filesystem and 59 // second parameter is the container filesystem 60 ImageFsStats(ctx context.Context) (imageFs *statsapi.FsStats, containerFs *statsapi.FsStats, callErr error) 61 // The following stats are provided by cAdvisor. 62 // 63 // GetCgroupStats returns the stats and the networking usage of the cgroup 64 // with the specified cgroupName. 65 GetCgroupStats(cgroupName string, updateStats bool) (*statsapi.ContainerStats, *statsapi.NetworkStats, error) 66 // GetCgroupCPUAndMemoryStats returns the CPU and memory stats of the cgroup with the specified cgroupName. 67 GetCgroupCPUAndMemoryStats(cgroupName string, updateStats bool) (*statsapi.ContainerStats, error) 68 69 // RootFsStats returns the stats of the node root filesystem. 70 RootFsStats() (*statsapi.FsStats, error) 71 72 // The following stats are provided by cAdvisor for legacy usage. 73 // 74 // GetContainerInfo returns the information of the container with the 75 // containerName managed by the pod with the uid. 76 GetContainerInfo(ctx context.Context, podFullName string, uid types.UID, containerName string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) 77 // GetRawContainerInfo returns the information of the container with the 78 // containerName. If subcontainers is true, this function will return the 79 // information of all the sub-containers as well. 80 GetRawContainerInfo(containerName string, req *cadvisorapi.ContainerInfoRequest, subcontainers bool) (map[string]*cadvisorapi.ContainerInfo, error) 81 // GetRequestedContainersInfo returns the information of the container with 82 // the containerName, and with the specified cAdvisor options. 83 GetRequestedContainersInfo(containerName string, options cadvisorv2.RequestOptions) (map[string]*cadvisorapi.ContainerInfo, error) 84 85 // The following information is provided by Kubelet. 86 // 87 // GetPodByName returns the spec of the pod with the name in the specified 88 // namespace. 89 GetPodByName(namespace, name string) (*v1.Pod, bool) 90 // GetNode returns the spec of the local node. 91 GetNode() (*v1.Node, error) 92 // GetNodeConfig returns the configuration of the local node. 93 GetNodeConfig() cm.NodeConfig 94 // ListVolumesForPod returns the stats of the volume used by the pod with 95 // the podUID. 96 ListVolumesForPod(podUID types.UID) (map[string]volume.Volume, bool) 97 // ListBlockVolumesForPod returns the stats of the volume used by the 98 // pod with the podUID. 99 ListBlockVolumesForPod(podUID types.UID) (map[string]volume.BlockVolume, bool) 100 // GetPods returns the specs of all the pods running on this node. 101 GetPods() []*v1.Pod 102 103 // RlimitStats returns the rlimit stats of system. 104 RlimitStats() (*statsapi.RlimitStats, error) 105 106 // GetPodCgroupRoot returns the literal cgroupfs value for the cgroup containing all pods 107 GetPodCgroupRoot() string 108 109 // GetPodByCgroupfs provides the pod that maps to the specified cgroup literal, as well 110 // as whether the pod was found. 111 GetPodByCgroupfs(cgroupfs string) (*v1.Pod, bool) 112 } 113 114 type handler struct { 115 provider Provider 116 summaryProvider SummaryProvider 117 } 118 119 // CreateHandlers creates the REST handlers for the stats. 120 func CreateHandlers(rootPath string, provider Provider, summaryProvider SummaryProvider) *restful.WebService { 121 h := &handler{provider, summaryProvider} 122 123 ws := &restful.WebService{} 124 ws.Path(rootPath). 125 Produces(restful.MIME_JSON) 126 127 endpoints := []struct { 128 path string 129 handler restful.RouteFunction 130 }{ 131 {"/summary", h.handleSummary}, 132 } 133 134 for _, e := range endpoints { 135 for _, method := range []string{"GET", "POST"} { 136 ws.Route(ws. 137 Method(method). 138 Path(e.path). 139 To(e.handler)) 140 } 141 } 142 143 return ws 144 } 145 146 // Handles stats summary requests to /stats/summary 147 // If "only_cpu_and_memory" GET param is true then only cpu and memory is returned in response. 148 func (h *handler) handleSummary(request *restful.Request, response *restful.Response) { 149 ctx := request.Request.Context() 150 onlyCPUAndMemory := false 151 err := request.Request.ParseForm() 152 if err != nil { 153 handleError(response, "/stats/summary", fmt.Errorf("parse form failed: %w", err)) 154 return 155 } 156 if onlyCluAndMemoryParam, found := request.Request.Form["only_cpu_and_memory"]; found && 157 len(onlyCluAndMemoryParam) == 1 && onlyCluAndMemoryParam[0] == "true" { 158 onlyCPUAndMemory = true 159 } 160 var summary *statsapi.Summary 161 if onlyCPUAndMemory { 162 summary, err = h.summaryProvider.GetCPUAndMemoryStats(ctx) 163 } else { 164 // external calls to the summary API use cached stats 165 forceStatsUpdate := false 166 summary, err = h.summaryProvider.Get(ctx, forceStatsUpdate) 167 } 168 if err != nil { 169 handleError(response, "/stats/summary", err) 170 } else { 171 writeResponse(response, summary) 172 } 173 } 174 175 func writeResponse(response *restful.Response, stats interface{}) { 176 if err := response.WriteAsJson(stats); err != nil { 177 klog.ErrorS(err, "Error writing response") 178 } 179 } 180 181 // handleError serializes an error object into an HTTP response. 182 // request is provided for logging. 183 func handleError(response *restful.Response, request string, err error) { 184 switch err { 185 case kubecontainer.ErrContainerNotFound: 186 response.WriteError(http.StatusNotFound, err) 187 default: 188 msg := fmt.Sprintf("Internal Error: %v", err) 189 klog.ErrorS(err, "HTTP InternalServerError serving", "request", request) 190 response.WriteErrorString(http.StatusInternalServerError, msg) 191 } 192 }