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  }