Replace diagnostics objects with Nova diagnostics objects

New objects are children of NovaObject class. Such parent
will give us a good control of objects versioning. Also it
will force contributors to dump objects version in case of
any changes. These objects will be used to transmit data
via RPC. Old objects were used only for storing data.
During RPC transmission they are transform into dictionaries.
It is not right approach because we will have some problems
in case of adding new diagnostics fields.

Version of compute RPC was bumped.

Also some changes were made in libvirt driver method
get_instance_diagnostics(). These changes were made to fill
new fields of 'Diagnostics' object.

Implementation of method get_instance_diagnostics()
for other virt drivers will be changed in future patches.

blueprint: restore-vm-diagnostics

Change-Id: I5e2d116df045f803c654f7810b939b5fc859cfbf
This commit is contained in:
Sergey Nikitin 2017-02-16 12:33:20 +04:00
parent 2cf846e1e7
commit a6335343cf
16 changed files with 205 additions and 722 deletions

View File

@ -13,7 +13,7 @@
"disabled_reason": null,
"report_count": 1,
"forced_down": false,
"version": 17,
"version": 18,
"availability_zone": null,
"uuid": "fa69c544-906b-4a6a-a9c6-c1f7a8078c73"
}

View File

@ -486,7 +486,7 @@ class ComputeVirtAPI(virtapi.VirtAPI):
class ComputeManager(manager.Manager):
"""Manages the running instances from creation to destruction."""
target = messaging.Target(version='4.13')
target = messaging.Target(version='4.14')
# How long to wait in seconds before re-issuing a shutdown
# signal to an instance during power off. The overall
@ -4269,8 +4269,7 @@ class ComputeManager(manager.Manager):
current_power_state = self._get_power_state(context, instance)
if current_power_state == power_state.RUNNING:
LOG.info(_LI("Retrieving diagnostics"), instance=instance)
diags = self.driver.get_instance_diagnostics(instance)
return diags.serialize()
return self.driver.get_instance_diagnostics(instance)
else:
raise exception.InstanceInvalidState(
attr='power state',

View File

@ -319,6 +319,11 @@ class ComputeAPI(object):
... Newton and Ocata support messaging version 4.13. So, any changes to
existing methods in 4.x after that point should be done so that they
can handle the version_cap being set to 4.13
* 4.14 - Make get_instance_diagnostics return a diagnostics object
instead of dictionary. Strictly speaking we don't need to bump
the version because this method was unused before. The version
was bumped to signal the availability of the corrected RPC API
'''
VERSION_ALIASES = {
@ -566,13 +571,17 @@ class ComputeAPI(object):
return cctxt.call(ctxt, 'get_diagnostics', instance=instance)
def get_instance_diagnostics(self, ctxt, instance):
version = '4.13'
version = '4.14'
client = self.router.client(ctxt)
if not client.can_send_version(version):
version = '4.0'
instance = objects_base.obj_to_primitive(instance)
# NOTE(snikitin): Since version 4.14 method
# get_instance_diagnostics() returns Diagnostics object instead of
# dictionary. But this method was unused before version 4.14. That
# is why we can raise an exception if RPC API version is too old.
raise exception.InstanceDiagnosticsNotSupported()
cctxt = client.prepare(server=_compute_host(None, instance),
version=version)
version=version)
return cctxt.call(ctxt, 'get_instance_diagnostics', instance=instance)
def get_vnc_console(self, ctxt, instance, console_type):

View File

@ -2042,6 +2042,10 @@ class AttachInterfaceNotSupported(Invalid):
"instance %(instance_uuid)s.")
class InstanceDiagnosticsNotSupported(Invalid):
msg_fmt = _("Instance diagnostics is not supported by compute node.")
class InvalidReservedMemoryPagesOption(Invalid):
msg_fmt = _("The format of the option 'reserved_huge_pages' is invalid. "
"(found '%(conf)s') Please refer to the nova "

View File

@ -31,7 +31,7 @@ LOG = logging.getLogger(__name__)
# NOTE(danms): This is the global service version counter
SERVICE_VERSION = 17
SERVICE_VERSION = 18
# NOTE(danms): This is our SERVICE_VERSION history. The idea is that any
@ -101,6 +101,8 @@ SERVICE_VERSION_HISTORY = (
# the old check in the API as the old computes fail if the volume is moved
# to 'attaching' state by reserve.
{'compute_rpc': '4.13'},
# Version 18: Compute RPC version 4.14
{'compute_rpc': '4.14'},
)

View File

@ -72,6 +72,7 @@ from nova.tests import fixtures
from nova.tests.unit.compute import eventlet_utils
from nova.tests.unit.compute import fake_resource_tracker
from nova.tests.unit import fake_block_device
from nova.tests.unit import fake_diagnostics
from nova.tests.unit import fake_instance
from nova.tests.unit import fake_network
from nova.tests.unit import fake_network_cache_model
@ -79,6 +80,7 @@ from nova.tests.unit import fake_notifier
from nova.tests.unit import fake_server_actions
from nova.tests.unit.image import fake as fake_image
from nova.tests.unit import matchers
from nova.tests.unit.objects import test_diagnostics
from nova.tests.unit.objects import test_flavor
from nova.tests.unit.objects import test_instance_numa_topology
from nova.tests.unit.objects import test_migration
@ -1430,7 +1432,8 @@ class ComputeVolumeTestCase(BaseTestCase):
get_swap.assert_called_once_with([])
class ComputeTestCase(BaseTestCase):
class ComputeTestCase(BaseTestCase,
test_diagnostics.DiagnosticsComparisonMixin):
def setUp(self):
super(ComputeTestCase, self).setUp()
self.useFixture(fixtures.SpawnIsSynchronousFixture())
@ -4028,30 +4031,33 @@ class ComputeTestCase(BaseTestCase):
diagnostics = self.compute.get_instance_diagnostics(self.context,
instance=instance)
expected = {'config_drive': True,
'cpu_details': [{'time': 17300000000}],
'disk_details': [{'errors_count': 0,
'id': 'fake-disk-id',
'read_bytes': 262144,
'read_requests': 112,
'write_bytes': 5778432,
'write_requests': 488}],
'driver': 'fake',
'hypervisor_os': 'fake-os',
'memory_details': {'maximum': 524288, 'used': 0},
'nic_details': [{'mac_address': '01:23:45:67:89:ab',
'rx_drop': 0,
'rx_errors': 0,
'rx_octets': 2070139,
'rx_packets': 26701,
'tx_drop': 0,
'tx_errors': 0,
'tx_octets': 140208,
'tx_packets': 662}],
'state': 'running',
'uptime': 46664,
'version': '1.0'}
self.assertEqual(expected, diagnostics)
expected = fake_diagnostics.fake_diagnostics_obj(
config_drive=True,
cpu_details=[{'id': 0, 'time': 17300000000, 'utilisation': 15}],
disk_details=[{'errors_count': 1,
'read_bytes': 262144,
'read_requests': 112,
'write_bytes': 5778432,
'write_requests': 488}],
driver='libvirt',
hypervisor='fake-hypervisor',
hypervisor_os='fake-os',
memory_details={'maximum': 524288, 'used': 0},
nic_details=[{'mac_address': '01:23:45:67:89:ab',
'rx_octets': 2070139,
'rx_errors': 100,
'rx_drop': 200,
'rx_packets': 26701,
'rx_rate': 300,
'tx_octets': 140208,
'tx_errors': 400,
'tx_drop': 500,
'tx_packets': 662,
'tx_rate': 600}],
state='running',
uptime=46664)
self.assertDiagnosticsEqual(expected, diagnostics)
self.compute.terminate_instance(self.context, instance, [], [])
def test_add_fixed_ip_usage_notification(self):

View File

@ -277,7 +277,7 @@ class ComputeRpcAPITestCase(test.NoDBTestCase):
expected_args = {'instance': self.fake_instance_obj}
self._test_compute_api('get_instance_diagnostics', 'call',
expected_args, instance=self.fake_instance_obj,
version='4.13')
version='4.14')
def test_get_vnc_console(self):
self._test_compute_api('get_vnc_console', 'call',

View File

@ -73,10 +73,12 @@ from nova.pci import manager as pci_manager
from nova.pci import utils as pci_utils
from nova import test
from nova.tests.unit import fake_block_device
from nova.tests.unit import fake_diagnostics
from nova.tests.unit import fake_instance
from nova.tests.unit import fake_network
import nova.tests.unit.image.fake
from nova.tests.unit import matchers
from nova.tests.unit.objects import test_diagnostics
from nova.tests.unit.objects import test_pci_device
from nova.tests.unit.objects import test_vcpu_model
from nova.tests.unit.virt.libvirt import fake_imagebackend
@ -370,6 +372,46 @@ def fake_disk_info_byname(instance, type='qcow2'):
return disk_info
def fake_diagnostics_object(with_cpus=False, with_disks=False, with_nic=False):
diag_dict = {'config_drive': False,
'driver': 'libvirt',
'hypervisor': 'kvm',
'hypervisor_os': 'linux',
'memory_details': {'maximum': 2048, 'used': 1234},
'state': 'running',
'uptime': 10}
if with_cpus:
diag_dict['cpu_details'] = []
for id, t in enumerate([15340000000, 1640000000,
3040000000, 1420000000]):
diag_dict['cpu_details'].append({'id': id, 'time': t})
if with_disks:
diag_dict['disk_details'] = []
for i in range(2):
diag_dict['disk_details'].append(
{'read_bytes': 688640,
'read_requests': 169,
'write_bytes': 0,
'write_requests': 0,
'errors_count': 1})
if with_nic:
diag_dict['nic_details'] = [
{'mac_address': '52:54:00:a4:38:38',
'rx_drop': 0,
'rx_errors': 0,
'rx_octets': 4408,
'rx_packets': 82,
'tx_drop': 0,
'tx_errors': 0,
'tx_octets': 0,
'tx_packets': 0}]
return fake_diagnostics.fake_diagnostics_obj(**diag_dict)
def fake_disk_info_json(instance, type='qcow2'):
"""Return fake instance_disk_info corresponding accurately to the
properties of the given Instance object.
@ -674,7 +716,8 @@ def _create_test_instance():
@ddt.ddt
class LibvirtConnTestCase(test.NoDBTestCase):
class LibvirtConnTestCase(test.NoDBTestCase,
test_diagnostics.DiagnosticsComparisonMixin):
REQUIRES_LOCKING = True
@ -12956,7 +12999,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
raise fakelibvirt.libvirtError('vcpus missing')
def blockStats(self, path):
return (169, 688640, 0, 0, -1)
return (169, 688640, 0, 0, 1)
def interfaceStats(self, path):
return (4408, 82, 0, 0, 0, 0, 0, 0)
@ -12979,12 +13022,12 @@ class LibvirtConnTestCase(test.NoDBTestCase):
'vda_read_req': 169,
'vda_write': 0,
'vda_write_req': 0,
'vda_errors': -1,
'vda_errors': 1,
'vdb_read': 688640,
'vdb_read_req': 169,
'vdb_write': 0,
'vdb_write_req': 0,
'vdb_errors': -1,
'vdb_errors': 1,
'memory': 280160,
'memory-actual': 220160,
'memory-rss': 200164,
@ -13005,36 +13048,8 @@ class LibvirtConnTestCase(test.NoDBTestCase):
instance.launched_at = lt
actual = drvr.get_instance_diagnostics(instance)
expected = {'config_drive': False,
'cpu_details': [],
'disk_details': [{'errors_count': 0,
'id': '',
'read_bytes': 688640,
'read_requests': 169,
'write_bytes': 0,
'write_requests': 0},
{'errors_count': 0,
'id': '',
'read_bytes': 688640,
'read_requests': 169,
'write_bytes': 0,
'write_requests': 0}],
'driver': 'libvirt',
'hypervisor_os': 'linux',
'memory_details': {'maximum': 2048, 'used': 1234},
'nic_details': [{'mac_address': '52:54:00:a4:38:38',
'rx_drop': 0,
'rx_errors': 0,
'rx_octets': 4408,
'rx_packets': 82,
'tx_drop': 0,
'tx_errors': 0,
'tx_octets': 0,
'tx_packets': 0}],
'state': 'running',
'uptime': 10,
'version': '1.0'}
self.assertEqual(expected, actual.serialize())
expected = fake_diagnostics_object(with_disks=True, with_nic=True)
self.assertDiagnosticsEqual(expected, actual)
def test_diagnostic_blockstats_exception(self):
xml = """
@ -13116,28 +13131,8 @@ class LibvirtConnTestCase(test.NoDBTestCase):
instance.launched_at = lt
actual = drvr.get_instance_diagnostics(instance)
expected = {'config_drive': False,
'cpu_details': [{'time': 15340000000},
{'time': 1640000000},
{'time': 3040000000},
{'time': 1420000000}],
'disk_details': [],
'driver': 'libvirt',
'hypervisor_os': 'linux',
'memory_details': {'maximum': 2048, 'used': 1234},
'nic_details': [{'mac_address': '52:54:00:a4:38:38',
'rx_drop': 0,
'rx_errors': 0,
'rx_octets': 4408,
'rx_packets': 82,
'tx_drop': 0,
'tx_errors': 0,
'tx_octets': 0,
'tx_packets': 0}],
'state': 'running',
'uptime': 10,
'version': '1.0'}
self.assertEqual(expected, actual.serialize())
expected = fake_diagnostics_object(with_cpus=True, with_nic=True)
self.assertDiagnosticsEqual(expected, actual)
def test_diagnostic_interfacestats_exception(self):
xml = """
@ -13176,7 +13171,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
(True, False)])
def blockStats(self, path):
return (169, 688640, 0, 0, -1)
return (169, 688640, 0, 0, 1)
def interfaceStats(self, path):
raise fakelibvirt.libvirtError('interfaceStat missing')
@ -13203,12 +13198,12 @@ class LibvirtConnTestCase(test.NoDBTestCase):
'vda_read_req': 169,
'vda_write': 0,
'vda_write_req': 0,
'vda_errors': -1,
'vda_errors': 1,
'vdb_read': 688640,
'vdb_read_req': 169,
'vdb_write': 0,
'vdb_write_req': 0,
'vdb_errors': -1,
'vdb_errors': 1,
'memory': 280160,
'memory-actual': 220160,
'memory-rss': 200164,
@ -13221,31 +13216,8 @@ class LibvirtConnTestCase(test.NoDBTestCase):
instance.launched_at = lt
actual = drvr.get_instance_diagnostics(instance)
expected = {'config_drive': False,
'cpu_details': [{'time': 15340000000},
{'time': 1640000000},
{'time': 3040000000},
{'time': 1420000000}],
'disk_details': [{'errors_count': 0,
'id': '',
'read_bytes': 688640,
'read_requests': 169,
'write_bytes': 0,
'write_requests': 0},
{'errors_count': 0,
'id': '',
'read_bytes': 688640,
'read_requests': 169,
'write_bytes': 0,
'write_requests': 0}],
'driver': 'libvirt',
'hypervisor_os': 'linux',
'memory_details': {'maximum': 2048, 'used': 1234},
'nic_details': [],
'state': 'running',
'uptime': 10,
'version': '1.0'}
self.assertEqual(expected, actual.serialize())
expected = fake_diagnostics_object(with_cpus=True, with_disks=True)
self.assertDiagnosticsEqual(expected, actual)
def test_diagnostic_memorystats_exception(self):
xml = """
@ -13284,7 +13256,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
(True, False)])
def blockStats(self, path):
return (169, 688640, 0, 0, -1)
return (169, 688640, 0, 0, 1)
def interfaceStats(self, path):
return (4408, 82, 0, 0, 0, 0, 0, 0)
@ -13311,12 +13283,12 @@ class LibvirtConnTestCase(test.NoDBTestCase):
'vda_read_req': 169,
'vda_write': 0,
'vda_write_req': 0,
'vda_errors': -1,
'vda_errors': 1,
'vdb_read': 688640,
'vdb_read_req': 169,
'vdb_write': 0,
'vdb_write_req': 0,
'vdb_errors': -1,
'vdb_errors': 1,
'memory': 280160,
'vnet0_rx': 4408,
'vnet0_rx_drop': 0,
@ -13335,39 +13307,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
instance.launched_at = lt
actual = drvr.get_instance_diagnostics(instance)
expected = {'config_drive': False,
'cpu_details': [{'time': 15340000000},
{'time': 1640000000},
{'time': 3040000000},
{'time': 1420000000}],
'disk_details': [{'errors_count': 0,
'id': '',
'read_bytes': 688640,
'read_requests': 169,
'write_bytes': 0,
'write_requests': 0},
{'errors_count': 0,
'id': '',
'read_bytes': 688640,
'read_requests': 169,
'write_bytes': 0,
'write_requests': 0}],
'driver': 'libvirt',
'hypervisor_os': 'linux',
'memory_details': {'maximum': 2048, 'used': 1234},
'nic_details': [{'mac_address': '52:54:00:a4:38:38',
'rx_drop': 0,
'rx_errors': 0,
'rx_octets': 4408,
'rx_packets': 82,
'tx_drop': 0,
'tx_errors': 0,
'tx_octets': 0,
'tx_packets': 0}],
'state': 'running',
'uptime': 10,
'version': '1.0'}
self.assertEqual(expected, actual.serialize())
expected = fake_diagnostics_object(with_cpus=True, with_disks=True,
with_nic=True)
self.assertDiagnosticsEqual(expected, actual)
def test_diagnostic_full(self):
xml = """
@ -13406,7 +13348,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
(True, False)])
def blockStats(self, path):
return (169, 688640, 0, 0, -1)
return (169, 688640, 0, 0, 1)
def interfaceStats(self, path):
return (4408, 82, 0, 0, 0, 0, 0, 0)
@ -13433,12 +13375,12 @@ class LibvirtConnTestCase(test.NoDBTestCase):
'vda_read_req': 169,
'vda_write': 0,
'vda_write_req': 0,
'vda_errors': -1,
'vda_errors': 1,
'vdb_read': 688640,
'vdb_read_req': 169,
'vdb_write': 0,
'vdb_write_req': 0,
'vdb_errors': -1,
'vdb_errors': 1,
'memory': 280160,
'memory-actual': 220160,
'memory-rss': 200164,
@ -13459,39 +13401,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
instance.launched_at = lt
actual = drvr.get_instance_diagnostics(instance)
expected = {'config_drive': False,
'cpu_details': [{'time': 15340000000},
{'time': 1640000000},
{'time': 3040000000},
{'time': 1420000000}],
'disk_details': [{'errors_count': 0,
'id': '',
'read_bytes': 688640,
'read_requests': 169,
'write_bytes': 0,
'write_requests': 0},
{'errors_count': 0,
'id': '',
'read_bytes': 688640,
'read_requests': 169,
'write_bytes': 0,
'write_requests': 0}],
'driver': 'libvirt',
'hypervisor_os': 'linux',
'memory_details': {'maximum': 2048, 'used': 1234},
'nic_details': [{'mac_address': '52:54:00:a4:38:38',
'rx_drop': 0,
'rx_errors': 0,
'rx_octets': 4408,
'rx_packets': 82,
'tx_drop': 0,
'tx_errors': 0,
'tx_octets': 0,
'tx_packets': 0}],
'state': 'running',
'uptime': 10,
'version': '1.0'}
self.assertEqual(expected, actual.serialize())
expected = fake_diagnostics_object(with_cpus=True, with_disks=True,
with_nic=True)
self.assertDiagnosticsEqual(expected, actual)
@mock.patch.object(host.Host, 'get_domain')
def test_diagnostic_full_with_multiple_interfaces(self, mock_get_domain):
@ -13536,7 +13448,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
(True, False)])
def blockStats(self, path):
return (169, 688640, 0, 0, -1)
return (169, 688640, 0, 0, 1)
def interfaceStats(self, path):
return (4408, 82, 0, 0, 0, 0, 0, 0)
@ -13563,12 +13475,12 @@ class LibvirtConnTestCase(test.NoDBTestCase):
'vda_read_req': 169,
'vda_write': 0,
'vda_write_req': 0,
'vda_errors': -1,
'vda_errors': 1,
'vdb_read': 688640,
'vdb_read_req': 169,
'vdb_write': 0,
'vdb_write_req': 0,
'vdb_errors': -1,
'vdb_errors': 1,
'memory': 280160,
'memory-actual': 220160,
'memory-rss': 200164,
@ -13597,48 +13509,18 @@ class LibvirtConnTestCase(test.NoDBTestCase):
instance.launched_at = lt
actual = drvr.get_instance_diagnostics(instance)
expected = {'config_drive': False,
'cpu_details': [{'time': 15340000000},
{'time': 1640000000},
{'time': 3040000000},
{'time': 1420000000}],
'disk_details': [{'errors_count': 0,
'id': '',
'read_bytes': 688640,
'read_requests': 169,
'write_bytes': 0,
'write_requests': 0},
{'errors_count': 0,
'id': '',
'read_bytes': 688640,
'read_requests': 169,
'write_bytes': 0,
'write_requests': 0}],
'driver': 'libvirt',
'hypervisor_os': 'linux',
'memory_details': {'maximum': 2048, 'used': 1234},
'nic_details': [{'mac_address': '52:54:00:a4:38:38',
'rx_drop': 0,
'rx_errors': 0,
'rx_octets': 4408,
'rx_packets': 82,
'tx_drop': 0,
'tx_errors': 0,
'tx_octets': 0,
'tx_packets': 0},
{'mac_address': '53:55:00:a5:39:39',
'rx_drop': 0,
'rx_errors': 0,
'rx_octets': 4408,
'rx_packets': 82,
'tx_drop': 0,
'tx_errors': 0,
'tx_octets': 0,
'tx_packets': 0}],
'state': 'running',
'uptime': 10.,
'version': '1.0'}
self.assertEqual(expected, actual.serialize())
expected = fake_diagnostics_object(with_cpus=True, with_disks=True,
with_nic=True)
expected.add_nic(mac_address='53:55:00:a5:39:39',
rx_drop=0,
rx_errors=0,
rx_octets=4408,
rx_packets=82,
tx_drop=0,
tx_errors=0,
tx_octets=0,
tx_packets=0)
self.assertDiagnosticsEqual(expected, actual)
@mock.patch.object(host.Host, "list_instance_domains")
def test_failing_vcpu_count(self, mock_list):

View File

@ -1,231 +0,0 @@
# Copyright (c) 2014 VMware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from nova import exception
from nova import test
from nova.virt import diagnostics
class DiagnosticsTests(test.NoDBTestCase):
def test_cpu_diagnostics_default(self):
cpu = diagnostics.CpuDiagnostics()
self.assertEqual(0, cpu.time)
def test_cpu_diagnostics(self):
cpu = diagnostics.CpuDiagnostics(time=7)
self.assertEqual(7, cpu.time)
def test_nic_diagnostics_default(self):
nic = diagnostics.NicDiagnostics()
self.assertEqual('00:00:00:00:00:00', nic.mac_address)
self.assertEqual(0, nic.rx_octets)
self.assertEqual(0, nic.rx_errors)
self.assertEqual(0, nic.rx_drop)
self.assertEqual(0, nic.rx_packets)
self.assertEqual(0, nic.tx_octets)
self.assertEqual(0, nic.tx_errors)
self.assertEqual(0, nic.tx_drop)
self.assertEqual(0, nic.tx_packets)
def test_nic_diagnostics(self):
nic = diagnostics.NicDiagnostics(mac_address='00:00:ca:fe:00:00',
rx_octets=1, rx_errors=2, rx_drop=3, rx_packets=4,
tx_octets=5, tx_errors=6, tx_drop=7, tx_packets=8)
self.assertEqual('00:00:ca:fe:00:00', nic.mac_address)
self.assertEqual(1, nic.rx_octets)
self.assertEqual(2, nic.rx_errors)
self.assertEqual(3, nic.rx_drop)
self.assertEqual(4, nic.rx_packets)
self.assertEqual(5, nic.tx_octets)
self.assertEqual(6, nic.tx_errors)
self.assertEqual(7, nic.tx_drop)
self.assertEqual(8, nic.tx_packets)
def test_disk_diagnostics_default(self):
disk = diagnostics.DiskDiagnostics()
self.assertEqual('', disk.id)
self.assertEqual(0, disk.read_bytes)
self.assertEqual(0, disk.read_requests)
self.assertEqual(0, disk.write_bytes)
self.assertEqual(0, disk.write_requests)
self.assertEqual(0, disk.errors_count)
def test_disk_diagnostics(self):
disk = diagnostics.DiskDiagnostics(id='fake_disk_id',
read_bytes=1, read_requests=2,
write_bytes=3, write_requests=4,
errors_count=5)
self.assertEqual('fake_disk_id', disk.id)
self.assertEqual(1, disk.read_bytes)
self.assertEqual(2, disk.read_requests)
self.assertEqual(3, disk.write_bytes)
self.assertEqual(4, disk.write_requests)
self.assertEqual(5, disk.errors_count)
def test_memory_diagnostics_default(self):
memory = diagnostics.MemoryDiagnostics()
self.assertEqual(0, memory.maximum)
self.assertEqual(0, memory.used)
def test_memory_diagnostics(self):
memory = diagnostics.MemoryDiagnostics(maximum=1, used=2)
self.assertEqual(1, memory.maximum)
self.assertEqual(2, memory.used)
def test_diagnostics_default(self):
diags = diagnostics.Diagnostics()
self.assertIsNone(diags.state)
self.assertIsNone(diags.driver)
self.assertIsNone(diags.hypervisor_os)
self.assertEqual(0, diags.uptime)
self.assertFalse(diags.config_drive)
self.assertEqual([], diags.cpu_details)
self.assertEqual([], diags.nic_details)
self.assertEqual([], diags.disk_details)
self.assertEqual(0, diags.memory_details.maximum)
self.assertEqual(0, diags.memory_details.used)
self.assertEqual('1.0', diags.version)
def test_diagnostics(self):
cpu_details = [diagnostics.CpuDiagnostics()]
nic_details = [diagnostics.NicDiagnostics()]
disk_details = [diagnostics.DiskDiagnostics()]
diags = diagnostics.Diagnostics(
state='fake-state', driver='fake-driver',
hypervisor_os='fake-os',
uptime=1, cpu_details=cpu_details,
nic_details=nic_details, disk_details=disk_details,
config_drive=True)
self.assertEqual('fake-state', diags.state)
self.assertEqual('fake-driver', diags.driver)
self.assertEqual('fake-os', diags.hypervisor_os)
self.assertEqual(1, diags.uptime)
self.assertTrue(diags.config_drive)
self.assertEqual(1, len(diags.cpu_details))
self.assertEqual(1, len(diags.nic_details))
self.assertEqual(1, len(diags.disk_details))
self.assertEqual(0, diags.memory_details.maximum)
self.assertEqual(0, diags.memory_details.used)
self.assertEqual('1.0', diags.version)
def test_add_cpu(self):
diags = diagnostics.Diagnostics()
self.assertEqual([], diags.cpu_details)
diags.add_cpu(time=7)
self.assertEqual(1, len(diags.cpu_details))
self.assertEqual(7, diags.cpu_details[0].time)
def test_add_nic(self):
diags = diagnostics.Diagnostics()
self.assertEqual([], diags.nic_details)
diags.add_nic(mac_address='00:00:ca:fe:00:00',
rx_octets=1, rx_errors=2, rx_drop=3, rx_packets=4,
tx_octets=5, tx_errors=6, tx_drop=7, tx_packets=8)
self.assertEqual(1, len(diags.nic_details))
self.assertEqual('00:00:ca:fe:00:00', diags.nic_details[0].mac_address)
self.assertEqual(1, diags.nic_details[0].rx_octets)
self.assertEqual(2, diags.nic_details[0].rx_errors)
self.assertEqual(3, diags.nic_details[0].rx_drop)
self.assertEqual(4, diags.nic_details[0].rx_packets)
self.assertEqual(5, diags.nic_details[0].tx_octets)
self.assertEqual(6, diags.nic_details[0].tx_errors)
self.assertEqual(7, diags.nic_details[0].tx_drop)
self.assertEqual(8, diags.nic_details[0].tx_packets)
def test_add_disk(self):
diags = diagnostics.Diagnostics()
self.assertEqual([], diags.disk_details)
diags.add_disk(id='fake_disk_id',
read_bytes=1, read_requests=2,
write_bytes=3, write_requests=4,
errors_count=5)
self.assertEqual(1, len(diags.disk_details))
self.assertEqual('fake_disk_id', diags.disk_details[0].id)
self.assertEqual(1, diags.disk_details[0].read_bytes)
self.assertEqual(2, diags.disk_details[0].read_requests)
self.assertEqual(3, diags.disk_details[0].write_bytes)
self.assertEqual(4, diags.disk_details[0].write_requests)
self.assertEqual(5, diags.disk_details[0].errors_count)
def test_diagnostics_serialize_default(self):
diags = diagnostics.Diagnostics()
expected = {'config_drive': False,
'cpu_details': [],
'disk_details': [],
'driver': None,
'hypervisor_os': None,
'memory_details': {'maximum': 0, 'used': 0},
'nic_details': [],
'state': None,
'uptime': 0,
'version': '1.0'}
result = diags.serialize()
self.assertEqual(expected, result)
def test_diagnostics_serialize(self):
cpu_details = [diagnostics.CpuDiagnostics()]
nic_details = [diagnostics.NicDiagnostics()]
disk_details = [diagnostics.DiskDiagnostics()]
diags = diagnostics.Diagnostics(
state='fake-state', driver='fake-driver',
hypervisor_os='fake-os',
uptime=1, cpu_details=cpu_details,
nic_details=nic_details, disk_details=disk_details,
config_drive=True)
expected = {'config_drive': True,
'cpu_details': [{'time': 0}],
'disk_details': [{'errors_count': 0,
'id': '',
'read_bytes': 0,
'read_requests': 0,
'write_bytes': 0,
'write_requests': 0}],
'driver': 'fake-driver',
'hypervisor_os': 'fake-os',
'memory_details': {'maximum': 0, 'used': 0},
'nic_details': [{'mac_address': '00:00:00:00:00:00',
'rx_drop': 0,
'rx_errors': 0,
'rx_octets': 0,
'rx_packets': 0,
'tx_drop': 0,
'tx_errors': 0,
'tx_octets': 0,
'tx_packets': 0}],
'state': 'fake-state',
'uptime': 1,
'version': '1.0'}
result = diags.serialize()
self.assertEqual(expected, result)
def test_diagnostics_invalid_input(self):
self.assertRaises(exception.InvalidInput,
diagnostics.Diagnostics,
cpu_details='invalid type')
self.assertRaises(exception.InvalidInput,
diagnostics.Diagnostics,
cpu_details=['invalid entry'])
self.assertRaises(exception.InvalidInput,
diagnostics.Diagnostics,
nic_details='invalid type')
self.assertRaises(exception.InvalidInput,
diagnostics.Diagnostics,
nic_details=['invalid entry'])
self.assertRaises(exception.InvalidInput,
diagnostics.Diagnostics,
disk_details='invalid type')
self.assertRaises(exception.InvalidInput,
diagnostics.Diagnostics,
disk_details=['invalid entry'])

View File

@ -45,9 +45,11 @@ from nova.image import glance
from nova.network import model as network_model
from nova import objects
from nova import test
from nova.tests.unit import fake_diagnostics
from nova.tests.unit import fake_instance
import nova.tests.unit.image.fake
from nova.tests.unit import matchers
from nova.tests.unit.objects import test_diagnostics
from nova.tests.unit import utils
from nova.tests.unit.virt.vmwareapi import fake as vmwareapi_fake
from nova.tests.unit.virt.vmwareapi import stubs
@ -182,7 +184,8 @@ class VMwareSessionTestCase(test.NoDBTestCase):
fake_invoke.assert_called_once_with(module, 'fira')
class VMwareAPIVMTestCase(test.NoDBTestCase):
class VMwareAPIVMTestCase(test.NoDBTestCase,
test_diagnostics.DiagnosticsComparisonMixin):
"""Unit tests for Vmware API connection calls."""
REQUIRES_LOCKING = True
@ -1649,22 +1652,22 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
def test_get_instance_diagnostics(self):
self._create_vm()
expected = {'uptime': 0,
'memory_details': {'used': 0, 'maximum': 512},
'nic_details': [],
'driver': 'vmwareapi',
'state': 'running',
'version': '1.0',
'cpu_details': [],
'disk_details': [],
'hypervisor_os': 'esxi',
'config_drive': 'False'}
expected = fake_diagnostics.fake_diagnostics_obj(
uptime=0,
memory_details={'used': 0, 'maximum': 512},
nic_details=[],
driver='vmwareapi',
state='running',
cpu_details=[],
disk_details=[],
hypervisor_os='esxi',
config_drive=True)
instance = objects.Instance(uuid=self.uuid,
config_drive=False,
system_metadata={},
node=self.instance_node)
actual = self.conn.get_instance_diagnostics(instance)
self.assertThat(actual.serialize(), matchers.DictMatches(expected))
self.assertDiagnosticsEqual(expected, actual)
def test_get_console_output(self):
self.assertRaises(NotImplementedError, self.conn.get_console_output,

View File

@ -52,6 +52,7 @@ from nova import test
from nova.tests import fixtures
from nova.tests.unit.api.openstack import fakes
from nova.tests.unit.db import fakes as db_fakes
from nova.tests.unit import fake_diagnostics
from nova.tests.unit import fake_flavor
from nova.tests.unit import fake_instance
from nova.tests.unit import fake_network
@ -59,6 +60,7 @@ from nova.tests.unit import fake_processutils
import nova.tests.unit.image.fake as fake_image
from nova.tests.unit import matchers
from nova.tests.unit.objects import test_aggregate
from nova.tests.unit.objects import test_diagnostics
from nova.tests.unit import utils as test_utils
from nova.tests.unit.virt.xenapi import stubs
from nova.tests import uuidsentinel as uuids
@ -278,7 +280,8 @@ class XenAPIVolumeTestCase(stubs.XenAPITestBaseNoDB):
# FIXME(sirp): convert this to use XenAPITestBaseNoDB
class XenAPIVMTestCase(stubs.XenAPITestBase):
class XenAPIVMTestCase(stubs.XenAPITestBase,
test_diagnostics.DiagnosticsComparisonMixin):
"""Unit tests for VM operations."""
def setUp(self):
super(XenAPIVMTestCase, self).setUp()
@ -423,35 +426,19 @@ class XenAPIVMTestCase(stubs.XenAPITestBase):
return re.sub(r'\s', '', f.read())
self.stubs.Set(vm_utils, '_get_rrd', fake_get_rrd)
expected = {
'config_drive': False,
'state': 'running',
'driver': 'xenapi',
'version': '1.0',
'uptime': 0,
'hypervisor_os': None,
'cpu_details': [{'time': 0}, {'time': 0},
{'time': 0}, {'time': 0}],
'nic_details': [{'mac_address': '00:00:00:00:00:00',
'rx_drop': 0,
'rx_errors': 0,
'rx_octets': 0,
'rx_packets': 0,
'tx_drop': 0,
'tx_errors': 0,
'tx_octets': 0,
'tx_packets': 0}],
'disk_details': [{'errors_count': 0,
'id': '',
'read_bytes': 0,
'read_requests': 0,
'write_bytes': 0,
'write_requests': 0}],
'memory_details': {'maximum': 8192, 'used': 0}}
expected = fake_diagnostics.fake_diagnostics_obj(
config_drive=False,
state='running',
driver='xenapi',
cpu_details=[{}, {}, {}, {}], # 4 CPUs with 'None' values
nic_details=[{}], # 1 NIC with 'None' values
disk_details=[{}], # 1 disk with 'None' values
memory_details={'maximum': 8192})
instance = self._create_instance(obj=True)
actual = self.conn.get_instance_diagnostics(instance)
self.assertEqual(expected, actual.serialize())
self.assertDiagnosticsEqual(expected, actual)
def test_get_vnc_console(self):
instance = self._create_instance(obj=True)

View File

@ -1,190 +0,0 @@
# Copyright (c) 2014 VMware, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from nova import exception
from nova.i18n import _
class CpuDiagnostics(object):
def __init__(self, time=0):
"""Create a new CpuDiagnostics object
:param time: CPU Time in nano seconds (Integer)
"""
self.time = time
class NicDiagnostics(object):
def __init__(self, mac_address='00:00:00:00:00:00',
rx_octets=0, rx_errors=0, rx_drop=0, rx_packets=0,
tx_octets=0, tx_errors=0, tx_drop=0, tx_packets=0):
"""Create a new NicDiagnostics object
:param mac_address: Mac address of the interface (String)
:param rx_octets: Received octets (Integer)
:param rx_errors: Received errors (Integer)
:param rx_drop: Received packets dropped (Integer)
:param rx_packets: Received packets (Integer)
:param tx_octets: Transmitted Octets (Integer)
:param tx_errors: Transmit errors (Integer)
:param tx_drop: Transmit dropped packets (Integer)
:param tx_packets: Transmit packets (Integer)
"""
self.mac_address = mac_address
self.rx_octets = rx_octets
self.rx_errors = rx_errors
self.rx_drop = rx_drop
self.rx_packets = rx_packets
self.tx_octets = tx_octets
self.tx_errors = tx_errors
self.tx_drop = tx_drop
self.tx_packets = tx_packets
class DiskDiagnostics(object):
def __init__(self, id='', read_bytes=0, read_requests=0,
write_bytes=0, write_requests=0, errors_count=0):
"""Create a new DiskDiagnostics object
:param id: Disk ID (String)
:param read_bytes: Disk reads in bytes(Integer)
:param read_requests: Read requests (Integer)
:param write_bytes: Disk writes in bytes (Integer)
:param write_requests: Write requests (Integer)
:param errors_count: Disk errors (Integer)
"""
self.id = id
self.read_bytes = read_bytes
self.read_requests = read_requests
self.write_bytes = write_bytes
self.write_requests = write_requests
self.errors_count = errors_count
class MemoryDiagnostics(object):
def __init__(self, maximum=0, used=0):
"""Create a new MemoryDiagnostics object
:param maximum: Amount of memory provisioned for the VM in MB (Integer)
:param used: Amount of memory used by the VM in MB (Integer)
"""
self.maximum = maximum
self.used = used
class Diagnostics(object):
# Version 1.0: Initial version
version = '1.0'
def __init__(self, state=None, driver=None, hypervisor_os=None,
uptime=0, cpu_details=None, nic_details=None,
disk_details=None, config_drive=False):
"""Create a new diagnostics object
:param state: The current state of the VM. Example values are:
'pending', 'running', 'paused', 'shutdown', 'crashed',
'suspended' and 'building' (String)
:param driver: A string denoting the driver on which the VM is running.
Examples may be: 'libvirt', 'xenapi', 'hyperv' and
'vmwareapi' (String)
:param hypervisor_os: A string denoting the hypervisor OS (String)
:param uptime: The amount of time in seconds that the VM has been
running (Integer)
:param cpu_details: And array of CpuDiagnostics or None.
:param nic_details: And array of NicDiagnostics or None.
:param disk_details: And array of DiskDiagnostics or None.
:param config_drive: Indicates if the config drive is supported on the
instance (Boolean)
"""
self.state = state
self.driver = driver
self.hypervisor_os = hypervisor_os
self.uptime = uptime
self.config_drive = config_drive
if cpu_details:
self._validate_type(cpu_details, CpuDiagnostics, 'cpu_details')
self.cpu_details = cpu_details
else:
self.cpu_details = []
if nic_details:
self._validate_type(nic_details, NicDiagnostics, 'nic_details')
self.nic_details = nic_details
else:
self.nic_details = []
if disk_details:
self._validate_type(disk_details, DiskDiagnostics, 'disk_details')
self.disk_details = disk_details
else:
self.disk_details = []
self.memory_details = MemoryDiagnostics()
def _validate_type(self, input, type, str_input):
if not isinstance(input, list):
reason = _("Invalid type for %s") % str_input
raise exception.InvalidInput(reason=reason)
for i in input:
if not isinstance(i, type):
reason = _("Invalid type for %s entry") % str_input
raise exception.InvalidInput(reason=reason)
def add_cpu(self, time=0):
self.cpu_details.append(CpuDiagnostics(time=time))
def add_nic(self, mac_address='00:00:00:00:00:00',
rx_octets=0, rx_errors=0, rx_drop=0, rx_packets=0,
tx_octets=0, tx_errors=0, tx_drop=0, tx_packets=0):
self.nic_details.append(NicDiagnostics(mac_address=mac_address,
rx_octets=rx_octets,
rx_errors=rx_errors,
rx_drop=rx_drop,
rx_packets=rx_packets,
tx_octets=tx_octets,
tx_errors=tx_errors,
tx_drop=tx_drop,
tx_packets=tx_packets))
def add_disk(self, id='', read_bytes=0, read_requests=0,
write_bytes=0, write_requests=0, errors_count=0):
self.disk_details.append(DiskDiagnostics(id=id,
read_bytes=read_bytes,
read_requests=read_requests,
write_bytes=write_bytes,
write_requests=write_requests,
errors_count=errors_count))
def serialize(self):
s = {}
for k, v in self.__dict__.items():
# Treat case of CpuDiagnostics, NicDiagnostics and
# DiskDiagnostics - these are lists
if isinstance(v, list):
l = []
for value in v:
l.append(value.__dict__)
s[k] = l
# Treat case of MemoryDiagnostics
elif isinstance(v, MemoryDiagnostics):
s[k] = v.__dict__
else:
s[k] = v
s['version'] = self.version
return s

View File

@ -36,8 +36,8 @@ import nova.conf
from nova.console import type as ctype
from nova import exception
from nova.i18n import _LW
from nova.objects import diagnostics as diagnostics_obj
from nova.objects import fields as obj_fields
from nova.virt import diagnostics
from nova.virt import driver
from nova.virt import hardware
from nova.virt import virtapi
@ -348,20 +348,28 @@ class FakeDriver(driver.ComputeDriver):
}
def get_instance_diagnostics(self, instance):
diags = diagnostics.Diagnostics(state='running', driver='fake',
hypervisor_os='fake-os', uptime=46664, config_drive=True)
diags.add_cpu(time=17300000000)
diags = diagnostics_obj.Diagnostics(
state='running', driver='libvirt', hypervisor='fake-hypervisor',
hypervisor_os='fake-os', uptime=46664, config_drive=True)
diags.add_cpu(id=0, time=17300000000, utilisation=15)
diags.add_nic(mac_address='01:23:45:67:89:ab',
rx_packets=26701,
rx_octets=2070139,
rx_errors=100,
rx_drop=200,
rx_packets=26701,
rx_rate=300,
tx_octets=140208,
tx_packets = 662)
diags.add_disk(id='fake-disk-id',
read_bytes=262144,
tx_errors=400,
tx_drop=500,
tx_packets = 662,
tx_rate=600)
diags.add_disk(read_bytes=262144,
read_requests=112,
write_bytes=5778432,
write_requests=488)
diags.memory_details.maximum = 524288
write_requests=488,
errors_count=1)
diags.memory_details = diagnostics_obj.MemoryDiagnostics(
maximum=524288, used=0)
return diags
def get_all_bw_counters(self, instances):

View File

@ -78,6 +78,7 @@ from nova import image
from nova import keymgr
from nova.network import model as network_model
from nova import objects
from nova.objects import diagnostics as diagnostics_obj
from nova.objects import fields
from nova.objects import migrate_data as migrate_data_obj
from nova.pci import manager as pci_manager
@ -86,7 +87,6 @@ from nova import utils
from nova import version
from nova.virt import block_device as driver_block_device
from nova.virt import configdrive
from nova.virt import diagnostics
from nova.virt.disk import api as disk_api
from nova.virt.disk.vfs import guestfs
from nova.virt import driver
@ -7690,20 +7690,22 @@ class LibvirtDriver(driver.ComputeDriver):
launched_at = timeutils.normalize_time(instance.launched_at)
uptime = timeutils.delta_seconds(launched_at,
timeutils.utcnow())
diags = diagnostics.Diagnostics(state=power_state.STATE_MAP[state],
diags = diagnostics_obj.Diagnostics(state=power_state.STATE_MAP[state],
driver='libvirt',
config_drive=config_drive,
hypervisor=CONF.libvirt.virt_type,
hypervisor_os='linux',
uptime=uptime)
diags.memory_details.maximum = max_mem / units.Mi
diags.memory_details.used = mem / units.Mi
diags.memory_details = diagnostics_obj.MemoryDiagnostics(
maximum=max_mem / units.Mi,
used=mem / units.Mi)
# get cpu time, might launch an exception if the method
# is not supported by the underlying hypervisor being
# used by libvirt
try:
for vcpu in guest.get_vcpus_info():
diags.add_cpu(time=vcpu.time)
diags.add_cpu(id=vcpu.id, time=vcpu.time)
except libvirt.libvirtError:
pass
# get io status
@ -7717,7 +7719,8 @@ class LibvirtDriver(driver.ComputeDriver):
diags.add_disk(read_bytes=stats[1],
read_requests=stats[0],
write_bytes=stats[3],
write_requests=stats[2])
write_requests=stats[2],
errors_count=stats[4])
except libvirt.libvirtError:
pass
for interface in dom_io["ifaces"]:

View File

@ -49,7 +49,6 @@ from nova import objects
from nova import utils
from nova import version
from nova.virt import configdrive
from nova.virt import diagnostics
from nova.virt import driver
from nova.virt import hardware
from nova.virt.vmwareapi import constants
@ -1549,13 +1548,14 @@ class VMwareVMOps(object):
state = power_state.STATE_MAP[constants.POWER_STATES[state]]
uptime = data.get('uptimeSeconds', 0)
config_drive = configdrive.required_by(instance)
diags = diagnostics.Diagnostics(state=state,
driver='vmwareapi',
config_drive=config_drive,
hypervisor_os='esxi',
uptime=uptime)
diags.memory_details.maximum = data.get('memorySizeMB', 0)
diags.memory_details.used = data.get('guestMemoryUsage', 0)
diags = objects.Diagnostics(state=state,
driver='vmwareapi',
config_drive=config_drive,
hypervisor_os='esxi',
uptime=uptime)
diags.memory_details = objects.MemoryDiagnostics(
maximum = data.get('memorySizeMB', 0),
used=data.get('guestMemoryUsage', 0))
# TODO(garyk): add in cpu, nic and disk stats
return diags

View File

@ -47,10 +47,10 @@ import nova.conf
from nova import exception
from nova.i18n import _, _LE, _LI, _LW
from nova.network import model as network_model
from nova.objects import diagnostics
from nova.objects import fields as obj_fields
from nova import utils
from nova.virt import configdrive
from nova.virt import diagnostics
from nova.virt.disk import api as disk
from nova.virt.disk.vfs import localfs as vfsimpl
from nova.virt import hardware
@ -1754,7 +1754,8 @@ def compile_instance_diagnostics(instance, vm_rec):
diags.add_disk()
max_mem_bytes = int(vm_rec['memory_dynamic_max'])
diags.memory_details.maximum = max_mem_bytes / units.Mi
diags.memory_details = diagnostics.MemoryDiagnostics(
maximum=max_mem_bytes / units.Mi)
return diags