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  }