Merge "VMware: add support for VM diagnostics"
This commit is contained in:
commit
6728c7e353
@ -653,9 +653,23 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
|
|||||||
instance=None)
|
instance=None)
|
||||||
|
|
||||||
def test_get_diagnostics(self):
|
def test_get_diagnostics(self):
|
||||||
# Simply tests that the VMwareESXDriver doesn't implement the
|
self._create_vm()
|
||||||
# get_diagnostics API.
|
expected = {'memoryReservation': 0, 'suspendInterval': 0,
|
||||||
self.assertRaises(NotImplementedError, self.conn.get_diagnostics, None)
|
'maxCpuUsage': 2000, 'toolsInstallerMounted': False,
|
||||||
|
'consumedOverheadMemory': 20, 'numEthernetCards': 1,
|
||||||
|
'numCpu': 1, 'featureRequirement': [{'key': 'cpuid.AES'}],
|
||||||
|
'memoryOverhead': 21417984,
|
||||||
|
'guestMemoryUsage': 0, 'connectionState': 'connected',
|
||||||
|
'memorySizeMB': 512, 'balloonedMemory': 0,
|
||||||
|
'vmPathName': 'fake_path', 'template': False,
|
||||||
|
'overallCpuUsage': 0, 'powerState': 'poweredOn',
|
||||||
|
'cpuReservation': 0, 'overallCpuDemand': 0,
|
||||||
|
'numVirtualDisks': 1, 'hostMemoryUsage': 141}
|
||||||
|
expected = dict([('vmware:' + k, v) for k, v in expected.items()])
|
||||||
|
self.assertThat(
|
||||||
|
self.conn.get_diagnostics({'name': 1, 'uuid': self.uuid,
|
||||||
|
'node': self.instance_node}),
|
||||||
|
matchers.DictMatches(expected))
|
||||||
|
|
||||||
def test_get_console_output(self):
|
def test_get_console_output(self):
|
||||||
self._create_instance_in_the_db()
|
self._create_instance_in_the_db()
|
||||||
@ -1215,13 +1229,6 @@ class VMwareAPIVCDriverTestCase(VMwareAPIVMTestCase):
|
|||||||
self.conn.unplug_vifs,
|
self.conn.unplug_vifs,
|
||||||
instance=self.instance, network_info=None)
|
instance=self.instance, network_info=None)
|
||||||
|
|
||||||
def test_get_diagnostics(self):
|
|
||||||
# Tests that the VMwareVCDriver doesn't implement get_diagnostics.
|
|
||||||
self._create_instance_in_the_db()
|
|
||||||
self.assertRaises(NotImplementedError,
|
|
||||||
self.conn.get_diagnostics,
|
|
||||||
self.instance)
|
|
||||||
|
|
||||||
def test_migrate_disk_and_power_off(self):
|
def test_migrate_disk_and_power_off(self):
|
||||||
def fake_update_instance_progress(context, instance, step,
|
def fake_update_instance_progress(context, instance, step,
|
||||||
total_steps):
|
total_steps):
|
||||||
|
@ -325,6 +325,38 @@ class VirtualMachine(ManagedObject):
|
|||||||
self.set("config.extraConfig", kwargs.get("extra_config", None))
|
self.set("config.extraConfig", kwargs.get("extra_config", None))
|
||||||
self.set('runtime.host', kwargs.get("runtime_host", None))
|
self.set('runtime.host', kwargs.get("runtime_host", None))
|
||||||
self.device = kwargs.get("virtual_device")
|
self.device = kwargs.get("virtual_device")
|
||||||
|
# Sample of diagnostics data is below.
|
||||||
|
config = [
|
||||||
|
('template', False),
|
||||||
|
('vmPathName', 'fake_path'),
|
||||||
|
('memorySizeMB', 512),
|
||||||
|
('cpuReservation', 0),
|
||||||
|
('memoryReservation', 0),
|
||||||
|
('numCpu', 1),
|
||||||
|
('numEthernetCards', 1),
|
||||||
|
('numVirtualDisks', 1)]
|
||||||
|
self.set("summary.config", config)
|
||||||
|
|
||||||
|
quickStats = [
|
||||||
|
('overallCpuUsage', 0),
|
||||||
|
('overallCpuDemand', 0),
|
||||||
|
('guestMemoryUsage', 0),
|
||||||
|
('hostMemoryUsage', 141),
|
||||||
|
('balloonedMemory', 0),
|
||||||
|
('consumedOverheadMemory', 20)]
|
||||||
|
self.set("summary.quickStats", quickStats)
|
||||||
|
|
||||||
|
key1 = {'key': 'cpuid.AES'}
|
||||||
|
key2 = {'key': 'cpuid.AVX'}
|
||||||
|
runtime = [
|
||||||
|
('connectionState', 'connected'),
|
||||||
|
('powerState', 'poweredOn'),
|
||||||
|
('toolsInstallerMounted', False),
|
||||||
|
('suspendInterval', 0),
|
||||||
|
('memoryOverhead', 21417984),
|
||||||
|
('maxCpuUsage', 2000),
|
||||||
|
('featureRequirement', [key1, key2])]
|
||||||
|
self.set("summary.runtime", runtime)
|
||||||
|
|
||||||
def reconfig(self, factory, val):
|
def reconfig(self, factory, val):
|
||||||
"""
|
"""
|
||||||
|
@ -51,6 +51,32 @@ def get_moref(value, type):
|
|||||||
return moref
|
return moref
|
||||||
|
|
||||||
|
|
||||||
|
def object_to_dict(obj, list_depth=1):
|
||||||
|
"""Convert Suds object into serializable format.
|
||||||
|
|
||||||
|
The calling function can limit the amount of list entries that
|
||||||
|
are converted.
|
||||||
|
"""
|
||||||
|
d = {}
|
||||||
|
for k, v in suds.sudsobject.asdict(obj).iteritems():
|
||||||
|
if hasattr(v, '__keylist__'):
|
||||||
|
d[k] = object_to_dict(v, list_depth=list_depth)
|
||||||
|
elif isinstance(v, list):
|
||||||
|
d[k] = []
|
||||||
|
used = 0
|
||||||
|
for item in v:
|
||||||
|
used = used + 1
|
||||||
|
if used > list_depth:
|
||||||
|
break
|
||||||
|
if hasattr(item, '__keylist__'):
|
||||||
|
d[k].append(object_to_dict(item, list_depth=list_depth))
|
||||||
|
else:
|
||||||
|
d[k].append(item)
|
||||||
|
else:
|
||||||
|
d[k] = v
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
class VIMMessagePlugin(suds.plugin.MessagePlugin):
|
class VIMMessagePlugin(suds.plugin.MessagePlugin):
|
||||||
def addAttributeForValue(self, node):
|
def addAttributeForValue(self, node):
|
||||||
# suds does not handle AnyType properly.
|
# suds does not handle AnyType properly.
|
||||||
|
@ -46,6 +46,7 @@ from nova import utils
|
|||||||
from nova.virt import configdrive
|
from nova.virt import configdrive
|
||||||
from nova.virt import driver
|
from nova.virt import driver
|
||||||
from nova.virt.vmwareapi import vif as vmwarevif
|
from nova.virt.vmwareapi import vif as vmwarevif
|
||||||
|
from nova.virt.vmwareapi import vim
|
||||||
from nova.virt.vmwareapi import vim_util
|
from nova.virt.vmwareapi import vim_util
|
||||||
from nova.virt.vmwareapi import vm_util
|
from nova.virt.vmwareapi import vm_util
|
||||||
from nova.virt.vmwareapi import vmware_images
|
from nova.virt.vmwareapi import vmware_images
|
||||||
@ -1294,10 +1295,36 @@ class VMwareVMOps(object):
|
|||||||
'num_cpu': int(query['summary.config.numCpu']),
|
'num_cpu': int(query['summary.config.numCpu']),
|
||||||
'cpu_time': 0}
|
'cpu_time': 0}
|
||||||
|
|
||||||
|
def _get_diagnostic_from_object_properties(self, props, wanted_props):
|
||||||
|
diagnostics = {}
|
||||||
|
while props:
|
||||||
|
for elem in props.objects:
|
||||||
|
for prop in elem.propSet:
|
||||||
|
if prop.name in wanted_props:
|
||||||
|
prop_dict = vim.object_to_dict(prop.val, list_depth=1)
|
||||||
|
diagnostics.update(prop_dict)
|
||||||
|
token = vm_util._get_token(props)
|
||||||
|
if not token:
|
||||||
|
break
|
||||||
|
|
||||||
|
props = self._session._call_method(vim_util,
|
||||||
|
"continue_to_get_objects",
|
||||||
|
token)
|
||||||
|
return diagnostics
|
||||||
|
|
||||||
def get_diagnostics(self, instance):
|
def get_diagnostics(self, instance):
|
||||||
"""Return data about VM diagnostics."""
|
"""Return data about VM diagnostics."""
|
||||||
msg = _("get_diagnostics not implemented for vmwareapi")
|
vm_ref = vm_util.get_vm_ref(self._session, instance)
|
||||||
raise NotImplementedError(msg)
|
lst_properties = ["summary.config",
|
||||||
|
"summary.quickStats",
|
||||||
|
"summary.runtime"]
|
||||||
|
vm_props = self._session._call_method(vim_util,
|
||||||
|
"get_object_properties", None, vm_ref, "VirtualMachine",
|
||||||
|
lst_properties)
|
||||||
|
data = self._get_diagnostic_from_object_properties(vm_props,
|
||||||
|
set(lst_properties))
|
||||||
|
# Add a namespace to all of the diagnostsics
|
||||||
|
return dict([('vmware:' + k, v) for k, v in data.items()])
|
||||||
|
|
||||||
def get_console_output(self, instance):
|
def get_console_output(self, instance):
|
||||||
"""Return snapshot of console."""
|
"""Return snapshot of console."""
|
||||||
|
Loading…
Reference in New Issue
Block a user