From 0e2feace4b76543b919a77f0688bd9c0207a60a9 Mon Sep 17 00:00:00 2001 From: Z903 Date: Wed, 9 Jun 2021 20:23:53 -0700 Subject: [PATCH 1/9] Fix for badly behaving super-micro sensor --- vmware_exporter/vmware_exporter.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vmware_exporter/vmware_exporter.py b/vmware_exporter/vmware_exporter.py index b15fc42..704c5b7 100755 --- a/vmware_exporter/vmware_exporter.py +++ b/vmware_exporter/vmware_exporter.py @@ -1695,7 +1695,10 @@ def _vmware_get_hosts(self, host_metrics): sensors = [s for s in sensors if ':' in s] for s in sensors: - sensor = dict(item.split("=") for item in s.split(":")[1:]) + sensor = dict(item.split("=") for item in re.split(r':(?=\w+=)', s)[1:]) + + if not all(key in sensor for key in ['sensorStatus', 'name', 'type', 'unit', 'value']): + continue sensor_status = { 'red': 0, From 028c11385b68614bc3e530e5689d0300d3d44f05 Mon Sep 17 00:00:00 2001 From: Z903 Date: Sat, 12 Jun 2021 01:56:58 -0700 Subject: [PATCH 2/9] Change serialization of alarms and sensors for objects --- tests/unit/test_helpers.py | 22 ++++- vmware_exporter/helpers.py | 131 ++++++++++++++++++++--------- vmware_exporter/vmware_exporter.py | 76 ++++++++--------- 3 files changed, 148 insertions(+), 81 deletions(-) diff --git a/tests/unit/test_helpers.py b/tests/unit/test_helpers.py index 14d98ba..2d3fef9 100644 --- a/tests/unit/test_helpers.py +++ b/tests/unit/test_helpers.py @@ -4,7 +4,7 @@ from pyVmomi import vim -from vmware_exporter.helpers import batch_fetch_properties, get_bool_env +from vmware_exporter.helpers import batch_fetch_properties, get_bool_env, serialize, deserialize class FakeView(vim.ManagedObject): @@ -16,6 +16,26 @@ def Destroy(self): pass +def test_serialize(): + + # Test basic usage + assert serialize('abc', 'def', g='1', h='2') == 'abc:def:g=1:h=2' + + # Test escaping + assert serialize('\\\n\r,:=') == '\\\\\\n\\r\\,\\:\\=' + + +def test_deserialize(): + + tests = [ + 'abc:def:g=1:h=2', + '\\\\\\n\\r\\,\\:\\=:\\\\\\n\\r\\,\\:\\==\\\\\\n\\r\\,\\:\\=' + ] + for value in tests: + arg, kwarg = deserialize(value) + assert serialize(*arg, **kwarg) == value + + def test_get_bool_env(): # Expected behaviour assert get_bool_env('NON_EXISTENT_ENV', True) diff --git a/vmware_exporter/helpers.py b/vmware_exporter/helpers.py index cb5fc98..5eb2f39 100644 --- a/vmware_exporter/helpers.py +++ b/vmware_exporter/helpers.py @@ -1,6 +1,65 @@ # autopep8'd import os from pyVmomi import vmodl +import re + + +def serialize(*arg, **kwarg): + """ + Serialize into the format + item1:item2:key1=value1:key2:value2 + """ + escape_dict = {'\\': '\\\\', '\n': '\\n', '\r': '\\r', ',': '\\,', ':': '\\:', '=': '\\='} + pattern = re.compile("|".join([re.escape(k) for k in sorted(escape_dict, key=len, reverse=True)]), flags=re.DOTALL) + items = [] + for item in arg: + items.append(pattern.sub(lambda x: escape_dict[x.group(0)], str(item))) + for k, v in kwarg.items(): + items.append("{}={}".format( + pattern.sub(lambda x: escape_dict[x.group(0)], str(k)), + pattern.sub(lambda x: escape_dict[x.group(0)], str(v)) + )) + return ':'.join(items) + + +def deserialize(s): + """ + Deserialize the format into a list and dict + item1:item2:key1=value1:key2:value2 + """ + escape_dict = {'\\r': '\r', '\\\\': '\\', '\\=': '=', '\\:': ':', '\\n': '\n', '\\,': ','} + pattern = re.compile("|".join([re.escape(k) for k in sorted(escape_dict, key=len, reverse=True)]), flags=re.DOTALL) + arg = [] + kwarg = {} + for name, eq, value in re.findall(r'((?:\\.|[^=:\\]+)+)(?:(=)((?:\\.|[^:\\]+)+))?', s): + if eq: + kwarg[pattern.sub(lambda x: escape_dict[x.group(0)], name)] = pattern.sub( + lambda x: escape_dict[x.group(0)], value) + else: + arg.append(pattern.sub(lambda x: escape_dict[x.group(0)], name)) + return (arg, kwarg) + + +class TriggeredAlarm(object): + def __init__(self, name, status): + self.name = name + self.sensorStatus = status + + def __str__(self): + return serialize('triggeredAlarm', self.name, self.sensorStatus) + + +class NumericSensorInfo(object): + def __init__(self, name, status, type="n/a", value="n/a", unitModifier="n/a", unit="n/a"): + self.name = name + self.type = type + self.sensorStatus = status + self.value = value + self.unitModifier = unitModifier + self.unit = unit + + def __str__(self): + return serialize('numericSensorInfo', name=self.name, type=self.type, sensorStatus=self.sensorStatus, value=self.value, unitModifier=self.unitModifier, unit=self.unit) def get_bool_env(key: str, default: bool): @@ -26,13 +85,9 @@ def batch_fetch_properties(content, obj_type, properties): if content.customFieldsManager and content.customFieldsManager.field: allCustomAttributesNames.update( - dict( - [ - (f.key, f.name) - for f in content.customFieldsManager.field - if f.managedObjectType in (obj_type, None) - ] - ) + (f.key, f.name) + for f in content.customFieldsManager.field + if f.managedObjectType in (obj_type, None) ) try: @@ -95,32 +150,37 @@ def batch_fetch_properties(content, obj_type, properties): """ triggered alarms """ + try: - alarms = list( - 'triggeredAlarm:{}:{}'.format(item.alarm.info.systemName.split('.')[1], item.overallStatus) - for item in prop.val - ) + properties[prop.name] = [ + TriggeredAlarm( + name=item.alarm.info.systemName.split('.')[1], + status=item.overallStatus + ) for item in prop.val + ] except Exception: - alarms = ['triggeredAlarm:AlarmsUnavailable:yellow'] - - properties[prop.name] = ','.join(alarms) + properties[prop.name] = [ + TriggeredAlarm( + name='AlarmsUnavailable', + status='yellow' + ) + ] elif 'runtime.healthSystemRuntime.systemHealthInfo.numericSensorInfo' == prop.name: """ handle numericSensorInfo """ - sensors = list( - 'numericSensorInfo:name={}:type={}:sensorStatus={}:value={}:unitModifier={}:unit={}'.format( - item.name, - item.sensorType, - item.healthState.key, - item.currentReading, - item.unitModifier, - item.baseUnits.lower() - ) - for item in prop.val - ) - properties[prop.name] = ','.join(sensors) + + properties[prop.name] = [ + NumericSensorInfo( + name=item.name, + type=item.sensorType, + status=item.healthState.key, + value=item.currentReading, + unitModifier=item.unitModifier, + unit=item.baseUnits.lower() + ) for item in prop.val + ] elif prop.name in [ 'runtime.healthSystemRuntime.hardwareStatusInfo.cpuStatusInfo', @@ -129,18 +189,13 @@ def batch_fetch_properties(content, obj_type, properties): """ handle hardwareStatusInfo """ - sensors = list( - 'numericSensorInfo:name={}:type={}:sensorStatus={}:value={}:unitModifier={}:unit={}'.format( - item.name, - "n/a", - item.status.key, - "n/a", - "n/a", - "n/a", - ) - for item in prop.val - ) - properties[prop.name] = ','.join(sensors) + + properties[prop.name] = [ + NumericSensorInfo( + name=item.name, + status=item.status.key + ) for item in prop.val + ] else: properties[prop.name] = prop.val diff --git a/vmware_exporter/vmware_exporter.py b/vmware_exporter/vmware_exporter.py index 704c5b7..71d1e18 100755 --- a/vmware_exporter/vmware_exporter.py +++ b/vmware_exporter/vmware_exporter.py @@ -1251,11 +1251,10 @@ def _vmware_get_datastores(self, ds_metrics): filter red and yellow alarms """ if self.fetch_alarms: - alarms = datastore.get('triggeredAlarmState').split(',') - alarms = [a for a in alarms if ':' in a] + alarms = datastore.get('triggeredAlarmState', []) # Red alarms - red_alarms = [':'.join(a.split(':')[:-1]) for a in alarms if a.split(':')[-1] == 'red'] + red_alarms = [alarm.name for alarm in alarms if alarm.sensorStatus == 'red'] red_alarms_label = ','.join(red_alarms) if red_alarms else 'n/a' ds_metrics['vmware_datastore_red_alarms'].add_metric( labels + [red_alarms_label], @@ -1263,7 +1262,7 @@ def _vmware_get_datastores(self, ds_metrics): ) # Yellow alarms - yellow_alarms = [':'.join(a.split(':')[:-1]) for a in alarms if a.split(':')[-1] == 'yellow'] + yellow_alarms = [alarm.name for alarm in alarms if alarm.sensorStatus == 'yellow'] yellow_alarms_label = ','.join(yellow_alarms) if yellow_alarms else 'n/a' ds_metrics['vmware_datastore_yellow_alarms'].add_metric( labels + [yellow_alarms_label], @@ -1531,11 +1530,10 @@ def _vmware_get_vms(self, metrics): filter red and yellow alarms """ if self.fetch_alarms and ('triggeredAlarmState' in row): - alarms = row.get('triggeredAlarmState').split(',') - alarms = [a for a in alarms if ':' in a] + alarms = row.get('triggeredAlarmState', []) # Red alarms - red_alarms = [':'.join(a.split(':')[:-1]) for a in alarms if a.split(':')[-1] == 'red'] + red_alarms = [alarm.name for alarm in alarms if alarm.sensorStatus == 'red'] red_alarms_label = ','.join(red_alarms) if red_alarms else 'n/a' metrics['vmware_vm_red_alarms'].add_metric( labels + [red_alarms_label], @@ -1543,7 +1541,7 @@ def _vmware_get_vms(self, metrics): ) # Yellow alarms - yellow_alarms = [':'.join(a.split(':')[:-1]) for a in alarms if a.split(':')[-1] == 'yellow'] + yellow_alarms = [alarm.name for alarm in alarms if alarm.sensorStatus == 'yellow'] yellow_alarms_label = ','.join(yellow_alarms) if yellow_alarms else 'n/a' metrics['vmware_vm_yellow_alarms'].add_metric( labels + [yellow_alarms_label], @@ -1669,10 +1667,10 @@ def _vmware_get_hosts(self, host_metrics): filter red and yellow alarms """ if self.fetch_alarms: - alarms = [a for a in host.get('triggeredAlarmState', '').split(',') if ':' in a] + alarms = host.get('triggeredAlarmState', []) # Red alarms - red_alarms = [':'.join(a.split(':')[:-1]) for a in alarms if a.split(':')[-1] == 'red'] + red_alarms = [alarm.name for alarm in alarms if alarm.sensorStatus == 'red'] red_alarms_label = ','.join(red_alarms) if red_alarms else 'n/a' host_metrics['vmware_host_red_alarms'].add_metric( labels + [red_alarms_label], @@ -1680,7 +1678,7 @@ def _vmware_get_hosts(self, host_metrics): ) # Yellow alarms - yellow_alarms = [':'.join(a.split(':')[:-1]) for a in alarms if a.split(':')[-1] == 'yellow'] + yellow_alarms = [alarm.name for alarm in alarms if alarm.sensorStatus == 'yellow'] yellow_alarms_label = ','.join(yellow_alarms) if yellow_alarms else 'n/a' host_metrics['vmware_host_yellow_alarms'].add_metric( labels + [yellow_alarms_label], @@ -1688,70 +1686,64 @@ def _vmware_get_hosts(self, host_metrics): ) # Numeric Sensor Info - sensors = host.get('runtime.healthSystemRuntime.systemHealthInfo.numericSensorInfo', '').split(',') + \ - host.get('runtime.healthSystemRuntime.hardwareStatusInfo.cpuStatusInfo', '').split(',') + \ - host.get('runtime.healthSystemRuntime.hardwareStatusInfo.memoryStatusInfo', '').split(',') + sensors = host.get('runtime.healthSystemRuntime.systemHealthInfo.numericSensorInfo', []) + \ + host.get('runtime.healthSystemRuntime.hardwareStatusInfo.cpuStatusInfo', []) + \ + host.get('runtime.healthSystemRuntime.hardwareStatusInfo.memoryStatusInfo', []) - sensors = [s for s in sensors if ':' in s] - - for s in sensors: - sensor = dict(item.split("=") for item in re.split(r':(?=\w+=)', s)[1:]) - - if not all(key in sensor for key in ['sensorStatus', 'name', 'type', 'unit', 'value']): - continue + for sensor in sensors: sensor_status = { 'red': 0, 'yellow': 1, 'green': 2, - 'unknown': 3, - }[sensor['sensorStatus'].lower()] + # 'unknown': 3, + }.get(sensor.sensorStatus.lower(), 'unknown') host_metrics['vmware_host_sensor_state'].add_metric( - labels + [sensor['name'], sensor['type']], + labels + [sensor.name, sensor.type], sensor_status ) # FAN speed - if sensor["unit"] == 'rpm': + if sensor.unit == 'rpm': host_metrics['vmware_host_sensor_fan'].add_metric( - labels + [sensor['name']], - int(sensor['value']) * (10 ** (int(sensor['unitModifier']))) + labels + [sensor.name], + int(sensor.value) * (10 ** (int(sensor.unitModifier))) ) # Temperature - if sensor["unit"] == 'degrees c': + if sensor.unit == 'degrees c': host_metrics['vmware_host_sensor_temperature'].add_metric( - labels + [sensor['name']], - int(sensor['value']) * (10 ** (int(sensor['unitModifier']))) + labels + [sensor.name], + int(sensor.value) * (10 ** (int(sensor.unitModifier))) ) # Power Voltage - if sensor["unit"] == 'volts': + if sensor.unit == 'volts': host_metrics['vmware_host_sensor_power_voltage'].add_metric( - labels + [sensor['name']], - int(sensor['value']) * (10 ** (int(sensor['unitModifier']))) + labels + [sensor.name], + int(sensor.value) * (10 ** (int(sensor.unitModifier))) ) # Power Current - if sensor["unit"] == 'amps': + if sensor.unit == 'amps': host_metrics['vmware_host_sensor_power_current'].add_metric( - labels + [sensor['name']], - int(sensor['value']) * (10 ** (int(sensor['unitModifier']))) + labels + [sensor.name], + int(sensor.value) * (10 ** (int(sensor.unitModifier))) ) # Power Watt - if sensor["unit"] == 'watts': + if sensor.unit == 'watts': host_metrics['vmware_host_sensor_power_watt'].add_metric( - labels + [sensor['name']], - int(sensor['value']) * (10 ** (int(sensor['unitModifier']))) + labels + [sensor.name], + int(sensor.value) * (10 ** (int(sensor.unitModifier))) ) # Redundancy - if sensor["unit"] == 'redundancy-discrete': + if sensor.unit == 'redundancy-discrete': host_metrics['vmware_host_sensor_redundancy'].add_metric( - labels + [sensor['name']], - int(sensor['value']) + labels + [sensor.name], + int(sensor.value) ) # Standby Mode From 7225abddf3f7cf9919b34ca05311f982277a1fcb Mon Sep 17 00:00:00 2001 From: Z903 Date: Wed, 7 Jul 2021 12:03:01 -0700 Subject: [PATCH 3/9] Add vmware_*_*_alarm metrics --- vmware_exporter/vmware_exporter.py | 147 ++++++++++++++++++++++------- 1 file changed, 111 insertions(+), 36 deletions(-) diff --git a/vmware_exporter/vmware_exporter.py b/vmware_exporter/vmware_exporter.py index 71d1e18..cad7367 100755 --- a/vmware_exporter/vmware_exporter.py +++ b/vmware_exporter/vmware_exporter.py @@ -312,6 +312,16 @@ def _create_metric_containers(self): 'vmware_host_red_alarms', 'A metric with the amount of host red alarms and labeled with the list of alarm names', labels=self._labelNames['hosts'] + ['alarms'] + ), + 'vmware_host_yellow_alarm': GaugeMetricFamily( + 'vmware_host_yellow_alarm', + 'A metric with the host and yellow alarm name', + labels=self._labelNames['hosts'] + ['alarm'] + ), + 'vmware_host_red_alarm': GaugeMetricFamily( + 'vmware_host_red_alarm', + 'A metric with the host and red alarm name', + labels=self._labelNames['hosts'] + ['alarm'] ) } ) @@ -330,6 +340,16 @@ def _create_metric_containers(self): 'vmware_datastore_red_alarms', 'A metric with the amount of datastore red alarms and labeled with the list of alarm names', labels=self._labelNames['datastores'] + ['alarms'] + ), + 'vmware_datastore_yellow_alarm': GaugeMetricFamily( + 'vmware_datastore_yellow_alarm', + 'A metric with the datastore and yellow alarm name', + labels=self._labelNames['datastores'] + ['alarm'] + ), + 'vmware_datastore_red_alarm': GaugeMetricFamily( + 'vmware_datastore_red_alarm', + 'A metric with datastore and red alarm name', + labels=self._labelNames['datastores'] + ['alarm'] ) } ) @@ -350,41 +370,51 @@ def _create_metric_containers(self): 'A metric with the amount of virtual machine red alarms and \ labeled with the list of alarm names', labels=self._labelNames['vms'] + ['alarms'] - ) - } - ) - metric_list['vmguests'].update( - { - 'vmware_vm_yellow_alarms': GaugeMetricFamily( - 'vmware_vm_yellow_alarms', - 'A metric with the amount of virtual machine yellow alarms and \ - labeled with the list of alarm names', - labels=self._labelNames['vms'] + ['alarms'] ), - 'vmware_vm_red_alarms': GaugeMetricFamily( - 'vmware_vm_red_alarms', - 'A metric with the amount of virtual machine red alarms and \ - labeled with the list of alarm names', - labels=self._labelNames['vms'] + ['alarms'] - ) - } - ) - metric_list['snapshots'].update( - { - 'vmware_vm_yellow_alarms': GaugeMetricFamily( - 'vmware_vm_yellow_alarms', - 'A metric with the amount of virtual machine yellow alarms and \ - labeled with the list of alarm names', - labels=self._labelNames['vms'] + ['alarms'] + 'vmware_vm_yellow_alarm': GaugeMetricFamily( + 'vmware_vm_yellow_alarm', + 'A metric with the virtual machine and yellow alarm name', + labels=self._labelNames['vms'] + ['alarm'] ), - 'vmware_vm_red_alarms': GaugeMetricFamily( - 'vmware_vm_red_alarms', - 'A metric with the amount of virtual machine red alarms and \ - labeled with the list of alarm names', - labels=self._labelNames['vms'] + ['alarms'] + 'vmware_vm_red_alarm': GaugeMetricFamily( + 'vmware_vm_red_alarm', + 'A metric with the virtual machine and red alarm name', + labels=self._labelNames['vms'] + ['alarm'] ) } ) + # metric_list['vmguests'].update( + # { + # 'vmware_vm_yellow_alarms': GaugeMetricFamily( + # 'vmware_vm_yellow_alarms', + # 'A metric with the amount of virtual machine yellow alarms and \ + # labeled with the list of alarm names', + # labels=self._labelNames['vms'] + ['alarms'] + # ), + # 'vmware_vm_red_alarms': GaugeMetricFamily( + # 'vmware_vm_red_alarms', + # 'A metric with the amount of virtual machine red alarms and \ + # labeled with the list of alarm names', + # labels=self._labelNames['vms'] + ['alarms'] + # ) + # } + # ) + # metric_list['snapshots'].update( + # { + # 'vmware_vm_yellow_alarms': GaugeMetricFamily( + # 'vmware_vm_yellow_alarms', + # 'A metric with the amount of virtual machine yellow alarms and \ + # labeled with the list of alarm names', + # labels=self._labelNames['vms'] + ['alarms'] + # ), + # 'vmware_vm_red_alarms': GaugeMetricFamily( + # 'vmware_vm_red_alarms', + # 'A metric with the amount of virtual machine red alarms and \ + # labeled with the list of alarm names', + # labels=self._labelNames['vms'] + ['alarms'] + # ) + # } + # ) metrics = {} for key, value in self.collect_only.items(): @@ -1253,8 +1283,22 @@ def _vmware_get_datastores(self, ds_metrics): if self.fetch_alarms: alarms = datastore.get('triggeredAlarmState', []) + for alarm in alarms: + if alarm.sensorStatus == 'red': + # Red alarms + ds_metrics['vmware_datastore_red_alarm'].add_metric( + labels + [alarm.name], + 1 + ) + elif alarm.sensorStatus == 'yellow': + # Yellow alarms + ds_metrics['vmware_datastore_yellow_alarm'].add_metric( + labels + [alarm.name], + 1 + ) + # Red alarms - red_alarms = [alarm.name for alarm in alarms if alarm.sensorStatus == 'red'] + red_alarms = ['triggeredAlarm:{}'.format(alarm.name) for alarm in alarms if alarm.sensorStatus == 'red'] red_alarms_label = ','.join(red_alarms) if red_alarms else 'n/a' ds_metrics['vmware_datastore_red_alarms'].add_metric( labels + [red_alarms_label], @@ -1262,7 +1306,8 @@ def _vmware_get_datastores(self, ds_metrics): ) # Yellow alarms - yellow_alarms = [alarm.name for alarm in alarms if alarm.sensorStatus == 'yellow'] + yellow_alarms = ['triggeredAlarm:{}'.format(alarm.name) + for alarm in alarms if alarm.sensorStatus == 'yellow'] yellow_alarms_label = ','.join(yellow_alarms) if yellow_alarms else 'n/a' ds_metrics['vmware_datastore_yellow_alarms'].add_metric( labels + [yellow_alarms_label], @@ -1532,8 +1577,22 @@ def _vmware_get_vms(self, metrics): if self.fetch_alarms and ('triggeredAlarmState' in row): alarms = row.get('triggeredAlarmState', []) + for alarm in alarms: + if alarm.sensorStatus == 'red': + # Red alarms + metrics['vmware_vm_red_alarm'].add_metric( + labels + [alarm.name], + 1 + ) + elif alarm.sensorStatus == 'yellow': + # Yellow alarms + metrics['vmware_vm_yellow_alarm'].add_metric( + labels + [alarm.name], + 1 + ) + # Red alarms - red_alarms = [alarm.name for alarm in alarms if alarm.sensorStatus == 'red'] + red_alarms = ['triggeredAlarm:{}'.format(alarm.name) for alarm in alarms if alarm.sensorStatus == 'red'] red_alarms_label = ','.join(red_alarms) if red_alarms else 'n/a' metrics['vmware_vm_red_alarms'].add_metric( labels + [red_alarms_label], @@ -1541,7 +1600,8 @@ def _vmware_get_vms(self, metrics): ) # Yellow alarms - yellow_alarms = [alarm.name for alarm in alarms if alarm.sensorStatus == 'yellow'] + yellow_alarms = ['triggeredAlarm:{}'.format(alarm.name) + for alarm in alarms if alarm.sensorStatus == 'yellow'] yellow_alarms_label = ','.join(yellow_alarms) if yellow_alarms else 'n/a' metrics['vmware_vm_yellow_alarms'].add_metric( labels + [yellow_alarms_label], @@ -1669,8 +1729,22 @@ def _vmware_get_hosts(self, host_metrics): if self.fetch_alarms: alarms = host.get('triggeredAlarmState', []) + for alarm in alarms: + if alarm.sensorStatus == 'red': + # Red alarms + host_metrics['vmware_host_red_alarm'].add_metric( + labels + [alarm.name], + 1 + ) + elif alarm.sensorStatus == 'yellow': + # Yellow alarms + host_metrics['vmware_host_yellow_alarm'].add_metric( + labels + [alarm.name], + 1 + ) + # Red alarms - red_alarms = [alarm.name for alarm in alarms if alarm.sensorStatus == 'red'] + red_alarms = ['triggeredAlarm:{}'.format(alarm.name) for alarm in alarms if alarm.sensorStatus == 'red'] red_alarms_label = ','.join(red_alarms) if red_alarms else 'n/a' host_metrics['vmware_host_red_alarms'].add_metric( labels + [red_alarms_label], @@ -1678,7 +1752,8 @@ def _vmware_get_hosts(self, host_metrics): ) # Yellow alarms - yellow_alarms = [alarm.name for alarm in alarms if alarm.sensorStatus == 'yellow'] + yellow_alarms = ['triggeredAlarm:{}'.format(alarm.name) + for alarm in alarms if alarm.sensorStatus == 'yellow'] yellow_alarms_label = ','.join(yellow_alarms) if yellow_alarms else 'n/a' host_metrics['vmware_host_yellow_alarms'].add_metric( labels + [yellow_alarms_label], From 4993ee99cc3b79944ef1a9a5722f4f45f705212b Mon Sep 17 00:00:00 2001 From: Z903 Date: Wed, 7 Jul 2021 12:03:58 -0700 Subject: [PATCH 4/9] Add --allow-url-target and remove 'default' as a requirement in config file --- vmware_exporter/vmware_exporter.py | 40 ++++++++++++++++++------------ 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/vmware_exporter/vmware_exporter.py b/vmware_exporter/vmware_exporter.py index cad7367..28e0627 100755 --- a/vmware_exporter/vmware_exporter.py +++ b/vmware_exporter/vmware_exporter.py @@ -1923,20 +1923,18 @@ def __init__(self, args): self.configure(args) def configure(self, args): + self.allow_url_target = args.allow_url_target if args.config_file: try: with open(args.config_file) as cf: self.config = yaml.load(cf, Loader=yaml.FullLoader) - - if 'default' not in self.config.keys(): - logging.error("Error, you must have a default section in config file (for now)") - exit(1) return except Exception as exception: raise SystemExit("Error while reading configuration file: {0}".format(exception.message)) - self.config = { - 'default': { + self.config = {} + if 'VSPHERE_USER' in os.environ: + self.config['default'] = { 'vsphere_host': os.environ.get('VSPHERE_HOST'), 'vsphere_user': os.environ.get('VSPHERE_USER'), 'vsphere_password': os.environ.get('VSPHERE_PASSWORD'), @@ -1953,7 +1951,6 @@ def configure(self, args): 'snapshots': get_bool_env('VSPHERE_COLLECT_SNAPSHOTS', True), } } - } for key in os.environ.keys(): if key == 'VSPHERE_USER': @@ -2003,16 +2000,25 @@ def _async_render_GET(self, request): @defer.inlineCallbacks def generate_latest_metrics(self, request): """ gets the latest metrics """ - section = request.args.get(b'section', [b'default'])[0].decode('utf-8') - if section not in self.config.keys(): - logging.info("{} is not a valid section, using default".format(section)) - section = 'default' - - if self.config[section].get('vsphere_host') and self.config[section].get('vsphere_host') != "None": - vsphere_host = self.config[section].get('vsphere_host') - elif request.args.get(b'target', [None])[0]: + section = None + if b'section' in request.args: + section = request.args[b'section'][0].decode('utf-8') + if section not in self.config: + if 'default' in self.config: + logging.info("{} is not a valid section, using default".format(section)) + section = 'default' + else: + request.setResponseCode(500) + logging.info("Invalid section and no default defined") + request.write(b'Invalid section defined!\n') + request.finish() + return + + if (self.config[section].get('vsphere_host') or "None") != "None": + vsphere_host = self.config[section]['vsphere_host'] + elif self.allow_url_target and request.args.get(b'target', [None])[0]: vsphere_host = request.args.get(b'target', [None])[0].decode('utf-8') - elif request.args.get(b'vsphere_host', [None])[0]: + elif self.allow_url_target and request.args.get(b'vsphere_host', [None])[0]: vsphere_host = request.args.get(b'vsphere_host')[0].decode('utf-8') else: request.setResponseCode(500) @@ -2094,6 +2100,8 @@ def main(argv=None): default=9272, help="HTTP port to expose metrics") parser.add_argument('-l', '--loglevel', dest='loglevel', default="INFO", help="Set application loglevel INFO, DEBUG") + parser.add_argument('--allow-url-target', action='store_true', + help="Allow vsphere host to be specified as url a parameter") args = parser.parse_args(argv or sys.argv[1:]) From c34898c85fe8182487801866df6d918d9e1bdcd6 Mon Sep 17 00:00:00 2001 From: Z903 Date: Wed, 7 Jul 2021 15:28:16 -0700 Subject: [PATCH 5/9] Fix type of sensor_status from 'unknown' to 3 --- vmware_exporter/vmware_exporter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vmware_exporter/vmware_exporter.py b/vmware_exporter/vmware_exporter.py index 28e0627..3cc5482 100755 --- a/vmware_exporter/vmware_exporter.py +++ b/vmware_exporter/vmware_exporter.py @@ -1772,7 +1772,7 @@ def _vmware_get_hosts(self, host_metrics): 'yellow': 1, 'green': 2, # 'unknown': 3, - }.get(sensor.sensorStatus.lower(), 'unknown') + }.get(sensor.sensorStatus.lower(), 3) host_metrics['vmware_host_sensor_state'].add_metric( labels + [sensor.name, sensor.type], From 63a9d68ab2d0d74dbdc6805a3d8b22c4747dd617 Mon Sep 17 00:00:00 2001 From: Z903 Date: Wed, 5 Jan 2022 16:39:53 -0800 Subject: [PATCH 6/9] Add timeout to VmwareCollector --- README.md | 65 ++++++++++++++++-------------- vmware_exporter/defer.py | 2 +- vmware_exporter/vmware_exporter.py | 26 ++++++++---- 3 files changed, 55 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 4ae89b3..947bdbc 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ default: vsphere_user: "user" vsphere_password: "password" ignore_ssl: False + timeout: 120 specs_size: 5000 fetch_custom_attributes: True fetch_tags: True @@ -83,6 +84,7 @@ esx: vsphere_user: 'root' vsphere_password: 'password' ignore_ssl: True + timeout: 120 specs_size: 5000 fetch_custom_attributes: True fetch_tags: True @@ -99,6 +101,7 @@ limited: vsphere_user: 'administrator@vsphere.local' vsphere_password: 'password' ignore_ssl: True + timeout: 120 specs_size: 5000 fetch_custom_attributes: True fetch_tags: True @@ -114,39 +117,41 @@ limited: Switching sections can be done by adding ?section=limited to the URL. #### Environment Variables -| Variable | Precedence | Defaults | Description | -| --------------------------------------| ---------------------- | -------- | --------------------------------------------------------------------------| -| `VSPHERE_HOST` | config, env, get_param | n/a | vsphere server to connect to | -| `VSPHERE_USER` | config, env | n/a | User for connecting to vsphere | -| `VSPHERE_PASSWORD` | config, env | n/a | Password for connecting to vsphere | -| `VSPHERE_SPECS_SIZE` | config, env | 5000 | Size of specs list for query stats function | -| `VSPHERE_IGNORE_SSL` | config, env | False | Ignore the ssl cert on the connection to vsphere host | -| `VSPHERE_FETCH_CUSTOM_ATTRIBUTES` | config, env | False | Set to true to collect objects custom attributes as metric labels | -| `VSPHERE_FETCH_TAGS` | config, env | False | Set to true to collect objects tags as metric labels | -| `VSPHERE_FETCH_ALARMS` | config, env | False | Fetch objects triggered alarms, and in case of hosts hdw alarms as well | -| `VSPHERE_COLLECT_HOSTS` | config, env | True | Set to false to disable collection of host metrics | -| `VSPHERE_COLLECT_DATASTORES` | config, env | True | Set to false to disable collection of datastore metrics | -| `VSPHERE_COLLECT_VMS` | config, env | True | Set to false to disable collection of virtual machine metrics | -| `VSPHERE_COLLECT_VMGUESTS` | config, env | True | Set to false to disable collection of virtual machine guest metrics | -| `VSPHERE_COLLECT_SNAPSHOTS` | config, env | True | Set to false to disable collection of snapshot metrics | +| Variable | Precedence | Defaults | Description | +| ---------------------------------------------| ---------------------- | -------- | ---------------------------------------------------------------------------------| +| `VSPHERE_HOST` | config, env, get_param | n/a | vsphere server to connect to | +| `VSPHERE_USER` | config, env | n/a | User for connecting to vsphere | +| `VSPHERE_PASSWORD` | config, env | n/a | Password for connecting to vsphere | +| `VSPHERE_SPECS_SIZE` | config, env | 5000 | Size of specs list for query stats function | +| `VSPHERE_IGNORE_SSL` | config, env | False | Ignore the ssl cert on the connection to vsphere host | +| `VSPHERE_TIMEOUT` | config, env | 120 | Set how long to wait before failing to collect | +| `VSPHERE_FETCH_CUSTOM_ATTRIBUTES` | config, env | False | Set to true to collect objects custom attributes as metric labels | +| `VSPHERE_FETCH_TAGS` | config, env | False | Set to true to collect objects tags as metric labels | +| `VSPHERE_FETCH_ALARMS` | config, env | False | Fetch objects triggered alarms, and in case of hosts hdw alarms as well | +| `VSPHERE_COLLECT_HOSTS` | config, env | True | Set to false to disable collection of host metrics | +| `VSPHERE_COLLECT_DATASTORES` | config, env | True | Set to false to disable collection of datastore metrics | +| `VSPHERE_COLLECT_VMS` | config, env | True | Set to false to disable collection of virtual machine metrics | +| `VSPHERE_COLLECT_VMGUESTS` | config, env | True | Set to false to disable collection of virtual machine guest metrics | +| `VSPHERE_COLLECT_SNAPSHOTS` | config, env | True | Set to false to disable collection of snapshot metrics | You can create new sections as well, with very similiar variables. For example, to create a `limited` section you can set: -| Variable | Precedence | Defaults | Description | -| ----------------------------------------------| ---------------------- | -------- | --------------------------------------------------------------------------| -| `VSPHERE_LIMITED_HOST` | config, env, get_param | n/a | vsphere server to connect to | -| `VSPHERE_LIMITED_USER` | config, env | n/a | User for connecting to vsphere | -| `VSPHERE_LIMITED_PASSWORD` | config, env | n/a | Password for connecting to vsphere | -| `VSPHERE_LIMITED_SPECS_SIZE` | config, env | 5000 | Size of specs list for query stats function | -| `VSPHERE_LIMITED_IGNORE_SSL` | config, env | False | Ignore the ssl cert on the connection to vsphere host | -| `VSPHERE_LIMITED_FETCH_CUSTOM_ATTRIBUTES` | config, env | False | Set to true to collect objects custom attributes as metric labels | -| `VSPHERE_LIMITED_FETCH_TAGS` | config, env | False | Set to true to collect objects tags as metric labels | -| `VSPHERE_LIMITED_FETCH_ALARMS` | config, env | False | Fetch objects triggered alarms, and in case of hosts hdw alarms as well | -| `VSPHERE_LIMITED_COLLECT_HOSTS` | config, env | True | Set to false to disable collection of host metrics | -| `VSPHERE_LIMITED_COLLECT_DATASTORES` | config, env | True | Set to false to disable collection of datastore metrics | -| `VSPHERE_LIMITED_COLLECT_VMS` | config, env | True | Set to false to disable collection of virtual machine metrics | -| `VSPHERE_LIMITED_COLLECT_VMGUESTS` | config, env | True | Set to false to disable collection of virtual machine guest metrics | -| `VSPHERE_LIMITED_COLLECT_SNAPSHOTS` | config, env | True | Set to false to disable collection of snapshot metrics | +| Variable | Precedence | Defaults | Description | +| ---------------------------------------------| ---------------------- | -------- | ---------------------------------------------------------------------------------| +| `VSPHERE_LIMITED_HOST` | config, env, get_param | n/a | vsphere server to connect to | +| `VSPHERE_LIMITED_USER` | config, env | n/a | User for connecting to vsphere | +| `VSPHERE_LIMITED_PASSWORD` | config, env | n/a | Password for connecting to vsphere | +| `VSPHERE_LIMITED_SPECS_SIZE` | config, env | 5000 | Size of specs list for query stats function | +| `VSPHERE_LIMITED_IGNORE_SSL` | config, env | False | Ignore the ssl cert on the connection to vsphere host | +| `VSPHERE_LIMITED_TIMEOUT` | config, env | 120 | Set how long to wait before failing to collect | +| `VSPHERE_LIMITED_FETCH_CUSTOM_ATTRIBUTES` | config, env | False | Set to true to collect objects custom attributes as metric labels | +| `VSPHERE_LIMITED_FETCH_TAGS` | config, env | False | Set to true to collect objects tags as metric labels | +| `VSPHERE_LIMITED_FETCH_ALARMS` | config, env | False | Fetch objects triggered alarms, and in case of hosts hdw alarms as well | +| `VSPHERE_LIMITED_COLLECT_HOSTS` | config, env | True | Set to false to disable collection of host metrics | +| `VSPHERE_LIMITED_COLLECT_DATASTORES` | config, env | True | Set to false to disable collection of datastore metrics | +| `VSPHERE_LIMITED_COLLECT_VMS` | config, env | True | Set to false to disable collection of virtual machine metrics | +| `VSPHERE_LIMITED_COLLECT_VMGUESTS` | config, env | True | Set to false to disable collection of virtual machine guest metrics | +| `VSPHERE_LIMITED_COLLECT_SNAPSHOTS` | config, env | True | Set to false to disable collection of snapshot metrics | You need to set at least `VSPHERE_SECTIONNAME_USER` for the section to be detected. diff --git a/vmware_exporter/defer.py b/vmware_exporter/defer.py index 724bde3..aadb4b2 100644 --- a/vmware_exporter/defer.py +++ b/vmware_exporter/defer.py @@ -43,7 +43,7 @@ class BranchingDeferred(defer.Deferred): ''' def __init__(self): - self.callbacks = [] + super().__init__() self.result = None def callback(self, result): diff --git a/vmware_exporter/vmware_exporter.py b/vmware_exporter/vmware_exporter.py index 3cc5482..680aff6 100755 --- a/vmware_exporter/vmware_exporter.py +++ b/vmware_exporter/vmware_exporter.py @@ -62,7 +62,8 @@ def __init__( fetch_custom_attributes=False, ignore_ssl=False, fetch_tags=False, - fetch_alarms=False + fetch_alarms=False, + timeout=None ): self.host = host @@ -71,6 +72,7 @@ def __init__( self.ignore_ssl = ignore_ssl self.collect_only = collect_only self.specs_size = int(specs_size) + self.timeout = int(timeout) if timeout else None self._session = None @@ -425,8 +427,14 @@ def _create_metric_containers(self): return metrics - @defer.inlineCallbacks def collect(self): + d_collect = self._collect() + if self.timeout is not None: + d_collect.addTimeout(self.timeout, reactor) + return d_collect + + @defer.inlineCallbacks + def _collect(self): """ collects metrics """ vsphere_host = self.host @@ -455,9 +463,10 @@ def collect(self): tasks.append(self._vmware_get_hosts(metrics)) tasks.append(self._vmware_get_host_perf_manager_metrics(metrics)) - yield parallelize(*tasks) - - yield self._vmware_disconnect() + try: + yield parallelize(*tasks) + finally: + yield self._vmware_disconnect() logging.info("Finished collecting metrics from {vsphere_host}".format(vsphere_host=vsphere_host)) @@ -1949,7 +1958,8 @@ def configure(self, args): 'datastores': get_bool_env('VSPHERE_COLLECT_DATASTORES', True), 'hosts': get_bool_env('VSPHERE_COLLECT_HOSTS', True), 'snapshots': get_bool_env('VSPHERE_COLLECT_SNAPSHOTS', True), - } + }, + 'timeout': get_bool_env('VSPHERE_TIMEOUT', 120), } for key in os.environ.keys(): @@ -1975,7 +1985,8 @@ def configure(self, args): 'datastores': get_bool_env('VSPHERE_{}_COLLECT_DATASTORES'.format(section), True), 'hosts': get_bool_env('VSPHERE_{}_COLLECT_HOSTS'.format(section), True), 'snapshots': get_bool_env('VSPHERE_{}_COLLECT_SNAPSHOTS'.format(section), True), - } + }, + 'timeout': get_bool_env('VSPHERE_{}_TIMEOUT'.format(section), 120), } def render_GET(self, request): @@ -2037,6 +2048,7 @@ def generate_latest_metrics(self, request): self.config[section]['ignore_ssl'], self.config[section]['fetch_tags'], self.config[section]['fetch_alarms'], + self.config[section]['timeout'], ) metrics = yield collector.collect() From ab16bb8ccdfe5d82f4d100583abf9cbfa1e44dc2 Mon Sep 17 00:00:00 2001 From: Z903 Date: Mon, 10 Jan 2022 12:42:00 -0800 Subject: [PATCH 7/9] Replace 500 with 400 as per https://github.com/pryorda/vmware_exporter/pull/273#discussion_r674169473 --- vmware_exporter/vmware_exporter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vmware_exporter/vmware_exporter.py b/vmware_exporter/vmware_exporter.py index 680aff6..5298281 100755 --- a/vmware_exporter/vmware_exporter.py +++ b/vmware_exporter/vmware_exporter.py @@ -2019,7 +2019,7 @@ def generate_latest_metrics(self, request): logging.info("{} is not a valid section, using default".format(section)) section = 'default' else: - request.setResponseCode(500) + request.setResponseCode(400) logging.info("Invalid section and no default defined") request.write(b'Invalid section defined!\n') request.finish() From 8ec432daba1591d5a1c5f4c8d8811534eb3d648a Mon Sep 17 00:00:00 2001 From: Z903 Date: Mon, 6 Feb 2023 12:27:25 -0800 Subject: [PATCH 8/9] Remove old commented out code --- vmware_exporter/vmware_exporter.py | 32 ------------------------------ 1 file changed, 32 deletions(-) diff --git a/vmware_exporter/vmware_exporter.py b/vmware_exporter/vmware_exporter.py index 5298281..34e7851 100755 --- a/vmware_exporter/vmware_exporter.py +++ b/vmware_exporter/vmware_exporter.py @@ -385,38 +385,6 @@ def _create_metric_containers(self): ) } ) - # metric_list['vmguests'].update( - # { - # 'vmware_vm_yellow_alarms': GaugeMetricFamily( - # 'vmware_vm_yellow_alarms', - # 'A metric with the amount of virtual machine yellow alarms and \ - # labeled with the list of alarm names', - # labels=self._labelNames['vms'] + ['alarms'] - # ), - # 'vmware_vm_red_alarms': GaugeMetricFamily( - # 'vmware_vm_red_alarms', - # 'A metric with the amount of virtual machine red alarms and \ - # labeled with the list of alarm names', - # labels=self._labelNames['vms'] + ['alarms'] - # ) - # } - # ) - # metric_list['snapshots'].update( - # { - # 'vmware_vm_yellow_alarms': GaugeMetricFamily( - # 'vmware_vm_yellow_alarms', - # 'A metric with the amount of virtual machine yellow alarms and \ - # labeled with the list of alarm names', - # labels=self._labelNames['vms'] + ['alarms'] - # ), - # 'vmware_vm_red_alarms': GaugeMetricFamily( - # 'vmware_vm_red_alarms', - # 'A metric with the amount of virtual machine red alarms and \ - # labeled with the list of alarm names', - # labels=self._labelNames['vms'] + ['alarms'] - # ) - # } - # ) metrics = {} for key, value in self.collect_only.items(): From 5c310f498ed79ed8a1dad7c02afcd55f650120f4 Mon Sep 17 00:00:00 2001 From: Z903 Date: Fri, 10 Feb 2023 22:15:04 -0800 Subject: [PATCH 9/9] Remove target and vsphere_host url parameters. Also update docs to reflect this change. --- README.md | 102 +++++++++++++---------------- vmware_exporter/vmware_exporter.py | 18 +---- 2 files changed, 47 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index 947bdbc..9f9c352 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ default: hosts: True snapshots: True -esx: +vcenter01: vsphere_host: vc.example2.com vsphere_user: 'root' vsphere_password: 'password' @@ -96,7 +96,7 @@ esx: hosts: True snapshots: True -limited: +vcenter02: vsphere_host: slowvc.example.com vsphere_user: 'administrator@vsphere.local' vsphere_password: 'password' @@ -117,41 +117,41 @@ limited: Switching sections can be done by adding ?section=limited to the URL. #### Environment Variables -| Variable | Precedence | Defaults | Description | -| ---------------------------------------------| ---------------------- | -------- | ---------------------------------------------------------------------------------| -| `VSPHERE_HOST` | config, env, get_param | n/a | vsphere server to connect to | -| `VSPHERE_USER` | config, env | n/a | User for connecting to vsphere | -| `VSPHERE_PASSWORD` | config, env | n/a | Password for connecting to vsphere | -| `VSPHERE_SPECS_SIZE` | config, env | 5000 | Size of specs list for query stats function | -| `VSPHERE_IGNORE_SSL` | config, env | False | Ignore the ssl cert on the connection to vsphere host | -| `VSPHERE_TIMEOUT` | config, env | 120 | Set how long to wait before failing to collect | -| `VSPHERE_FETCH_CUSTOM_ATTRIBUTES` | config, env | False | Set to true to collect objects custom attributes as metric labels | -| `VSPHERE_FETCH_TAGS` | config, env | False | Set to true to collect objects tags as metric labels | -| `VSPHERE_FETCH_ALARMS` | config, env | False | Fetch objects triggered alarms, and in case of hosts hdw alarms as well | -| `VSPHERE_COLLECT_HOSTS` | config, env | True | Set to false to disable collection of host metrics | -| `VSPHERE_COLLECT_DATASTORES` | config, env | True | Set to false to disable collection of datastore metrics | -| `VSPHERE_COLLECT_VMS` | config, env | True | Set to false to disable collection of virtual machine metrics | -| `VSPHERE_COLLECT_VMGUESTS` | config, env | True | Set to false to disable collection of virtual machine guest metrics | -| `VSPHERE_COLLECT_SNAPSHOTS` | config, env | True | Set to false to disable collection of snapshot metrics | +| Variable | Precedence | Defaults | Description | +| ---------------------------------------------| ------------| -------- | ---------------------------------------------------------------------------------| +| `VSPHERE_HOST` | config, env | n/a | vsphere server to connect to | +| `VSPHERE_USER` | config, env | n/a | User for connecting to vsphere | +| `VSPHERE_PASSWORD` | config, env | n/a | Password for connecting to vsphere | +| `VSPHERE_SPECS_SIZE` | config, env | 5000 | Size of specs list for query stats function | +| `VSPHERE_IGNORE_SSL` | config, env | False | Ignore the ssl cert on the connection to vsphere host | +| `VSPHERE_TIMEOUT` | config, env | 120 | Set how long to wait before failing to collect | +| `VSPHERE_FETCH_CUSTOM_ATTRIBUTES` | config, env | False | Set to true to collect objects custom attributes as metric labels | +| `VSPHERE_FETCH_TAGS` | config, env | False | Set to true to collect objects tags as metric labels | +| `VSPHERE_FETCH_ALARMS` | config, env | False | Fetch objects triggered alarms, and in case of hosts hdw alarms as well | +| `VSPHERE_COLLECT_HOSTS` | config, env | True | Set to false to disable collection of host metrics | +| `VSPHERE_COLLECT_DATASTORES` | config, env | True | Set to false to disable collection of datastore metrics | +| `VSPHERE_COLLECT_VMS` | config, env | True | Set to false to disable collection of virtual machine metrics | +| `VSPHERE_COLLECT_VMGUESTS` | config, env | True | Set to false to disable collection of virtual machine guest metrics | +| `VSPHERE_COLLECT_SNAPSHOTS` | config, env | True | Set to false to disable collection of snapshot metrics | You can create new sections as well, with very similiar variables. For example, to create a `limited` section you can set: -| Variable | Precedence | Defaults | Description | -| ---------------------------------------------| ---------------------- | -------- | ---------------------------------------------------------------------------------| -| `VSPHERE_LIMITED_HOST` | config, env, get_param | n/a | vsphere server to connect to | -| `VSPHERE_LIMITED_USER` | config, env | n/a | User for connecting to vsphere | -| `VSPHERE_LIMITED_PASSWORD` | config, env | n/a | Password for connecting to vsphere | -| `VSPHERE_LIMITED_SPECS_SIZE` | config, env | 5000 | Size of specs list for query stats function | -| `VSPHERE_LIMITED_IGNORE_SSL` | config, env | False | Ignore the ssl cert on the connection to vsphere host | -| `VSPHERE_LIMITED_TIMEOUT` | config, env | 120 | Set how long to wait before failing to collect | -| `VSPHERE_LIMITED_FETCH_CUSTOM_ATTRIBUTES` | config, env | False | Set to true to collect objects custom attributes as metric labels | -| `VSPHERE_LIMITED_FETCH_TAGS` | config, env | False | Set to true to collect objects tags as metric labels | -| `VSPHERE_LIMITED_FETCH_ALARMS` | config, env | False | Fetch objects triggered alarms, and in case of hosts hdw alarms as well | -| `VSPHERE_LIMITED_COLLECT_HOSTS` | config, env | True | Set to false to disable collection of host metrics | -| `VSPHERE_LIMITED_COLLECT_DATASTORES` | config, env | True | Set to false to disable collection of datastore metrics | -| `VSPHERE_LIMITED_COLLECT_VMS` | config, env | True | Set to false to disable collection of virtual machine metrics | -| `VSPHERE_LIMITED_COLLECT_VMGUESTS` | config, env | True | Set to false to disable collection of virtual machine guest metrics | -| `VSPHERE_LIMITED_COLLECT_SNAPSHOTS` | config, env | True | Set to false to disable collection of snapshot metrics | +| Variable | Precedence | Defaults | Description | +| ---------------------------------------------| ----------- | -------- | ---------------------------------------------------------------------------------| +| `VSPHERE_LIMITED_HOST` | config, env | n/a | vsphere server to connect to | +| `VSPHERE_LIMITED_USER` | config, env | n/a | User for connecting to vsphere | +| `VSPHERE_LIMITED_PASSWORD` | config, env | n/a | Password for connecting to vsphere | +| `VSPHERE_LIMITED_SPECS_SIZE` | config, env | 5000 | Size of specs list for query stats function | +| `VSPHERE_LIMITED_IGNORE_SSL` | config, env | False | Ignore the ssl cert on the connection to vsphere host | +| `VSPHERE_LIMITED_TIMEOUT` | config, env | 120 | Set how long to wait before failing to collect | +| `VSPHERE_LIMITED_FETCH_CUSTOM_ATTRIBUTES` | config, env | False | Set to true to collect objects custom attributes as metric labels | +| `VSPHERE_LIMITED_FETCH_TAGS` | config, env | False | Set to true to collect objects tags as metric labels | +| `VSPHERE_LIMITED_FETCH_ALARMS` | config, env | False | Fetch objects triggered alarms, and in case of hosts hdw alarms as well | +| `VSPHERE_LIMITED_COLLECT_HOSTS` | config, env | True | Set to false to disable collection of host metrics | +| `VSPHERE_LIMITED_COLLECT_DATASTORES` | config, env | True | Set to false to disable collection of datastore metrics | +| `VSPHERE_LIMITED_COLLECT_VMS` | config, env | True | Set to false to disable collection of virtual machine metrics | +| `VSPHERE_LIMITED_COLLECT_VMGUESTS` | config, env | True | Set to false to disable collection of virtual machine guest metrics | +| `VSPHERE_LIMITED_COLLECT_SNAPSHOTS` | config, env | True | Set to false to disable collection of snapshot metrics | You need to set at least `VSPHERE_SECTIONNAME_USER` for the section to be detected. @@ -160,18 +160,24 @@ You need to set at least `VSPHERE_SECTIONNAME_USER` for the section to be detect You can use the following parameters in the Prometheus configuration file. The `params` section is used to manage multiple login/passwords. ``` +# Example of Multiple vCenter usage per #23 + - job_name: 'vmware_vcenter' metrics_path: '/metrics' static_configs: - targets: - - 'vcenter.company.com' + - default + - vcenter01 + - vcenter02 relabel_configs: - source_labels: [__address__] - target_label: __param_target - - source_labels: [__param_target] + target_label: __param_section + - source_labels: [__param_section] target_label: instance - target_label: __address__ - replacement: localhost:9272 + replacement: exporter_ip:9272 + +# Example using file service discovery - job_name: 'vmware_esx' metrics_path: '/metrics' @@ -182,28 +188,12 @@ You can use the following parameters in the Prometheus configuration file. The ` section: [esx] relabel_configs: - source_labels: [__address__] - target_label: __param_target - - source_labels: [__param_target] + target_label: __param_section + - source_labels: [__param_section] target_label: instance - target_label: __address__ replacement: localhost:9272 -# Example of Multiple vCenter usage per #23 - -- job_name: vmware_export - metrics_path: /metrics - static_configs: - - targets: - - vcenter01 - - vcenter02 - - vcenter03 - relabel_configs: - - source_labels: [__address__] - target_label: __param_target - - source_labels: [__param_target] - target_label: instance - - target_label: __address__ - replacement: exporter_ip:9272 ``` ## Current Status diff --git a/vmware_exporter/vmware_exporter.py b/vmware_exporter/vmware_exporter.py index 34e7851..7138381 100755 --- a/vmware_exporter/vmware_exporter.py +++ b/vmware_exporter/vmware_exporter.py @@ -1900,7 +1900,6 @@ def __init__(self, args): self.configure(args) def configure(self, args): - self.allow_url_target = args.allow_url_target if args.config_file: try: with open(args.config_file) as cf: @@ -1993,21 +1992,8 @@ def generate_latest_metrics(self, request): request.finish() return - if (self.config[section].get('vsphere_host') or "None") != "None": - vsphere_host = self.config[section]['vsphere_host'] - elif self.allow_url_target and request.args.get(b'target', [None])[0]: - vsphere_host = request.args.get(b'target', [None])[0].decode('utf-8') - elif self.allow_url_target and request.args.get(b'vsphere_host', [None])[0]: - vsphere_host = request.args.get(b'vsphere_host')[0].decode('utf-8') - else: - request.setResponseCode(500) - logging.info("No vsphere_host or target defined") - request.write(b'No vsphere_host or target defined!\n') - request.finish() - return - collector = VmwareCollector( - vsphere_host, + self.config[section]['vsphere_host'], self.config[section]['vsphere_user'], self.config[section]['vsphere_password'], self.config[section]['collect_only'], @@ -2080,8 +2066,6 @@ def main(argv=None): default=9272, help="HTTP port to expose metrics") parser.add_argument('-l', '--loglevel', dest='loglevel', default="INFO", help="Set application loglevel INFO, DEBUG") - parser.add_argument('--allow-url-target', action='store_true', - help="Allow vsphere host to be specified as url a parameter") args = parser.parse_args(argv or sys.argv[1:])