Merge "Report minimal metrics for stopped (SHUTOFF) VMs"
This commit is contained in:
@@ -63,6 +63,12 @@ OPTS = [
|
||||
"of resource_update_interval. This option is only used "
|
||||
"for agent polling to Nova API, so it will work only "
|
||||
"when 'instance_discovery_method' is set to 'naive'."),
|
||||
cfg.BoolOpt('report_stopped_instance_metrics',
|
||||
default=False,
|
||||
help="Report a minimal set of metrics (power.state, vcpus, "
|
||||
"memory, disk.device.capacity, disk.device.usage) for "
|
||||
"stopped (SHUTOFF) instances. Only works with the "
|
||||
"'libvirt_metadata' instance discovery method."),
|
||||
cfg.BoolOpt('fetch_extra_metadata',
|
||||
default=False,
|
||||
help="Whether or not additional instance attributes that "
|
||||
|
||||
@@ -61,23 +61,24 @@ class LibvirtInspector(virt_inspector.Inspector):
|
||||
except Exception as ex:
|
||||
raise virt_inspector.InspectorException(str(ex))
|
||||
|
||||
def _get_domain_not_shut_off_or_raise(self, instance):
|
||||
def _get_domain(self, instance, raise_if_shutoff):
|
||||
instance_name = util.instance_name(instance)
|
||||
domain = self._lookup_by_uuid(instance)
|
||||
|
||||
state = domain.info()[0]
|
||||
if state == libvirt.VIR_DOMAIN_SHUTOFF:
|
||||
msg = _('Failed to inspect data of instance '
|
||||
'<name=%(name)s, id=%(id)s>, '
|
||||
'domain state is SHUTOFF.') % {
|
||||
'name': instance_name, 'id': instance.id}
|
||||
raise virt_inspector.InstanceShutOffException(msg)
|
||||
if raise_if_shutoff:
|
||||
state = domain.info()[0]
|
||||
if state == libvirt.VIR_DOMAIN_SHUTOFF:
|
||||
msg = _('Failed to inspect data of instance '
|
||||
'<name=%(name)s, id=%(id)s>, '
|
||||
'domain state is SHUTOFF.') % {
|
||||
'name': instance_name, 'id': instance.id}
|
||||
raise virt_inspector.InstanceShutOffException(msg)
|
||||
|
||||
return domain
|
||||
|
||||
@libvirt_utils.retry_on_disconnect
|
||||
def inspect_vnics(self, instance, duration):
|
||||
domain = self._get_domain_not_shut_off_or_raise(instance)
|
||||
domain = self._get_domain(instance, True)
|
||||
|
||||
tree = etree.fromstring(domain.XMLDesc(0))
|
||||
for iface in tree.findall('devices/interface'):
|
||||
@@ -169,7 +170,7 @@ class LibvirtInspector(virt_inspector.Inspector):
|
||||
|
||||
@libvirt_utils.retry_on_disconnect
|
||||
def inspect_disks(self, instance, duration):
|
||||
domain = self._get_domain_not_shut_off_or_raise(instance)
|
||||
domain = self._get_domain(instance, True)
|
||||
for device in self._get_disk_devices(domain):
|
||||
try:
|
||||
block_stats = domain.blockStats(device)
|
||||
@@ -191,7 +192,8 @@ class LibvirtInspector(virt_inspector.Inspector):
|
||||
|
||||
@libvirt_utils.retry_on_disconnect
|
||||
def inspect_disk_info(self, instance, duration):
|
||||
domain = self._get_domain_not_shut_off_or_raise(instance)
|
||||
domain = self._get_domain(
|
||||
instance, not self.conf.compute.report_stopped_instance_metrics)
|
||||
for device in self._get_disk_devices(domain):
|
||||
block_info = domain.blockInfo(device)
|
||||
# if vm mount cdrom, libvirt will align by 4K bytes, capacity may
|
||||
@@ -206,7 +208,18 @@ class LibvirtInspector(virt_inspector.Inspector):
|
||||
@libvirt_utils.raise_nodata_if_unsupported
|
||||
@libvirt_utils.retry_on_disconnect
|
||||
def inspect_instance(self, instance, duration=None):
|
||||
domain = self._get_domain_not_shut_off_or_raise(instance)
|
||||
domain = self._get_domain(
|
||||
instance, not self.conf.compute.report_stopped_instance_metrics)
|
||||
|
||||
if self.conf.compute.report_stopped_instance_metrics:
|
||||
dom_info = domain.info()
|
||||
state = dom_info[0]
|
||||
if state == libvirt.VIR_DOMAIN_SHUTOFF:
|
||||
return virt_inspector.InstanceStats(
|
||||
power_state=state,
|
||||
cpu_number=dom_info[3],
|
||||
memory_actual=dom_info[1] / units.Ki,
|
||||
)
|
||||
|
||||
memory_actual = None
|
||||
memory_available = None
|
||||
|
||||
@@ -129,3 +129,46 @@ class TestVCPUsPollster(base.TestPollsterBase):
|
||||
_verify_cpu_metering(1)
|
||||
_verify_cpu_metering(1)
|
||||
_verify_cpu_metering(2)
|
||||
|
||||
def test_get_samples_shutoff(self):
|
||||
self._mock_inspect_instance(
|
||||
virt_inspector.InstanceStats(power_state=5, cpu_number=4,
|
||||
memory_actual=2048.0),
|
||||
)
|
||||
mgr = manager.AgentManager(0, self.CONF)
|
||||
pollster = instance_stats.VCPUsPollster(self.CONF)
|
||||
cache = {}
|
||||
samples = list(pollster.get_samples(mgr, cache, [self.instance]))
|
||||
self.assertEqual(1, len(samples))
|
||||
self.assertEqual('vcpus', samples[0].name)
|
||||
self.assertEqual(4, samples[0].volume)
|
||||
|
||||
|
||||
class TestPowerStatePollster(base.TestPollsterBase):
|
||||
|
||||
def test_get_samples_shutoff(self):
|
||||
self._mock_inspect_instance(
|
||||
virt_inspector.InstanceStats(power_state=5, cpu_number=2,
|
||||
memory_actual=1024.0),
|
||||
)
|
||||
mgr = manager.AgentManager(0, self.CONF)
|
||||
pollster = instance_stats.PowerStatePollster(self.CONF)
|
||||
cache = {}
|
||||
samples = list(pollster.get_samples(mgr, cache, [self.instance]))
|
||||
self.assertEqual(1, len(samples))
|
||||
self.assertEqual('power.state', samples[0].name)
|
||||
self.assertEqual(5, samples[0].volume)
|
||||
|
||||
|
||||
class TestCPUPollsterShutoff(base.TestPollsterBase):
|
||||
|
||||
def test_get_samples_shutoff_no_cpu_time(self):
|
||||
self._mock_inspect_instance(
|
||||
virt_inspector.InstanceStats(power_state=5, cpu_number=2,
|
||||
memory_actual=1024.0),
|
||||
)
|
||||
mgr = manager.AgentManager(0, self.CONF)
|
||||
pollster = instance_stats.CPUPollster(self.CONF)
|
||||
cache = {}
|
||||
samples = list(pollster.get_samples(mgr, cache, [self.instance]))
|
||||
self.assertEqual(0, len(samples))
|
||||
|
||||
@@ -111,7 +111,7 @@ class TestLibvirtInspection(base.BaseTestCase):
|
||||
self.assertEqual(2, stats.cpu_number)
|
||||
self.assertEqual(999999, stats.cpu_time)
|
||||
|
||||
def test_inspect_cpus_with_domain_shutoff(self):
|
||||
def test_inspect_instance_with_domain_shutoff(self):
|
||||
domain = mock.Mock()
|
||||
domain.info.return_value = (5, 0, 0, 2, 999999)
|
||||
conn = mock.Mock()
|
||||
@@ -123,6 +123,31 @@ class TestLibvirtInspection(base.BaseTestCase):
|
||||
self.inspector.inspect_instance,
|
||||
self.instance, None)
|
||||
|
||||
def test_inspect_instance_with_domain_shutoff_reporting_enabled(self):
|
||||
self.inspector.conf.set_override(
|
||||
'report_stopped_instance_metrics', True, group='compute')
|
||||
domain = mock.Mock()
|
||||
domain.info.return_value = (5, 2097152, 0, 2, 0)
|
||||
conn = mock.Mock()
|
||||
conn.lookupByUUIDString.return_value = domain
|
||||
|
||||
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
|
||||
'refresh_libvirt_connection', return_value=conn):
|
||||
stats = self.inspector.inspect_instance(self.instance, None)
|
||||
self.assertEqual(5, stats.power_state)
|
||||
self.assertEqual(2, stats.cpu_number)
|
||||
self.assertEqual(2097152 / units.Ki, stats.memory_actual)
|
||||
self.assertIsNone(stats.cpu_time)
|
||||
self.assertIsNone(stats.memory_available)
|
||||
self.assertIsNone(stats.memory_usage)
|
||||
self.assertIsNone(stats.memory_resident)
|
||||
self.assertIsNone(stats.memory_swap_in)
|
||||
self.assertIsNone(stats.memory_swap_out)
|
||||
self.assertIsNone(stats.cpu_cycles)
|
||||
self.assertIsNone(stats.instructions)
|
||||
self.assertIsNone(stats.cache_references)
|
||||
self.assertIsNone(stats.cache_misses)
|
||||
|
||||
def test_inspect_vnics(self):
|
||||
dom_xml = """
|
||||
<domain type='kvm'>
|
||||
@@ -352,6 +377,42 @@ class TestLibvirtInspection(base.BaseTestCase):
|
||||
self.assertEqual(2, disks[0].allocation)
|
||||
self.assertEqual(3, disks[0].physical)
|
||||
|
||||
def test_inspect_disk_info_with_domain_shutoff(self):
|
||||
self.inspector.conf.set_override(
|
||||
'report_stopped_instance_metrics', True, group='compute')
|
||||
dom_xml = """
|
||||
<domain type='kvm'>
|
||||
<devices>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='qcow2' cache='none'/>
|
||||
<source file='/path/instance-00000001/disk'/>
|
||||
<target dev='vda' bus='virtio'/>
|
||||
<alias name='virtio-disk0'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00'
|
||||
slot='0x04' function='0x0'/>
|
||||
</disk>
|
||||
</devices>
|
||||
</domain>
|
||||
"""
|
||||
domain = mock.Mock()
|
||||
domain.XMLDesc.return_value = dom_xml
|
||||
domain.blockInfo.return_value = (10737418240, 2147483648, 3221225472,
|
||||
-1)
|
||||
domain.info.return_value = (5, 0, 0, 2, 0)
|
||||
conn = mock.Mock()
|
||||
conn.lookupByUUIDString.return_value = domain
|
||||
|
||||
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
|
||||
'refresh_libvirt_connection', return_value=conn):
|
||||
disks = list(self.inspector.inspect_disk_info(
|
||||
self.instance, None))
|
||||
|
||||
self.assertEqual(1, len(disks))
|
||||
self.assertEqual('vda', disks[0].device)
|
||||
self.assertEqual(10737418240, disks[0].capacity)
|
||||
self.assertEqual(2147483648, disks[0].allocation)
|
||||
self.assertEqual(3221225472, disks[0].physical)
|
||||
|
||||
def test_inspect_disk_info_network_type(self):
|
||||
dom_xml = """
|
||||
<domain type='kvm'>
|
||||
@@ -445,17 +506,23 @@ class TestLibvirtInspection(base.BaseTestCase):
|
||||
|
||||
self.assertEqual(0, len(disks))
|
||||
|
||||
def test_inspect_memory_usage_with_domain_shutoff(self):
|
||||
def test_inspect_memory_with_domain_shutoff(self):
|
||||
self.inspector.conf.set_override(
|
||||
'report_stopped_instance_metrics', True, group='compute')
|
||||
domain = mock.Mock()
|
||||
domain.info.return_value = (5, 0, 51200, 2, 999999)
|
||||
domain.info.return_value = (5, 524288, 51200, 4, 0)
|
||||
conn = mock.Mock()
|
||||
conn.lookupByUUIDString.return_value = domain
|
||||
|
||||
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
|
||||
'refresh_libvirt_connection', return_value=conn):
|
||||
self.assertRaises(virt_inspector.InstanceShutOffException,
|
||||
self.inspector.inspect_instance,
|
||||
self.instance, None)
|
||||
stats = self.inspector.inspect_instance(self.instance, None)
|
||||
self.assertEqual(5, stats.power_state)
|
||||
self.assertEqual(4, stats.cpu_number)
|
||||
self.assertEqual(524288 / units.Ki, stats.memory_actual)
|
||||
self.assertIsNone(stats.memory_usage)
|
||||
self.assertIsNone(stats.memory_available)
|
||||
self.assertIsNone(stats.memory_resident)
|
||||
|
||||
def test_inspect_memory_with_empty_stats(self):
|
||||
domain = mock.Mock()
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
A new ``[compute] report_stopped_instance_metrics`` option (disabled by
|
||||
default) allows the libvirt compute pollster to report a minimal set
|
||||
of metrics for stopped (SHUTOFF) VMs: ``power.state``, ``vcpus``,
|
||||
``memory``, ``disk.device.capacity``, and ``disk.device.usage``.
|
||||
Runtime metrics (such as ``cpu``, ``memory.usage``,
|
||||
``memory.resident``, network and disk I/O stats) are never reported
|
||||
for stopped VMs. Shelved-offloaded VMs are not affected as Nova
|
||||
removes their libvirt domain entirely.
|
||||
Reference in New Issue
Block a user