Add aggregate num instances constraint to solver scheduler
This adds the AggregateNumInstancesConstraint that matches NumInstancesFilter in filter scheduler. Change-Id: If57070755b9f9a99379008aa519250f80cdb7b4e
This commit is contained in:
parent
010cc4fe58
commit
2646f4ddc6
|
@ -0,0 +1,52 @@
|
|||
# Copyright (c) 2015 Cisco Systems 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 oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from nova.i18n import _LW
|
||||
from nova_solverscheduler.scheduler.solvers.constraints \
|
||||
import num_instances_constraint
|
||||
from nova_solverscheduler.scheduler.solvers import utils
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.import_opt('max_instances_per_host',
|
||||
'nova.scheduler.filters.num_instances_filter')
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AggregateNumInstancesConstraint(
|
||||
num_instances_constraint.NumInstancesConstraint):
|
||||
"""AggregateNumInstancesConstraint with per-aggregate max num instances
|
||||
per host.
|
||||
|
||||
Fall back to global max_instances_per_host if no per-aggregate setting
|
||||
found.
|
||||
"""
|
||||
|
||||
def _get_max_instances_per_host(self, host_state, filter_properties):
|
||||
aggregate_vals = utils.aggregate_values_from_key(
|
||||
host_state, 'max_instances_per_host')
|
||||
|
||||
try:
|
||||
value = utils.validate_num_values(
|
||||
aggregate_vals, CONF.max_instances_per_host, cast_to=int)
|
||||
except ValueError as e:
|
||||
LOG.warning(_LW("Could not decode max_instances_per_host: '%s'"),
|
||||
e)
|
||||
value = CONF.max_instances_per_host
|
||||
|
||||
return value
|
|
@ -30,6 +30,9 @@ class NumInstancesConstraint(constraints.BaseLinearConstraint):
|
|||
each host can launch.
|
||||
"""
|
||||
|
||||
def _get_max_instances_per_host(self, host_state, filter_properties):
|
||||
return CONF.max_instances_per_host
|
||||
|
||||
def get_constraint_matrix(self, hosts, filter_properties):
|
||||
num_hosts = len(hosts)
|
||||
num_instances = filter_properties.get('num_instances')
|
||||
|
@ -37,9 +40,9 @@ class NumInstancesConstraint(constraints.BaseLinearConstraint):
|
|||
constraint_matrix = [[True for j in xrange(num_instances)]
|
||||
for i in xrange(num_hosts)]
|
||||
|
||||
max_instances = CONF.max_instances_per_host
|
||||
|
||||
for i in xrange(num_hosts):
|
||||
max_instances = self._get_max_instances_per_host(hosts[i],
|
||||
filter_properties)
|
||||
num_host_instances = hosts[i].num_instances
|
||||
acceptable_num_instances = int(max_instances - num_host_instances)
|
||||
if acceptable_num_instances < 0:
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
# Copyright (c) 2015 Cisco Systems, 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.
|
||||
|
||||
import mock
|
||||
|
||||
from nova import context
|
||||
from nova import test
|
||||
from nova_solverscheduler.scheduler.solvers.constraints \
|
||||
import aggregate_num_instances
|
||||
from nova_solverscheduler.tests.scheduler import solver_scheduler_fakes \
|
||||
as fakes
|
||||
|
||||
|
||||
class TestAggregateNumInstancesConstraint(test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
super(TestAggregateNumInstancesConstraint, self).setUp()
|
||||
self.constraint_cls = aggregate_num_instances.\
|
||||
AggregateNumInstancesConstraint
|
||||
self.context = context.RequestContext('fake', 'fake')
|
||||
self._generate_fake_constraint_input()
|
||||
|
||||
def _generate_fake_constraint_input(self):
|
||||
self.fake_filter_properties = {
|
||||
'context': self.context,
|
||||
'num_instances': 3}
|
||||
host1 = fakes.FakeSolverSchedulerHostState('host1', 'node1', {})
|
||||
host2 = fakes.FakeSolverSchedulerHostState('host2', 'node1', {})
|
||||
host3 = fakes.FakeSolverSchedulerHostState('host3', 'node1', {})
|
||||
host4 = fakes.FakeSolverSchedulerHostState('host4', 'node1', {})
|
||||
self.fake_hosts = [host1, host2, host3, host4]
|
||||
|
||||
@mock.patch('nova_solverscheduler.scheduler.solvers.utils.'
|
||||
'aggregate_values_from_key')
|
||||
def test_get_constraint_matrix(self, agg_mock):
|
||||
self.flags(max_instances_per_host=1)
|
||||
|
||||
def _agg_mock_side_effect(*args, **kwargs):
|
||||
if args[0].host == 'host1':
|
||||
return set(['2', '3'])
|
||||
if args[0].host == 'host2':
|
||||
return set(['4'])
|
||||
if args[0].host == 'host3':
|
||||
return set([])
|
||||
if args[0].host == 'host4':
|
||||
return set(['invalidval'])
|
||||
agg_mock.side_effect = _agg_mock_side_effect
|
||||
|
||||
expected_cons_mat = [
|
||||
[True, True, False],
|
||||
[True, True, True],
|
||||
[True, False, False],
|
||||
[True, False, False]]
|
||||
cons_mat = self.constraint_cls().get_constraint_matrix(
|
||||
self.fake_hosts, self.fake_filter_properties)
|
||||
agg_mock.assert_any_call(self.fake_hosts[0], 'max_instances_per_host')
|
||||
agg_mock.assert_any_call(self.fake_hosts[1], 'max_instances_per_host')
|
||||
agg_mock.assert_any_call(self.fake_hosts[2], 'max_instances_per_host')
|
||||
agg_mock.assert_any_call(self.fake_hosts[3], 'max_instances_per_host')
|
||||
self.assertEqual(expected_cons_mat, cons_mat)
|
Loading…
Reference in New Issue