summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorQiu Yu <unicell@gmail.com>2013-06-21 17:55:31 +0800
committerQiu Yu <unicell@gmail.com>2013-06-21 22:09:29 +0800
commitc32a6d5ec3426528b1f3194b0810c0592e0007d6 (patch)
tree48cc778ee97333db8fb88d08e35de08451f5b2ce /nova
parentfacf42d0bab7a4f97c654a5724189609ad185559 (diff)
downloadnova-c32a6d5ec3426528b1f3194b0810c0592e0007d6.tar.gz
nova-c32a6d5ec3426528b1f3194b0810c0592e0007d6.tar.xz
nova-c32a6d5ec3426528b1f3194b0810c0592e0007d6.zip
Add AggregateCoreFilter
Implements blueprint per-aggregate-resource-ratio * AggregateCoreFilter to support per-aggregate cpu_allocation_ratio * Falls back to global setting if per-aggregate value not found DocImpact Change-Id: I9230f46e2490226f3c50d616aa173d4722095087
Diffstat (limited to 'nova')
-rw-r--r--nova/scheduler/filters/core_filter.py57
-rw-r--r--nova/tests/scheduler/test_host_filters.py46
2 files changed, 99 insertions, 4 deletions
diff --git a/nova/scheduler/filters/core_filter.py b/nova/scheduler/filters/core_filter.py
index 4eb6ebcf1..6e733a237 100644
--- a/nova/scheduler/filters/core_filter.py
+++ b/nova/scheduler/filters/core_filter.py
@@ -17,6 +17,7 @@
from oslo.config import cfg
+from nova import db
from nova.openstack.common import log as logging
from nova.scheduler import filters
@@ -24,14 +25,19 @@ LOG = logging.getLogger(__name__)
cpu_allocation_ratio_opt = cfg.FloatOpt('cpu_allocation_ratio',
default=16.0,
- help='Virtual CPU to Physical CPU allocation ratio')
+ help='Virtual CPU to physical CPU allocation ratio which affects '
+ 'all CPU filters. This configuration specifies a global ratio '
+ 'for CoreFilter. For AggregateCoreFilter, it will fall back to '
+ 'this configuration value if no per-aggregate setting found.')
CONF = cfg.CONF
CONF.register_opt(cpu_allocation_ratio_opt)
-class CoreFilter(filters.BaseHostFilter):
- """CoreFilter filters based on CPU core utilization."""
+class BaseCoreFilter(filters.BaseHostFilter):
+
+ def _get_cpu_allocation_ratio(self, host_state, filter_properties):
+ raise NotImplementedError
def host_passes(self, host_state, filter_properties):
"""Return True if host has sufficient CPU cores."""
@@ -45,7 +51,9 @@ class CoreFilter(filters.BaseHostFilter):
return True
instance_vcpus = instance_type['vcpus']
- vcpus_total = host_state.vcpus_total * CONF.cpu_allocation_ratio
+ cpu_allocation_ratio = self._get_cpu_allocation_ratio(host_state,
+ filter_properties)
+ vcpus_total = host_state.vcpus_total * cpu_allocation_ratio
# Only provide a VCPU limit to compute if the virt driver is reporting
# an accurate count of installed VCPUs. (XenServer driver does not)
@@ -53,3 +61,44 @@ class CoreFilter(filters.BaseHostFilter):
host_state.limits['vcpu'] = vcpus_total
return (vcpus_total - host_state.vcpus_used) >= instance_vcpus
+
+
+class CoreFilter(BaseCoreFilter):
+ """CoreFilter filters based on CPU core utilization."""
+
+ def _get_cpu_allocation_ratio(self, host_state, filter_properties):
+ return CONF.cpu_allocation_ratio
+
+
+class AggregateCoreFilter(BaseCoreFilter):
+ """AggregateRamFilter with per-aggregate CPU subscription flag.
+
+ Fall back to global cpu_allocation_ratio if no per-aggregate setting found.
+ """
+
+ def _get_cpu_allocation_ratio(self, host_state, filter_properties):
+ context = filter_properties['context'].elevated()
+ # TODO(uni): DB query in filter is a performance hit, especially for
+ # system with lots of hosts. Will need a general solution here to fix
+ # all filters with aggregate DB call things.
+ metadata = db.aggregate_metadata_get_by_host(
+ context, host_state.host, key='cpu_allocation_ratio')
+ aggregate_vals = metadata.get('cpu_allocation_ratio', set())
+ num_values = len(aggregate_vals)
+
+ if num_values == 0:
+ return CONF.cpu_allocation_ratio
+
+ if num_values > 1:
+ LOG.warning(_("%(num_values)d ratio values found, "
+ "of which the minimum value will be used."),
+ {'num_values': num_values})
+
+ try:
+ ratio = float(min(aggregate_vals))
+ except ValueError as e:
+ LOG.warning(_("Could not decode cpu_allocation_ratio: "
+ "'%(e)s'") % locals())
+ ratio = CONF.cpu_allocation_ratio
+
+ return ratio
diff --git a/nova/tests/scheduler/test_host_filters.py b/nova/tests/scheduler/test_host_filters.py
index 9306615ed..531ad8b0b 100644
--- a/nova/tests/scheduler/test_host_filters.py
+++ b/nova/tests/scheduler/test_host_filters.py
@@ -1317,6 +1317,52 @@ class HostFiltersTestCase(test.NoDBTestCase):
{'vcpus_total': 4, 'vcpus_used': 8})
self.assertFalse(filt_cls.host_passes(host, filter_properties))
+ def test_aggregate_core_filter_value_error(self):
+ filt_cls = self.class_map['AggregateCoreFilter']()
+ filter_properties = {'context': self.context,
+ 'instance_type': {'vcpus': 1}}
+ self.flags(cpu_allocation_ratio=2)
+ host = fakes.FakeHostState('host1', 'node1',
+ {'vcpus_total': 4, 'vcpus_used': 7})
+ self._create_aggregate_with_host(name='fake_aggregate',
+ hosts=['host1'],
+ metadata={'cpu_allocation_ratio': 'XXX'})
+ self.assertTrue(filt_cls.host_passes(host, filter_properties))
+ self.assertEqual(4 * 2, host.limits['vcpu'])
+
+ def test_aggregate_core_filter_default_value(self):
+ filt_cls = self.class_map['AggregateCoreFilter']()
+ filter_properties = {'context': self.context,
+ 'instance_type': {'vcpus': 1}}
+ self.flags(cpu_allocation_ratio=2)
+ host = fakes.FakeHostState('host1', 'node1',
+ {'vcpus_total': 4, 'vcpus_used': 8})
+ # False: fallback to default flag w/o aggregates
+ self.assertFalse(filt_cls.host_passes(host, filter_properties))
+ self._create_aggregate_with_host(name='fake_aggregate',
+ hosts=['host1'],
+ metadata={'cpu_allocation_ratio': '3'})
+ # True: use ratio from aggregates
+ self.assertTrue(filt_cls.host_passes(host, filter_properties))
+ self.assertEqual(4 * 3, host.limits['vcpu'])
+
+ def test_aggregate_core_filter_conflict_values(self):
+ filt_cls = self.class_map['AggregateCoreFilter']()
+ filter_properties = {'context': self.context,
+ 'instance_type': {'vcpus': 1}}
+ self.flags(cpu_allocation_ratio=1)
+ host = fakes.FakeHostState('host1', 'node1',
+ {'vcpus_total': 4, 'vcpus_used': 8})
+ self._create_aggregate_with_host(name='fake_aggregate1',
+ hosts=['host1'],
+ metadata={'cpu_allocation_ratio': '2'})
+ self._create_aggregate_with_host(name='fake_aggregate2',
+ hosts=['host1'],
+ metadata={'cpu_allocation_ratio': '3'})
+ # use the minimum ratio from aggregates
+ self.assertFalse(filt_cls.host_passes(host, filter_properties))
+ self.assertEqual(4 * 2, host.limits['vcpu'])
+
@staticmethod
def _make_zone_request(zone, is_admin=False):
ctxt = context.RequestContext('fake', 'fake', is_admin=is_admin)