1/* 2Copyright 2017 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package stats 18 19import ( 20 "fmt" 21 22 cadvisorapiv1 "github.com/google/cadvisor/info/v1" 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 "k8s.io/apimachinery/pkg/types" 25 internalapi "k8s.io/cri-api/pkg/apis" 26 statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1" 27 "k8s.io/kubernetes/pkg/kubelet/cadvisor" 28 kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" 29 kubepod "k8s.io/kubernetes/pkg/kubelet/pod" 30 "k8s.io/kubernetes/pkg/kubelet/server/stats" 31 "k8s.io/kubernetes/pkg/kubelet/stats/pidlimit" 32 "k8s.io/kubernetes/pkg/kubelet/status" 33) 34 35// NewCRIStatsProvider returns a Provider that provides the node stats 36// from cAdvisor and the container stats from CRI. 37func NewCRIStatsProvider( 38 cadvisor cadvisor.Interface, 39 resourceAnalyzer stats.ResourceAnalyzer, 40 podManager kubepod.Manager, 41 runtimeCache kubecontainer.RuntimeCache, 42 runtimeService internalapi.RuntimeService, 43 imageService internalapi.ImageManagerService, 44 hostStatsProvider HostStatsProvider, 45 disableAcceleratorUsageMetrics bool, 46) *Provider { 47 return newStatsProvider(cadvisor, podManager, runtimeCache, newCRIStatsProvider(cadvisor, resourceAnalyzer, 48 runtimeService, imageService, hostStatsProvider, disableAcceleratorUsageMetrics)) 49} 50 51// NewCadvisorStatsProvider returns a containerStatsProvider that provides both 52// the node and the container stats from cAdvisor. 53func NewCadvisorStatsProvider( 54 cadvisor cadvisor.Interface, 55 resourceAnalyzer stats.ResourceAnalyzer, 56 podManager kubepod.Manager, 57 runtimeCache kubecontainer.RuntimeCache, 58 imageService kubecontainer.ImageService, 59 statusProvider status.PodStatusProvider, 60 hostStatsProvider HostStatsProvider, 61) *Provider { 62 return newStatsProvider(cadvisor, podManager, runtimeCache, newCadvisorStatsProvider(cadvisor, resourceAnalyzer, imageService, statusProvider, hostStatsProvider)) 63} 64 65// newStatsProvider returns a new Provider that provides node stats from 66// cAdvisor and the container stats using the containerStatsProvider. 67func newStatsProvider( 68 cadvisor cadvisor.Interface, 69 podManager kubepod.Manager, 70 runtimeCache kubecontainer.RuntimeCache, 71 containerStatsProvider containerStatsProvider, 72) *Provider { 73 return &Provider{ 74 cadvisor: cadvisor, 75 podManager: podManager, 76 runtimeCache: runtimeCache, 77 containerStatsProvider: containerStatsProvider, 78 } 79} 80 81// Provider provides the stats of the node and the pod-managed containers. 82type Provider struct { 83 cadvisor cadvisor.Interface 84 podManager kubepod.Manager 85 runtimeCache kubecontainer.RuntimeCache 86 containerStatsProvider 87 rlimitStatsProvider 88} 89 90// containerStatsProvider is an interface that provides the stats of the 91// containers managed by pods. 92type containerStatsProvider interface { 93 ListPodStats() ([]statsapi.PodStats, error) 94 ListPodStatsAndUpdateCPUNanoCoreUsage() ([]statsapi.PodStats, error) 95 ListPodCPUAndMemoryStats() ([]statsapi.PodStats, error) 96 ImageFsStats() (*statsapi.FsStats, error) 97 ImageFsDevice() (string, error) 98} 99 100type rlimitStatsProvider interface { 101 RlimitStats() (*statsapi.RlimitStats, error) 102} 103 104// RlimitStats returns base information about process count 105func (p *Provider) RlimitStats() (*statsapi.RlimitStats, error) { 106 return pidlimit.Stats() 107} 108 109// GetCgroupStats returns the stats of the cgroup with the cgroupName. Note that 110// this function doesn't generate filesystem stats. 111func (p *Provider) GetCgroupStats(cgroupName string, updateStats bool) (*statsapi.ContainerStats, *statsapi.NetworkStats, error) { 112 info, err := getCgroupInfo(p.cadvisor, cgroupName, updateStats) 113 if err != nil { 114 return nil, nil, fmt.Errorf("failed to get cgroup stats for %q: %v", cgroupName, err) 115 } 116 // Rootfs and imagefs doesn't make sense for raw cgroup. 117 s := cadvisorInfoToContainerStats(cgroupName, info, nil, nil) 118 n := cadvisorInfoToNetworkStats(info) 119 return s, n, nil 120} 121 122// GetCgroupCPUAndMemoryStats returns the CPU and memory stats of the cgroup with the cgroupName. Note that 123// this function doesn't generate filesystem stats. 124func (p *Provider) GetCgroupCPUAndMemoryStats(cgroupName string, updateStats bool) (*statsapi.ContainerStats, error) { 125 info, err := getCgroupInfo(p.cadvisor, cgroupName, updateStats) 126 if err != nil { 127 return nil, fmt.Errorf("failed to get cgroup stats for %q: %v", cgroupName, err) 128 } 129 // Rootfs and imagefs doesn't make sense for raw cgroup. 130 s := cadvisorInfoToContainerCPUAndMemoryStats(cgroupName, info) 131 return s, nil 132} 133 134// RootFsStats returns the stats of the node root filesystem. 135func (p *Provider) RootFsStats() (*statsapi.FsStats, error) { 136 rootFsInfo, err := p.cadvisor.RootFsInfo() 137 if err != nil { 138 return nil, fmt.Errorf("failed to get rootFs info: %v", err) 139 } 140 141 var nodeFsInodesUsed *uint64 142 if rootFsInfo.Inodes != nil && rootFsInfo.InodesFree != nil { 143 nodeFsIU := *rootFsInfo.Inodes - *rootFsInfo.InodesFree 144 nodeFsInodesUsed = &nodeFsIU 145 } 146 147 // Get the root container stats's timestamp, which will be used as the 148 // imageFs stats timestamp. Don't force a stats update, as we only want the timestamp. 149 rootStats, err := getCgroupStats(p.cadvisor, "/", false) 150 if err != nil { 151 return nil, fmt.Errorf("failed to get root container stats: %v", err) 152 } 153 154 return &statsapi.FsStats{ 155 Time: metav1.NewTime(rootStats.Timestamp), 156 AvailableBytes: &rootFsInfo.Available, 157 CapacityBytes: &rootFsInfo.Capacity, 158 UsedBytes: &rootFsInfo.Usage, 159 InodesFree: rootFsInfo.InodesFree, 160 Inodes: rootFsInfo.Inodes, 161 InodesUsed: nodeFsInodesUsed, 162 }, nil 163} 164 165// GetContainerInfo returns stats (from cAdvisor) for a container. 166func (p *Provider) GetContainerInfo(podFullName string, podUID types.UID, containerName string, req *cadvisorapiv1.ContainerInfoRequest) (*cadvisorapiv1.ContainerInfo, error) { 167 // Resolve and type convert back again. 168 // We need the static pod UID but the kubecontainer API works with types.UID. 169 podUID = types.UID(p.podManager.TranslatePodUID(podUID)) 170 171 pods, err := p.runtimeCache.GetPods() 172 if err != nil { 173 return nil, err 174 } 175 pod := kubecontainer.Pods(pods).FindPod(podFullName, podUID) 176 container := pod.FindContainerByName(containerName) 177 if container == nil { 178 return nil, kubecontainer.ErrContainerNotFound 179 } 180 181 ci, err := p.cadvisor.DockerContainer(container.ID.ID, req) 182 if err != nil { 183 return nil, err 184 } 185 return &ci, nil 186} 187 188// GetRawContainerInfo returns the stats (from cadvisor) for a non-Kubernetes 189// container. 190func (p *Provider) GetRawContainerInfo(containerName string, req *cadvisorapiv1.ContainerInfoRequest, subcontainers bool) (map[string]*cadvisorapiv1.ContainerInfo, error) { 191 if subcontainers { 192 return p.cadvisor.SubcontainerInfo(containerName, req) 193 } 194 containerInfo, err := p.cadvisor.ContainerInfo(containerName, req) 195 if err != nil { 196 return nil, err 197 } 198 return map[string]*cadvisorapiv1.ContainerInfo{ 199 containerInfo.Name: containerInfo, 200 }, nil 201} 202 203// HasDedicatedImageFs returns true if a dedicated image filesystem exists for storing images. 204func (p *Provider) HasDedicatedImageFs() (bool, error) { 205 device, err := p.containerStatsProvider.ImageFsDevice() 206 if err != nil { 207 return false, err 208 } 209 rootFsInfo, err := p.cadvisor.RootFsInfo() 210 if err != nil { 211 return false, err 212 } 213 return device != rootFsInfo.Device, nil 214} 215