github.com/galamsiva2020/kubernetes-heapster-monitoring@v0.0.0-20210823134957-3c1baa7c1e70/metrics/processors/pod_based_enricher.go (about) 1 // Copyright 2015 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package processors 16 17 import ( 18 "fmt" 19 20 "github.com/golang/glog" 21 22 "k8s.io/heapster/metrics/util" 23 24 kube_api "k8s.io/api/core/v1" 25 v1listers "k8s.io/client-go/listers/core/v1" 26 "k8s.io/heapster/metrics/core" 27 ) 28 29 type PodBasedEnricher struct { 30 podLister v1listers.PodLister 31 labelCopier *util.LabelCopier 32 } 33 34 func (this *PodBasedEnricher) Name() string { 35 return "pod_based_enricher" 36 } 37 38 func (this *PodBasedEnricher) Process(batch *core.DataBatch) (*core.DataBatch, error) { 39 newMs := make(map[string]*core.MetricSet, len(batch.MetricSets)) 40 for k, v := range batch.MetricSets { 41 switch v.Labels[core.LabelMetricSetType.Key] { 42 case core.MetricSetTypePod: 43 namespace := v.Labels[core.LabelNamespaceName.Key] 44 podName := v.Labels[core.LabelPodName.Key] 45 pod, err := this.getPod(namespace, podName) 46 if err != nil { 47 glog.V(3).Infof("Failed to get pod %s from cache: %v", core.PodKey(namespace, podName), err) 48 continue 49 } 50 this.addPodInfo(k, v, pod, batch, newMs) 51 case core.MetricSetTypePodContainer: 52 namespace := v.Labels[core.LabelNamespaceName.Key] 53 podName := v.Labels[core.LabelPodName.Key] 54 pod, err := this.getPod(namespace, podName) 55 if err != nil { 56 glog.V(3).Infof("Failed to get pod %s from cache: %v", core.PodKey(namespace, podName), err) 57 continue 58 } 59 this.addContainerInfo(k, v, pod, batch, newMs) 60 } 61 } 62 for k, v := range newMs { 63 batch.MetricSets[k] = v 64 } 65 return batch, nil 66 } 67 68 func (this *PodBasedEnricher) getPod(namespace, name string) (*kube_api.Pod, error) { 69 pod, err := this.podLister.Pods(namespace).Get(name) 70 if err != nil { 71 return nil, err 72 } 73 if pod == nil { 74 return nil, fmt.Errorf("cannot find pod definition") 75 } 76 return pod, nil 77 } 78 79 func (this *PodBasedEnricher) addContainerInfo(key string, containerMs *core.MetricSet, pod *kube_api.Pod, batch *core.DataBatch, newMs map[string]*core.MetricSet) { 80 for _, container := range pod.Spec.Containers { 81 if key == core.PodContainerKey(pod.Namespace, pod.Name, container.Name) { 82 updateContainerResourcesAndLimits(containerMs, container) 83 if _, ok := containerMs.Labels[core.LabelContainerBaseImage.Key]; !ok { 84 containerMs.Labels[core.LabelContainerBaseImage.Key] = container.Image 85 } 86 break 87 } 88 } 89 90 for _, containerStatus := range pod.Status.ContainerStatuses { 91 if key == core.PodContainerKey(pod.Namespace, pod.Name, containerStatus.Name) { 92 containerMs.MetricValues[core.MetricRestartCount.Name] = intValue(int64(containerStatus.RestartCount)) 93 if !pod.Status.StartTime.IsZero() { 94 containerMs.EntityCreateTime = pod.Status.StartTime.Time 95 } 96 break 97 } 98 } 99 100 containerMs.Labels[core.LabelPodId.Key] = string(pod.UID) 101 this.labelCopier.Copy(pod.Labels, containerMs.Labels) 102 103 namespace := containerMs.Labels[core.LabelNamespaceName.Key] 104 podName := containerMs.Labels[core.LabelPodName.Key] 105 106 podKey := core.PodKey(namespace, podName) 107 _, oldfound := batch.MetricSets[podKey] 108 if !oldfound { 109 _, newfound := newMs[podKey] 110 if !newfound { 111 glog.V(2).Infof("Pod %s not found, creating a stub", podKey) 112 podMs := &core.MetricSet{ 113 MetricValues: make(map[string]core.MetricValue), 114 Labels: map[string]string{ 115 core.LabelMetricSetType.Key: core.MetricSetTypePod, 116 core.LabelNamespaceName.Key: namespace, 117 core.LabelPodName.Key: podName, 118 core.LabelNodename.Key: containerMs.Labels[core.LabelNodename.Key], 119 core.LabelHostname.Key: containerMs.Labels[core.LabelHostname.Key], 120 core.LabelHostID.Key: containerMs.Labels[core.LabelHostID.Key], 121 }, 122 } 123 if !pod.Status.StartTime.IsZero() { 124 podMs.EntityCreateTime = pod.Status.StartTime.Time 125 } 126 newMs[podKey] = podMs 127 this.addPodInfo(podKey, podMs, pod, batch, newMs) 128 } 129 } 130 } 131 132 func (this *PodBasedEnricher) addPodInfo(key string, podMs *core.MetricSet, pod *kube_api.Pod, batch *core.DataBatch, newMs map[string]*core.MetricSet) { 133 134 // Add UID and create time to pod 135 podMs.Labels[core.LabelPodId.Key] = string(pod.UID) 136 if !pod.Status.StartTime.IsZero() { 137 podMs.EntityCreateTime = pod.Status.StartTime.Time 138 } 139 this.labelCopier.Copy(pod.Labels, podMs.Labels) 140 141 // Add cpu/mem requests and limits to containers 142 for _, container := range pod.Spec.Containers { 143 containerKey := core.PodContainerKey(pod.Namespace, pod.Name, container.Name) 144 if _, found := batch.MetricSets[containerKey]; found { 145 continue 146 } 147 if _, found := newMs[containerKey]; found { 148 continue 149 } 150 glog.V(2).Infof("Container %s not found, creating a stub", containerKey) 151 containerMs := &core.MetricSet{ 152 MetricValues: make(map[string]core.MetricValue), 153 Labels: map[string]string{ 154 core.LabelMetricSetType.Key: core.MetricSetTypePodContainer, 155 core.LabelNamespaceName.Key: pod.Namespace, 156 core.LabelPodName.Key: pod.Name, 157 core.LabelContainerName.Key: container.Name, 158 core.LabelContainerBaseImage.Key: container.Image, 159 core.LabelPodId.Key: string(pod.UID), 160 core.LabelNodename.Key: podMs.Labels[core.LabelNodename.Key], 161 core.LabelHostname.Key: podMs.Labels[core.LabelHostname.Key], 162 core.LabelHostID.Key: podMs.Labels[core.LabelHostID.Key], 163 }, 164 EntityCreateTime: podMs.CollectionStartTime, 165 } 166 this.labelCopier.Copy(pod.Labels, containerMs.Labels) 167 updateContainerResourcesAndLimits(containerMs, container) 168 newMs[containerKey] = containerMs 169 } 170 } 171 172 func updateContainerResourcesAndLimits(metricSet *core.MetricSet, container kube_api.Container) { 173 requests := container.Resources.Requests 174 175 for key, val := range container.Resources.Requests { 176 metric, found := core.ResourceRequestMetrics[key] 177 // Inserts a metric to core.ResourceRequestMetrics if there is no 178 // existing one for the given resource. The name of this metric is 179 // ResourceName/request where ResourceName is the name of the resource 180 // requested in container resource requests. 181 if !found { 182 metric = core.Metric{ 183 MetricDescriptor: core.MetricDescriptor{ 184 Name: string(key) + "/request", 185 Description: string(key) + " resource request. This metric is Kubernetes specific.", 186 Type: core.MetricGauge, 187 ValueType: core.ValueInt64, 188 Units: core.UnitsCount, 189 }, 190 } 191 core.ResourceRequestMetrics[key] = metric 192 } 193 if key == kube_api.ResourceCPU { 194 metricSet.MetricValues[metric.Name] = intValue(val.MilliValue()) 195 } else { 196 metricSet.MetricValues[metric.Name] = intValue(val.Value()) 197 } 198 } 199 200 // For primary resources like cpu and memory, explicitly sets their request resource 201 // metric to zero if they are not requested. 202 if _, found := requests[kube_api.ResourceCPU]; !found { 203 metricSet.MetricValues[core.MetricCpuRequest.Name] = intValue(0) 204 } 205 if _, found := requests[kube_api.ResourceMemory]; !found { 206 metricSet.MetricValues[core.MetricMemoryRequest.Name] = intValue(0) 207 } 208 if _, found := requests[kube_api.ResourceEphemeralStorage]; !found { 209 metricSet.MetricValues[core.MetricEphemeralStorageRequest.Name] = intValue(0) 210 } 211 212 limits := container.Resources.Limits 213 if val, found := limits[kube_api.ResourceCPU]; found { 214 metricSet.MetricValues[core.MetricCpuLimit.Name] = intValue(val.MilliValue()) 215 } else { 216 metricSet.MetricValues[core.MetricCpuLimit.Name] = intValue(0) 217 } 218 if val, found := limits[kube_api.ResourceMemory]; found { 219 metricSet.MetricValues[core.MetricMemoryLimit.Name] = intValue(val.Value()) 220 } else { 221 metricSet.MetricValues[core.MetricMemoryLimit.Name] = intValue(0) 222 } 223 if val, found := limits[kube_api.ResourceEphemeralStorage]; found { 224 metricSet.MetricValues[core.MetricEphemeralStorageLimit.Name] = intValue(val.Value()) 225 } else { 226 metricSet.MetricValues[core.MetricEphemeralStorageLimit.Name] = intValue(0) 227 } 228 } 229 230 func intValue(value int64) core.MetricValue { 231 return core.MetricValue{ 232 IntValue: value, 233 MetricType: core.MetricGauge, 234 ValueType: core.ValueInt64, 235 } 236 } 237 238 func NewPodBasedEnricher(podLister v1listers.PodLister, labelCopier *util.LabelCopier) (*PodBasedEnricher, error) { 239 return &PodBasedEnricher{ 240 podLister: podLister, 241 labelCopier: labelCopier, 242 }, nil 243 }