use new instance polling interface

ceilometer has a new polling interface that inspects instance at once
rather than individual parts at a time.

Includes changes for vnic polling interface and disk polling interface.

Change-Id: Ieb68420eba002a36569db41c36ddf827bb9edfea
This commit is contained in:
gord chung 2017-03-21 14:47:31 +00:00 committed by Drew Thorstensen
parent fdac541e70
commit 562b5182f8
2 changed files with 73 additions and 122 deletions

View File

@ -84,12 +84,18 @@ class PowerVMInspector(virt_inspector.Inspector):
LOG.debug("Host UUID: %s" % hosts[0].uuid)
return hosts[0].uuid
def inspect_cpus(self, instance):
"""Inspect the CPU statistics for an instance.
def inspect_instance(self, instance, duration=None):
"""Inspect the statistics for an instance.
:param instance: the target instance
:return: the number of CPUs and cumulative CPU time
:param duration: the last 'n' seconds, over which the value should be
inspected.
The PowerVM implementation does not make use of the duration
field.
:return: the instance statistics
"""
uuid = self._puuid(instance)
cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid)
@ -102,20 +108,8 @@ class PowerVMInspector(virt_inspector.Inspector):
cpu_time = (cur_metric.processor.util_cap_proc_cycles +
cur_metric.processor.util_uncap_proc_cycles)
return virt_inspector.CPUStats(number=cur_metric.processor.virt_procs,
time=cpu_time)
cpu_num = cur_metric.processor.virt_procs
def inspect_cpu_util(self, instance, duration=None):
"""Inspect the CPU Utilization (%) for an instance.
:param instance: the target instance
:param duration: the last 'n' seconds, over which the value should be
inspected.
The PowerVM implementation does not make use of the duration
field.
:return: the percentage of CPU utilization
"""
# The duration is ignored. There is precedent for this in other
# inspectors if the platform doesn't support duration.
#
@ -126,17 +120,8 @@ class PowerVMInspector(virt_inspector.Inspector):
# Get the current and previous sample. Delta is performed between
# these two.
uuid = self._puuid(instance)
cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid)
prev_date, prev_metric = self.vm_metrics.get_previous_metric(uuid)
# If the current is none, then the instance can not be found in the
# sample and an error should be raised.
if cur_metric is None:
raise virt_inspector.InstanceNotFoundException(
_('VM %s not found in PowerVM Metrics Sample.') %
instance.name)
# Get the current data.
cur_util_cap = cur_metric.processor.util_cap_proc_cycles
cur_util_uncap = cur_metric.processor.util_uncap_proc_cycles
@ -157,9 +142,8 @@ class PowerVMInspector(virt_inspector.Inspector):
"It is either a new VM or was recently migrated. "
"It will be collected in the next inspection "
"cycle."), instance.name)
message = (_("Unable to derive CPU Utilization for VM %s.") %
instance.name)
raise virt_inspector.InstanceNotFoundException(message)
return virt_inspector.InstanceStats(
cpu_time=cpu_time, cpu_number=cpu_num)
# Gather the previous metrics
prev_util_cap = prev_metric.processor.util_cap_proc_cycles
@ -203,14 +187,13 @@ class PowerVMInspector(virt_inspector.Inspector):
# If the entitled is zero, that generally means that the VM has not
# been started yet (everything else would be zero as well). So to
# avoid a divide by zero error, just return 0% in that case.
if entitled == 0:
return virt_inspector.CPUUtilStats(util=0.0)
util = float(util_cap + util_uncap - idle - donated) / float(entitled)
util = (float(util_cap + util_uncap - idle - donated) / float(entitled)
if entitled else 0.0)
# Utilization is reported as percents. Therefore, multiply by 100.0
# to get a readable percentage based format.
return virt_inspector.CPUUtilStats(util=util * 100.0)
return virt_inspector.InstanceStats(
cpu_util=util * 100.0, cpu_time=cpu_time, cpu_number=cpu_num)
@staticmethod
def mac_for_metric_cna(metric_cna, client_cnas):
@ -279,14 +262,13 @@ class PowerVMInspector(virt_inspector.Inspector):
# The name will be the location code. MAC is identified from
# above. Others appear libvirt specific.
interface = virt_inspector.Interface(
name=metric_cna.physical_location,
mac=mac, fref=None, parameters=None)
#
# PowerVM doesn't specify drops by receive vs. transmit. Since we
# have the client adapter, we assume all are receive drops.
# There are no error metrics available.
stats = virt_inspector.InterfaceStats(
yield virt_inspector.InterfaceStats(
name=metric_cna.physical_location,
mac=mac, fref=None, parameters=None,
rx_bytes=metric_cna.received_bytes,
rx_packets=metric_cna.received_packets,
rx_drop=metric_cna.dropped_packets,
@ -296,9 +278,6 @@ class PowerVMInspector(virt_inspector.Inspector):
tx_drop=0,
tx_errors=0)
# Yield the stats up to the invoker
yield (interface, stats)
def inspect_vnic_rates(self, instance, duration=None):
"""Inspect the vNIC rate statistics for an instance.
@ -358,12 +337,6 @@ class PowerVMInspector(virt_inspector.Inspector):
if mac is None:
continue
# The name will be the location code. MAC is identified from
# above. Others appear libvirt specific.
interface = virt_inspector.Interface(
name=metric_cna.physical_location,
mac=mac, fref=None, parameters=None)
# Note that here, the previous may be none. That simply indicates
# that the adapter was dynamically added to the VM before the
# previous collection. Not the migration scenario above.
@ -378,10 +351,13 @@ class PowerVMInspector(virt_inspector.Inspector):
# in time between the two samples.
rx_rate = float(rx_bytes_diff) / float(date_delta_num)
tx_rate = float(tx_bytes_diff) / float(date_delta_num)
stats = virt_inspector.InterfaceRateStats(rx_rate, tx_rate)
# Yield the results back to the invoker.
yield (interface, stats)
# The name will be the location code. MAC is identified from
# above. Others appear libvirt specific.
yield virt_inspector.InterfaceRateStats(
name=metric_cna.physical_location,
mac=mac, fref=None, parameters=None,
rx_bytes_rate=rx_rate, tx_bytes_rate=tx_rate)
def inspect_disks(self, instance):
"""Inspect the disk statistics for an instance.
@ -419,12 +395,10 @@ class PowerVMInspector(virt_inspector.Inspector):
for adpt in adpts:
# PowerVM only shows the connection (SCSI or FC). Name after
# the connection name
disk = virt_inspector.Disk(device=adpt.name)
stats = virt_inspector.DiskStats(
read_requests=adpt.num_reads, read_bytes=adpt.read_bytes,
write_requests=adpt.num_writes, write_bytes=adpt.write_bytes,
errors=0)
yield (disk, stats)
yield virt_inspector.DiskStats(
device=adpt.name, read_requests=adpt.num_reads,
read_bytes=adpt.read_bytes, write_requests=adpt.num_writes,
write_bytes=adpt.write_bytes, errors=0)
def inspect_disk_iops(self, instance):
"""Inspect the Disk Input/Output operations per second for an instance.
@ -494,6 +468,5 @@ class PowerVMInspector(virt_inspector.Inspector):
# PowerVM only shows the connection (SCSI or FC). Name after
# the connection name
disk = virt_inspector.Disk(device=cur_adpt.name)
stats = virt_inspector.DiskIOPSStats(iops_count=iops)
yield (disk, stats)
yield virt_inspector.DiskIOPSStats(device=cur_adpt.name,
iops_count=iops)

View File

@ -79,41 +79,18 @@ class TestPowerVMInspector(base.BaseTestCase):
self.inspector = p_inspect.PowerVMInspector(None)
self.inspector.vm_metrics = self.mock_metrics
def test_inspect_cpus(self):
"""Validates PowerVM's inspect_cpus method."""
def test_inspect_instance_stats(self):
"""Validates PowerVM's inspect_instance method."""
# Validate that an error is raised if the instance can't be found
# in the sample
self.mock_metrics.get_latest_metric.return_value = None, None
self.assertRaises(virt_inspector.InstanceNotFoundException,
self.inspector.inspect_cpus, mock.Mock())
# Build a response from the metric cache.
metric = mock.MagicMock()
metric.processor.util_cap_proc_cycles = 5
metric.processor.util_uncap_proc_cycles = 6
metric.processor.virt_procs = 12
self.mock_metrics.get_latest_metric.return_value = mock.Mock(), metric
# Invoke with the test data
resp = self.inspector.inspect_cpus(mock.Mock())
# Validate the metrics that came back
self.assertEqual(11, resp.time)
self.assertEqual(12, resp.number)
def test_inspect_cpu_util(self):
"""Validates PowerVM's inspect_cpu_util method."""
# Validate that an error is raised if the instance can't be found in
# the sample data.
self.mock_metrics.get_latest_metric.return_value = None, None
self.mock_metrics.get_previous_metric.return_value = None, None
self.assertRaises(virt_inspector.InstanceNotFoundException,
self.inspector.inspect_cpu_util,
mock.Mock(), duration=30)
self.inspector.inspect_instance, mock.Mock())
def mock_metric(util_cap, util_uncap, idle, donated, entitled):
"""Helper method to create mock proc metrics."""
metric = mock.MagicMock()
metric.processor.virt_procs = 12
metric.processor.util_cap_proc_cycles = util_cap
metric.processor.util_uncap_proc_cycles = util_uncap
metric.processor.idle_proc_cycles = idle
@ -126,8 +103,9 @@ class TestPowerVMInspector(base.BaseTestCase):
self.mock_metrics.get_latest_metric.return_value = (
mock.Mock(), mock_metric(7000, 50, 1000, 5000, 10000))
self.mock_metrics.get_previous_metric.return_value = None, None
self.assertRaises(virt_inspector.InstanceNotFoundException,
self.inspector.inspect_cpu_util, mock.Mock())
resp = self.inspector.inspect_instance(mock.Mock())
self.assertEqual(7050, resp.cpu_time)
self.assertEqual(12, resp.cpu_number)
# Mock up a mixed use environment.
cur = mock_metric(7000, 50, 1000, 5000, 10000)
@ -136,8 +114,8 @@ class TestPowerVMInspector(base.BaseTestCase):
self.mock_metrics.get_previous_metric.return_value = mock.Mock(), prev
# Execute and validate
resp = self.inspector.inspect_cpu_util(mock.Mock())
self.assertEqual(.5, resp.util)
resp = self.inspector.inspect_instance(mock.Mock())
self.assertEqual(.5, resp.cpu_util)
# Mock an instance with a dedicated processor, but idling and donating
# cycles to others. In these scenarios, util_cap shows full use, but
@ -148,8 +126,8 @@ class TestPowerVMInspector(base.BaseTestCase):
self.mock_metrics.get_previous_metric.return_value = mock.Mock(), prev
# Execute and validate
resp = self.inspector.inspect_cpu_util(mock.Mock())
self.assertEqual(51.0, resp.util)
resp = self.inspector.inspect_instance(mock.Mock())
self.assertEqual(51.0, resp.cpu_util)
# Mock an instance with a shared processor. By nature, this doesn't
# idle or donate. If it is 'idling' it is simply giving the cycles
@ -160,8 +138,8 @@ class TestPowerVMInspector(base.BaseTestCase):
self.mock_metrics.get_previous_metric.return_value = mock.Mock(), prev
# Execute and validate
resp = self.inspector.inspect_cpu_util(mock.Mock())
self.assertEqual(80.0, resp.util)
resp = self.inspector.inspect_instance(mock.Mock())
self.assertEqual(80.0, resp.cpu_util)
# Mock an instance with a shared processor - but using cycles from
# the uncap pool. This means it is using extra cycles from other
@ -173,8 +151,8 @@ class TestPowerVMInspector(base.BaseTestCase):
# Execute and validate. This should be running at 300% CPU
# utilization. Fast!
resp = self.inspector.inspect_cpu_util(mock.Mock())
self.assertEqual(300.0, resp.util)
resp = self.inspector.inspect_instance(mock.Mock())
self.assertEqual(300.0, resp.cpu_util)
# Mock an instance that hasn't been started yet.
cur = mock_metric(0, 0, 0, 0, 0)
@ -183,8 +161,8 @@ class TestPowerVMInspector(base.BaseTestCase):
self.mock_metrics.get_previous_metric.return_value = mock.Mock(), prev
# This should have 0% utilization
resp = self.inspector.inspect_cpu_util(mock.Mock())
self.assertEqual(0.0, resp.util)
resp = self.inspector.inspect_instance(mock.Mock())
self.assertEqual(0.0, resp.cpu_util)
@staticmethod
def _mock_vnic_metric(rec_bytes, tx_bytes, rec_pkts, tx_pkts, phys_loc,
@ -252,9 +230,9 @@ class TestPowerVMInspector(base.BaseTestCase):
resp = list(self.inspector.inspect_vnics(mock.Mock()))
self.assertEqual(3, len(resp))
interface1, stats1 = resp[0]
self.assertEqual('aa:bb:cc:dd:ee:ff', interface1.mac)
self.assertEqual('a', interface1.name)
stats1 = resp[0]
self.assertEqual('aa:bb:cc:dd:ee:ff', stats1.mac)
self.assertEqual('a', stats1.name)
self.assertEqual(1000, stats1.rx_bytes)
self.assertEqual(1000, stats1.tx_bytes)
self.assertEqual(10, stats1.rx_packets)
@ -302,23 +280,23 @@ class TestPowerVMInspector(base.BaseTestCase):
self.assertEqual(3, len(resp))
# First metric. No delta
interface1, stats1 = resp[0]
self.assertEqual('aa:bb:cc:dd:ee:ff', interface1.mac)
self.assertEqual('a', interface1.name)
stats1 = resp[0]
self.assertEqual('aa:bb:cc:dd:ee:ff', stats1.mac)
self.assertEqual('a', stats1.name)
self.assertEqual(0, stats1.rx_bytes_rate)
self.assertEqual(0, stats1.tx_bytes_rate)
# Second metric
interface2, stats2 = resp[1]
self.assertEqual('aa:bb:cc:dd:ee:11', interface2.mac)
self.assertEqual('b', interface2.name)
stats2 = resp[1]
self.assertEqual('aa:bb:cc:dd:ee:11', stats2.mac)
self.assertEqual('b', stats2.name)
self.assertEqual(60.0, stats2.rx_bytes_rate)
self.assertEqual(60.0, stats2.tx_bytes_rate)
# Third metric had no previous.
interface3, stats3 = resp[2]
self.assertEqual('aa:bb:cc:dd:ee:22', interface3.mac)
self.assertEqual('c', interface3.name)
stats3 = resp[2]
self.assertEqual('aa:bb:cc:dd:ee:22', stats3.mac)
self.assertEqual('c', stats3.name)
self.assertEqual(100.0, stats3.rx_bytes_rate)
self.assertEqual(100.0, stats3.tx_bytes_rate)
@ -387,17 +365,17 @@ class TestPowerVMInspector(base.BaseTestCase):
self.assertEqual(3, len(resp))
# Two vSCSI's
disk1, stats1 = resp[0]
self.assertEqual('vscsi1', disk1.device)
stats1 = resp[0]
self.assertEqual('vscsi1', stats1.device)
self.assertEqual(33, stats1.iops_count)
disk2, stats2 = resp[1]
self.assertEqual('vscsi2', disk2.device)
stats2 = resp[1]
self.assertEqual('vscsi2', stats2.device)
self.assertEqual(133, stats2.iops_count)
# Next is the vFC metric
disk3, stats3 = resp[2]
self.assertEqual('vfc1', disk3.device)
stats3 = resp[2]
self.assertEqual('vfc1', stats3.device)
self.assertEqual(66, stats3.iops_count)
def test_inspect_disks(self):
@ -425,16 +403,16 @@ class TestPowerVMInspector(base.BaseTestCase):
self.assertEqual(3, len(resp))
# Two vSCSIs.
disk1, stats1 = resp[0]
self.assertEqual('vscsi1', disk1.device)
stats1 = resp[0]
self.assertEqual('vscsi1', stats1.device)
self.assertEqual(1000, stats1.read_requests)
self.assertEqual(100000, stats1.read_bytes)
self.assertEqual(1000, stats1.write_requests)
self.assertEqual(100000, stats1.write_bytes)
self.assertEqual(0, stats1.errors)
disk2, stats2 = resp[1]
self.assertEqual('vscsi2', disk2.device)
stats2 = resp[1]
self.assertEqual('vscsi2', stats2.device)
self.assertEqual(2000, stats2.read_requests)
self.assertEqual(200000, stats2.read_bytes)
self.assertEqual(2000, stats2.write_requests)
@ -442,8 +420,8 @@ class TestPowerVMInspector(base.BaseTestCase):
self.assertEqual(0, stats1.errors)
# Next is the vFC metric
disk3, stats3 = resp[2]
self.assertEqual('vfc1', disk3.device)
stats3 = resp[2]
self.assertEqual('vfc1', stats3.device)
self.assertEqual(3000, stats3.read_requests)
self.assertEqual(300000, stats3.read_bytes)
self.assertEqual(3000, stats3.write_requests)