Skip to content

Commit a1bb45a

Browse files
kremerspryorda
authored andcommitted
fix(metric-errors): fixing labeling bugs
* Added test showing the metrics problem with different access privs Signed-off-by: Martin Kremers <[email protected]> * fix(wrong labels): restricted access user resultet in wrong labeling Signed-off-by: Martin Kremers <[email protected]> Precommit-Verified: 2c286246f4ed6f28b351d7ee9e2966f72d21bfe407f3b7f5a303e1271633fb71
1 parent 68db001 commit a1bb45a

File tree

2 files changed

+141
-10
lines changed

2 files changed

+141
-10
lines changed

tests/unit/test_vmware_exporter.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,128 @@ def test_collect_vms():
259259
assert metrics['vmware_vm_memory_max'].samples[0][2] == 1024
260260

261261

262+
@pytest_twisted.inlineCallbacks
263+
# @pytest.mark.skip
264+
def test_metrics_without_hostaccess():
265+
boot_time = EPOCH + datetime.timedelta(seconds=60)
266+
disk = mock.Mock()
267+
disk.diskPath = '/boot'
268+
disk.capacity = 100
269+
disk.freeSpace = 50
270+
271+
collect_only = {
272+
'vms': True,
273+
'vmguests': True,
274+
'datastores': False,
275+
'hosts': False,
276+
'snapshots': False,
277+
}
278+
279+
collector = VmwareCollector(
280+
'127.0.0.1',
281+
'root',
282+
'password',
283+
collect_only,
284+
)
285+
metrics = collector._create_metric_containers()
286+
collector.content = _succeed(mock.Mock())
287+
collector.__dict__['host_labels'] = _succeed({'': []})
288+
289+
with mock.patch.object(collector, 'batch_fetch_properties') as batch_fetch_properties:
290+
batch_fetch_properties.return_value = _succeed({
291+
'vm-1': {
292+
'name': 'vm-x',
293+
'runtime.host': vim.ManagedObject('notfound:1'),
294+
'runtime.powerState': 'poweredOn',
295+
'summary.config.numCpu': 1,
296+
'summary.config.memorySizeMB': 1024,
297+
'runtime.bootTime': boot_time,
298+
'guest.disk': [disk],
299+
'guest.toolsStatus': 'toolsOk',
300+
'guest.toolsVersion': '10336',
301+
'guest.toolsVersionStatus2': 'guestToolsUnmanaged',
302+
}
303+
})
304+
assert collector.vm_labels.result == {'vm-1': ['vm-x']}
305+
yield collector._vmware_get_vms(metrics)
306+
307+
# 113 AssertionError {'partition': '/boot'} vs {'host_name': '/boot'}
308+
assert metrics['vmware_vm_guest_disk_capacity'].samples[0][1] == {
309+
'vm_name': 'vm-x',
310+
'partition': '/boot',
311+
'host_name': 'n/a',
312+
'cluster_name': 'n/a',
313+
'dc_name': 'n/a',
314+
}
315+
316+
# Fail due to expected labels ['vm-1', 'host-1', 'dc', 'cluster-1']
317+
# but found ['vm-1']
318+
assert metrics['vmware_vm_power_state'].samples[0][1] == {
319+
'vm_name': 'vm-x',
320+
'host_name': 'n/a',
321+
'cluster_name': 'n/a',
322+
'dc_name': 'n/a',
323+
}
324+
325+
326+
@pytest_twisted.inlineCallbacks
327+
def test_no_error_onempty_vms():
328+
collect_only = {
329+
'vms': True,
330+
'vmguests': True,
331+
'datastores': False,
332+
'hosts': False,
333+
'snapshots': False,
334+
}
335+
collector = VmwareCollector(
336+
'127.0.0.1',
337+
'root',
338+
'password',
339+
collect_only,
340+
ignore_ssl=True,
341+
)
342+
343+
metrics = collector._create_metric_containers()
344+
345+
metric_1 = mock.Mock()
346+
metric_1.id.counterId = 9
347+
metric_1.value = [9]
348+
349+
metric_2 = mock.Mock()
350+
metric_2.id.counterId = 1
351+
metric_2.value = [1]
352+
353+
ent_1 = mock.Mock()
354+
ent_1.value = [metric_1, metric_2]
355+
ent_1.entity = vim.ManagedObject('vm:1')
356+
357+
content = mock.Mock()
358+
content.perfManager.QueryStats.return_value = [ent_1]
359+
collector.content = _succeed(content)
360+
361+
collector.__dict__['counter_ids'] = _succeed({
362+
'cpu.ready.summation': 1,
363+
'cpu.usage.average': 2,
364+
'cpu.usagemhz.average': 3,
365+
'disk.usage.average': 4,
366+
'disk.read.average': 5,
367+
'disk.write.average': 6,
368+
'mem.usage.average': 7,
369+
'net.received.average': 8,
370+
'net.transmitted.average': 9,
371+
})
372+
373+
collector.__dict__['vm_labels'] = _succeed({'': []})
374+
collector.__dict__['vm_inventory'] = _succeed({'': {}})
375+
376+
# Try to test for querySpec=[]
377+
# threads.deferToThread(content.perfManager.QueryStats, querySpec=specs),
378+
# TypeError Required field "querySpec" not provided (not @optional)
379+
yield collector._vmware_get_vm_perf_manager_metrics(metrics)
380+
381+
assert metrics['vmware_vm_power_state'].samples == []
382+
383+
262384
@pytest_twisted.inlineCallbacks
263385
def test_collect_vm_perf():
264386
collect_only = {

vmware_exporter/vmware_exporter.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -597,17 +597,19 @@ def _vmware_get_vm_perf_manager_metrics(self, vm_metrics):
597597

598598
content = yield self.content
599599

600-
results, labels = yield parallelize(
601-
threads.deferToThread(content.perfManager.QueryStats, querySpec=specs),
602-
self.vm_labels,
603-
)
600+
if len(specs) > 0:
601+
results, labels = yield parallelize(
602+
threads.deferToThread(content.perfManager.QueryStats, querySpec=specs),
603+
self.vm_labels,
604+
)
605+
606+
for ent in results:
607+
for metric in ent.value:
608+
vm_metrics[metric_names[metric.id.counterId]].add_metric(
609+
labels[ent.entity._moId],
610+
float(sum(metric.value)),
611+
)
604612

605-
for ent in results:
606-
for metric in ent.value:
607-
vm_metrics[metric_names[metric.id.counterId]].add_metric(
608-
labels[ent.entity._moId],
609-
float(sum(metric.value)),
610-
)
611613
logging.info('FIN: _vmware_get_vm_perf_manager_metrics')
612614

613615
@defer.inlineCallbacks
@@ -626,6 +628,13 @@ def _vmware_get_vms(self, metrics):
626628
continue
627629

628630
labels = vm_labels[moid]
631+
labels_cnt = len(labels)
632+
633+
if labels_cnt < 4:
634+
logging.info("Only ${cnt}/4 labels (vm, host, dc, cluster) found, filling n/a".format(cnt=labels_cnt))
635+
636+
for i in range(labels_cnt, 4):
637+
labels.append('n/a')
629638

630639
if 'runtime.powerState' in row:
631640
power_state = 1 if row['runtime.powerState'] == 'poweredOn' else 0

0 commit comments

Comments
 (0)