Fix MetricWeigher to use MonitorMetricList

The commit I4dfbea27ce6c3eecc1a8658b1f9dc0feb2298705 changes
'HostState.metrics' to 'objects.MonitorMetricList'. But MetricWeigher
still use the old dictionary of 'host_manager.MetricItem'. This patch
corrects the behavior of MetricWeigher with related tests, and delete
unused MetricItem.

Co-Authored-By: Sylvain Bauza <sbauza@redhat.com>

Change-Id: I7c98c2e189318e85a733f0287ef507c7bad36472
Closes-Bug: #1493680
This commit is contained in:
Yingxin Cheng 2015-09-09 11:20:19 -04:00 committed by Sylvain Bauza
parent bffdec0f0f
commit fd2b868d41
4 changed files with 85 additions and 67 deletions

View File

@ -105,11 +105,6 @@ class ReadOnlyDict(IterableUserDict):
raise TypeError() raise TypeError()
# Representation of a single metric value from a compute node.
MetricItem = collections.namedtuple(
'MetricItem', ['value', 'timestamp', 'source'])
@utils.expects_func_args('self', 'instance') @utils.expects_func_args('self', 'instance')
def set_update_time_on_success(function): def set_update_time_on_success(function):
"""Set updated time of HostState when consuming succeed.""" """Set updated time of HostState when consuming succeed."""

View File

@ -84,9 +84,12 @@ class MetricsWeigher(weights.BaseHostWeigher):
def _weigh_object(self, host_state, weight_properties): def _weigh_object(self, host_state, weight_properties):
value = 0.0 value = 0.0
# NOTE(sbauza): Keying a dict of Metrics per metric name given that we
# have a MonitorMetricList object
metrics_dict = {m.name: m for m in host_state.metrics}
for (name, ratio) in self.setting: for (name, ratio) in self.setting:
try: try:
value += host_state.metrics[name].value * ratio value += metrics_dict[name].value * ratio
except KeyError: except KeyError:
if CONF.metrics.required: if CONF.metrics.required:
raise exception.ComputeHostMetricNotFound( raise exception.ComputeHostMetricNotFound(

View File

@ -18,6 +18,7 @@ from oslo_utils import timeutils
from six.moves import range from six.moves import range
from nova import exception from nova import exception
from nova import objects
from nova.scheduler import caching_scheduler from nova.scheduler import caching_scheduler
from nova.scheduler import host_manager from nova.scheduler import host_manager
from nova.tests.unit.scheduler import test_scheduler from nova.tests.unit.scheduler import test_scheduler
@ -137,6 +138,7 @@ class CachingSchedulerTestCase(test_scheduler.SchedulerTestCase):
} }
host_state.cpu_allocation_ratio = 16.0 host_state.cpu_allocation_ratio = 16.0
host_state.ram_allocation_ratio = 1.5 host_state.ram_allocation_ratio = 1.5
host_state.metrics = objects.MonitorMetricList(objects=[])
return host_state return host_state
@mock.patch('nova.db.instance_extra_get_by_instance_uuid', @mock.patch('nova.db.instance_extra_get_by_instance_uuid',

View File

@ -14,13 +14,19 @@ Tests For Scheduler metrics weights.
""" """
from nova import exception from nova import exception
from nova.scheduler import host_manager from nova.objects import fields
from nova.objects import monitor_metric
from nova.scheduler import weights from nova.scheduler import weights
from nova.scheduler.weights import metrics from nova.scheduler.weights import metrics
from nova import test from nova import test
from nova.tests.unit.scheduler import fakes from nova.tests.unit.scheduler import fakes
idle = fields.MonitorMetricType.CPU_IDLE_TIME
kernel = fields.MonitorMetricType.CPU_KERNEL_TIME
user = fields.MonitorMetricType.CPU_USER_TIME
class MetricsWeigherTestCase(test.NoDBTestCase): class MetricsWeigherTestCase(test.NoDBTestCase):
def setUp(self): def setUp(self):
super(MetricsWeigherTestCase, self).setUp() super(MetricsWeigherTestCase, self).setUp()
@ -36,25 +42,28 @@ class MetricsWeigherTestCase(test.NoDBTestCase):
hosts, weight_properties)[0] hosts, weight_properties)[0]
def _get_all_hosts(self): def _get_all_hosts(self):
def fake_metric(value): def fake_metric(name, value):
return host_manager.MetricItem(value=value, timestamp='fake-time', return monitor_metric.MonitorMetric(name=name, value=value)
source='fake-source')
def fake_list(objs):
m_list = [fake_metric(name, val) for name, val in objs]
return monitor_metric.MonitorMetricList(objects=m_list)
host_values = [ host_values = [
('host1', 'node1', {'metrics': {'foo': fake_metric(512), ('host1', 'node1', {'metrics': fake_list([(idle, 512),
'bar': fake_metric(1)}}), (kernel, 1)])}),
('host2', 'node2', {'metrics': {'foo': fake_metric(1024), ('host2', 'node2', {'metrics': fake_list([(idle, 1024),
'bar': fake_metric(2)}}), (kernel, 2)])}),
('host3', 'node3', {'metrics': {'foo': fake_metric(3072), ('host3', 'node3', {'metrics': fake_list([(idle, 3072),
'bar': fake_metric(1)}}), (kernel, 1)])}),
('host4', 'node4', {'metrics': {'foo': fake_metric(8192), ('host4', 'node4', {'metrics': fake_list([(idle, 8192),
'bar': fake_metric(0)}}), (kernel, 0)])}),
('host5', 'node5', {'metrics': {'foo': fake_metric(768), ('host5', 'node5', {'metrics': fake_list([(idle, 768),
'bar': fake_metric(0), (kernel, 0),
'zot': fake_metric(1)}}), (user, 1)])}),
('host6', 'node6', {'metrics': {'foo': fake_metric(2048), ('host6', 'node6', {'metrics': fake_list([(idle, 2048),
'bar': fake_metric(0), (kernel, 0),
'zot': fake_metric(2)}}), (user, 2)])}),
] ]
return [fakes.FakeHostState(host, node, values) return [fakes.FakeHostState(host, node, values)
for host, node, values in host_values] for host, node, values in host_values]
@ -66,48 +75,57 @@ class MetricsWeigherTestCase(test.NoDBTestCase):
self.assertEqual(expected_host, weighed_host.obj.host) self.assertEqual(expected_host, weighed_host.obj.host)
def test_single_resource(self): def test_single_resource(self):
# host1: foo=512 # host1: idle=512
# host2: foo=1024 # host2: idle=1024
# host3: foo=3072 # host3: idle=3072
# host4: foo=8192 # host4: idle=8192
# so, host4 should win: # so, host4 should win:
setting = ['foo=1'] setting = [idle + '=1']
self._do_test(setting, 1.0, 'host4') self._do_test(setting, 1.0, 'host4')
def test_multiple_resource(self): def test_multiple_resource(self):
# host1: foo=512, bar=1 # host1: idle=512, kernel=1
# host2: foo=1024, bar=2 # host2: idle=1024, kernel=2
# host3: foo=3072, bar=1 # host3: idle=3072, kernel=1
# host4: foo=8192, bar=0 # host4: idle=8192, kernel=0
# so, host2 should win: # so, host2 should win:
setting = ['foo=0.0001', 'bar=1'] setting = [idle + '=0.0001', kernel + '=1']
self._do_test(setting, 1.0, 'host2') self._do_test(setting, 1.0, 'host2')
def test_single_resource_duplicate_setting(self):
# host1: idle=512
# host2: idle=1024
# host3: idle=3072
# host4: idle=8192
# so, host1 should win (sum of settings is negative):
setting = [idle + '=-2', idle + '=1']
self._do_test(setting, 1.0, 'host1')
def test_single_resourcenegtive_ratio(self): def test_single_resourcenegtive_ratio(self):
# host1: foo=512 # host1: idle=512
# host2: foo=1024 # host2: idle=1024
# host3: foo=3072 # host3: idle=3072
# host4: foo=8192 # host4: idle=8192
# so, host1 should win: # so, host1 should win:
setting = ['foo=-1'] setting = [idle + '=-1']
self._do_test(setting, 1.0, 'host1') self._do_test(setting, 1.0, 'host1')
def test_multiple_resource_missing_ratio(self): def test_multiple_resource_missing_ratio(self):
# host1: foo=512, bar=1 # host1: idle=512, kernel=1
# host2: foo=1024, bar=2 # host2: idle=1024, kernel=2
# host3: foo=3072, bar=1 # host3: idle=3072, kernel=1
# host4: foo=8192, bar=0 # host4: idle=8192, kernel=0
# so, host4 should win: # so, host4 should win:
setting = ['foo=0.0001', 'bar'] setting = [idle + '=0.0001', kernel]
self._do_test(setting, 1.0, 'host4') self._do_test(setting, 1.0, 'host4')
def test_multiple_resource_wrong_ratio(self): def test_multiple_resource_wrong_ratio(self):
# host1: foo=512, bar=1 # host1: idle=512, kernel=1
# host2: foo=1024, bar=2 # host2: idle=1024, kernel=2
# host3: foo=3072, bar=1 # host3: idle=3072, kernel=1
# host4: foo=8192, bar=0 # host4: idle=8192, kernel=0
# so, host4 should win: # so, host4 should win:
setting = ['foo=0.0001', 'bar = 2.0t'] setting = [idle + '=0.0001', kernel + ' = 2.0t']
self._do_test(setting, 1.0, 'host4') self._do_test(setting, 1.0, 'host4')
def _check_parsing_result(self, weigher, setting, results): def _check_parsing_result(self, weigher, setting, results):
@ -120,23 +138,23 @@ class MetricsWeigherTestCase(test.NoDBTestCase):
def test_parse_setting(self): def test_parse_setting(self):
weigher = self.weighers[0] weigher = self.weighers[0]
self._check_parsing_result(weigher, self._check_parsing_result(weigher,
['foo=1'], [idle + '=1'],
[('foo', 1.0)]) [(idle, 1.0)])
self._check_parsing_result(weigher, self._check_parsing_result(weigher,
['foo=1', 'bar=-2.1'], [idle + '=1', kernel + '=-2.1'],
[('foo', 1.0), ('bar', -2.1)]) [(idle, 1.0), (kernel, -2.1)])
self._check_parsing_result(weigher, self._check_parsing_result(weigher,
['foo=a1', 'bar=-2.1'], [idle + '=a1', kernel + '=-2.1'],
[('bar', -2.1)]) [(kernel, -2.1)])
self._check_parsing_result(weigher, self._check_parsing_result(weigher,
['foo', 'bar=-2.1'], [idle, kernel + '=-2.1'],
[('bar', -2.1)]) [(kernel, -2.1)])
self._check_parsing_result(weigher, self._check_parsing_result(weigher,
['=5', 'bar=-2.1'], ['=5', kernel + '=-2.1'],
[('bar', -2.1)]) [(kernel, -2.1)])
def test_metric_not_found_required(self): def test_metric_not_found_required(self):
setting = ['foo=1', 'zot=2'] setting = [idle + '=1', user + '=2']
self.assertRaises(exception.ComputeHostMetricNotFound, self.assertRaises(exception.ComputeHostMetricNotFound,
self._do_test, self._do_test,
setting, setting,
@ -144,13 +162,13 @@ class MetricsWeigherTestCase(test.NoDBTestCase):
'host4') 'host4')
def test_metric_not_found_non_required(self): def test_metric_not_found_non_required(self):
# host1: foo=512, bar=1 # host1: idle=512, kernel=1
# host2: foo=1024, bar=2 # host2: idle=1024, kernel=2
# host3: foo=3072, bar=1 # host3: idle=3072, kernel=1
# host4: foo=8192, bar=0 # host4: idle=8192, kernel=0
# host5: foo=768, bar=0, zot=1 # host5: idle=768, kernel=0, user=1
# host6: foo=2048, bar=0, zot=2 # host6: idle=2048, kernel=0, user=2
# so, host5 should win: # so, host5 should win:
self.flags(required=False, group='metrics') self.flags(required=False, group='metrics')
setting = ['foo=0.0001', 'zot=-1'] setting = [idle + '=0.0001', user + '=-1']
self._do_test(setting, 1.0, 'host5') self._do_test(setting, 1.0, 'host5')