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  }