filter: add per-aggregate filter to configure disk_allocation_ratio

Adds a filter AggregateDiskFilter which provides the ability to
read from aggregates metadata the "disk_allocation_ratio".

DocImpact
Implements: blueprint per-aggregate-disk-allocation-ratio
Change-Id: I79d59fcdfb09e67ed6f12113615c673624b24a19
This commit is contained in:
Sahid Orentino Ferdjaoui 2014-08-12 09:49:29 +02:00 committed by Sahid Orentino Ferdjaoui
parent 7fb2a039dd
commit 56a9512f14
3 changed files with 83 additions and 1 deletions

View File

@ -94,6 +94,11 @@ There are some standard filter classes to use (:mod:`nova.scheduler.filters`):
``disk_allocation_ration`` setting. It's virtual disk to physical disk
allocation ratio and it's 1.0 by default. The total allow allocated disk size will
be physical disk multiplied this ratio.
* |AggregateDiskFilter| - filters hosts by disk allocation with per-aggregate
``disk_allocation_ratio`` setting. If no per-aggregate value is found, it will
fall back to the global default ``disk_allocation_ratio``. If more than one value
is found for a host (meaning the host is in two or more different aggregates with
different ratio settings), the minimum value will be used.
* |NumInstancesFilter| - filters hosts by number of running instances on it.
hosts with too many instances will be filtered.
``max_instances_per_host`` setting. Maximum number of instances allowed to run on
@ -360,6 +365,7 @@ in :mod:``nova.tests.scheduler``.
.. |RamFilter| replace:: :class:`RamFilter <nova.scheduler.filters.ram_filter.RamFilter>`
.. |AggregateRamFilter| replace:: :class:`AggregateRamFilter <nova.scheduler.filters.ram_filter.AggregateRamFilter>`
.. |DiskFilter| replace:: :class:`DiskFilter <nova.scheduler.filters.disk_filter.DiskFilter>`
.. |AggregateDiskFilter| replace:: :class:`AggregateDiskFilter <nova.scheduler.filters.disk_filter.AggregateDiskFilter>`
.. |NumInstancesFilter| replace:: :class:`NumInstancesFilter <nova.scheduler.filters.num_instances_filter.NumInstancesFilter>`
.. |IoOpsFilter| replace:: :class:`IoOpsFilter <nova.scheduler.filters.io_ops_filter.IoOpsFilter>`
.. |AggregateIoOpsFilter| replace:: :class:`AggregateIoOpsFilter <nova.scheduler.filters.io_ops_filter.AggregateIoOpsFilter>`

View File

@ -15,8 +15,10 @@
from oslo.config import cfg
from nova.i18n import _LW
from nova.openstack.common import log as logging
from nova.scheduler import filters
from nova.scheduler.filters import utils
LOG = logging.getLogger(__name__)
@ -30,6 +32,9 @@ CONF.register_opt(disk_allocation_ratio_opt)
class DiskFilter(filters.BaseHostFilter):
"""Disk Filter with over subscription flag."""
def _get_disk_allocation_ratio(self, host_state, filter_properties):
return CONF.disk_allocation_ratio
def host_passes(self, host_state, filter_properties):
"""Filter based on disk usage."""
instance_type = filter_properties.get('instance_type')
@ -40,7 +45,10 @@ class DiskFilter(filters.BaseHostFilter):
free_disk_mb = host_state.free_disk_mb
total_usable_disk_mb = host_state.total_usable_disk_gb * 1024
disk_mb_limit = total_usable_disk_mb * CONF.disk_allocation_ratio
disk_allocation_ratio = self._get_disk_allocation_ratio(
host_state, filter_properties)
disk_mb_limit = total_usable_disk_mb * disk_allocation_ratio
used_disk_mb = total_usable_disk_mb - free_disk_mb
usable_disk_mb = disk_mb_limit - used_disk_mb
@ -55,3 +63,28 @@ class DiskFilter(filters.BaseHostFilter):
disk_gb_limit = disk_mb_limit / 1024
host_state.limits['disk_gb'] = disk_gb_limit
return True
class AggregateDiskFilter(DiskFilter):
"""AggregateDiskFilter with per-aggregate disk allocation ratio flag.
Fall back to global disk_allocation_ratio if no per-aggregate setting
found.
"""
def _get_disk_allocation_ratio(self, host_state, filter_properties):
# 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.
aggregate_vals = utils.aggregate_values_from_db(
filter_properties['context'],
host_state.host,
'disk_allocation_ratio')
try:
ratio = utils.validate_num_values(
aggregate_vals, CONF.disk_allocation_ratio, cast_to=float)
except ValueError as e:
LOG.warn(_LW("Could not decode disk_allocation_ratio: '%s'"), e)
ratio = CONF.disk_allocation_ratio
return ratio

View File

@ -1927,3 +1927,46 @@ class HostFiltersTestCase(test.NoDBTestCase):
metadata={'max_io_ops_per_host': 'XXX'})
filter_properties = {'context': self.context}
self.assertTrue(filt_cls.host_passes(host, filter_properties))
def test_aggregate_disk_filter_value_error(self):
self._stub_service_is_up(True)
filt_cls = self.class_map['AggregateDiskFilter']()
self.flags(disk_allocation_ratio=1.0)
filter_properties = {
'context': self.context,
'instance_type': {'root_gb': 1,
'ephemeral_gb': 1,
'swap': 1024}}
service = {'disabled': False}
host = fakes.FakeHostState('host1', 'node1',
{'free_disk_mb': 3 * 1024,
'total_usable_disk_gb': 1,
'service': service})
self._create_aggregate_with_host(name='fake_aggregate',
hosts=['host1'],
metadata={'disk_allocation_ratio': 'XXX'})
self.assertTrue(filt_cls.host_passes(host, filter_properties))
def test_aggregate_disk_filter_default_value(self):
self._stub_service_is_up(True)
filt_cls = self.class_map['AggregateDiskFilter']()
self.flags(disk_allocation_ratio=1.0)
filter_properties = {
'context': self.context,
'instance_type': {'root_gb': 2,
'ephemeral_gb': 1,
'swap': 1024}}
service = {'disabled': False}
host = fakes.FakeHostState('host1', 'node1',
{'free_disk_mb': 3 * 1024,
'total_usable_disk_gb': 1,
'service': service})
# Uses global conf.
self.assertFalse(filt_cls.host_passes(host, filter_properties))
# Uses an aggregate with ratio
self._create_aggregate_with_host(
name='fake_aggregate',
hosts=['host1'],
metadata={'disk_allocation_ratio': '2'})
self.assertTrue(filt_cls.host_passes(host, filter_properties))