k8s.io/perf-tests/clusterloader2@v0.0.0-20240304094227-64bdb12da87e/pkg/measurement/util/kubelet/kubelet.go (about) 1 /* 2 Copyright 2018 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 package kubelet 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 "time" 24 25 clientset "k8s.io/client-go/kubernetes" 26 stats "k8s.io/kubelet/pkg/apis/stats/v1alpha1" 27 "k8s.io/perf-tests/clusterloader2/pkg/measurement/util" 28 ) 29 30 const ( 31 singleCallTimeout = 5 * time.Minute 32 ) 33 34 // GetOneTimeResourceUsageOnNode queries the node's /stats/summary endpoint 35 // and returns the resource usage of all systemContainers and containerNames 36 // returned by the containerNames function. 37 func GetOneTimeResourceUsageOnNode(c clientset.Interface, nodeName string, port int, containerNames func() []string) (util.ResourceUsagePerContainer, error) { 38 // Get information of all containers on the node. 39 summary, err := getStatsSummary(c, nodeName, port) 40 if err != nil { 41 return nil, err 42 } 43 44 f := func(name string, newStats *stats.ContainerStats) *util.ContainerResourceUsage { 45 if newStats == nil || newStats.CPU == nil || newStats.Memory == nil { 46 return nil 47 } 48 return &util.ContainerResourceUsage{ 49 Name: name, 50 Timestamp: newStats.StartTime.Time, 51 CPUUsageInCores: float64(removeUint64Ptr(newStats.CPU.UsageNanoCores)) / 1000000000, 52 MemoryUsageInBytes: removeUint64Ptr(newStats.Memory.UsageBytes), 53 MemoryWorkingSetInBytes: removeUint64Ptr(newStats.Memory.WorkingSetBytes), 54 MemoryRSSInBytes: removeUint64Ptr(newStats.Memory.RSSBytes), 55 CPUInterval: 0, 56 } 57 } 58 // Process container infos that are relevant to us. 59 containers := containerNames() 60 usageMap := make(util.ResourceUsagePerContainer, len(containers)+len(summary.Node.SystemContainers)) 61 for _, pod := range summary.Pods { 62 for _, container := range pod.Containers { 63 isInteresting := false 64 for _, interestingContainerName := range containers { 65 if container.Name == interestingContainerName { 66 isInteresting = true 67 break 68 } 69 } 70 if !isInteresting { 71 continue 72 } 73 if usage := f(pod.PodRef.Name+"/"+container.Name, &container); usage != nil { 74 usageMap[pod.PodRef.Name+"/"+container.Name] = usage 75 } 76 } 77 } 78 79 // Always process the system container information: kubelet and pods 80 for _, sysContainer := range summary.Node.SystemContainers { 81 if usage := f(nodeName+"/"+sysContainer.Name, &sysContainer); usage != nil { 82 usageMap[nodeName+"/"+sysContainer.Name] = usage 83 } 84 } 85 return usageMap, nil 86 } 87 88 // getStatsSummary contacts kubelet for the container information. 89 func getStatsSummary(c clientset.Interface, nodeName string, port int) (*stats.Summary, error) { 90 ctx, cancel := context.WithTimeout(context.Background(), singleCallTimeout) 91 defer cancel() 92 93 data, err := c.CoreV1().RESTClient().Get(). 94 Resource("nodes"). 95 SubResource("proxy"). 96 Name(fmt.Sprintf("%v:%v", nodeName, port)). 97 Suffix("stats/summary"). 98 Do(ctx).Raw() 99 100 if err != nil { 101 return nil, err 102 } 103 104 summary := stats.Summary{} 105 err = json.Unmarshal(data, &summary) 106 if err != nil { 107 return nil, err 108 } 109 return &summary, nil 110 } 111 112 func removeUint64Ptr(ptr *uint64) uint64 { 113 if ptr == nil { 114 return 0 115 } 116 return *ptr 117 }