diff options
| author | Jenkins <jenkins@review.openstack.org> | 2012-05-24 01:00:23 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2012-05-24 01:00:23 +0000 |
| commit | 10c5d74dcd7cddc4dcefe27180eae5eb8587b1b6 (patch) | |
| tree | 195d431ca3381ae42e8f159e3458889371b7867e | |
| parent | eed5ccc27d7f12266d6bc5da2dcc3932bb1fddb5 (diff) | |
| parent | 7ab519806dfc6b44ada9fdd9eec3a342c5f9263f (diff) | |
Merge "Add scheduler filter: TypeAffinityFilter"
| -rw-r--r-- | nova/db/api.py | 9 | ||||
| -rw-r--r-- | nova/db/sqlalchemy/api.py | 6 | ||||
| -rw-r--r-- | nova/scheduler/filters/type_filter.py | 39 | ||||
| -rw-r--r-- | nova/tests/scheduler/test_host_filters.py | 29 |
4 files changed, 80 insertions, 3 deletions
diff --git a/nova/db/api.py b/nova/db/api.py index f2f74cc55..ff72aff37 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -571,15 +571,20 @@ def instance_get_active_by_window_joined(context, begin, end=None, def instance_get_all_by_project(context, project_id): - """Get all instance belonging to a project.""" + """Get all instances belonging to a project.""" return IMPL.instance_get_all_by_project(context, project_id) def instance_get_all_by_host(context, host): - """Get all instance belonging to a host.""" + """Get all instances belonging to a host.""" return IMPL.instance_get_all_by_host(context, host) +def instance_get_all_by_host_and_not_type(context, host, type_id=None): + """Get all instances belonging to a host with a different type_id.""" + return IMPL.instance_get_all_by_host_and_not_type(context, host, type_id) + + def instance_get_all_by_reservation(context, reservation_id): """Get all instances belonging to a reservation.""" return IMPL.instance_get_all_by_reservation(context, reservation_id) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 56a25ad71..88ddeac34 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1548,6 +1548,12 @@ def instance_get_all_by_host(context, host): return _instance_get_all_query(context).filter_by(host=host).all() +@require_admin_context +def instance_get_all_by_host_and_not_type(context, host, type_id=None): + return _instance_get_all_query(context).filter_by(host=host).\ + filter(models.Instance.instance_type_id != type_id).all() + + @require_context def instance_get_all_by_project(context, project_id): authorize_project_context(context, project_id) diff --git a/nova/scheduler/filters/type_filter.py b/nova/scheduler/filters/type_filter.py new file mode 100644 index 000000000..a8d842d52 --- /dev/null +++ b/nova/scheduler/filters/type_filter.py @@ -0,0 +1,39 @@ +# Copyright (c) 2012 The Cloudscaling Group, Inc. +# +# 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. + +from nova import db +from nova.scheduler import filters + + +class TypeAffinityFilter(filters.BaseHostFilter): + """TypeAffinityFilter doesn't allow more then one VM type per host. + + Note: this works best with compute_fill_first_cost_fn_weight + (dispersion) set to 1 (-1 by default). + """ + + def host_passes(self, host_state, filter_properties): + """Dynamically limits hosts to one instance type + + Return False if host has any instance types other then the requested + type. Return True if all instance types match or if host is empty. + """ + + instance_type = filter_properties.get('instance_type') + context = filter_properties['context'].elevated() + instances_other_type = db.instance_get_all_by_host_and_not_type( + context, host_state.host, instance_type['id']) + return len(instances_other_type) == 0 diff --git a/nova/tests/scheduler/test_host_filters.py b/nova/tests/scheduler/test_host_filters.py index 5659d9467..22a162aa2 100644 --- a/nova/tests/scheduler/test_host_filters.py +++ b/nova/tests/scheduler/test_host_filters.py @@ -45,7 +45,7 @@ class HostFiltersTestCase(test.TestCase): ['and', ['>=', '$free_ram_mb', 1024], ['>=', '$free_disk_mb', 200 * 1024]]) # This has a side effect of testing 'get_filter_classes' - # when specifing a method (in this case, our standard filters) + # when specifying a method (in this case, our standard filters) classes = filters.get_filter_classes( ['nova.scheduler.filters.standard_filters']) self.class_map = {} @@ -174,6 +174,33 @@ class HostFiltersTestCase(test.TestCase): 'service': service}) self.assertTrue(filt_cls.host_passes(host, filter_properties)) + def test_type_filter(self): + self._stub_service_is_up(True) + filt_cls = self.class_map['TypeAffinityFilter']() + + filter_properties = {'context': self.context, + 'instance_type': {'id': 1}} + filter2_properties = {'context': self.context, + 'instance_type': {'id': 2}} + + capabilities = {'enabled': True} + service = {'disabled': False} + host = fakes.FakeHostState('fake_host', 'compute', + {'capabilities': capabilities, + 'service': service}) + #True since empty + self.assertTrue(filt_cls.host_passes(host, filter_properties)) + fakes.FakeInstance(context=self.context, + params={'host': 'fake_host', 'instance_type_id': 1}) + #True since same type + self.assertTrue(filt_cls.host_passes(host, filter_properties)) + #False since different type + self.assertFalse(filt_cls.host_passes(host, filter2_properties)) + #False since node not homogeneous + fakes.FakeInstance(context=self.context, + params={'host': 'fake_host', 'instance_type_id': 2}) + self.assertFalse(filt_cls.host_passes(host, filter_properties)) + def test_ram_filter_fails_on_memory(self): self._stub_service_is_up(True) filt_cls = self.class_map['RamFilter']() |
