k8s.io/kubernetes@v1.29.3/pkg/kubelet/stats/host_stats_provider.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 stats
    18  
    19  import (
    20  	"fmt"
    21  	"os"
    22  	"path/filepath"
    23  
    24  	cadvisorapiv2 "github.com/google/cadvisor/info/v2"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/types"
    27  	statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
    28  	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
    29  	"k8s.io/kubernetes/pkg/kubelet/kuberuntime"
    30  	"k8s.io/kubernetes/pkg/volume"
    31  )
    32  
    33  // PodEtcHostsPathFunc is a function to fetch a etc hosts path by pod uid and whether etc host path is supported by the runtime
    34  type PodEtcHostsPathFunc func(podUID types.UID) string
    35  
    36  // metricsProviderByPath maps a path to its metrics provider
    37  type metricsProviderByPath map[string]volume.MetricsProvider
    38  
    39  // HostStatsProvider defines an interface for providing host stats associated with pod.
    40  type HostStatsProvider interface {
    41  	// getPodLogStats gets stats associated with pod log usage
    42  	getPodLogStats(podNamespace, podName string, podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error)
    43  	// getPodContainerLogStats gets stats associated with container log usage
    44  	getPodContainerLogStats(podNamespace, podName string, podUID types.UID, containerName string, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error)
    45  	// getPodEtcHostsStats gets stats associated with pod etc-hosts usage
    46  	getPodEtcHostsStats(podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error)
    47  }
    48  
    49  type hostStatsProvider struct {
    50  	// osInterface is the interface for syscalls.
    51  	osInterface kubecontainer.OSInterface
    52  	// podEtcHostsPathFunc fetches a pod etc hosts path by uid.
    53  	podEtcHostsPathFunc PodEtcHostsPathFunc
    54  }
    55  
    56  // NewHostStatsProvider returns a new HostStatsProvider type struct.
    57  func NewHostStatsProvider(osInterface kubecontainer.OSInterface, podEtcHostsPathFunc PodEtcHostsPathFunc) HostStatsProvider {
    58  	return hostStatsProvider{
    59  		osInterface:         osInterface,
    60  		podEtcHostsPathFunc: podEtcHostsPathFunc,
    61  	}
    62  }
    63  
    64  func (h hostStatsProvider) getPodLogStats(podNamespace, podName string, podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) {
    65  	metricsByPath, err := h.podLogMetrics(podNamespace, podName, podUID)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	return metricsByPathToFsStats(metricsByPath, rootFsInfo)
    70  }
    71  
    72  // getPodContainerLogStats gets stats for container
    73  func (h hostStatsProvider) getPodContainerLogStats(podNamespace, podName string, podUID types.UID, containerName string, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) {
    74  	metricsByPath, err := h.podContainerLogMetrics(podNamespace, podName, podUID, containerName)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	return metricsByPathToFsStats(metricsByPath, rootFsInfo)
    79  }
    80  
    81  // getPodEtcHostsStats gets status for pod etc hosts usage
    82  func (h hostStatsProvider) getPodEtcHostsStats(podUID types.UID, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) {
    83  	// Runtimes may not support etc hosts file (Windows with docker)
    84  	podEtcHostsPath := h.podEtcHostsPathFunc(podUID)
    85  	// Some pods have an explicit /etc/hosts mount and the Kubelet will not create an etc-hosts file for them
    86  	if _, err := os.Stat(podEtcHostsPath); os.IsNotExist(err) {
    87  		return nil, nil
    88  	}
    89  
    90  	metrics := volume.NewMetricsDu(podEtcHostsPath)
    91  	hostMetrics, err := metrics.GetMetrics()
    92  	if err != nil {
    93  		return nil, fmt.Errorf("failed to get stats %v", err)
    94  	}
    95  	result := rootFsInfoToFsStats(rootFsInfo)
    96  	usedBytes := uint64(hostMetrics.Used.Value())
    97  	inodesUsed := uint64(hostMetrics.InodesUsed.Value())
    98  	result.UsedBytes = addUsage(result.UsedBytes, &usedBytes)
    99  	result.InodesUsed = addUsage(result.InodesUsed, &inodesUsed)
   100  	result.Time = maxUpdateTime(&result.Time, &hostMetrics.Time)
   101  	return result, nil
   102  }
   103  
   104  func (h hostStatsProvider) podLogMetrics(podNamespace, podName string, podUID types.UID) (metricsProviderByPath, error) {
   105  	podLogsDirectoryPath := kuberuntime.BuildPodLogsDirectory(podNamespace, podName, podUID)
   106  	return h.fileMetricsByDir(podLogsDirectoryPath)
   107  }
   108  
   109  func (h hostStatsProvider) podContainerLogMetrics(podNamespace, podName string, podUID types.UID, containerName string) (metricsProviderByPath, error) {
   110  	podContainerLogsDirectoryPath := kuberuntime.BuildContainerLogsDirectory(podNamespace, podName, podUID, containerName)
   111  	return h.fileMetricsByDir(podContainerLogsDirectoryPath)
   112  }
   113  
   114  // fileMetricsByDir returns metrics by path for each file under specified directory
   115  func (h hostStatsProvider) fileMetricsByDir(dirname string) (metricsProviderByPath, error) {
   116  	files, err := h.osInterface.ReadDir(dirname)
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  	results := metricsProviderByPath{}
   121  	for _, f := range files {
   122  		if f.IsDir() {
   123  			continue
   124  		}
   125  		// Only include *files* under pod log directory.
   126  		fpath := filepath.Join(dirname, f.Name())
   127  		results[fpath] = volume.NewMetricsDu(fpath)
   128  	}
   129  	return results, nil
   130  }
   131  
   132  // metricsByPathToFsStats converts a metrics provider by path to fs stats
   133  func metricsByPathToFsStats(metricsByPath metricsProviderByPath, rootFsInfo *cadvisorapiv2.FsInfo) (*statsapi.FsStats, error) {
   134  	result := rootFsInfoToFsStats(rootFsInfo)
   135  	for fpath, metrics := range metricsByPath {
   136  		hostMetrics, err := metrics.GetMetrics()
   137  		if err != nil {
   138  			return nil, fmt.Errorf("failed to get fsstats for %q: %v", fpath, err)
   139  		}
   140  		usedBytes := uint64(hostMetrics.Used.Value())
   141  		inodesUsed := uint64(hostMetrics.InodesUsed.Value())
   142  		result.UsedBytes = addUsage(result.UsedBytes, &usedBytes)
   143  		result.InodesUsed = addUsage(result.InodesUsed, &inodesUsed)
   144  		result.Time = maxUpdateTime(&result.Time, &hostMetrics.Time)
   145  	}
   146  	return result, nil
   147  }
   148  
   149  // rootFsInfoToFsStats is a utility to convert rootFsInfo into statsapi.FsStats
   150  func rootFsInfoToFsStats(rootFsInfo *cadvisorapiv2.FsInfo) *statsapi.FsStats {
   151  	return &statsapi.FsStats{
   152  		Time:           metav1.NewTime(rootFsInfo.Timestamp),
   153  		AvailableBytes: &rootFsInfo.Available,
   154  		CapacityBytes:  &rootFsInfo.Capacity,
   155  		InodesFree:     rootFsInfo.InodesFree,
   156  		Inodes:         rootFsInfo.Inodes,
   157  	}
   158  }