Skip to content

Commit 89700ad

Browse files
committed
feat(volumes): Added support for volume and volume snapshot metrics
Also fixes datetime deprecation and deferring problem using a newer version than twisted 24.7.0 Because fetching all the snapshots takes quite some time, I've deactivated it by default, because scrape timeouts need to set higher for this. #274
1 parent 9f9bfaf commit 89700ad

File tree

2 files changed

+79
-11
lines changed

2 files changed

+79
-11
lines changed

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
prometheus-client==0.0.19
22
pytz
33
pyvmomi>=6.5
4-
twisted>=14.0.2
4+
twisted==24.7.0
55
pyyaml>=5.1
66
service-identity
7+
requests

vmware_exporter/vmware_exporter.py

Lines changed: 77 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ def __init__(
101101
'datastores': ['ds_name', 'dc_name', 'ds_cluster'],
102102
'hosts': ['host_name', 'dc_name', 'cluster_name'],
103103
'host_perf': ['host_name', 'dc_name', 'cluster_name'],
104+
'volumes': ['datastore', 'volume', 'backing_file_path'],
104105
}
105106

106107
# if tags are gonna be fetched 'tags' will be a label too
@@ -295,6 +296,23 @@ def _create_metric_containers(self):
295296
'VMWare sensor redundancy value (1=ok / 0=ko) labeled by sensor name from the host.',
296297
labels=self._labelNames['hosts'] + ['name']),
297298
}
299+
metric_list['volumes'] = {
300+
'vmware_volume_snapshots': GaugeMetricFamily(
301+
'vmware_volume_snapshots',
302+
'Number of snaphots for the volume',
303+
labels=self._labelNames['volumes'],
304+
),
305+
'vmware_volume_capacity_bytes': GaugeMetricFamily(
306+
'vmware_volume_capacity_bytes',
307+
'The configured capacity of the volume',
308+
labels=self._labelNames['volumes'],
309+
),
310+
'vmware_volume_snapshot_createtime': GaugeMetricFamily(
311+
'vmware_volume_snapshot_createtime',
312+
'Create time of snapshot as a unix timestamp',
313+
labels=self._labelNames['volumes'] + ['snapshot_id'],
314+
)
315+
}
298316

299317
"""
300318
if alarms are being retrieved, metrics have to been created here
@@ -427,6 +445,9 @@ def collect(self):
427445
tasks.append(self._vmware_get_hosts(metrics))
428446
tasks.append(self._vmware_get_host_perf_manager_metrics(metrics))
429447

448+
if collect_only['volumes'] is True:
449+
tasks.append(self._vmware_get_volumes(metrics))
450+
430451
yield parallelize(*tasks)
431452

432453
yield self._vmware_disconnect()
@@ -534,7 +555,7 @@ def tags(self):
534555
and linked to object moid
535556
"""
536557
logging.info("Fetching tags")
537-
start = datetime.datetime.utcnow()
558+
start = datetime.datetime.now(datetime.UTC)
538559

539560
attachedObjs = yield self._attachedObjectsOnTags
540561
tagNames = yield self._tagNames
@@ -556,7 +577,7 @@ def tags(self):
556577
else:
557578
tags[section][obj.get('id')].append(tagName)
558579

559-
fetch_time = datetime.datetime.utcnow() - start
580+
fetch_time = datetime.datetime.now(datetime.UTC) - start
560581
logging.info("Fetched tags ({fetch_time})".format(fetch_time=fetch_time))
561582

562583
return tags
@@ -612,7 +633,7 @@ def batch_fetch_properties(self, objtype, properties):
612633
@defer.inlineCallbacks
613634
def datastore_inventory(self):
614635
logging.info("Fetching vim.Datastore inventory")
615-
start = datetime.datetime.utcnow()
636+
start = datetime.datetime.now(datetime.UTC)
616637
properties = [
617638
'name',
618639
'summary.capacity',
@@ -657,7 +678,7 @@ def datastore_inventory(self):
657678
]
658679
)
659680

660-
fetch_time = datetime.datetime.utcnow() - start
681+
fetch_time = datetime.datetime.now(datetime.UTC) - start
661682
logging.info("Fetched vim.Datastore inventory ({fetch_time})".format(fetch_time=fetch_time))
662683

663684
return datastores
@@ -666,7 +687,7 @@ def datastore_inventory(self):
666687
@defer.inlineCallbacks
667688
def host_system_inventory(self):
668689
logging.info("Fetching vim.HostSystem inventory")
669-
start = datetime.datetime.utcnow()
690+
start = datetime.datetime.now(datetime.UTC)
670691
properties = [
671692
'name',
672693
'parent',
@@ -723,7 +744,7 @@ def host_system_inventory(self):
723744
]
724745
)
725746

726-
fetch_time = datetime.datetime.utcnow() - start
747+
fetch_time = datetime.datetime.now(datetime.UTC) - start
727748
logging.info("Fetched vim.HostSystem inventory ({fetch_time})".format(fetch_time=fetch_time))
728749

729750
return host_systems
@@ -732,7 +753,7 @@ def host_system_inventory(self):
732753
@defer.inlineCallbacks
733754
def vm_inventory(self):
734755
logging.info("Fetching vim.VirtualMachine inventory")
735-
start = datetime.datetime.utcnow()
756+
start = datetime.datetime.now(datetime.UTC)
736757
properties = [
737758
'name',
738759
'runtime.host',
@@ -792,7 +813,7 @@ def vm_inventory(self):
792813
]
793814
)
794815

795-
fetch_time = datetime.datetime.utcnow() - start
816+
fetch_time = datetime.datetime.now(datetime.UTC) - start
796817
logging.info("Fetched vim.VirtualMachine inventory ({fetch_time})".format(fetch_time=fetch_time))
797818

798819
return virtual_machines
@@ -1701,8 +1722,8 @@ def _vmware_get_hosts(self, host_metrics):
17011722

17021723
# Numeric Sensor Info
17031724
sensors = host.get('runtime.healthSystemRuntime.systemHealthInfo.numericSensorInfo', '').split(',') + \
1704-
host.get('runtime.healthSystemRuntime.hardwareStatusInfo.cpuStatusInfo', '').split(',') + \
1705-
host.get('runtime.healthSystemRuntime.hardwareStatusInfo.memoryStatusInfo', '').split(',')
1725+
host.get('runtime.healthSystemRuntime.hardwareStatusInfo.cpuStatusInfo', '').split(',') + \
1726+
host.get('runtime.healthSystemRuntime.hardwareStatusInfo.memoryStatusInfo', '').split(',')
17061727

17071728
sensors = [s for s in sensors if ':' in s]
17081729

@@ -1847,6 +1868,50 @@ def _vmware_get_hosts(self, host_metrics):
18471868
logging.info("Finished host metrics collection")
18481869
return results
18491870

1871+
@defer.inlineCallbacks
1872+
def _vmware_get_volumes(self, vol_metrics):
1873+
"""
1874+
Get Volume information
1875+
"""
1876+
1877+
datastores = yield parallelize(self.datastore_inventory)
1878+
content = yield self.content
1879+
1880+
for datastore_id, datastore in datastores[0].items():
1881+
volumes = content.vStorageObjectManager.ListVStorageObject(datastore['obj'])
1882+
for volume_ref in volumes:
1883+
try:
1884+
volume = content.vStorageObjectManager.RetrieveVStorageObject(volume_ref, datastore['obj'])
1885+
except vim.fault.NotFound:
1886+
logging.error("Volume %s was listed in the datastore, but the storage object could not be found",
1887+
volume_ref.id)
1888+
except Exception as error:
1889+
logging.error("Error fetching volume information for volume %s: %s", volume_ref.id, error)
1890+
try:
1891+
snapshot_info = content.vStorageObjectManager.RetrieveSnapshotInfo(volume_ref, datastore['obj'])
1892+
vol_metrics['vmware_volume_snapshots'].add_metric([
1893+
datastore['name'],
1894+
volume.config.name,
1895+
volume.config.backing.filePath
1896+
], len(snapshot_info.snapshots))
1897+
1898+
vol_metrics['vmware_volume_capacity_bytes'].add_metric([
1899+
datastore['name'],
1900+
volume.config.name,
1901+
volume.config.backing.filePath
1902+
], volume.config.capacityInMB * 1024 * 1024)
1903+
1904+
for snapshot in snapshot_info.snapshots:
1905+
vol_metrics['vmware_volume_snapshot_createtime'].add_metric([
1906+
datastore['name'],
1907+
volume.config.name,
1908+
volume.config.backing.filePath,
1909+
snapshot.id.id,
1910+
], int(snapshot.createTime.timestamp()))
1911+
except vim.fault.NotFound:
1912+
logging.error("Snapshot info for volume %s not found",volume_ref.id)
1913+
except Exception as error:
1914+
logging.error("Error fetching snapshot information for volume: %s", volume_ref.id, error)
18501915

18511916
class ListCollector(object):
18521917

@@ -1896,6 +1961,7 @@ def configure(self, args):
18961961
'datastores': get_bool_env('VSPHERE_COLLECT_DATASTORES', True),
18971962
'hosts': get_bool_env('VSPHERE_COLLECT_HOSTS', True),
18981963
'snapshots': get_bool_env('VSPHERE_COLLECT_SNAPSHOTS', True),
1964+
'volumes': get_bool_env('VSPHERE_COLLECT_VOLUMES', False),
18991965
}
19001966
}
19011967
}
@@ -1923,6 +1989,7 @@ def configure(self, args):
19231989
'datastores': get_bool_env('VSPHERE_{}_COLLECT_DATASTORES'.format(section), True),
19241990
'hosts': get_bool_env('VSPHERE_{}_COLLECT_HOSTS'.format(section), True),
19251991
'snapshots': get_bool_env('VSPHERE_{}_COLLECT_SNAPSHOTS'.format(section), True),
1992+
'volumes': get_bool_env('VSPHERE_COLLECT_VOLUMES', False),
19261993
}
19271994
}
19281995

0 commit comments

Comments
 (0)