1
16
17 package podresources
18
19 import (
20 "context"
21 "fmt"
22
23 v1 "k8s.io/api/core/v1"
24 utilfeature "k8s.io/apiserver/pkg/util/feature"
25 kubefeatures "k8s.io/kubernetes/pkg/features"
26 "k8s.io/kubernetes/pkg/kubelet/metrics"
27 "k8s.io/kubernetes/pkg/kubelet/types"
28
29 podresourcesv1 "k8s.io/kubelet/pkg/apis/podresources/v1"
30 )
31
32
33 type v1PodResourcesServer struct {
34 podsProvider PodsProvider
35 devicesProvider DevicesProvider
36 cpusProvider CPUsProvider
37 memoryProvider MemoryProvider
38 dynamicResourcesProvider DynamicResourcesProvider
39 }
40
41
42
43 func NewV1PodResourcesServer(providers PodResourcesProviders) podresourcesv1.PodResourcesListerServer {
44 return &v1PodResourcesServer{
45 podsProvider: providers.Pods,
46 devicesProvider: providers.Devices,
47 cpusProvider: providers.Cpus,
48 memoryProvider: providers.Memory,
49 dynamicResourcesProvider: providers.DynamicResources,
50 }
51 }
52
53
54 func (p *v1PodResourcesServer) List(ctx context.Context, req *podresourcesv1.ListPodResourcesRequest) (*podresourcesv1.ListPodResourcesResponse, error) {
55 metrics.PodResourcesEndpointRequestsTotalCount.WithLabelValues("v1").Inc()
56 metrics.PodResourcesEndpointRequestsListCount.WithLabelValues("v1").Inc()
57
58 pods := p.podsProvider.GetPods()
59 podResources := make([]*podresourcesv1.PodResources, len(pods))
60 p.devicesProvider.UpdateAllocatedDevices()
61
62 for i, pod := range pods {
63 pRes := podresourcesv1.PodResources{
64 Name: pod.Name,
65 Namespace: pod.Namespace,
66 Containers: make([]*podresourcesv1.ContainerResources, 0, len(pod.Spec.Containers)),
67 }
68
69 if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.SidecarContainers) {
70 pRes.Containers = make([]*podresourcesv1.ContainerResources, 0, len(pod.Spec.InitContainers)+len(pod.Spec.Containers))
71
72 for _, container := range pod.Spec.InitContainers {
73 if !types.IsRestartableInitContainer(&container) {
74 continue
75 }
76
77 pRes.Containers = append(pRes.Containers, p.getContainerResources(pod, &container))
78 }
79 }
80
81 for _, container := range pod.Spec.Containers {
82 pRes.Containers = append(pRes.Containers, p.getContainerResources(pod, &container))
83 }
84 podResources[i] = &pRes
85 }
86
87 response := &podresourcesv1.ListPodResourcesResponse{
88 PodResources: podResources,
89 }
90 return response, nil
91 }
92
93
94 func (p *v1PodResourcesServer) GetAllocatableResources(ctx context.Context, req *podresourcesv1.AllocatableResourcesRequest) (*podresourcesv1.AllocatableResourcesResponse, error) {
95 metrics.PodResourcesEndpointRequestsTotalCount.WithLabelValues("v1").Inc()
96 metrics.PodResourcesEndpointRequestsGetAllocatableCount.WithLabelValues("v1").Inc()
97
98 response := &podresourcesv1.AllocatableResourcesResponse{
99 Devices: p.devicesProvider.GetAllocatableDevices(),
100 CpuIds: p.cpusProvider.GetAllocatableCPUs(),
101 Memory: p.memoryProvider.GetAllocatableMemory(),
102 }
103
104 return response, nil
105 }
106
107
108 func (p *v1PodResourcesServer) Get(ctx context.Context, req *podresourcesv1.GetPodResourcesRequest) (*podresourcesv1.GetPodResourcesResponse, error) {
109 metrics.PodResourcesEndpointRequestsTotalCount.WithLabelValues("v1").Inc()
110 metrics.PodResourcesEndpointRequestsGetCount.WithLabelValues("v1").Inc()
111
112 if !utilfeature.DefaultFeatureGate.Enabled(kubefeatures.KubeletPodResourcesGet) {
113 metrics.PodResourcesEndpointErrorsGetCount.WithLabelValues("v1").Inc()
114 return nil, fmt.Errorf("PodResources API Get method disabled")
115 }
116
117 pod, exist := p.podsProvider.GetPodByName(req.PodNamespace, req.PodName)
118 if !exist {
119 metrics.PodResourcesEndpointErrorsGetCount.WithLabelValues("v1").Inc()
120 return nil, fmt.Errorf("pod %s in namespace %s not found", req.PodName, req.PodNamespace)
121 }
122
123 podResources := &podresourcesv1.PodResources{
124 Name: pod.Name,
125 Namespace: pod.Namespace,
126 Containers: make([]*podresourcesv1.ContainerResources, 0, len(pod.Spec.Containers)),
127 }
128
129 if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.SidecarContainers) {
130 podResources.Containers = make([]*podresourcesv1.ContainerResources, 0, len(pod.Spec.InitContainers)+len(pod.Spec.Containers))
131
132 for _, container := range pod.Spec.InitContainers {
133 if !types.IsRestartableInitContainer(&container) {
134 continue
135 }
136
137 podResources.Containers = append(podResources.Containers, p.getContainerResources(pod, &container))
138 }
139 }
140
141 for _, container := range pod.Spec.Containers {
142 podResources.Containers = append(podResources.Containers, p.getContainerResources(pod, &container))
143 }
144
145 response := &podresourcesv1.GetPodResourcesResponse{
146 PodResources: podResources,
147 }
148 return response, nil
149 }
150
151 func (p *v1PodResourcesServer) getContainerResources(pod *v1.Pod, container *v1.Container) *podresourcesv1.ContainerResources {
152 containerResources := &podresourcesv1.ContainerResources{
153 Name: container.Name,
154 Devices: p.devicesProvider.GetDevices(string(pod.UID), container.Name),
155 CpuIds: p.cpusProvider.GetCPUs(string(pod.UID), container.Name),
156 Memory: p.memoryProvider.GetMemory(string(pod.UID), container.Name),
157 }
158 if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.KubeletPodResourcesDynamicResources) {
159 containerResources.DynamicResources = p.dynamicResourcesProvider.GetDynamicResources(pod, container)
160 }
161
162 return containerResources
163 }
164
View as plain text