From 56559489d423fc2cedcfbabd571cfebd65407280 Mon Sep 17 00:00:00 2001 From: Richard Tief Date: Wed, 21 Feb 2024 15:22:13 +0100 Subject: [PATCH 1/9] feat:export complex nested values as a metric --- BaseCollector.py | 1 + collectors/PropertiesCollector.py | 16 ++++++++ collectors/SDRSPropertiesCollector.py | 56 +++++++++++++++++++++++++++ collectors/SDRSStatsCollector.py | 2 +- tests/collector_config.yaml | 5 +++ 5 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 collectors/SDRSPropertiesCollector.py diff --git a/BaseCollector.py b/BaseCollector.py index 13dea3e9..01f5f957 100644 --- a/BaseCollector.py +++ b/BaseCollector.py @@ -24,6 +24,7 @@ def __init__(self): self.label_names = [] self.project_ids = [] self.collect_running = False + self.nested_value_metric_keys = [] @abstractmethod def collect(self): diff --git a/collectors/PropertiesCollector.py b/collectors/PropertiesCollector.py index b4896055..85af5f6b 100644 --- a/collectors/PropertiesCollector.py +++ b/collectors/PropertiesCollector.py @@ -9,12 +9,17 @@ class PropertiesCollector(BaseCollector): def get_resource_uuids(self): raise NotImplementedError("Please Implement this method") + def unlock_nested_values(self): + raise NotImplementedError("Please Implement this method") + def get_labels(self, resource_id: str, project_ids: list): raise NotImplementedError("Please Implement this method") def collect(self): self.collect_running = True logger.info(f'{self.name} starts with collecting the metrics') + if self.nested_value_metric_keys: + logger.info(f'Found nested metric values for: {self.name}, keys: {self.nested_value_metric_keys}') token = self.get_target_tokens() token = token.setdefault(self.target, '') @@ -60,6 +65,17 @@ def collect(self): metric_data = value_entry.get('data', [False])[0] metric_value = value_entry.get('values', [False])[0] + if statkey in self.nested_value_metric_keys: + n_labels, n_label_values, n_value = self.unlock_nested_values(statkey, metric_value) + labels.extend(n_label_values) + + if labels[0] not in metrics[statkey]['gauge']._labelnames: + for label in n_labels: + metrics[statkey]['gauge']._labelnames += (label,) + + metrics[statkey]['gauge'].add_metric(labels=labels, value=n_value) + continue + if statkey in metrics: # enum metrics if metrics[statkey]['expected']: diff --git a/collectors/SDRSPropertiesCollector.py b/collectors/SDRSPropertiesCollector.py new file mode 100644 index 00000000..3c0e353d --- /dev/null +++ b/collectors/SDRSPropertiesCollector.py @@ -0,0 +1,56 @@ +from collectors.PropertiesCollector import PropertiesCollector +import json + +class SDRSPropertiesCollector(PropertiesCollector): + + def __init__(self): + super().__init__() + self.vrops_entity_name = 'storagepod' + self.label_names = [self.vrops_entity_name, 'vcenter', 'datacenter'] + self.nested_value_metric_keys = [ + "config|sdrsconfig|vmStorageAntiAffinityRules" + ] + + def get_resource_uuids(self): + return self.get_SDRS_clusters_by_target() + + def get_labels(self, resource_id, project_ids): + return [self.sdrs_clusters[resource_id]['name'], + self.sdrs_clusters[resource_id]['vcenter'], + self.sdrs_clusters[resource_id]['parent_dc_name'].lower()] if resource_id in self.sdrs_clusters else [] + + def unlock_nested_values(self, statkey, metric_value): + + match statkey: + case "config|sdrsconfig|vmStorageAntiAffinityRules": + return self.config_sdrsconfig_vmStorageAntiAffinityRules(metric_value) + + def config_sdrsconfig_vmStorageAntiAffinityRules(self, metric_value): + + metric_value = json.loads(metric_value) + rules = metric_value.get("rules") if metric_value.get("rules") else [] + + amount_rules = len(rules) if rules else 0 + + rule_labels = ['rules', 'rule_name', 'rule_type', 'valid', 'virtualmachines'] + rule_label_values = [] + + for i, rule in enumerate(rules): + rule_label_values.extend([ + f'{i+1}/{amount_rules}', + rule.get('name'), + rule.get('type'), + str(rule.get('valid')).lower(), + self.vm_mapping_helper(rule.get('virtualMachines')) + ]) + + return rule_labels, rule_label_values, amount_rules + + def vm_mapping_helper(self, vm_list): + mapped_vms = [] + vms = self.get_vms(self.target) + for rule_vm in vm_list: + for vm in vms: + if rule_vm == vms[vm].get('internal_name'): + mapped_vms.append(vms[vm].get('name')) + return str(mapped_vms) diff --git a/collectors/SDRSStatsCollector.py b/collectors/SDRSStatsCollector.py index 0fb93a5e..0c266de2 100644 --- a/collectors/SDRSStatsCollector.py +++ b/collectors/SDRSStatsCollector.py @@ -14,4 +14,4 @@ def get_resource_uuids(self): def get_labels(self, resource_id, project_ids): return [self.sdrs_clusters[resource_id]['name'], self.sdrs_clusters[resource_id]['vcenter'], - self.sdrs_clusters[resource_id]['parent_dc_name'].lower()] if resource_id in self.sdrs_clusters else [] \ No newline at end of file + self.sdrs_clusters[resource_id]['parent_dc_name'].lower()] if resource_id in self.sdrs_clusters else [] diff --git a/tests/collector_config.yaml b/tests/collector_config.yaml index a905c616..6809670c 100644 --- a/tests/collector_config.yaml +++ b/tests/collector_config.yaml @@ -10,6 +10,7 @@ default_collectors: - 'DistributedvSwitchPropertiesCollector' - 'DatastoreStatsCollector' - 'SDRSStatsCollector' + - 'SDRSPropertiesCollector' - 'DatastorePropertiesCollector' - 'HostSystemStatsCollector' - 'HostSystemPropertiesCollector' @@ -102,6 +103,10 @@ SDRSStatsCollector: - metric_suffix: "capacity_remaining_percentage" key: "OnlineCapacityAnalytics|capacityRemainingPercentage" +SDRSPropertiesCollector: + - metric_suffix: "config_sdrsconfig_vmStorageAntiAffinityRules" + key: "config|sdrsconfig|vmStorageAntiAffinityRules" + DatastorePropertiesCollector: - metric_suffix: "summary_datastore_accessible" expected: "PoweredOn" From 4c238661ddacd2337ae99f51e793e5bcd70328e4 Mon Sep 17 00:00:00 2001 From: Richard Tief Date: Thu, 22 Feb 2024 10:35:15 +0100 Subject: [PATCH 2/9] one metric per vm --- collectors/PropertiesCollector.py | 19 ++++++++++--------- collectors/SDRSPropertiesCollector.py | 26 +++++++++++++++----------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/collectors/PropertiesCollector.py b/collectors/PropertiesCollector.py index 85af5f6b..9473c3b4 100644 --- a/collectors/PropertiesCollector.py +++ b/collectors/PropertiesCollector.py @@ -9,7 +9,7 @@ class PropertiesCollector(BaseCollector): def get_resource_uuids(self): raise NotImplementedError("Please Implement this method") - def unlock_nested_values(self): + def unlock_nested_values(self, s, m): raise NotImplementedError("Please Implement this method") def get_labels(self, resource_id: str, project_ids: list): @@ -66,14 +66,15 @@ def collect(self): metric_value = value_entry.get('values', [False])[0] if statkey in self.nested_value_metric_keys: - n_labels, n_label_values, n_value = self.unlock_nested_values(statkey, metric_value) - labels.extend(n_label_values) - - if labels[0] not in metrics[statkey]['gauge']._labelnames: - for label in n_labels: - metrics[statkey]['gauge']._labelnames += (label,) - - metrics[statkey]['gauge'].add_metric(labels=labels, value=n_value) + add_labels, add_label_value_list, add_value = self.unlock_nested_values(statkey, metric_value) + if add_labels[0] not in metrics[statkey]['gauge']._labelnames: + for add_label in add_labels: + metrics[statkey]['gauge']._labelnames += (add_label,) + + for add_label_value in add_label_value_list: + _ = [labels.append(l) for l in add_label_value] + metrics[statkey]['gauge'].add_metric(labels=labels, value=add_value) + _ = [labels.remove(l) for l in add_label_value] continue if statkey in metrics: diff --git a/collectors/SDRSPropertiesCollector.py b/collectors/SDRSPropertiesCollector.py index 3c0e353d..b9fde51c 100644 --- a/collectors/SDRSPropertiesCollector.py +++ b/collectors/SDRSPropertiesCollector.py @@ -32,19 +32,23 @@ def config_sdrsconfig_vmStorageAntiAffinityRules(self, metric_value): amount_rules = len(rules) if rules else 0 - rule_labels = ['rules', 'rule_name', 'rule_type', 'valid', 'virtualmachines'] + rule_labels = ['rule', 'rule_name', 'rule_type', 'valid', 'virtualmachine'] rule_label_values = [] - for i, rule in enumerate(rules): - rule_label_values.extend([ - f'{i+1}/{amount_rules}', - rule.get('name'), - rule.get('type'), - str(rule.get('valid')).lower(), - self.vm_mapping_helper(rule.get('virtualMachines')) - ]) + value = 0 - return rule_labels, rule_label_values, amount_rules + for i, rule in enumerate(rules): + mapped_vms = self.vm_mapping_helper(rule.get('virtualMachines')) + value = len(mapped_vms) + for vm in mapped_vms: + rule_label_values.append([ + f'{i+1}/{amount_rules}', + rule.get('name'), + rule.get('type'), + str(rule.get('valid')).lower(), + vm + ]) + return rule_labels, rule_label_values, value def vm_mapping_helper(self, vm_list): mapped_vms = [] @@ -53,4 +57,4 @@ def vm_mapping_helper(self, vm_list): for vm in vms: if rule_vm == vms[vm].get('internal_name'): mapped_vms.append(vms[vm].get('name')) - return str(mapped_vms) + return mapped_vms From bd91bffd817a29343b72d6aa062250bbdc24ded3 Mon Sep 17 00:00:00 2001 From: Richard Tief <56597015+richardtief@users.noreply.github.com> Date: Fri, 23 Feb 2024 09:45:12 +0100 Subject: [PATCH 3/9] remove condition Co-authored-by: Tommy Sauer --- collectors/SDRSPropertiesCollector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collectors/SDRSPropertiesCollector.py b/collectors/SDRSPropertiesCollector.py index b9fde51c..ccbe5eae 100644 --- a/collectors/SDRSPropertiesCollector.py +++ b/collectors/SDRSPropertiesCollector.py @@ -30,7 +30,7 @@ def config_sdrsconfig_vmStorageAntiAffinityRules(self, metric_value): metric_value = json.loads(metric_value) rules = metric_value.get("rules") if metric_value.get("rules") else [] - amount_rules = len(rules) if rules else 0 + amount_rules = len(rules) rule_labels = ['rule', 'rule_name', 'rule_type', 'valid', 'virtualmachine'] rule_label_values = [] From a5a5a8f09e5a3c9758d274c0204920c641d7cb21 Mon Sep 17 00:00:00 2001 From: Richard Tief <56597015+richardtief@users.noreply.github.com> Date: Fri, 23 Feb 2024 09:45:52 +0100 Subject: [PATCH 4/9] remove assignment Co-authored-by: Tommy Sauer --- collectors/SDRSPropertiesCollector.py | 1 - 1 file changed, 1 deletion(-) diff --git a/collectors/SDRSPropertiesCollector.py b/collectors/SDRSPropertiesCollector.py index ccbe5eae..64945f64 100644 --- a/collectors/SDRSPropertiesCollector.py +++ b/collectors/SDRSPropertiesCollector.py @@ -39,7 +39,6 @@ def config_sdrsconfig_vmStorageAntiAffinityRules(self, metric_value): for i, rule in enumerate(rules): mapped_vms = self.vm_mapping_helper(rule.get('virtualMachines')) - value = len(mapped_vms) for vm in mapped_vms: rule_label_values.append([ f'{i+1}/{amount_rules}', From 60eeadfdeeedc591ef96468808cc3406138aca4a Mon Sep 17 00:00:00 2001 From: Richard Tief <56597015+richardtief@users.noreply.github.com> Date: Fri, 23 Feb 2024 09:46:06 +0100 Subject: [PATCH 5/9] return value directly Co-authored-by: Tommy Sauer --- collectors/SDRSPropertiesCollector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collectors/SDRSPropertiesCollector.py b/collectors/SDRSPropertiesCollector.py index 64945f64..c1bbb3c0 100644 --- a/collectors/SDRSPropertiesCollector.py +++ b/collectors/SDRSPropertiesCollector.py @@ -38,7 +38,7 @@ def config_sdrsconfig_vmStorageAntiAffinityRules(self, metric_value): value = 0 for i, rule in enumerate(rules): - mapped_vms = self.vm_mapping_helper(rule.get('virtualMachines')) + mapped_vms = self.vm_mapping_helper(rule.get('virtualMachines'), []) for vm in mapped_vms: rule_label_values.append([ f'{i+1}/{amount_rules}', From 438c9b618bc3744a31bc925b28a72042be44cb7f Mon Sep 17 00:00:00 2001 From: Richard Tief <56597015+richardtief@users.noreply.github.com> Date: Fri, 23 Feb 2024 09:46:38 +0100 Subject: [PATCH 6/9] return value directly Co-authored-by: Tommy Sauer --- collectors/SDRSPropertiesCollector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collectors/SDRSPropertiesCollector.py b/collectors/SDRSPropertiesCollector.py index c1bbb3c0..86b674db 100644 --- a/collectors/SDRSPropertiesCollector.py +++ b/collectors/SDRSPropertiesCollector.py @@ -47,7 +47,7 @@ def config_sdrsconfig_vmStorageAntiAffinityRules(self, metric_value): str(rule.get('valid')).lower(), vm ]) - return rule_labels, rule_label_values, value + return rule_labels, rule_label_values, len(mapped_vms) def vm_mapping_helper(self, vm_list): mapped_vms = [] From 569cdf391b77af0eca95157add917767ec1c75b8 Mon Sep 17 00:00:00 2001 From: Richard Tief Date: Mon, 26 Feb 2024 15:16:02 +0100 Subject: [PATCH 7/9] cleanup, move label extension to a dedicated function --- BaseCollector.py | 6 ++++++ collectors/PropertiesCollector.py | 15 +++++---------- collectors/SDRSPropertiesCollector.py | 6 ++---- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/BaseCollector.py b/BaseCollector.py index 01f5f957..b4cd1b68 100644 --- a/BaseCollector.py +++ b/BaseCollector.py @@ -374,6 +374,12 @@ def generate_alert_metrics(self, label_names: list) -> InfoMetricFamily: labels=label_names) return alert_metric + def add_metric_labels(self, metric_object: GaugeMetricFamily, labels): + if labels[0] not in metric_object._labelnames: + for label in labels: + metric_object._labelnames += (label,) + return + def describe(self): collector_config = self.read_collector_config() for metric in collector_config[self.name]: diff --git a/collectors/PropertiesCollector.py b/collectors/PropertiesCollector.py index 9473c3b4..a4131c20 100644 --- a/collectors/PropertiesCollector.py +++ b/collectors/PropertiesCollector.py @@ -67,21 +67,17 @@ def collect(self): if statkey in self.nested_value_metric_keys: add_labels, add_label_value_list, add_value = self.unlock_nested_values(statkey, metric_value) - if add_labels[0] not in metrics[statkey]['gauge']._labelnames: - for add_label in add_labels: - metrics[statkey]['gauge']._labelnames += (add_label,) + + self.add_metric_labels(metrics[statkey]['gauge'], add_labels) for add_label_value in add_label_value_list: - _ = [labels.append(l) for l in add_label_value] - metrics[statkey]['gauge'].add_metric(labels=labels, value=add_value) - _ = [labels.remove(l) for l in add_label_value] + metrics[statkey]['gauge'].add_metric(labels=labels+add_label_value, value=add_value) continue if statkey in metrics: # enum metrics if metrics[statkey]['expected']: - if 'state' not in metrics[statkey]['gauge']._labelnames: - metrics[statkey]['gauge']._labelnames += ('state',) + self.add_metric_labels(metrics[statkey]['gauge'], ['state']) state = metric_value if metric_value else 'n/a' labels.append(state) @@ -91,8 +87,7 @@ def collect(self): # string values elif metric_value: metric_suffix = metrics[statkey]['metric_suffix'] - if metric_suffix not in metrics[statkey]['gauge']._labelnames: - metrics[statkey]['gauge']._labelnames += (metric_suffix,) + self.add_metric_labels(metrics[statkey]['gauge'], [metric_suffix]) labels.append(metric_value) metrics[statkey]['gauge'].add_metric(labels=labels, value=1) diff --git a/collectors/SDRSPropertiesCollector.py b/collectors/SDRSPropertiesCollector.py index 86b674db..ef23f4ee 100644 --- a/collectors/SDRSPropertiesCollector.py +++ b/collectors/SDRSPropertiesCollector.py @@ -35,10 +35,8 @@ def config_sdrsconfig_vmStorageAntiAffinityRules(self, metric_value): rule_labels = ['rule', 'rule_name', 'rule_type', 'valid', 'virtualmachine'] rule_label_values = [] - value = 0 - for i, rule in enumerate(rules): - mapped_vms = self.vm_mapping_helper(rule.get('virtualMachines'), []) + mapped_vms = self.vm_mapping_helper(rule.get('virtualMachines', [])) for vm in mapped_vms: rule_label_values.append([ f'{i+1}/{amount_rules}', @@ -47,7 +45,7 @@ def config_sdrsconfig_vmStorageAntiAffinityRules(self, metric_value): str(rule.get('valid')).lower(), vm ]) - return rule_labels, rule_label_values, len(mapped_vms) + return rule_labels, rule_label_values, 1 def vm_mapping_helper(self, vm_list): mapped_vms = [] From 9ce6e909072e1ebde5bc49f9c8d37176a1f9777d Mon Sep 17 00:00:00 2001 From: Richard Tief <56597015+richardtief@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:21:11 +0100 Subject: [PATCH 8/9] Update collectors/SDRSPropertiesCollector.py Co-authored-by: Tommy Sauer --- collectors/SDRSPropertiesCollector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collectors/SDRSPropertiesCollector.py b/collectors/SDRSPropertiesCollector.py index ef23f4ee..10c77eed 100644 --- a/collectors/SDRSPropertiesCollector.py +++ b/collectors/SDRSPropertiesCollector.py @@ -28,7 +28,7 @@ def unlock_nested_values(self, statkey, metric_value): def config_sdrsconfig_vmStorageAntiAffinityRules(self, metric_value): metric_value = json.loads(metric_value) - rules = metric_value.get("rules") if metric_value.get("rules") else [] + rules = metric_value.get("rules") or [] amount_rules = len(rules) From 888a7b7d1277239eea146aef576dbab87ee140c0 Mon Sep 17 00:00:00 2001 From: Richard Tief Date: Tue, 27 Feb 2024 09:57:51 +0100 Subject: [PATCH 9/9] ensure json.loads() --- collectors/PropertiesCollector.py | 7 +++++++ collectors/SDRSPropertiesCollector.py | 12 ++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/collectors/PropertiesCollector.py b/collectors/PropertiesCollector.py index a4131c20..d69bc609 100644 --- a/collectors/PropertiesCollector.py +++ b/collectors/PropertiesCollector.py @@ -66,8 +66,15 @@ def collect(self): metric_value = value_entry.get('values', [False])[0] if statkey in self.nested_value_metric_keys: + add_labels, add_label_value_list, add_value = self.unlock_nested_values(statkey, metric_value) + if not add_labels: + metric_suffix = metrics[statkey]['metric_suffix'] + self.add_metric_labels(metrics[statkey]['gauge'], [metric_suffix]) + metrics[statkey]['gauge'].add_metric(labels=labels+[metric_suffix], value=0) + continue + self.add_metric_labels(metrics[statkey]['gauge'], add_labels) for add_label_value in add_label_value_list: diff --git a/collectors/SDRSPropertiesCollector.py b/collectors/SDRSPropertiesCollector.py index 10c77eed..857db30e 100644 --- a/collectors/SDRSPropertiesCollector.py +++ b/collectors/SDRSPropertiesCollector.py @@ -1,5 +1,8 @@ from collectors.PropertiesCollector import PropertiesCollector import json +import logging + +logger = logging.getLogger('vrops-exporter') class SDRSPropertiesCollector(PropertiesCollector): @@ -27,9 +30,14 @@ def unlock_nested_values(self, statkey, metric_value): def config_sdrsconfig_vmStorageAntiAffinityRules(self, metric_value): - metric_value = json.loads(metric_value) - rules = metric_value.get("rules") or [] + try: + metric_value = json.loads(metric_value) + except (TypeError, json.decoder.JSONDecodeError) as e: + logger.warning(f'metric_value is not a valid json: {e.args}, {metric_value}') + return [], [], 0 + + rules = metric_value.get("rules") or [] amount_rules = len(rules) rule_labels = ['rule', 'rule_name', 'rule_type', 'valid', 'virtualmachine']