diff options
author | Zhiteng Huang <zhiteng.huang@intel.com> | 2012-12-10 15:33:30 +0800 |
---|---|---|
committer | Zhiteng Huang <zhiteng.huang@intel.com> | 2013-01-04 11:56:04 +0800 |
commit | 629bfd53dab67afbe6d70b010b7df0d0c57d39fe (patch) | |
tree | e9d46fd19182153670e92b428030a97eda7de57a | |
parent | 5177c7918b4d48645071234f8474b824759d71ef (diff) | |
download | oslo-629bfd53dab67afbe6d70b010b7df0d0c57d39fe.tar.gz oslo-629bfd53dab67afbe6d70b010b7df0d0c57d39fe.tar.xz oslo-629bfd53dab67afbe6d70b010b7df0d0c57d39fe.zip |
Add common base weigher/weigher handler for filter scheduler
Filter scheduler is being used for more than one core projects (Nova
and Cinder as of writing), the implementation shared a lot of common
code. This patch is to move base weigher (weighing function), weigher
handler for filter scheduler into oslo to reduce possible porting.
implement bp: common-weights
Change-Id: I2d1b37438663b53e035cc262875a283e5e2ee970
-rw-r--r-- | openstack/common/scheduler/weight.py | 91 | ||||
-rw-r--r-- | openstack/common/scheduler/weights/__init__.py | 45 | ||||
-rw-r--r-- | setup.py | 6 | ||||
-rw-r--r-- | tests/unit/fakes.py | 35 | ||||
-rw-r--r-- | tests/unit/scheduler/test_weights.py | 32 |
5 files changed, 209 insertions, 0 deletions
diff --git a/openstack/common/scheduler/weight.py b/openstack/common/scheduler/weight.py new file mode 100644 index 0000000..c5df9da --- /dev/null +++ b/openstack/common/scheduler/weight.py @@ -0,0 +1,91 @@ +# Copyright (c) 2011-2012 OpenStack, LLC. +# 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. + +""" +Pluggable Weighing support +""" + +import inspect + +from stevedore import extension + + +class WeighedObject(object): + """Object with weight information.""" + def __init__(self, obj, weight): + self.obj = obj + self.weight = weight + + def __repr__(self): + return "<WeighedObject '%s': %s>" % (self.obj, self.weight) + + +class BaseWeigher(object): + """Base class for pluggable weighers.""" + def _weight_multiplier(self): + """How weighted this weigher should be. Normally this would + be overriden in a subclass based on a config value. + """ + return 1.0 + + def _weigh_object(self, obj, weight_properties): + """Override in a subclass to specify a weight for a specific + object. + """ + return 0.0 + + def weigh_objects(self, weighed_obj_list, weight_properties): + """Weigh multiple objects. Override in a subclass if you need + need access to all objects in order to manipulate weights. + """ + constant = self._weight_multiplier() + for obj in weighed_obj_list: + obj.weight += (constant * + self._weigh_object(obj.obj, weight_properties)) + + +class BaseWeightHandler(object): + object_class = WeighedObject + + def __init__(self, weighed_object_type, weight_namespace): + self.namespace = weight_namespace + self.weighed_object_type = weighed_object_type + self.weight_manager = extension.ExtensionManager(weight_namespace) + + def _is_correct_class(self, obj): + """Return whether an object is a class of the correct type and + is not prefixed with an underscore. + """ + return (inspect.isclass(obj) and + not obj.__name__.startswith('_') and + issubclass(obj, self.weighed_object_type)) + + def get_all_classes(self): + return [x.plugin for x in self.weight_manager + if self._is_correct_class(x.plugin)] + + def get_weighed_objects(self, weigher_classes, obj_list, + weighing_properties): + """Return a sorted (highest score first) list of WeighedObjects.""" + + if not obj_list: + return [] + + weighed_objs = [self.object_class(obj, 0.0) for obj in obj_list] + for weigher_cls in weigher_classes: + weigher = weigher_cls() + weigher.weigh_objects(weighed_objs, weighing_properties) + + return sorted(weighed_objs, key=lambda x: x.weight, reverse=True) diff --git a/openstack/common/scheduler/weights/__init__.py b/openstack/common/scheduler/weights/__init__.py new file mode 100644 index 0000000..476ff8c --- /dev/null +++ b/openstack/common/scheduler/weights/__init__.py @@ -0,0 +1,45 @@ +# Copyright (c) 2011 OpenStack, LLC. +# 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. + +""" +Scheduler host weights +""" + + +from openstack.common.scheduler import weight + + +class WeighedHost(weight.WeighedObject): + def to_dict(self): + return { + 'weight': self.weight, + 'host': self.obj.host, + } + + def __repr__(self): + return ("WeighedHost [host: %s, weight: %s]" % + (self.obj.host, self.weight)) + + +class BaseHostWeigher(weight.BaseWeigher): + """Base class for host weights.""" + pass + + +class HostWeightHandler(weight.BaseWeightHandler): + object_class = WeighedHost + + def __init__(self, namespace): + super(HostWeightHandler, self).__init__(BaseHostWeigher, namespace) @@ -33,6 +33,11 @@ filters = [ "openstack.common.scheduler.filters.json_filter:JsonFilter", ] +weights = [ + "FakeWeigher1 = tests.unit.fakes:FakeWeigher1", + "FakeWeigher2 = tests.unit.fakes:FakeWeigher2", +] + setuptools.setup( name='openstack.common', version=setup.get_post_version('openstack'), @@ -60,6 +65,7 @@ setuptools.setup( setup_requires=['setuptools-git>=0.4'], entry_points={ "openstack.common.scheduler.filters": filters, + "openstack.common.tests.fakes.weights": weights, }, namespace_packages=['openstack'], ) diff --git a/tests/unit/fakes.py b/tests/unit/fakes.py new file mode 100644 index 0000000..81fc503 --- /dev/null +++ b/tests/unit/fakes.py @@ -0,0 +1,35 @@ +# Copyright 2012 Intel Inc, OpenStack LLC. +# 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. +""" +Fakes For filter and weight tests. +""" + + +from openstack.common.scheduler import weights + + +class FakeWeigher1(weights.BaseHostWeigher): + def __init__(self): + pass + + +class FakeWeigher2(weights.BaseHostWeigher): + def __init__(self): + pass + + +class FakeClass(object): + def __init__(self): + pass diff --git a/tests/unit/scheduler/test_weights.py b/tests/unit/scheduler/test_weights.py new file mode 100644 index 0000000..478a143 --- /dev/null +++ b/tests/unit/scheduler/test_weights.py @@ -0,0 +1,32 @@ +# Copyright 2011-2012 OpenStack LLC. +# 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. +""" +Tests For Scheduler weights. +""" + +import unittest + +from openstack.common.scheduler import weight +from tests.unit import fakes + + +class TestWeightHandler(unittest.TestCase): + def test_get_all_classes(self): + namespace = "openstack.common.tests.fakes.weights" + handler = weight.BaseWeightHandler(weight.BaseWeigher, namespace) + classes = handler.get_all_classes() + self.assertTrue(fakes.FakeWeigher1 in classes) + self.assertTrue(fakes.FakeWeigher2 in classes) + self.assertFalse(fakes.FakeClass in classes) |