k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/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 // GetRequestedContainersInfo returns the information of the container with 73 // the containerName, and with the specified cAdvisor options. 74 GetRequestedContainersInfo(containerName string, options cadvisorv2.RequestOptions) (map[string]*cadvisorapi.ContainerInfo, error) 75 76 // The following information is provided by Kubelet. 77 // 78 // GetPodByName returns the spec of the pod with the name in the specified 79 // namespace. 80 GetPodByName(namespace, name string) (*v1.Pod, bool) 81 // GetNode returns the spec of the local node. 82 GetNode() (*v1.Node, error) 83 // GetNodeConfig returns the configuration of the local node. 84 GetNodeConfig() cm.NodeConfig 85 // ListVolumesForPod returns the stats of the volume used by the pod with 86 // the podUID. 87 ListVolumesForPod(podUID types.UID) (map[string]volume.Volume, bool) 88 // ListBlockVolumesForPod returns the stats of the volume used by the 89 // pod with the podUID. 90 ListBlockVolumesForPod(podUID types.UID) (map[string]volume.BlockVolume, bool) 91 // GetPods returns the specs of all the pods running on this node. 92 GetPods() []*v1.Pod 93 94 // RlimitStats returns the rlimit stats of system. 95 RlimitStats() (*statsapi.RlimitStats, error) 96 97 // GetPodCgroupRoot returns the literal cgroupfs value for the cgroup containing all pods 98 GetPodCgroupRoot() string 99 100 // GetPodByCgroupfs provides the pod that maps to the specified cgroup literal, as well 101 // as whether the pod was found. 102 GetPodByCgroupfs(cgroupfs string) (*v1.Pod, bool) 103 } 104 105 type handler struct { 106 provider Provider 107 summaryProvider SummaryProvider 108 } 109 110 // CreateHandlers creates the REST handlers for the stats. 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 // Handles stats summary requests to /stats/summary 138 // If "only_cpu_and_memory" GET param is true then only cpu and memory is returned in response. 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 // external calls to the summary API use cached stats 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 // handleError serializes an error object into an HTTP response. 173 // request is provided for logging. 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 }