github.com/jonaz/heapster@v1.3.0-beta.0.0.20170208112634-cd3c15ca3d29/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 "k8s.io/heapster/metrics/core" 25 kube_api "k8s.io/kubernetes/pkg/api" 26 "k8s.io/kubernetes/pkg/client/cache" 27 ) 28 29 type PodBasedEnricher struct { 30 podLister *cache.StoreToPodLister 31 } 32 33 func (this *PodBasedEnricher) Name() string { 34 return "pod_based_enricher" 35 } 36 37 func (this *PodBasedEnricher) Process(batch *core.DataBatch) (*core.DataBatch, error) { 38 newMs := make(map[string]*core.MetricSet, len(batch.MetricSets)) 39 for k, v := range batch.MetricSets { 40 switch v.Labels[core.LabelMetricSetType.Key] { 41 case core.MetricSetTypePod: 42 namespace := v.Labels[core.LabelNamespaceName.Key] 43 podName := v.Labels[core.LabelPodName.Key] 44 pod, err := this.getPod(namespace, podName) 45 if err != nil { 46 glog.V(3).Infof("Failed to get pod %s from cache: %v", core.PodKey(namespace, podName), err) 47 continue 48 } 49 addPodInfo(k, v, pod, batch, newMs) 50 case core.MetricSetTypePodContainer: 51 namespace := v.Labels[core.LabelNamespaceName.Key] 52 podName := v.Labels[core.LabelPodName.Key] 53 pod, err := this.getPod(namespace, podName) 54 if err != nil { 55 glog.V(3).Infof("Failed to get pod %s from cache: %v", core.PodKey(namespace, podName), err) 56 continue 57 } 58 addContainerInfo(k, v, pod, batch, newMs) 59 } 60 } 61 for k, v := range newMs { 62 batch.MetricSets[k] = v 63 } 64 return batch, nil 65 } 66 67 func (this *PodBasedEnricher) getPod(namespace, name string) (*kube_api.Pod, error) { 68 pod, err := this.podLister.Pods(namespace).Get(name) 69 if err != nil { 70 return nil, err 71 } 72 if pod == nil { 73 return nil, fmt.Errorf("cannot find pod definition") 74 } 75 return pod, nil 76 } 77 78 func addContainerInfo(key string, containerMs *core.MetricSet, pod *kube_api.Pod, batch *core.DataBatch, newMs map[string]*core.MetricSet) { 79 for _, container := range pod.Spec.Containers { 80 if key == core.PodContainerKey(pod.Namespace, pod.Name, container.Name) { 81 updateContainerResourcesAndLimits(containerMs, container) 82 if _, ok := containerMs.Labels[core.LabelContainerBaseImage.Key]; !ok { 83 containerMs.Labels[core.LabelContainerBaseImage.Key] = container.Image 84 } 85 break 86 } 87 } 88 89 containerMs.Labels[core.LabelPodId.Key] = string(pod.UID) 90 containerMs.Labels[core.LabelLabels.Key] = util.LabelsToString(pod.Labels) 91 92 namespace := containerMs.Labels[core.LabelNamespaceName.Key] 93 podName := containerMs.Labels[core.LabelPodName.Key] 94 95 podKey := core.PodKey(namespace, podName) 96 _, oldfound := batch.MetricSets[podKey] 97 if !oldfound { 98 _, newfound := newMs[podKey] 99 if !newfound { 100 glog.V(2).Infof("Pod %s not found, creating a stub", podKey) 101 podMs := &core.MetricSet{ 102 MetricValues: make(map[string]core.MetricValue), 103 Labels: map[string]string{ 104 core.LabelMetricSetType.Key: core.MetricSetTypePod, 105 core.LabelNamespaceName.Key: namespace, 106 core.LabelPodNamespace.Key: namespace, 107 core.LabelPodName.Key: podName, 108 core.LabelNodename.Key: containerMs.Labels[core.LabelNodename.Key], 109 core.LabelHostname.Key: containerMs.Labels[core.LabelHostname.Key], 110 core.LabelHostID.Key: containerMs.Labels[core.LabelHostID.Key], 111 }, 112 } 113 newMs[podKey] = podMs 114 addPodInfo(podKey, podMs, pod, batch, newMs) 115 } 116 } 117 } 118 119 func addPodInfo(key string, podMs *core.MetricSet, pod *kube_api.Pod, batch *core.DataBatch, newMs map[string]*core.MetricSet) { 120 121 // Add UID to pod 122 podMs.Labels[core.LabelPodId.Key] = string(pod.UID) 123 podMs.Labels[core.LabelLabels.Key] = util.LabelsToString(pod.Labels) 124 125 // Add cpu/mem requests and limits to containers 126 for _, container := range pod.Spec.Containers { 127 containerKey := core.PodContainerKey(pod.Namespace, pod.Name, container.Name) 128 if _, found := batch.MetricSets[containerKey]; !found { 129 if _, found := newMs[containerKey]; !found { 130 glog.V(2).Infof("Container %s not found, creating a stub", containerKey) 131 containerMs := &core.MetricSet{ 132 MetricValues: make(map[string]core.MetricValue), 133 Labels: map[string]string{ 134 core.LabelMetricSetType.Key: core.MetricSetTypePodContainer, 135 core.LabelNamespaceName.Key: pod.Namespace, 136 core.LabelPodNamespace.Key: pod.Namespace, 137 core.LabelPodName.Key: pod.Name, 138 core.LabelContainerName.Key: container.Name, 139 core.LabelContainerBaseImage.Key: container.Image, 140 core.LabelPodId.Key: string(pod.UID), 141 core.LabelLabels.Key: util.LabelsToString(pod.Labels), 142 core.LabelNodename.Key: podMs.Labels[core.LabelNodename.Key], 143 core.LabelHostname.Key: podMs.Labels[core.LabelHostname.Key], 144 core.LabelHostID.Key: podMs.Labels[core.LabelHostID.Key], 145 }, 146 } 147 updateContainerResourcesAndLimits(containerMs, container) 148 newMs[containerKey] = containerMs 149 } 150 } 151 } 152 } 153 154 func updateContainerResourcesAndLimits(metricSet *core.MetricSet, container kube_api.Container) { 155 requests := container.Resources.Requests 156 if val, found := requests[kube_api.ResourceCPU]; found { 157 metricSet.MetricValues[core.MetricCpuRequest.Name] = intValue(val.MilliValue()) 158 } else { 159 metricSet.MetricValues[core.MetricCpuRequest.Name] = intValue(0) 160 } 161 if val, found := requests[kube_api.ResourceMemory]; found { 162 metricSet.MetricValues[core.MetricMemoryRequest.Name] = intValue(val.Value()) 163 } else { 164 metricSet.MetricValues[core.MetricMemoryRequest.Name] = intValue(0) 165 } 166 167 limits := container.Resources.Limits 168 if val, found := limits[kube_api.ResourceCPU]; found { 169 metricSet.MetricValues[core.MetricCpuLimit.Name] = intValue(val.MilliValue()) 170 } else { 171 metricSet.MetricValues[core.MetricCpuLimit.Name] = intValue(0) 172 } 173 if val, found := limits[kube_api.ResourceMemory]; found { 174 metricSet.MetricValues[core.MetricMemoryLimit.Name] = intValue(val.Value()) 175 } else { 176 metricSet.MetricValues[core.MetricMemoryLimit.Name] = intValue(0) 177 } 178 } 179 180 func intValue(value int64) core.MetricValue { 181 return core.MetricValue{ 182 IntValue: value, 183 MetricType: core.MetricGauge, 184 ValueType: core.ValueInt64, 185 } 186 } 187 188 func NewPodBasedEnricher(podLister *cache.StoreToPodLister) (*PodBasedEnricher, error) { 189 return &PodBasedEnricher{ 190 podLister: podLister, 191 }, nil 192 }