Add helpers to create per-aggregate filters

This patchset introduce a new file of utility methods
to deal with aggregate metadata.
As well it updates related filters to use this new logic.
* AggregateRamFilter
* AggregateCoreFilter,
* AggregateTypeAffinityFilter

Closes-Bug: #1301340
Change-Id: I5e4aebe9e61cfbdc7b9e6b5de0788fc6670eb936
This commit is contained in:
Sahid Orentino Ferdjaoui 2014-03-03 17:35:35 +01:00
parent 76d6dee94d
commit 878f767b9e
5 changed files with 128 additions and 41 deletions

View File

@ -17,10 +17,10 @@
from oslo.config import cfg
from nova import db
from nova.openstack.common.gettextutils import _
from nova.openstack.common.gettextutils 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__)
@ -48,7 +48,7 @@ class BaseCoreFilter(filters.BaseHostFilter):
if not host_state.vcpus_total:
# Fail safe
LOG.warning(_("VCPUs not set; assuming CPU collection broken"))
LOG.warning(_LW("VCPUs not set; assuming CPU collection broken"))
return True
instance_vcpus = instance_type['vcpus']
@ -78,27 +78,18 @@ class AggregateCoreFilter(BaseCoreFilter):
"""
def _get_cpu_allocation_ratio(self, host_state, filter_properties):
context = filter_properties['context']
# 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})
aggregate_vals = utils.aggregate_values_from_db(
filter_properties['context'],
host_state.host,
'cpu_allocation_ratio')
try:
ratio = float(min(aggregate_vals))
ratio = utils.validate_num_values(
aggregate_vals, CONF.cpu_allocation_ratio, cast_to=float)
except ValueError as e:
LOG.warning(_("Could not decode cpu_allocation_ratio: '%s'"), e)
LOG.warning(_LW("Could not decode cpu_allocation_ratio: '%s'"), e)
ratio = CONF.cpu_allocation_ratio
return ratio

View File

@ -16,10 +16,10 @@
from oslo.config import cfg
from nova import db
from nova.openstack.common.gettextutils import _
from nova.openstack.common.gettextutils 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__)
@ -80,27 +80,19 @@ class AggregateRamFilter(BaseRamFilter):
"""
def _get_ram_allocation_ratio(self, host_state, filter_properties):
context = filter_properties['context']
# 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='ram_allocation_ratio')
aggregate_vals = metadata.get('ram_allocation_ratio', set())
num_values = len(aggregate_vals)
if num_values == 0:
return CONF.ram_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})
aggregate_vals = utils.aggregate_values_from_db(
filter_properties['context'],
host_state.host,
'ram_allocation_ratio')
try:
ratio = float(min(aggregate_vals))
ratio = utils.validate_num_values(
aggregate_vals, CONF.ram_allocation_ratio, cast_to=float)
except ValueError as e:
LOG.warning(_("Could not decode ram_allocation_ratio: '%s'"), e)
LOG.warning(_LW("Could not decode ram_allocation_ratio: '%s'"), e)
ratio = CONF.ram_allocation_ratio
return ratio

View File

@ -16,6 +16,7 @@
from nova import db
from nova.scheduler import filters
from nova.scheduler.filters import utils
class TypeAffinityFilter(filters.BaseHostFilter):
@ -51,8 +52,13 @@ class AggregateTypeAffinityFilter(filters.BaseHostFilter):
def host_passes(self, host_state, filter_properties):
instance_type = filter_properties.get('instance_type')
context = filter_properties['context']
metadata = db.aggregate_metadata_get_by_host(
context, host_state.host, key='instance_type')
return (len(metadata) == 0 or
instance_type['name'] in metadata['instance_type'])
# 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, 'instance_type')
if not aggregate_vals:
return True
return instance_type['name'] in aggregate_vals

View File

@ -0,0 +1,54 @@
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Bench of utility methods used by filters."""
from nova.objects import aggregate
from nova.openstack.common.gettextutils import _LI
from nova.openstack.common import log as logging
LOG = logging.getLogger(__name__)
def aggregate_values_from_db(context, host, key_name):
"""Returns a set of values based on a metadata key for a specific host."""
# TODO(sahid): 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.
aggrlist = aggregate.AggregateList.get_by_host(
context.elevated(), host, key=key_name)
aggregate_vals = set(aggr.metadata[key_name] for aggr in aggrlist)
return aggregate_vals
def validate_num_values(vals, default=None, cast_to=int, based_on=min):
"""Returns a corretly casted value based on a set of values.
This method is useful to work with per-aggregate filters, It takes
a set of values then return the 'based_on'{min/max} converted to
'cast_to' of the set or the default value.
Note: The cast implies a possible ValueError
"""
num_values = len(vals)
if num_values == 0:
return default
if num_values > 1:
LOG.info(_LI("%(num_values)d values found, "
"of which the minimum value will be used."),
{'num_values': num_values})
return cast_to(based_on(vals))

View File

@ -0,0 +1,44 @@
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
from nova.scheduler.filters import utils
from nova import test
class UtilsTestCase(test.NoDBTestCase):
def test_validate_num_values(self):
f = utils.validate_num_values
self.assertEqual("x", f(set(), default="x"))
self.assertEqual(1, f(set(["1"]), cast_to=int))
self.assertEqual(1.0, f(set(["1"]), cast_to=float))
self.assertEqual(1, f(set([1, 2]), based_on=min))
self.assertEqual(2, f(set([1, 2]), based_on=max))
@mock.patch("nova.objects.aggregate.AggregateList.get_by_host")
def test_aggregate_values_from_db(self, get_by_host):
aggrA = mock.MagicMock()
aggrB = mock.MagicMock()
context = mock.MagicMock()
get_by_host.return_value = [aggrA, aggrB]
aggrA.metadata = {'k1': 1, 'k2': 2}
aggrB.metadata = {'k1': 3, 'k2': 4}
values = utils.aggregate_values_from_db(context, 'h1', key_name='k1')
self.assertTrue(context.elevated.called)
self.assertEqual(set([1, 3]), values)