github.com/aclisp/heapster@v0.19.2-0.20160613100040-51756f899a96/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 o, exists, err := this.podLister.Get( 69 &kube_api.Pod{ 70 ObjectMeta: kube_api.ObjectMeta{ 71 Namespace: namespace, 72 Name: name, 73 }, 74 }, 75 ) 76 if err != nil { 77 return nil, err 78 } 79 if !exists || o == nil { 80 return nil, fmt.Errorf("cannot find pod definition") 81 } 82 pod, ok := o.(*kube_api.Pod) 83 if !ok { 84 return nil, fmt.Errorf("cache contains wrong type") 85 } 86 return pod, nil 87 } 88 89 func addContainerInfo(key string, containerMs *core.MetricSet, pod *kube_api.Pod, batch *core.DataBatch, newMs map[string]*core.MetricSet) { 90 for _, container := range pod.Spec.Containers { 91 if key == core.PodContainerKey(pod.Namespace, pod.Name, container.Name) { 92 updateContainerResourcesAndLimits(containerMs, container) 93 if _, ok := containerMs.Labels[core.LabelContainerBaseImage.Key]; !ok { 94 containerMs.Labels[core.LabelContainerBaseImage.Key] = container.Image 95 } 96 break 97 } 98 } 99 100 containerMs.Labels[core.LabelPodId.Key] = string(pod.UID) 101 containerMs.Labels[core.LabelLabels.Key] = util.LabelsToString(pod.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 := batch.MetricSets[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.LabelPodNamespace.Key: namespace, 118 core.LabelPodName.Key: podName, 119 core.LabelNodename.Key: containerMs.Labels[core.LabelNodename.Key], 120 core.LabelHostname.Key: containerMs.Labels[core.LabelHostname.Key], 121 core.LabelHostID.Key: containerMs.Labels[core.LabelHostID.Key], 122 }, 123 } 124 newMs[podKey] = podMs 125 addPodInfo(podKey, podMs, pod, batch, newMs) 126 } 127 } 128 } 129 130 func addPodInfo(key string, podMs *core.MetricSet, pod *kube_api.Pod, batch *core.DataBatch, newMs map[string]*core.MetricSet) { 131 132 // Add UID to pod 133 podMs.Labels[core.LabelPodId.Key] = string(pod.UID) 134 podMs.Labels[core.LabelLabels.Key] = util.LabelsToString(pod.Labels, ",") 135 136 // Add cpu/mem requests and limits to containers 137 for _, container := range pod.Spec.Containers { 138 containerKey := core.PodContainerKey(pod.Namespace, pod.Name, container.Name) 139 if _, found := batch.MetricSets[containerKey]; !found { 140 if _, found := newMs[containerKey]; !found { 141 glog.V(2).Infof("Container %s not found, creating a stub", containerKey) 142 containerMs := &core.MetricSet{ 143 MetricValues: make(map[string]core.MetricValue), 144 Labels: map[string]string{ 145 core.LabelMetricSetType.Key: core.MetricSetTypePodContainer, 146 core.LabelNamespaceName.Key: pod.Namespace, 147 core.LabelPodNamespace.Key: pod.Namespace, 148 core.LabelPodName.Key: pod.Name, 149 core.LabelContainerName.Key: container.Name, 150 core.LabelContainerBaseImage.Key: container.Image, 151 core.LabelPodId.Key: string(pod.UID), 152 core.LabelLabels.Key: util.LabelsToString(pod.Labels, ","), 153 core.LabelNodename.Key: podMs.Labels[core.LabelNodename.Key], 154 core.LabelHostname.Key: podMs.Labels[core.LabelHostname.Key], 155 core.LabelHostID.Key: podMs.Labels[core.LabelHostID.Key], 156 }, 157 } 158 updateContainerResourcesAndLimits(containerMs, container) 159 newMs[containerKey] = containerMs 160 } 161 } 162 } 163 } 164 165 func updateContainerResourcesAndLimits(metricSet *core.MetricSet, container kube_api.Container) { 166 requests := container.Resources.Requests 167 if val, found := requests[kube_api.ResourceCPU]; found { 168 metricSet.MetricValues[core.MetricCpuRequest.Name] = intValue(val.MilliValue()) 169 } else { 170 metricSet.MetricValues[core.MetricCpuRequest.Name] = intValue(0) 171 } 172 if val, found := requests[kube_api.ResourceMemory]; found { 173 metricSet.MetricValues[core.MetricMemoryRequest.Name] = intValue(val.Value()) 174 } else { 175 metricSet.MetricValues[core.MetricMemoryRequest.Name] = intValue(0) 176 } 177 178 limits := container.Resources.Limits 179 if val, found := limits[kube_api.ResourceCPU]; found { 180 metricSet.MetricValues[core.MetricCpuLimit.Name] = intValue(val.MilliValue()) 181 } else { 182 metricSet.MetricValues[core.MetricCpuLimit.Name] = intValue(0) 183 } 184 if val, found := limits[kube_api.ResourceMemory]; found { 185 metricSet.MetricValues[core.MetricMemoryLimit.Name] = intValue(val.Value()) 186 } else { 187 metricSet.MetricValues[core.MetricMemoryLimit.Name] = intValue(0) 188 } 189 } 190 191 func intValue(value int64) core.MetricValue { 192 return core.MetricValue{ 193 IntValue: value, 194 MetricType: core.MetricGauge, 195 ValueType: core.ValueInt64, 196 } 197 } 198 199 func NewPodBasedEnricher(podLister *cache.StoreToPodLister) (*PodBasedEnricher, error) { 200 return &PodBasedEnricher{ 201 podLister: podLister, 202 }, nil 203 }