1
16
17 package stats
18
19 import (
20 "context"
21 "fmt"
22
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 "k8s.io/kubernetes/pkg/kubelet/server/stats"
30 "k8s.io/kubernetes/pkg/kubelet/stats/pidlimit"
31 "k8s.io/kubernetes/pkg/kubelet/status"
32 kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
33 "k8s.io/utils/ptr"
34 )
35
36
37
38 type PodManager interface {
39 TranslatePodUID(uid types.UID) kubetypes.ResolvedPodUID
40 }
41
42
43
44 func NewCRIStatsProvider(
45 cadvisor cadvisor.Interface,
46 resourceAnalyzer stats.ResourceAnalyzer,
47 podManager PodManager,
48 runtimeCache kubecontainer.RuntimeCache,
49 runtimeService internalapi.RuntimeService,
50 imageService internalapi.ImageManagerService,
51 hostStatsProvider HostStatsProvider,
52 podAndContainerStatsFromCRI bool,
53 ) *Provider {
54 return newStatsProvider(cadvisor, podManager, runtimeCache, newCRIStatsProvider(cadvisor, resourceAnalyzer,
55 runtimeService, imageService, hostStatsProvider, podAndContainerStatsFromCRI))
56 }
57
58
59
60 func NewCadvisorStatsProvider(
61 cadvisor cadvisor.Interface,
62 resourceAnalyzer stats.ResourceAnalyzer,
63 podManager PodManager,
64 runtimeCache kubecontainer.RuntimeCache,
65 imageService kubecontainer.ImageService,
66 statusProvider status.PodStatusProvider,
67 hostStatsProvider HostStatsProvider,
68 ) *Provider {
69 return newStatsProvider(cadvisor, podManager, runtimeCache, newCadvisorStatsProvider(cadvisor, resourceAnalyzer, imageService, statusProvider, hostStatsProvider))
70 }
71
72
73
74 func newStatsProvider(
75 cadvisor cadvisor.Interface,
76 podManager PodManager,
77 runtimeCache kubecontainer.RuntimeCache,
78 containerStatsProvider containerStatsProvider,
79 ) *Provider {
80 return &Provider{
81 cadvisor: cadvisor,
82 podManager: podManager,
83 runtimeCache: runtimeCache,
84 containerStatsProvider: containerStatsProvider,
85 }
86 }
87
88
89 type Provider struct {
90 cadvisor cadvisor.Interface
91 podManager PodManager
92 runtimeCache kubecontainer.RuntimeCache
93 containerStatsProvider
94 }
95
96
97
98 type containerStatsProvider interface {
99 ListPodStats(ctx context.Context) ([]statsapi.PodStats, error)
100 ListPodStatsAndUpdateCPUNanoCoreUsage(ctx context.Context) ([]statsapi.PodStats, error)
101 ListPodCPUAndMemoryStats(ctx context.Context) ([]statsapi.PodStats, error)
102 ImageFsStats(ctx context.Context) (*statsapi.FsStats, *statsapi.FsStats, error)
103 ImageFsDevice(ctx context.Context) (string, error)
104 }
105
106
107 func (p *Provider) RlimitStats() (*statsapi.RlimitStats, error) {
108 return pidlimit.Stats()
109 }
110
111
112
113 func (p *Provider) GetCgroupStats(cgroupName string, updateStats bool) (*statsapi.ContainerStats, *statsapi.NetworkStats, error) {
114 info, err := getCgroupInfo(p.cadvisor, cgroupName, updateStats)
115 if err != nil {
116 return nil, nil, fmt.Errorf("failed to get cgroup stats for %q: %v", cgroupName, err)
117 }
118
119 s := cadvisorInfoToContainerStats(cgroupName, info, nil, nil)
120 n := cadvisorInfoToNetworkStats(info)
121 return s, n, nil
122 }
123
124
125
126 func (p *Provider) GetCgroupCPUAndMemoryStats(cgroupName string, updateStats bool) (*statsapi.ContainerStats, error) {
127 info, err := getCgroupInfo(p.cadvisor, cgroupName, updateStats)
128 if err != nil {
129 return nil, fmt.Errorf("failed to get cgroup stats for %q: %v", cgroupName, err)
130 }
131
132 s := cadvisorInfoToContainerCPUAndMemoryStats(cgroupName, info)
133 return s, nil
134 }
135
136
137 func (p *Provider) RootFsStats() (*statsapi.FsStats, error) {
138 rootFsInfo, err := p.cadvisor.RootFsInfo()
139 if err != nil {
140 return nil, fmt.Errorf("failed to get rootFs info: %v", err)
141 }
142
143 var nodeFsInodesUsed *uint64
144 if rootFsInfo.Inodes != nil && rootFsInfo.InodesFree != nil {
145 nodeFsIU := *rootFsInfo.Inodes - *rootFsInfo.InodesFree
146 nodeFsInodesUsed = &nodeFsIU
147 }
148
149
150
151 rootStats, err := getCgroupStats(p.cadvisor, "/", false)
152 if err != nil {
153 return nil, fmt.Errorf("failed to get root container stats: %v", err)
154 }
155
156 return &statsapi.FsStats{
157 Time: metav1.NewTime(rootStats.Timestamp),
158 AvailableBytes: &rootFsInfo.Available,
159 CapacityBytes: &rootFsInfo.Capacity,
160 UsedBytes: &rootFsInfo.Usage,
161 InodesFree: rootFsInfo.InodesFree,
162 Inodes: rootFsInfo.Inodes,
163 InodesUsed: nodeFsInodesUsed,
164 }, nil
165 }
166
167
168
169 func (p *Provider) HasDedicatedImageFs(ctx context.Context) (bool, error) {
170 device, err := p.containerStatsProvider.ImageFsDevice(ctx)
171 if err != nil {
172 return false, err
173 }
174 rootFsInfo, err := p.cadvisor.RootFsInfo()
175 if err != nil {
176 return false, err
177 }
178
179
180 if device == rootFsInfo.Device {
181 imageFs, containerFs, err := p.ImageFsStats(ctx)
182 if err != nil {
183 return false, err
184 }
185 if !equalFileSystems(imageFs, containerFs) {
186 return true, nil
187 }
188 }
189 return device != rootFsInfo.Device, nil
190 }
191
192 func equalFileSystems(a, b *statsapi.FsStats) bool {
193 if a == nil || b == nil {
194 return false
195 }
196 if !ptr.Equal(a.AvailableBytes, b.AvailableBytes) {
197 return false
198 }
199 if !ptr.Equal(a.CapacityBytes, b.CapacityBytes) {
200 return false
201 }
202 if !ptr.Equal(a.InodesUsed, b.InodesUsed) {
203 return false
204 }
205 if !ptr.Equal(a.InodesFree, b.InodesFree) {
206 return false
207 }
208 if !ptr.Equal(a.Inodes, b.Inodes) {
209 return false
210 }
211 return true
212 }
213
View as plain text