From 4dad638e453a9b68db65f5e3b964153a93bfc98c Mon Sep 17 00:00:00 2001 From: Ahmed Mezghani Date: Fri, 25 Mar 2022 14:02:06 +0100 Subject: [PATCH] fix the namespace tag name for object count metrics --- .../kubernetes_state/kubernetes_state.py | 50 +++++++++++++------ .../tests/test_kubernetes_state.py | 50 ++++++++++++++----- 2 files changed, 71 insertions(+), 29 deletions(-) diff --git a/kubernetes_state/datadog_checks/kubernetes_state/kubernetes_state.py b/kubernetes_state/datadog_checks/kubernetes_state/kubernetes_state.py index 552c844678cf1..d009f019adfc8 100644 --- a/kubernetes_state/datadog_checks/kubernetes_state/kubernetes_state.py +++ b/kubernetes_state/datadog_checks/kubernetes_state/kubernetes_state.py @@ -95,9 +95,18 @@ def __init__(self, name, init_config, instances): 'kube_persistentvolume_status_phase': { 'metric_name': 'persistentvolumes.by_phase', 'allowed_labels': ['storageclass', 'phase'], + 'label_mapper_override': { + 'phase': 'phase' + }, # prevent kube_labels_mapper from converting the persistentvolume phase into pod_phase }, 'kube_service_spec_type': {'metric_name': 'service.count', 'allowed_labels': ['namespace', 'type']}, - 'kube_namespace_status_phase': {'metric_name': 'namespace.count', 'allowed_labels': ['phase']}, + 'kube_namespace_status_phase': { + 'metric_name': 'namespace.count', + 'allowed_labels': ['phase'], + 'label_mapper_override': { + 'phase': 'phase' + }, # prevent kube_labels_mapper from converting the namespace phase tag into pod_phase + }, 'kube_replicaset_owner': { 'metric_name': 'replicaset.count', 'allowed_labels': ['namespace', 'owner_name', 'owner_kind'], @@ -900,13 +909,7 @@ def sum_values_by_tags(self, metric, scraper_config): object_counter = Counter() for sample in metric.samples: - tags = [] - for l in config['allowed_labels']: - tag = self._label_to_tag(l, sample[self.SAMPLE_LABELS], scraper_config) - if tag is None: - tag = self._format_tag(l, "unknown", scraper_config) - tags.append(tag) - tags += scraper_config['custom_tags'] + tags = self._tags_for_count(sample, config, scraper_config) object_counter[tuple(sorted(tags))] += sample[self.SAMPLE_VALUE] for tags, count in iteritems(object_counter): @@ -919,19 +922,31 @@ def count_objects_by_tags(self, metric, scraper_config): object_counter = Counter() for sample in metric.samples: - tags = [] - for l in config['allowed_labels']: - tag = self._label_to_tag(l, sample[self.SAMPLE_LABELS], scraper_config) - if tag is None: - tag = self._format_tag(l, "unknown", scraper_config) - tags.append(tag) - tags += scraper_config['custom_tags'] + tags = self._tags_for_count(sample, config, scraper_config) object_counter[tuple(sorted(tags))] += 1 for tags, count in iteritems(object_counter): self.gauge(metric_name, count, tags=list(tags)) - def _build_tags(self, label_name, label_value, scraper_config, hostname=None): + def _tags_for_count(self, sample, count_config, scraper_config): + """ + Extracts tags for object count elements. + """ + tags = [] + for l in count_config['allowed_labels']: + value = sample[self.SAMPLE_LABELS].get(l, None) + if not value: + tag = self._format_tag(l, "unknown", scraper_config) + tags.append(tag) + continue + l_mapper_override = count_config.get('label_mapper_override', None) + allowed_tags = self._build_tags(l, value, scraper_config, l_mapper_override=l_mapper_override) + if allowed_tags: + tags += allowed_tags + tags += scraper_config['custom_tags'] + return tags + + def _build_tags(self, label_name, label_value, scraper_config, hostname=None, l_mapper_override=None): """ Build a list of formatted tags from `label_name` parameter. It also depend of the check configuration ('keep_ksm_labels' parameter) @@ -941,6 +956,9 @@ def _build_tags(self, label_name, label_value, scraper_config, hostname=None): tag_name = scraper_config['labels_mapper'].get(label_name, label_name) # then try to use the kube_labels_mapper kube_tag_name = kube_labels_mapper.get(tag_name, tag_name) + # try label mapper override + if l_mapper_override: + kube_tag_name = l_mapper_override.get(tag_name, tag_name) label_value = to_string(label_value).lower() tags.append('{}:{}'.format(to_string(kube_tag_name), label_value)) if self.keep_ksm_labels and (kube_tag_name != tag_name): diff --git a/kubernetes_state/tests/test_kubernetes_state.py b/kubernetes_state/tests/test_kubernetes_state.py index 66d9e3d1c5324..bb7546511243c 100644 --- a/kubernetes_state/tests/test_kubernetes_state.py +++ b/kubernetes_state/tests/test_kubernetes_state.py @@ -372,22 +372,22 @@ def test_update_kube_state_metrics(aggregator, instance, check): # services count aggregator.assert_metric( NAMESPACE + '.service.count', - tags=['namespace:default', 'type:clusterip', 'optional:tag1'], + tags=['kube_namespace:default', 'namespace:default', 'type:clusterip', 'optional:tag1'], value=3, ) aggregator.assert_metric( NAMESPACE + '.service.count', - tags=['namespace:default', 'type:loadbalancer', 'optional:tag1'], + tags=['kube_namespace:default', 'namespace:default', 'type:loadbalancer', 'optional:tag1'], value=2, ) aggregator.assert_metric( NAMESPACE + '.service.count', - tags=['namespace:kube-system', 'type:clusterip', 'optional:tag1'], + tags=['kube_namespace:kube-system', 'namespace:kube-system', 'type:clusterip', 'optional:tag1'], value=4, ) aggregator.assert_metric( NAMESPACE + '.service.count', - tags=['namespace:kube-system', 'type:nodeport', 'optional:tag1'], + tags=['kube_namespace:kube-system', 'namespace:kube-system', 'type:nodeport', 'optional:tag1'], value=1, ) @@ -406,53 +406,77 @@ def test_update_kube_state_metrics(aggregator, instance, check): # replicasets count aggregator.assert_metric( NAMESPACE + '.replicaset.count', - tags=['namespace:kube-system', 'owner_kind:deployment', 'owner_name:l7-default-backend', 'optional:tag1'], + tags=[ + 'kube_namespace:kube-system', + 'namespace:kube-system', + 'owner_kind:deployment', + 'owner_name:l7-default-backend', + 'optional:tag1', + ], value=1, ) aggregator.assert_metric( NAMESPACE + '.replicaset.count', - tags=['namespace:kube-system', 'owner_kind:deployment', 'owner_name:metrics-server-v0.3.6', 'optional:tag1'], + tags=[ + 'kube_namespace:kube-system', + 'namespace:kube-system', + 'owner_kind:deployment', + 'owner_name:metrics-server-v0.3.6', + 'optional:tag1', + ], value=1, ) aggregator.assert_metric( NAMESPACE + '.replicaset.count', - tags=['namespace:kube-system', 'owner_kind:deployment', 'owner_name:kube-dns-autoscaler', 'optional:tag1'], + tags=[ + 'kube_namespace:kube-system', + 'namespace:kube-system', + 'owner_kind:deployment', + 'owner_name:kube-dns-autoscaler', + 'optional:tag1', + ], value=1, ) # jobs count aggregator.assert_metric( NAMESPACE + '.job.count', - tags=['namespace:default', 'owner_kind:cronjob', 'owner_name:a-cronjob', 'optional:tag1'], + tags=[ + 'kube_namespace:default', + 'namespace:default', + 'owner_kind:cronjob', + 'owner_name:a-cronjob', + 'optional:tag1', + ], value=1, ) aggregator.assert_metric( NAMESPACE + '.job.count', - tags=['namespace:default', 'owner_kind:', 'owner_name:', 'optional:tag1'], + tags=['kube_namespace:default', 'namespace:default', 'owner_kind:', 'owner_name:', 'optional:tag1'], value=1, ) # deployments count aggregator.assert_metric( NAMESPACE + '.deployment.count', - tags=['namespace:default', 'optional:tag1'], + tags=['kube_namespace:default', 'namespace:default', 'optional:tag1'], value=2, ) aggregator.assert_metric( NAMESPACE + '.deployment.count', - tags=['namespace:kube-system', 'optional:tag1'], + tags=['kube_namespace:kube-system', 'namespace:kube-system', 'optional:tag1'], value=2, ) # statefulset count aggregator.assert_metric( NAMESPACE + '.statefulset.count', - tags=['namespace:default', 'optional:tag1'], + tags=['kube_namespace:default', 'namespace:default', 'optional:tag1'], value=2, ) aggregator.assert_metric( NAMESPACE + '.statefulset.count', - tags=['namespace:kube-system', 'optional:tag1'], + tags=['kube_namespace:kube-system', 'namespace:kube-system', 'optional:tag1'], value=2, )