Merge "Reorganize scheduler and merge code from Oslo incubator"

This commit is contained in:
Jenkins 2015-12-03 00:53:00 +00:00 committed by Gerrit Code Review
commit 0ed23b2f3e
54 changed files with 1813 additions and 761 deletions

View File

@ -76,7 +76,7 @@ fi
# Common opts
SHARE_NAME_PREFIX=${SHARE_NAME_PREFIX:-share-}
MANILA_ENABLED_SHARE_PROTOCOLS=${ENABLED_SHARE_PROTOCOLS:-"NFS,CIFS"}
MANILA_SCHEDULER_DRIVER=${MANILA_SCHEDULER_DRIVER:-manila.scheduler.filter_scheduler.FilterScheduler}
MANILA_SCHEDULER_DRIVER=${MANILA_SCHEDULER_DRIVER:-manila.scheduler.drivers.filter.FilterScheduler}
MANILA_SERVICE_SECGROUP="manila-service"
# Following env var defines whether to apply downgrade migrations setting up DB or not.

View File

@ -317,7 +317,7 @@ Open Manila configuration file `/etc/manila/manila.conf`::
share_name_template = share-%s
# Set scheduler driver with usage of filters. Recommended.
scheduler_driver = manila.scheduler.filter_scheduler.FilterScheduler
scheduler_driver = manila.scheduler.drivers.filter.FilterScheduler
# Set following two opts to True to get maximum info in logging.
verbose = True

View File

@ -1,16 +0,0 @@
oslo-incubator
--------------
A number of modules from oslo-incubator are imported into this project.
You can clone the oslo-incubator repository using the following url:
git://git.openstack.org/openstack/oslo-incubator
These modules are "incubating" in oslo-incubator and are kept in sync
with the help of oslo-incubator's update.py script. See:
https://wiki.openstack.org/wiki/Oslo#Syncing_Code_from_Incubator
The copy of the code should never be directly modified here. Please
always update oslo-incubator first and then run the script to copy
the changes across.

View File

@ -1,71 +0,0 @@
# Copyright (c) 2011-2012 OpenStack Foundation.
# 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.
"""
Filter support
"""
import inspect
from stevedore import extension
class BaseFilter(object):
"""Base class for all filter classes."""
def _filter_one(self, obj, filter_properties):
"""Return True if it passes the filter, False otherwise.
Override this in a subclass.
"""
return True
def filter_all(self, filter_obj_list, filter_properties):
"""Yield objects that pass the filter.
Can be overriden in a subclass, if you need to base filtering
decisions on all objects. Otherwise, one can just override
_filter_one() to filter a single object.
"""
for obj in filter_obj_list:
if self._filter_one(obj, filter_properties):
yield obj
class BaseFilterHandler(object):
""" Base class to handle loading filter classes.
This class should be subclassed where one needs to use filters.
"""
def __init__(self, filter_class_type, filter_namespace):
self.namespace = filter_namespace
self.filter_class_type = filter_class_type
self.filter_manager = extension.ExtensionManager(filter_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.filter_class_type))
def get_all_classes(self):
return [x.plugin for x in self.filter_manager
if self._is_correct_class(x.plugin)]
def get_filtered_objects(self, filter_classes, objs,
filter_properties):
for filter_cls in filter_classes:
objs = filter_cls().filter_all(objs, filter_properties)
return list(objs)

View File

@ -1,91 +0,0 @@
# Copyright (c) 2011-2012 OpenStack Foundation.
# 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)

View File

@ -39,14 +39,14 @@ import manila.network.neutron.neutron_network_plugin
import manila.network.nova_network_plugin
import manila.network.standalone_network_plugin
import manila.quota
import manila.scheduler.driver
import manila.scheduler.drivers.base
import manila.scheduler.drivers.simple
import manila.scheduler.host_manager
import manila.scheduler.manager
import manila.scheduler.scheduler_options
import manila.scheduler.simple
import manila.scheduler.weights
import manila.scheduler.weights.capacity
import manila.scheduler.weights.pool
import manila.scheduler.weighers
import manila.scheduler.weighers.capacity
import manila.scheduler.weighers.pool
import manila.service
import manila.share.api
import manila.share.driver
@ -99,13 +99,13 @@ _global_opt_lists = [
manila.network.nova_network_plugin.nova_single_network_plugin_opts,
manila.network.standalone_network_plugin.standalone_network_plugin_opts,
manila.quota.quota_opts,
manila.scheduler.driver.scheduler_driver_opts,
manila.scheduler.drivers.base.scheduler_driver_opts,
manila.scheduler.host_manager.host_manager_opts,
[manila.scheduler.manager.scheduler_driver_opt],
[manila.scheduler.scheduler_options.scheduler_json_config_location_opt],
manila.scheduler.simple.simple_scheduler_opts,
manila.scheduler.weights.capacity.capacity_weight_opts,
manila.scheduler.weights.pool.pool_weight_opts,
manila.scheduler.drivers.simple.simple_scheduler_opts,
manila.scheduler.weighers.capacity.capacity_weight_opts,
manila.scheduler.weighers.pool.pool_weight_opts,
manila.service.service_opts,
manila.share.api.share_api_opts,
manila.share.driver.ganesha_opts,

View File

@ -1,25 +0,0 @@
# Copyright (c) 2010 OpenStack, LLC.
#
# 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.
"""
:mod:`manila.scheduler` -- Scheduler Nodes
=====================================================
.. automodule:: manila.scheduler
:platform: Unix
:synopsis: Module that picks a volume node to create a volume.
.. moduleauthor:: Sandy Walsh <sandy.walsh@rackspace.com>
.. moduleauthor:: Ed Leafe <ed@leafe.com>
.. moduleauthor:: Chris Behrens <cbehrens@codestud.com>
"""

View File

@ -32,7 +32,9 @@ class BaseHandler(object):
self.extension_manager = extension.ExtensionManager(modifier_namespace)
def _is_correct_class(self, cls):
"""Return whether an object is a class of the correct type and
"""Check if an object is the correct type.
Return whether an object is a class of the correct type and
is not prefixed with an underscore.
"""
return (inspect.isclass(cls) and

View File

@ -25,12 +25,12 @@ from oslo_config import cfg
from manila import exception
from manila.i18n import _
from manila.scheduler import driver
from manila.scheduler.drivers import base
CONF = cfg.CONF
class ChanceScheduler(driver.Scheduler):
class ChanceScheduler(base.Scheduler):
"""Implements Scheduler as a random node selector."""
def _filter_hosts(self, request_spec, hosts, **kwargs):
@ -65,7 +65,7 @@ class ChanceScheduler(driver.Scheduler):
share_id = request_spec['share_id']
snapshot_id = request_spec['snapshot_id']
updated_share = driver.share_update_db(context, share_id, host)
updated_share = base.share_update_db(context, share_id, host)
self.share_rpcapi.create_share_instance(
context,
updated_share.instance,

View File

@ -26,7 +26,7 @@ from oslo_log import log
from manila import exception
from manila.i18n import _
from manila.i18n import _LE, _LI
from manila.scheduler import driver
from manila.scheduler.drivers import base
from manila.scheduler import scheduler_options
from manila.share import share_types
@ -34,7 +34,7 @@ CONF = cfg.CONF
LOG = log.getLogger(__name__)
class FilterScheduler(driver.Scheduler):
class FilterScheduler(base.Scheduler):
"""Scheduler that can be used for filtering and weighing."""
def __init__(self, *args, **kwargs):
super(FilterScheduler, self).__init__(*args, **kwargs)
@ -42,10 +42,6 @@ class FilterScheduler(driver.Scheduler):
self.options = scheduler_options.SchedulerOptions()
self.max_attempts = self._max_attempts()
def schedule(self, context, topic, method, *args, **kwargs):
"""Return best-suited host for request."""
self._schedule(context, topic, *args, **kwargs)
def _get_configuration_options(self):
"""Fetch options dictionary. Broken out for testing."""
return self.options.get_configuration()
@ -95,7 +91,7 @@ class FilterScheduler(driver.Scheduler):
share_id = request_spec['share_id']
snapshot_id = request_spec['snapshot_id']
updated_share = driver.share_update_db(context, share_id, host)
updated_share = base.share_update_db(context, share_id, host)
self._post_select_populate_filter_properties(filter_properties,
weighed_host.obj)
@ -296,7 +292,7 @@ class FilterScheduler(driver.Scheduler):
msg = _LI("Chose host %(host)s for create_consistency_group %(cg_id)s")
LOG.info(msg % {'host': host, 'cg_id': group_id})
updated_group = driver.cg_update_db(context, group_id, host)
updated_group = base.cg_update_db(context, group_id, host)
self.share_rpcapi.create_consistency_group(context,
updated_group, host)

View File

@ -24,8 +24,8 @@ from oslo_config import cfg
from manila import db
from manila import exception
from manila.i18n import _
from manila.scheduler import chance
from manila.scheduler import driver
from manila.scheduler.drivers import base
from manila.scheduler.drivers import chance
from manila import utils
simple_scheduler_opts = [
@ -64,8 +64,9 @@ class SimpleScheduler(chance.ChanceScheduler):
msg = _("Not enough allocatable share gigabytes remaining")
raise exception.NoValidHost(reason=msg)
if utils.service_is_up(service) and not service['disabled']:
updated_share = driver.share_update_db(context, share_id,
service['host'])
updated_share = base.share_update_db(context,
share_id,
service['host'])
self.share_rpcapi.create_share_instance(
context,
updated_share.instance,

View File

@ -13,10 +13,10 @@
# License for the specific language governing permissions and limitations
# under the License.
from manila.openstack.common.scheduler import filters
from manila.scheduler.filters import base_host
class AvailabilityZoneFilter(filters.BaseHostFilter):
class AvailabilityZoneFilter(base_host.BaseHostFilter):
"""Filters Hosts by availability zone."""
# Availability zones do not change within a request

View File

@ -18,8 +18,8 @@ Filter support
"""
import logging
from manila.openstack.common._i18n import _LI
from manila.openstack.common.scheduler import base_handler
from manila.i18n import _LI
from manila.scheduler import base_handler
LOG = logging.getLogger(__name__)
@ -27,7 +27,9 @@ LOG = logging.getLogger(__name__)
class BaseFilter(object):
"""Base class for all filter classes."""
def _filter_one(self, obj, filter_properties):
"""Return True if it passes the filter, False otherwise.
"""Check if an object passes a filter.
Return True if it passes the filter, False otherwise.
Override this in a subclass.
"""
return True
@ -48,7 +50,9 @@ class BaseFilter(object):
run_filter_once_per_request = False
def run_filter_for_index(self, index):
"""Return True if the filter needs to be run for the "index-th"
"""Check if filter needs to be run for the "index-th" instance.
Return True if the filter needs to be run for the "index-th"
instance in a request. Only need to override this if a filter
needs anything other than "first only" or "all" behaviour.
"""

View File

@ -17,10 +17,10 @@
Scheduler host filters
"""
from manila.openstack.common.scheduler import base_filter
from manila.scheduler.filters import base
class BaseHostFilter(base_filter.BaseFilter):
class BaseHostFilter(base.BaseFilter):
"""Base class for host filters."""
def _filter_one(self, obj, filter_properties):
"""Return True if the object passes the filter, otherwise False."""
@ -28,11 +28,12 @@ class BaseHostFilter(base_filter.BaseFilter):
def host_passes(self, host_state, filter_properties):
"""Return True if the HostState passes the filter, otherwise False.
Override this in a subclass.
"""
raise NotImplementedError()
class HostFilterHandler(base_filter.BaseFilterHandler):
class HostFilterHandler(base.BaseFilterHandler):
def __init__(self, namespace):
super(HostFilterHandler, self).__init__(BaseHostFilter, namespace)

View File

@ -17,17 +17,19 @@ import logging
import six
from manila.openstack.common.scheduler import filters
from manila.openstack.common.scheduler.filters import extra_specs_ops
from manila.scheduler.filters import base_host
from manila.scheduler.filters import extra_specs_ops
LOG = logging.getLogger(__name__)
class CapabilitiesFilter(filters.BaseHostFilter):
class CapabilitiesFilter(base_host.BaseHostFilter):
"""HostFilter to work with resource (instance & volume) type records."""
def _satisfies_extra_specs(self, capabilities, resource_type):
"""Check that the capabilities provided by the services satisfy
"""Compare capabilities against extra specs.
Check that the capabilities provided by the services satisfy
the extra specs associated with the resource type.
"""
extra_specs = resource_type.get('extra_specs', [])

View File

@ -23,12 +23,12 @@ from oslo_log import log
from manila.i18n import _LE
from manila.i18n import _LW
from manila.openstack.common.scheduler import filters
from manila.scheduler.filters import base_host
LOG = log.getLogger(__name__)
class CapacityFilter(filters.BaseHostFilter):
class CapacityFilter(base_host.BaseHostFilter):
"""CapacityFilter filters based on share host's capacity utilization."""
def host_passes(self, host_state, filter_properties):

View File

@ -16,13 +16,13 @@
from oslo_log import log
from manila.openstack.common.scheduler import filters
from manila.scheduler.filters import base_host
from manila.share import utils as share_utils
LOG = log.getLogger(__name__)
class ConsistencyGroupFilter(filters.BaseHostFilter):
class ConsistencyGroupFilter(base_host.BaseHostFilter):
"""ConsistencyGroupFilter filters host based on compatibility with CG."""
def host_passes(self, host_state, filter_properties):

View File

@ -15,12 +15,12 @@
import logging
from manila.openstack.common.scheduler import filters
from manila.scheduler.filters import base_host
LOG = logging.getLogger(__name__)
class IgnoreAttemptedHostsFilter(filters.BaseHostFilter):
class IgnoreAttemptedHostsFilter(base_host.BaseHostFilter):
"""Filter out previously attempted hosts
A host passes this filter if it has not already been attempted for

View File

@ -18,15 +18,16 @@ import operator
from oslo_serialization import jsonutils
import six
from manila.openstack.common.scheduler import filters
from manila.scheduler.filters import base_host
class JsonFilter(filters.BaseHostFilter):
"""Host Filter to allow simple JSON-based grammar for
selecting hosts.
"""
class JsonFilter(base_host.BaseHostFilter):
"""Host Filter to allow simple JSON-based grammar for selecting hosts."""
def _op_compare(self, args, op):
"""Returns True if the specified operator can successfully
"""Check if operator can compare the first arg with the others.
Returns True if the specified operator can successfully
compare the first item in the args with all the rest. Will
return False if only one item is in the list.
"""
@ -88,7 +89,9 @@ class JsonFilter(filters.BaseHostFilter):
}
def _parse_string(self, string, host_state):
"""Strings prefixed with $ are capability lookups in the
"""Parse string.
Strings prefixed with $ are capability lookups in the
form '$variable' where 'variable' is an attribute in the
HostState class. If $variable is a dictionary, you may
use: $variable.dictkey
@ -126,7 +129,9 @@ class JsonFilter(filters.BaseHostFilter):
return result
def host_passes(self, host_state, filter_properties):
"""Return a list of hosts that can fulfill the requirements
"""Filters hosts.
Return a list of hosts that can fulfill the requirements
specified in the query.
"""
# TODO(zhiteng) Add description for filter_properties structure

View File

@ -15,12 +15,12 @@
from oslo_log import log
from manila.openstack.common.scheduler import filters
from manila.scheduler.filters import base_host
LOG = log.getLogger(__name__)
class RetryFilter(filters.BaseHostFilter):
class RetryFilter(base_host.BaseHostFilter):
"""Filter out already tried nodes for scheduling purposes."""
def host_passes(self, host_state, filter_properties):

View File

@ -34,8 +34,8 @@ import six
from manila import db
from manila import exception
from manila.i18n import _LI, _LW
from manila.openstack.common.scheduler import filters
from manila.openstack.common.scheduler import weights
from manila.scheduler.filters import base_host as base_host_filter
from manila.scheduler.weighers import base_host as base_host_weigher
from manila.share import utils as share_utils
from manila import utils
@ -379,11 +379,11 @@ class HostManager(object):
def __init__(self):
self.service_states = {} # { <host>: {<service>: {cap k : v}}}
self.host_state_map = {}
self.filter_handler = filters.HostFilterHandler('manila.scheduler.'
'filters')
self.filter_handler = base_host_filter.HostFilterHandler(
'manila.scheduler.filters')
self.filter_classes = self.filter_handler.get_all_classes()
self.weight_handler = weights.HostWeightHandler('manila.scheduler.'
'weights')
self.weight_handler = base_host_weigher.HostWeightHandler(
'manila.scheduler.weighers')
self.weight_classes = self.weight_handler.get_all_classes()
def _choose_host_filters(self, filter_cls_names):

View File

@ -37,13 +37,24 @@ from manila.share import rpcapi as share_rpcapi
LOG = log.getLogger(__name__)
scheduler_driver_opt = cfg.StrOpt('scheduler_driver',
default='manila.scheduler.filter_scheduler.'
'FilterScheduler',
default='manila.scheduler.drivers.'
'filter.FilterScheduler',
help='Default scheduler driver to use.')
CONF = cfg.CONF
CONF.register_opt(scheduler_driver_opt)
# Drivers that need to change module paths or class names can add their
# old/new path here to maintain backward compatibility.
MAPPING = {
'manila.scheduler.chance.ChanceScheduler':
'manila.scheduler.drivers.chance.ChanceScheduler',
'manila.scheduler.filter_scheduler.FilterScheduler':
'manila.scheduler.drivers.filter.FilterScheduler',
'manila.scheduler.simple.SimpleScheduler':
'manila.scheduler.drivers.simple.SimpleScheduler',
}
class SchedulerManager(manager.Manager):
"""Chooses a host to create shares."""
@ -52,8 +63,19 @@ class SchedulerManager(manager.Manager):
def __init__(self, scheduler_driver=None, service_name=None,
*args, **kwargs):
if not scheduler_driver:
scheduler_driver = CONF.scheduler_driver
if scheduler_driver in MAPPING:
msg_args = {
'old': scheduler_driver,
'new': MAPPING[scheduler_driver],
}
LOG.warning(_LW("Scheduler driver path %(old)s is deprecated, "
"update your configuration to the new path "
"%(new)s"), msg_args)
scheduler_driver = MAPPING[scheduler_driver]
self.driver = importutils.import_object(scheduler_driver)
super(SchedulerManager, self).__init__(*args, **kwargs)

View File

@ -21,7 +21,7 @@ import abc
import six
from manila.openstack.common.scheduler import base_handler
from manila.scheduler import base_handler
def normalize(weight_list, minval=None, maxval=None):
@ -70,7 +70,7 @@ class BaseWeigher(object):
The attributes maxval and minval can be specified to set up the maximum
and minimum values for the weighed objects. These values will then be
taken into account in the normalization step, instead of taking the values
from the calculated weights.
from the calculated weighers.
"""
minval = None
@ -87,18 +87,16 @@ class BaseWeigher(object):
@abc.abstractmethod
def _weigh_object(self, obj, weight_properties):
"""Override in a subclass to specify a weight for a specific
object.
"""
"""Override in a subclass to specify a weight for a specific object."""
def weigh_objects(self, weighed_obj_list, weight_properties):
"""Weigh multiple objects.
Override in a subclass if you need access to all objects in order
to calculate weights. Do not modify the weight of an object here,
just return a list of weights.
to calculate weighers. Do not modify the weight of an object here,
just return a list of weighers.
"""
# Calculate the weights
# Calculate the weighers
weights = []
for obj in weighed_obj_list:
weight = self._weigh_object(obj.obj, weight_properties)
@ -135,7 +133,7 @@ class BaseWeightHandler(base_handler.BaseHandler):
weigher = weigher_cls()
weights = weigher.weigh_objects(weighed_objs, weighing_properties)
# Normalize the weights
# Normalize the weighers
weights = normalize(weights,
minval=weigher.minval,
maxval=weigher.maxval)

View File

@ -14,14 +14,13 @@
# under the License.
"""
Scheduler host weights
Scheduler host weighers
"""
from manila.openstack.common.scheduler import base_weight
from manila.scheduler.weighers import base
class WeighedHost(base_weight.WeighedObject):
class WeighedHost(base.WeighedObject):
def to_dict(self):
return {
'weight': self.weight,
@ -33,12 +32,12 @@ class WeighedHost(base_weight.WeighedObject):
(self.obj.host, self.weight))
class BaseHostWeigher(base_weight.BaseWeigher):
"""Base class for host weights."""
class BaseHostWeigher(base.BaseWeigher):
"""Base class for host weighers."""
pass
class HostWeightHandler(base_weight.BaseWeightHandler):
class HostWeightHandler(base.BaseWeightHandler):
object_class = WeighedHost
def __init__(self, namespace):

View File

@ -32,7 +32,7 @@ import math
from oslo_config import cfg
from manila.openstack.common.scheduler import weights
from manila.scheduler.weighers import base_host
capacity_weight_opts = [
cfg.FloatOpt('capacity_weight_multiplier',
@ -45,13 +45,13 @@ CONF = cfg.CONF
CONF.register_opts(capacity_weight_opts)
class CapacityWeigher(weights.BaseHostWeigher):
class CapacityWeigher(base_host.BaseHostWeigher):
def weight_multiplier(self):
"""Override the weight multiplier."""
return CONF.capacity_weight_multiplier
def _weigh_object(self, host_state, weight_properties):
"""Higher weights win. We want spreading to be the default."""
"""Higher weighers win. We want spreading to be the default."""
reserved = float(host_state.reserved_percentage) / 100
free_space = host_state.free_capacity_gb
total_space = host_state.total_capacity_gb
@ -81,7 +81,7 @@ class CapacityWeigher(weights.BaseHostWeigher):
weight_properties)
# NOTE(u_glide): Replace -inf with (minimum - 1) and
# inf with (maximum + 1) to avoid errors in
# manila.openstack.common.scheduler.base_weight.normalize() method
# manila.scheduler.weighers.base.normalize() method
if self.minval == float('-inf'):
self.minval = self.maxval
for val in weights:

View File

@ -17,7 +17,7 @@ from oslo_config import cfg
from manila import context
from manila.db import api as db_api
from manila.openstack.common.scheduler import weights
from manila.scheduler.weighers import base_host
from manila.share import utils
pool_weight_opts = [
@ -32,7 +32,7 @@ CONF = cfg.CONF
CONF.register_opts(pool_weight_opts)
class PoolWeigher(weights.BaseHostWeigher):
class PoolWeigher(base_host.BaseHostWeigher):
def weight_multiplier(self):
"""Override the weight multiplier."""
return CONF.pool_weight_multiplier

View File

@ -0,0 +1,105 @@
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# 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 Base Scheduler
"""
import mock
from oslo_config import cfg
from oslo_utils import timeutils
from manila import context
from manila import db
from manila.scheduler.drivers import base
from manila import test
from manila import utils
CONF = cfg.CONF
class SchedulerTestCase(test.TestCase):
"""Test case for base scheduler driver class."""
# So we can subclass this test and re-use tests if we need.
driver_cls = base.Scheduler
def setUp(self):
super(SchedulerTestCase, self).setUp()
self.driver = self.driver_cls()
self.context = context.RequestContext('fake_user', 'fake_project')
self.topic = 'fake_topic'
def test_update_service_capabilities(self):
service_name = 'fake_service'
host = 'fake_host'
capabilities = {'fake_capability': 'fake_value'}
with mock.patch.object(self.driver.host_manager,
'update_service_capabilities', mock.Mock()):
self.driver.update_service_capabilities(
service_name, host, capabilities)
self.driver.host_manager.update_service_capabilities.\
assert_called_once_with(service_name, host, capabilities)
def test_hosts_up(self):
service1 = {'host': 'host1'}
service2 = {'host': 'host2'}
services = [service1, service2]
def fake_service_is_up(*args, **kwargs):
if args[0]['host'] == 'host1':
return False
return True
with mock.patch.object(db, 'service_get_all_by_topic',
mock.Mock(return_value=services)):
with mock.patch.object(utils, 'service_is_up',
mock.Mock(side_effect=fake_service_is_up)):
result = self.driver.hosts_up(self.context, self.topic)
self.assertEqual(['host2'], result)
db.service_get_all_by_topic.assert_called_once_with(
self.context, self.topic)
class SchedulerDriverBaseTestCase(SchedulerTestCase):
"""Test cases for base scheduler driver class methods.
These can't fail if the driver is changed.
"""
def test_unimplemented_schedule(self):
fake_args = (1, 2, 3)
fake_kwargs = {'cat': 'meow'}
self.assertRaises(NotImplementedError, self.driver.schedule,
self.context, self.topic, 'schedule_something',
*fake_args, **fake_kwargs)
class SchedulerDriverModuleTestCase(test.TestCase):
"""Test case for scheduler driver module methods."""
def setUp(self):
super(SchedulerDriverModuleTestCase, self).setUp()
self.context = context.RequestContext('fake_user', 'fake_project')
@mock.patch.object(db, 'share_update', mock.Mock())
def test_share_host_update_db(self):
with mock.patch.object(timeutils, 'utcnow',
mock.Mock(return_value='fake-now')):
base.share_update_db(self.context, 31337, 'fake_host')
db.share_update.assert_called_once_with(
self.context, 31337,
{'host': 'fake_host', 'scheduled_at': 'fake-now'})

View File

@ -23,20 +23,20 @@ from oslo_utils import strutils
from manila.common import constants
from manila import context
from manila import exception
from manila.scheduler import driver
from manila.scheduler import filter_scheduler
from manila.scheduler.drivers import base
from manila.scheduler.drivers import filter
from manila.scheduler import host_manager
from manila.tests.scheduler.drivers import test_base
from manila.tests.scheduler import fakes
from manila.tests.scheduler import test_scheduler
SNAPSHOT_SUPPORT = constants.ExtraSpecs.SNAPSHOT_SUPPORT
@ddt.ddt
class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
class FilterSchedulerTestCase(test_base.SchedulerTestCase):
"""Test case for Filter Scheduler."""
driver_cls = filter_scheduler.FilterScheduler
driver_cls = filter.FilterScheduler
def test_create_share_no_hosts(self):
# Ensure empty hosts/child_zones result in NoValidHosts exception.
@ -315,7 +315,7 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
self.mock_object(sched, "_get_best_host_for_consistency_group",
mock.Mock(return_value=fake_host))
fake_updated_group = mock.Mock()
self.mock_object(driver, "cg_update_db", mock.Mock(
self.mock_object(base, "cg_update_db", mock.Mock(
return_value=fake_updated_group))
self.mock_object(sched.share_rpcapi, "create_consistency_group")
@ -324,8 +324,8 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
sched._get_best_host_for_consistency_group.assert_called_once_with(
fake_context, request_spec)
driver.cg_update_db.assert_called_once_with(fake_context, 'fake_id',
fake_host)
base.cg_update_db.assert_called_once_with(
fake_context, 'fake_id', fake_host)
sched.share_rpcapi.create_consistency_group.assert_called_once_with(
fake_context, fake_updated_group, fake_host)

View File

@ -0,0 +1,169 @@
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# 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 Simple Scheduler
"""
import mock
from oslo_config import cfg
from manila import context
from manila import db
from manila import exception
from manila.scheduler.drivers import base
from manila.scheduler.drivers import simple
from manila.share import rpcapi as share_rpcapi
from manila import test
from manila.tests import db_utils
from manila import utils
CONF = cfg.CONF
class SimpleSchedulerSharesTestCase(test.TestCase):
"""Test case for simple scheduler create share method."""
def setUp(self):
super(SimpleSchedulerSharesTestCase, self).setUp()
self.mock_object(share_rpcapi, 'ShareAPI')
self.driver = simple.SimpleScheduler()
self.context = context.RequestContext('fake_user', 'fake_project')
self.admin_context = context.RequestContext('fake_admin_user',
'fake_project')
self.admin_context.is_admin = True
@mock.patch.object(utils, 'service_is_up', mock.Mock(return_value=True))
def test_create_share_if_two_services_up(self):
share_id = 'fake'
fake_share = {'id': share_id, 'size': 1}
fake_service_1 = {'disabled': False, 'host': 'fake_host1'}
fake_service_2 = {'disabled': False, 'host': 'fake_host2'}
fake_result = [(fake_service_1, 2), (fake_service_2, 1)]
fake_request_spec = {
'share_id': share_id,
'share_properties': fake_share,
}
self.mock_object(db, 'service_get_all_share_sorted',
mock.Mock(return_value=fake_result))
self.mock_object(base, 'share_update_db',
mock.Mock(return_value=db_utils.create_share()))
self.driver.schedule_create_share(self.context,
fake_request_spec, {})
utils.service_is_up.assert_called_once_with(utils.IsAMatcher(dict))
db.service_get_all_share_sorted.assert_called_once_with(
utils.IsAMatcher(context.RequestContext))
base.share_update_db.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share_id, 'fake_host1')
def test_create_share_if_services_not_available(self):
share_id = 'fake'
fake_share = {'id': share_id, 'size': 1}
fake_result = []
fake_request_spec = {
'share_id': share_id,
'share_properties': fake_share,
}
with mock.patch.object(db, 'service_get_all_share_sorted',
mock.Mock(return_value=fake_result)):
self.assertRaises(exception.NoValidHost,
self.driver.schedule_create_share,
self.context, fake_request_spec, {})
db.service_get_all_share_sorted.assert_called_once_with(
utils.IsAMatcher(context.RequestContext))
def test_create_share_if_max_gigabytes_exceeded(self):
share_id = 'fake'
fake_share = {'id': share_id, 'size': 10001}
fake_service_1 = {'disabled': False, 'host': 'fake_host1'}
fake_service_2 = {'disabled': False, 'host': 'fake_host2'}
fake_result = [(fake_service_1, 5), (fake_service_2, 7)]
fake_request_spec = {
'share_id': share_id,
'share_properties': fake_share,
}
with mock.patch.object(db, 'service_get_all_share_sorted',
mock.Mock(return_value=fake_result)):
self.assertRaises(exception.NoValidHost,
self.driver.schedule_create_share,
self.context, fake_request_spec, {})
db.service_get_all_share_sorted.assert_called_once_with(
utils.IsAMatcher(context.RequestContext))
@mock.patch.object(utils, 'service_is_up', mock.Mock(return_value=True))
def test_create_share_availability_zone(self):
share_id = 'fake'
fake_share = {
'id': share_id,
'size': 1,
}
fake_instance = {
'availability_zone_id': 'fake',
}
fake_service_1 = {
'disabled': False, 'host': 'fake_host1',
'availability_zone_id': 'fake',
}
fake_service_2 = {
'disabled': False, 'host': 'fake_host2',
'availability_zone_id': 'super_fake',
}
fake_result = [(fake_service_1, 0), (fake_service_2, 1)]
fake_request_spec = {
'share_id': share_id,
'share_properties': fake_share,
'share_instance_properties': fake_instance,
}
self.mock_object(db, 'service_get_all_share_sorted',
mock.Mock(return_value=fake_result))
self.mock_object(base, 'share_update_db',
mock.Mock(return_value=db_utils.create_share()))
self.driver.schedule_create_share(self.context,
fake_request_spec, {})
utils.service_is_up.assert_called_once_with(fake_service_1)
base.share_update_db.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share_id,
fake_service_1['host'])
db.service_get_all_share_sorted.assert_called_once_with(
utils.IsAMatcher(context.RequestContext))
@mock.patch.object(utils, 'service_is_up', mock.Mock(return_value=True))
def test_create_share_availability_zone_on_host(self):
share_id = 'fake'
fake_share = {
'id': share_id,
'availability_zone': 'fake:fake',
'size': 1,
}
fake_service = {'disabled': False, 'host': 'fake'}
fake_request_spec = {
'share_id': share_id,
'share_properties': fake_share,
}
self.mock_object(db, 'service_get_all_share_sorted',
mock.Mock(return_value=[(fake_service, 1)]))
self.mock_object(base, 'share_update_db',
mock.Mock(return_value=db_utils.create_share()))
self.driver.schedule_create_share(self.admin_context,
fake_request_spec, {})
utils.service_is_up.assert_called_once_with(fake_service)
db.service_get_all_share_sorted.assert_called_once_with(
utils.IsAMatcher(context.RequestContext))
base.share_update_db.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share_id, 'fake')

View File

@ -19,8 +19,9 @@ Fakes For Scheduler tests.
from oslo_utils import timeutils
import six
from manila.scheduler import filter_scheduler
from manila.scheduler.drivers import filter
from manila.scheduler import host_manager
from manila.scheduler.weighers import base_host as base_host_weigher
SHARE_SERVICES_NO_POOLS = [
dict(id=1, host='host1', topic='share', disabled=False,
@ -167,7 +168,7 @@ SHARE_SERVICE_STATES_WITH_POOLS = {
}
class FakeFilterScheduler(filter_scheduler.FilterScheduler):
class FakeFilterScheduler(filter.FilterScheduler):
def __init__(self, *args, **kwargs):
super(FakeFilterScheduler, self).__init__(*args, **kwargs)
self.host_manager = host_manager.HostManager()
@ -260,3 +261,18 @@ def mock_host_manager_db_calls(mock_obj, disabled=None):
else:
mock_obj.return_value = [service for service in services
if service['disabled'] == disabled]
class FakeWeigher1(base_host_weigher.BaseHostWeigher):
def __init__(self):
pass
class FakeWeigher2(base_host_weigher.BaseHostWeigher):
def __init__(self):
pass
class FakeClass(object):
def __init__(self):
pass

View File

@ -0,0 +1,66 @@
# Copyright 2011 OpenStack Foundation.
# 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 AvailabilityZoneFilter.
"""
from oslo_context import context
from manila.scheduler.filters import availability_zone
from manila import test
from manila.tests.scheduler import fakes
class HostFiltersTestCase(test.TestCase):
"""Test case for AvailabilityZoneFilter."""
def setUp(self):
super(HostFiltersTestCase, self).setUp()
self.context = context.RequestContext('fake', 'fake')
self.filter = availability_zone.AvailabilityZoneFilter()
@staticmethod
def _make_zone_request(zone, is_admin=False):
ctxt = context.RequestContext('fake', 'fake', is_admin=is_admin)
return {
'context': ctxt,
'request_spec': {
'resource_properties': {
'availability_zone_id': zone
}
}
}
def test_availability_zone_filter_same(self):
service = {'availability_zone_id': 'nova'}
request = self._make_zone_request('nova')
host = fakes.FakeHostState('host1',
{'service': service})
self.assertTrue(self.filter.host_passes(host, request))
def test_availability_zone_filter_different(self):
service = {'availability_zone_id': 'nova'}
request = self._make_zone_request('bad')
host = fakes.FakeHostState('host1',
{'service': service})
self.assertFalse(self.filter.host_passes(host, request))
def test_availability_zone_filter_empty(self):
service = {'availability_zone_id': 'nova'}
request = {}
host = fakes.FakeHostState('host1',
{'service': service})
self.assertTrue(self.filter.host_passes(host, request))

View File

@ -0,0 +1,159 @@
# Copyright (c) 2013 OpenStack Foundation.
#
# 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 manila.scheduler.filters import base
from manila import test
class TestBaseFilter(test.TestCase):
def setUp(self):
super(TestBaseFilter, self).setUp()
self.filter = base.BaseFilter()
def test_filter_one_is_called(self):
filters = [1, 2, 3, 4]
filter_properties = {'x': 'y'}
side_effect = lambda value, props: value in [2, 3]
self.mock_object(self.filter,
'_filter_one',
mock.Mock(side_effect=side_effect))
result = list(self.filter.filter_all(filters, filter_properties))
self.assertEqual([2, 3], result)
class FakeExtension(object):
def __init__(self, plugin):
self.plugin = plugin
class BaseFakeFilter(base.BaseFilter):
pass
class FakeFilter1(BaseFakeFilter):
"""Derives from BaseFakeFilter and has a fake entry point defined.
Entry point is returned by fake ExtensionManager.
Should be included in the output of all_classes.
"""
class FakeFilter2(BaseFakeFilter):
"""Derives from BaseFakeFilter but has no entry point.
Should be not included in all_classes.
"""
class FakeFilter3(base.BaseFilter):
"""Does not derive from BaseFakeFilter.
Should not be included.
"""
class FakeFilter4(BaseFakeFilter):
"""Derives from BaseFakeFilter and has an entry point.
Should be included.
"""
class FakeFilter5(BaseFakeFilter):
"""Derives from BaseFakeFilter but has no entry point.
Should not be included.
"""
run_filter_once_per_request = True
class FakeExtensionManager(list):
def __init__(self, namespace):
classes = [FakeFilter1, FakeFilter3, FakeFilter4]
exts = map(FakeExtension, classes)
super(FakeExtensionManager, self).__init__(exts)
self.namespace = namespace
class TestBaseFilterHandler(test.TestCase):
def setUp(self):
super(TestBaseFilterHandler, self).setUp()
self.mock_object(base.base_handler.extension,
'ExtensionManager',
FakeExtensionManager)
self.handler = base.BaseFilterHandler(BaseFakeFilter, 'fake_filters')
def test_get_all_classes(self):
# In order for a FakeFilter to be returned by get_all_classes, it has
# to comply with these rules:
# * It must be derived from BaseFakeFilter
# AND
# * It must have a python entrypoint assigned (returned by
# FakeExtensionManager)
expected = [FakeFilter1, FakeFilter4]
result = self.handler.get_all_classes()
self.assertEqual(expected, result)
def _get_filtered_objects(self, filter_classes, index=0):
filter_objs_initial = [1, 2, 3, 4]
filter_properties = {'x': 'y'}
return self.handler.get_filtered_objects(filter_classes,
filter_objs_initial,
filter_properties,
index)
@mock.patch.object(FakeFilter4, 'filter_all')
@mock.patch.object(FakeFilter3, 'filter_all', return_value=None)
def test_get_filtered_objects_return_none(self, fake3_filter_all,
fake4_filter_all):
filter_classes = [FakeFilter1, FakeFilter2, FakeFilter3, FakeFilter4]
result = self._get_filtered_objects(filter_classes)
self.assertIsNone(result)
self.assertFalse(fake4_filter_all.called)
def test_get_filtered_objects(self):
filter_objs_expected = [1, 2, 3, 4]
filter_classes = [FakeFilter1, FakeFilter2, FakeFilter3, FakeFilter4]
result = self._get_filtered_objects(filter_classes)
self.assertEqual(filter_objs_expected, result)
def test_get_filtered_objects_with_filter_run_once(self):
filter_objs_expected = [1, 2, 3, 4]
filter_classes = [FakeFilter5]
with mock.patch.object(FakeFilter5, 'filter_all',
return_value=filter_objs_expected
) as fake5_filter_all:
result = self._get_filtered_objects(filter_classes)
self.assertEqual(filter_objs_expected, result)
self.assertEqual(1, fake5_filter_all.call_count)
result = self._get_filtered_objects(filter_classes, index=1)
self.assertEqual(filter_objs_expected, result)
self.assertEqual(1, fake5_filter_all.call_count)
result = self._get_filtered_objects(filter_classes, index=2)
self.assertEqual(filter_objs_expected, result)
self.assertEqual(1, fake5_filter_all.call_count)

View File

@ -0,0 +1,56 @@
# Copyright 2011 OpenStack Foundation.
# 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 Host Filters.
"""
from oslo_context import context
from oslo_serialization import jsonutils
from manila.scheduler.filters import base_host
from manila import test
class TestFilter(test.TestCase):
pass
class TestBogusFilter(object):
"""Class that doesn't inherit from BaseHostFilter."""
pass
class HostFiltersTestCase(test.TestCase):
"""Test case for host filters."""
def setUp(self):
super(HostFiltersTestCase, self).setUp()
self.context = context.RequestContext('fake', 'fake')
self.json_query = jsonutils.dumps(
['and', ['>=', '$free_ram_mb', 1024],
['>=', '$free_disk_mb', 200 * 1024]])
namespace = 'manila.scheduler.filters'
filter_handler = base_host.HostFilterHandler(namespace)
classes = filter_handler.get_all_classes()
self.class_map = {}
for cls in classes:
self.class_map[cls.__name__] = cls
def test_all_filters(self):
# Double check at least a couple of known filters exist
self.assertTrue('JsonFilter' in self.class_map)
self.assertTrue('CapabilitiesFilter' in self.class_map)
self.assertTrue('AvailabilityZoneFilter' in self.class_map)

View File

@ -0,0 +1,101 @@
# Copyright 2011 OpenStack Foundation.
# 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 CapabilitiesFilter.
"""
from oslo_context import context
from manila.scheduler.filters import capabilities
from manila import test
from manila.tests.scheduler import fakes
class HostFiltersTestCase(test.TestCase):
"""Test case for CapabilitiesFilter."""
def setUp(self):
super(HostFiltersTestCase, self).setUp()
self.context = context.RequestContext('fake', 'fake')
self.filter = capabilities.CapabilitiesFilter()
def _do_test_type_filter_extra_specs(self, ecaps, especs, passes):
capabilities = {'enabled': True}
capabilities.update(ecaps)
service = {'disabled': False}
filter_properties = {'resource_type': {'name': 'fake_type',
'extra_specs': especs}}
host = fakes.FakeHostState('host1',
{'free_capacity_gb': 1024,
'capabilities': capabilities,
'service': service})
assertion = self.assertTrue if passes else self.assertFalse
assertion(self.filter.host_passes(host, filter_properties))
def test_capability_filter_passes_extra_specs_simple(self):
self._do_test_type_filter_extra_specs(
ecaps={'opt1': '1', 'opt2': '2'},
especs={'opt1': '1', 'opt2': '2'},
passes=True)
def test_capability_filter_fails_extra_specs_simple(self):
self._do_test_type_filter_extra_specs(
ecaps={'opt1': '1', 'opt2': '2'},
especs={'opt1': '1', 'opt2': '222'},
passes=False)
def test_capability_filter_passes_extra_specs_complex(self):
self._do_test_type_filter_extra_specs(
ecaps={'opt1': 10, 'opt2': 5},
especs={'opt1': '>= 2', 'opt2': '<= 8'},
passes=True)
def test_capability_filter_fails_extra_specs_complex(self):
self._do_test_type_filter_extra_specs(
ecaps={'opt1': 10, 'opt2': 5},
especs={'opt1': '>= 2', 'opt2': '>= 8'},
passes=False)
def test_capability_filter_passes_scope_extra_specs(self):
self._do_test_type_filter_extra_specs(
ecaps={'scope_lv1': {'opt1': 10}},
especs={'capabilities:scope_lv1:opt1': '>= 2'},
passes=True)
def test_capability_filter_passes_fakescope_extra_specs(self):
self._do_test_type_filter_extra_specs(
ecaps={'scope_lv1': {'opt1': 10}, 'opt2': 5},
especs={'scope_lv1:opt1': '= 2', 'opt2': '>= 3'},
passes=True)
def test_capability_filter_fails_scope_extra_specs(self):
self._do_test_type_filter_extra_specs(
ecaps={'scope_lv1': {'opt1': 10}},
especs={'capabilities:scope_lv1:opt1': '<= 2'},
passes=False)
def test_capability_filter_passes_multi_level_scope_extra_specs(self):
self._do_test_type_filter_extra_specs(
ecaps={'scope_lv0': {'scope_lv1':
{'scope_lv2': {'opt1': 10}}}},
especs={'capabilities:scope_lv0:scope_lv1:scope_lv2:opt1': '>= 2'},
passes=True)
def test_capability_filter_fails_wrong_scope_extra_specs(self):
self._do_test_type_filter_extra_specs(
ecaps={'scope_lv0': {'opt1': 10}},
especs={'capabilities:scope_lv1:opt1': '>= 2'},
passes=False)

View File

@ -12,14 +12,13 @@
# License for the specific language governing permissions and limitations
# under the License.
"""
Tests For Scheduler Host Filters.
Tests For CapacityFilter.
"""
import ddt
from oslo_serialization import jsonutils
from manila import context
from manila.openstack.common.scheduler import filters
from manila.scheduler.filters import capacity
from manila import test
from manila.tests.scheduler import fakes
from manila import utils
@ -27,21 +26,12 @@ from manila import utils
@ddt.ddt
class HostFiltersTestCase(test.TestCase):
"""Test case for host filters."""
"""Test case CapacityFilter."""
def setUp(self):
super(HostFiltersTestCase, self).setUp()
self.context = context.RequestContext('fake', 'fake')
self.json_query = jsonutils.dumps(
['and', ['>=', '$free_capacity_gb', 1024],
['>=', '$total_capacity_gb', 10 * 1024]])
# This has a side effect of testing 'get_filter_classes'
# when specifying a method (in this case, our standard filters)
filter_handler = filters.HostFilterHandler('manila.scheduler.filters')
classes = filter_handler.get_all_classes()
self.class_map = {}
for cls in classes:
self.class_map[cls.__name__] = cls
self.filter = capacity.CapacityFilter()
def _stub_service_is_up(self, ret_value):
def fake_service_is_up(service):
@ -54,7 +44,6 @@ class HostFiltersTestCase(test.TestCase):
@ddt.unpack
def test_capacity_filter_passes(self, size, share_on, host):
self._stub_service_is_up(True)
filt_cls = self.class_map['CapacityFilter']()
filter_properties = {'size': size,
'share_exists_on': share_on}
service = {'disabled': False}
@ -63,7 +52,7 @@ class HostFiltersTestCase(test.TestCase):
'free_capacity_gb': 200,
'updated_at': None,
'service': service})
self.assertTrue(filt_cls.host_passes(host, filter_properties))
self.assertTrue(self.filter.host_passes(host, filter_properties))
@ddt.data(
{'free_capacity': 120, 'total_capacity': 200,
@ -74,7 +63,6 @@ class HostFiltersTestCase(test.TestCase):
def test_capacity_filter_fails(self, free_capacity, total_capacity,
reserved):
self._stub_service_is_up(True)
filt_cls = self.class_map['CapacityFilter']()
filter_properties = {'size': 100}
service = {'disabled': False}
host = fakes.FakeHostState('host1',
@ -83,19 +71,18 @@ class HostFiltersTestCase(test.TestCase):
'reserved_percentage': reserved,
'updated_at': None,
'service': service})
self.assertFalse(filt_cls.host_passes(host, filter_properties))
self.assertFalse(self.filter.host_passes(host, filter_properties))
def test_capacity_filter_passes_unknown(self):
free = 'unknown'
self._stub_service_is_up(True)
filt_cls = self.class_map['CapacityFilter']()
filter_properties = {'size': 100}
service = {'disabled': False}
host = fakes.FakeHostState('host1',
{'free_capacity_gb': free,
'updated_at': None,
'service': service})
self.assertTrue(filt_cls.host_passes(host, filter_properties))
self.assertTrue(self.filter.host_passes(host, filter_properties))
@ddt.data(
{'free_capacity': 'unknown', 'total_capacity': 'unknown'},
@ -104,7 +91,6 @@ class HostFiltersTestCase(test.TestCase):
def test_capacity_filter_passes_total(self, free_capacity,
total_capacity):
self._stub_service_is_up(True)
filt_cls = self.class_map['CapacityFilter']()
filter_properties = {'size': 100}
service = {'disabled': False}
host = fakes.FakeHostState('host1',
@ -113,7 +99,7 @@ class HostFiltersTestCase(test.TestCase):
'reserved_percentage': 0,
'updated_at': None,
'service': service})
self.assertTrue(filt_cls.host_passes(host, filter_properties))
self.assertTrue(self.filter.host_passes(host, filter_properties))
@ddt.data(
{'free': 200, 'total': 'unknown', 'reserved': 5},
@ -122,7 +108,6 @@ class HostFiltersTestCase(test.TestCase):
@ddt.unpack
def test_capacity_filter_fails_total(self, free, total, reserved):
self._stub_service_is_up(True)
filt_cls = self.class_map['CapacityFilter']()
filter_properties = {'size': 100}
service = {'disabled': False}
host = fakes.FakeHostState('host1',
@ -131,7 +116,7 @@ class HostFiltersTestCase(test.TestCase):
'reserved_percentage': reserved,
'updated_at': None,
'service': service})
self.assertFalse(filt_cls.host_passes(host, filter_properties))
self.assertFalse(self.filter.host_passes(host, filter_properties))
@ddt.data(
{'size': 100, 'cap_thin': '<is> True',
@ -159,7 +144,6 @@ class HostFiltersTestCase(test.TestCase):
def test_filter_thin_passes(self, size, cap_thin, total, free, provisioned,
max_ratio, reserved, thin_prov):
self._stub_service_is_up(True)
filt_cls = self.class_map['CapacityFilter']()
filter_properties = {'size': size,
'capabilities:thin_provisioning': cap_thin}
service = {'disabled': False}
@ -172,7 +156,7 @@ class HostFiltersTestCase(test.TestCase):
'thin_provisioning': thin_prov,
'updated_at': None,
'service': service})
self.assertTrue(filt_cls.host_passes(host, filter_properties))
self.assertTrue(self.filter.host_passes(host, filter_properties))
@ddt.data(
{'size': 200, 'cap_thin': '<is> True',
@ -203,7 +187,6 @@ class HostFiltersTestCase(test.TestCase):
def test_filter_thin_fails(self, size, cap_thin, total, free, provisioned,
max_ratio, reserved, thin_prov):
self._stub_service_is_up(True)
filt_cls = self.class_map['CapacityFilter']()
filter_properties = {'size': size,
'capabilities:thin_provisioning': cap_thin}
service = {'disabled': False}
@ -216,27 +199,4 @@ class HostFiltersTestCase(test.TestCase):
'thin_provisioning': thin_prov,
'updated_at': None,
'service': service})
self.assertFalse(filt_cls.host_passes(host, filter_properties))
def test_retry_filter_disabled(self):
# Test case where retry/re-scheduling is disabled.
filt_cls = self.class_map['RetryFilter']()
host = fakes.FakeHostState('host1', {})
filter_properties = {}
self.assertTrue(filt_cls.host_passes(host, filter_properties))
def test_retry_filter_pass(self):
# Node not previously tried.
filt_cls = self.class_map['RetryFilter']()
host = fakes.FakeHostState('host1', {})
retry = dict(num_attempts=2, hosts=['host2'])
filter_properties = dict(retry=retry)
self.assertTrue(filt_cls.host_passes(host, filter_properties))
def test_retry_filter_fail(self):
# Node was already tried.
filt_cls = self.class_map['RetryFilter']()
host = fakes.FakeHostState('host1', {})
retry = dict(num_attempts=1, hosts=['host1'])
filter_properties = dict(retry=retry)
self.assertFalse(filt_cls.host_passes(host, filter_properties))
self.assertFalse(self.filter.host_passes(host, filter_properties))

View File

@ -0,0 +1,237 @@
# Copyright 2011 OpenStack Foundation.
# 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 Host Filters.
"""
from manila.scheduler.filters import extra_specs_ops
from manila import test
class ExtraSpecsOpsTestCase(test.TestCase):
def _do_extra_specs_ops_test(self, value, req, matches):
assertion = self.assertTrue if matches else self.assertFalse
assertion(extra_specs_ops.match(value, req))
def test_extra_specs_matches_simple(self):
self._do_extra_specs_ops_test(
value='1',
req='1',
matches=True)
def test_extra_specs_fails_simple(self):
self._do_extra_specs_ops_test(
value='',
req='1',
matches=False)
def test_extra_specs_fails_simple2(self):
self._do_extra_specs_ops_test(
value='3',
req='1',
matches=False)
def test_extra_specs_fails_simple3(self):
self._do_extra_specs_ops_test(
value='222',
req='2',
matches=False)
def test_extra_specs_fails_with_bogus_ops(self):
self._do_extra_specs_ops_test(
value='4',
req='> 2',
matches=False)
def test_extra_specs_matches_with_op_eq(self):
self._do_extra_specs_ops_test(
value='123',
req='= 123',
matches=True)
def test_extra_specs_matches_with_op_eq2(self):
self._do_extra_specs_ops_test(
value='124',
req='= 123',
matches=True)
def test_extra_specs_fails_with_op_eq(self):
self._do_extra_specs_ops_test(
value='34',
req='= 234',
matches=False)
def test_extra_specs_fails_with_op_eq3(self):
self._do_extra_specs_ops_test(
value='34',
req='=',
matches=False)
def test_extra_specs_matches_with_op_seq(self):
self._do_extra_specs_ops_test(
value='123',
req='s== 123',
matches=True)
def test_extra_specs_fails_with_op_seq(self):
self._do_extra_specs_ops_test(
value='1234',
req='s== 123',
matches=False)
def test_extra_specs_matches_with_op_sneq(self):
self._do_extra_specs_ops_test(
value='1234',
req='s!= 123',
matches=True)
def test_extra_specs_fails_with_op_sneq(self):
self._do_extra_specs_ops_test(
value='123',
req='s!= 123',
matches=False)
def test_extra_specs_fails_with_op_sge(self):
self._do_extra_specs_ops_test(
value='1000',
req='s>= 234',
matches=False)
def test_extra_specs_fails_with_op_sle(self):
self._do_extra_specs_ops_test(
value='1234',
req='s<= 1000',
matches=False)
def test_extra_specs_fails_with_op_sl(self):
self._do_extra_specs_ops_test(
value='2',
req='s< 12',
matches=False)
def test_extra_specs_fails_with_op_sg(self):
self._do_extra_specs_ops_test(
value='12',
req='s> 2',
matches=False)
def test_extra_specs_matches_with_op_in(self):
self._do_extra_specs_ops_test(
value='12311321',
req='<in> 11',
matches=True)
def test_extra_specs_matches_with_op_in2(self):
self._do_extra_specs_ops_test(
value='12311321',
req='<in> 12311321',
matches=True)
def test_extra_specs_matches_with_op_in3(self):
self._do_extra_specs_ops_test(
value='12311321',
req='<in> 12311321 <in>',
matches=True)
def test_extra_specs_fails_with_op_in(self):
self._do_extra_specs_ops_test(
value='12310321',
req='<in> 11',
matches=False)
def test_extra_specs_fails_with_op_in2(self):
self._do_extra_specs_ops_test(
value='12310321',
req='<in> 11 <in>',
matches=False)
def test_extra_specs_matches_with_op_is(self):
self._do_extra_specs_ops_test(
value=True,
req='<is> True',
matches=True)
def test_extra_specs_matches_with_op_is2(self):
self._do_extra_specs_ops_test(
value=False,
req='<is> False',
matches=True)
def test_extra_specs_matches_with_op_is3(self):
self._do_extra_specs_ops_test(
value=False,
req='<is> Nonsense',
matches=True)
def test_extra_specs_fails_with_op_is(self):
self._do_extra_specs_ops_test(
value=True,
req='<is> False',
matches=False)
def test_extra_specs_fails_with_op_is2(self):
self._do_extra_specs_ops_test(
value=False,
req='<is> True',
matches=False)
def test_extra_specs_matches_with_op_or(self):
self._do_extra_specs_ops_test(
value='12',
req='<or> 11 <or> 12',
matches=True)
def test_extra_specs_matches_with_op_or2(self):
self._do_extra_specs_ops_test(
value='12',
req='<or> 11 <or> 12 <or>',
matches=True)
def test_extra_specs_fails_with_op_or(self):
self._do_extra_specs_ops_test(
value='13',
req='<or> 11 <or> 12',
matches=False)
def test_extra_specs_fails_with_op_or2(self):
self._do_extra_specs_ops_test(
value='13',
req='<or> 11 <or> 12 <or>',
matches=False)
def test_extra_specs_matches_with_op_le(self):
self._do_extra_specs_ops_test(
value='2',
req='<= 10',
matches=True)
def test_extra_specs_fails_with_op_le(self):
self._do_extra_specs_ops_test(
value='3',
req='<= 2',
matches=False)
def test_extra_specs_matches_with_op_ge(self):
self._do_extra_specs_ops_test(
value='3',
req='>= 1',
matches=True)
def test_extra_specs_fails_with_op_ge(self):
self._do_extra_specs_ops_test(
value='2',
req='>= 3',
matches=False)

View File

@ -0,0 +1,53 @@
# Copyright 2011 OpenStack Foundation.
# 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 IgnoreAttemptedHost filter.
"""
from oslo_context import context
from manila.scheduler.filters import ignore_attempted_hosts
from manila import test
from manila.tests.scheduler import fakes
class HostFiltersTestCase(test.TestCase):
"""Test case for IgnoreAttemptedHost filter."""
def setUp(self):
super(HostFiltersTestCase, self).setUp()
self.context = context.RequestContext('fake', 'fake')
self.filter = ignore_attempted_hosts.IgnoreAttemptedHostsFilter()
def test_ignore_attempted_hosts_filter_disabled(self):
# Test case where re-scheduling is disabled.
host = fakes.FakeHostState('host1', {})
filter_properties = {}
self.assertTrue(self.filter.host_passes(host, filter_properties))
def test_ignore_attempted_hosts_filter_pass(self):
# Node not previously tried.
host = fakes.FakeHostState('host1', {})
attempted = dict(num_attempts=2, hosts=['host2'])
filter_properties = dict(retry=attempted)
self.assertTrue(self.filter.host_passes(host, filter_properties))
def test_ignore_attempted_hosts_filter_fail(self):
# Node was already tried.
host = fakes.FakeHostState('host1', {})
attempted = dict(num_attempts=2, hosts=['host1'])
filter_properties = dict(retry=attempted)
self.assertFalse(self.filter.host_passes(host, filter_properties))

View File

@ -0,0 +1,326 @@
# Copyright 2011 OpenStack Foundation.
# 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 JsonFilter.
"""
from oslo_context import context
from oslo_serialization import jsonutils
from manila.scheduler.filters import json
from manila import test
from manila.tests.scheduler import fakes
class HostFiltersTestCase(test.TestCase):
"""Test case for JsonFilter."""
def setUp(self):
super(HostFiltersTestCase, self).setUp()
self.context = context.RequestContext('fake', 'fake')
self.json_query = jsonutils.dumps(
['and', ['>=', '$free_ram_mb', 1024],
['>=', '$free_disk_mb', 200 * 1024]])
self.filter = json.JsonFilter()
def test_json_filter_passes(self):
filter_properties = {'resource_type': {'memory_mb': 1024,
'root_gb': 200,
'ephemeral_gb': 0},
'scheduler_hints': {'query': self.json_query}}
capabilities = {'enabled': True}
host = fakes.FakeHostState('host1',
{'free_ram_mb': 1024,
'free_disk_mb': 200 * 1024,
'capabilities': capabilities})
self.assertTrue(self.filter.host_passes(host, filter_properties))
def test_json_filter_passes_with_no_query(self):
filter_properties = {'resource_type': {'memory_mb': 1024,
'root_gb': 200,
'ephemeral_gb': 0}}
capabilities = {'enabled': True}
host = fakes.FakeHostState('host1',
{'free_ram_mb': 0,
'free_disk_mb': 0,
'capabilities': capabilities})
self.assertTrue(self.filter.host_passes(host, filter_properties))
def test_json_filter_fails_on_memory(self):
filter_properties = {'resource_type': {'memory_mb': 1024,
'root_gb': 200,
'ephemeral_gb': 0},
'scheduler_hints': {'query': self.json_query}}
capabilities = {'enabled': True}
host = fakes.FakeHostState('host1',
{'free_ram_mb': 1023,
'free_disk_mb': 200 * 1024,
'capabilities': capabilities})
self.assertFalse(self.filter.host_passes(host, filter_properties))
def test_json_filter_fails_on_disk(self):
filter_properties = {'resource_type': {'memory_mb': 1024,
'root_gb': 200,
'ephemeral_gb': 0},
'scheduler_hints': {'query': self.json_query}}
capabilities = {'enabled': True}
host = fakes.FakeHostState('host1',
{'free_ram_mb': 1024,
'free_disk_mb': (200 * 1024) - 1,
'capabilities': capabilities})
self.assertFalse(self.filter.host_passes(host, filter_properties))
def test_json_filter_fails_on_caps_disabled(self):
json_query = jsonutils.dumps(
['and', ['>=', '$free_ram_mb', 1024],
['>=', '$free_disk_mb', 200 * 1024],
'$capabilities.enabled'])
filter_properties = {'resource_type': {'memory_mb': 1024,
'root_gb': 200,
'ephemeral_gb': 0},
'scheduler_hints': {'query': json_query}}
capabilities = {'enabled': False}
host = fakes.FakeHostState('host1',
{'free_ram_mb': 1024,
'free_disk_mb': 200 * 1024,
'capabilities': capabilities})
self.assertFalse(self.filter.host_passes(host, filter_properties))
def test_json_filter_fails_on_service_disabled(self):
json_query = jsonutils.dumps(
['and', ['>=', '$free_ram_mb', 1024],
['>=', '$free_disk_mb', 200 * 1024],
['not', '$service.disabled']])
filter_properties = {'resource_type': {'memory_mb': 1024,
'local_gb': 200},
'scheduler_hints': {'query': json_query}}
capabilities = {'enabled': True}
host = fakes.FakeHostState('host1',
{'free_ram_mb': 1024,
'free_disk_mb': 200 * 1024,
'capabilities': capabilities})
self.assertFalse(self.filter.host_passes(host, filter_properties))
def test_json_filter_happy_day(self):
"""Test json filter more thoroughly."""
raw = ['and',
'$capabilities.enabled',
['=', '$capabilities.opt1', 'match'],
['or',
['and',
['<', '$free_ram_mb', 30],
['<', '$free_disk_mb', 300]],
['and',
['>', '$free_ram_mb', 30],
['>', '$free_disk_mb', 300]]]]
filter_properties = {
'scheduler_hints': {
'query': jsonutils.dumps(raw),
},
}
# Passes
capabilities = {'enabled': True, 'opt1': 'match'}
service = {'disabled': False}
host = fakes.FakeHostState('host1',
{'free_ram_mb': 10,
'free_disk_mb': 200,
'capabilities': capabilities,
'service': service})
self.assertTrue(self.filter.host_passes(host, filter_properties))
# Passes
capabilities = {'enabled': True, 'opt1': 'match'}
service = {'disabled': False}
host = fakes.FakeHostState('host1',
{'free_ram_mb': 40,
'free_disk_mb': 400,
'capabilities': capabilities,
'service': service})
self.assertTrue(self.filter.host_passes(host, filter_properties))
# Fails due to capabilities being disabled
capabilities = {'enabled': False, 'opt1': 'match'}
service = {'disabled': False}
host = fakes.FakeHostState('host1',
{'free_ram_mb': 40,
'free_disk_mb': 400,
'capabilities': capabilities,
'service': service})
self.assertFalse(self.filter.host_passes(host, filter_properties))
# Fails due to being exact memory/disk we don't want
capabilities = {'enabled': True, 'opt1': 'match'}
service = {'disabled': False}
host = fakes.FakeHostState('host1',
{'free_ram_mb': 30,
'free_disk_mb': 300,
'capabilities': capabilities,
'service': service})
self.assertFalse(self.filter.host_passes(host, filter_properties))
# Fails due to memory lower but disk higher
capabilities = {'enabled': True, 'opt1': 'match'}
service = {'disabled': False}
host = fakes.FakeHostState('host1',
{'free_ram_mb': 20,
'free_disk_mb': 400,
'capabilities': capabilities,
'service': service})
self.assertFalse(self.filter.host_passes(host, filter_properties))
# Fails due to capabilities 'opt1' not equal
capabilities = {'enabled': True, 'opt1': 'no-match'}
service = {'enabled': True}
host = fakes.FakeHostState('host1',
{'free_ram_mb': 20,
'free_disk_mb': 400,
'capabilities': capabilities,
'service': service})
self.assertFalse(self.filter.host_passes(host, filter_properties))
def test_json_filter_basic_operators(self):
host = fakes.FakeHostState('host1',
{'capabilities': {'enabled': True}})
# (operator, arguments, expected_result)
ops_to_test = [
['=', [1, 1], True],
['=', [1, 2], False],
['<', [1, 2], True],
['<', [1, 1], False],
['<', [2, 1], False],
['>', [2, 1], True],
['>', [2, 2], False],
['>', [2, 3], False],
['<=', [1, 2], True],
['<=', [1, 1], True],
['<=', [2, 1], False],
['>=', [2, 1], True],
['>=', [2, 2], True],
['>=', [2, 3], False],
['in', [1, 1], True],
['in', [1, 1, 2, 3], True],
['in', [4, 1, 2, 3], False],
['not', [True], False],
['not', [False], True],
['or', [True, False], True],
['or', [False, False], False],
['and', [True, True], True],
['and', [False, False], False],
['and', [True, False], False],
# Nested ((True or False) and (2 > 1)) == Passes
['and', [['or', True, False], ['>', 2, 1]], True]]
for (op, args, expected) in ops_to_test:
raw = [op] + args
filter_properties = {
'scheduler_hints': {
'query': jsonutils.dumps(raw),
},
}
self.assertEqual(expected,
self.filter.host_passes(host, filter_properties))
# This results in [False, True, False, True] and if any are True
# then it passes...
raw = ['not', True, False, True, False]
filter_properties = {
'scheduler_hints': {
'query': jsonutils.dumps(raw),
},
}
self.assertTrue(self.filter.host_passes(host, filter_properties))
# This results in [False, False, False] and if any are True
# then it passes...which this doesn't
raw = ['not', True, True, True]
filter_properties = {
'scheduler_hints': {
'query': jsonutils.dumps(raw),
},
}
self.assertFalse(self.filter.host_passes(host, filter_properties))
def test_json_filter_unknown_operator_raises(self):
raw = ['!=', 1, 2]
filter_properties = {
'scheduler_hints': {
'query': jsonutils.dumps(raw),
},
}
host = fakes.FakeHostState('host1',
{'capabilities': {'enabled': True}})
self.assertRaises(KeyError,
self.filter.host_passes, host, filter_properties)
def test_json_filter_empty_filters_pass(self):
host = fakes.FakeHostState('host1',
{'capabilities': {'enabled': True}})
raw = []
filter_properties = {
'scheduler_hints': {
'query': jsonutils.dumps(raw),
},
}
self.assertTrue(self.filter.host_passes(host, filter_properties))
raw = {}
filter_properties = {
'scheduler_hints': {
'query': jsonutils.dumps(raw),
},
}
self.assertTrue(self.filter.host_passes(host, filter_properties))
def test_json_filter_invalid_num_arguments_fails(self):
host = fakes.FakeHostState('host1',
{'capabilities': {'enabled': True}})
raw = ['>', ['and', ['or', ['not', ['<', ['>=', ['<=', ['in', ]]]]]]]]
filter_properties = {
'scheduler_hints': {
'query': jsonutils.dumps(raw),
},
}
self.assertFalse(self.filter.host_passes(host, filter_properties))
raw = ['>', 1]
filter_properties = {
'scheduler_hints': {
'query': jsonutils.dumps(raw),
},
}
self.assertFalse(self.filter.host_passes(host, filter_properties))
def test_json_filter_unknown_variable_ignored(self):
host = fakes.FakeHostState('host1',
{'capabilities': {'enabled': True}})
raw = ['=', '$........', 1, 1]
filter_properties = {
'scheduler_hints': {
'query': jsonutils.dumps(raw),
},
}
self.assertTrue(self.filter.host_passes(host, filter_properties))
raw = ['=', '$foo', 2, 2]
filter_properties = {
'scheduler_hints': {
'query': jsonutils.dumps(raw),
},
}
self.assertTrue(self.filter.host_passes(host, filter_properties))

View File

@ -0,0 +1,50 @@
# Copyright 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.
"""
Tests For RetryFilter.
"""
from manila import context
from manila.scheduler.filters import retry
from manila import test
from manila.tests.scheduler import fakes
class HostFiltersTestCase(test.TestCase):
"""Test case for RetryFilter."""
def setUp(self):
super(HostFiltersTestCase, self).setUp()
self.context = context.RequestContext('fake', 'fake')
self.filter = retry.RetryFilter()
def test_retry_filter_disabled(self):
# Test case where retry/re-scheduling is disabled.
host = fakes.FakeHostState('host1', {})
filter_properties = {}
self.assertTrue(self.filter.host_passes(host, filter_properties))
def test_retry_filter_pass(self):
# Node not previously tried.
host = fakes.FakeHostState('host1', {})
retry = dict(num_attempts=2, hosts=['host2'])
filter_properties = dict(retry=retry)
self.assertTrue(self.filter.host_passes(host, filter_properties))
def test_retry_filter_fail(self):
# Node was already tried.
host = fakes.FakeHostState('host1', {})
retry = dict(num_attempts=1, hosts=['host1'])
filter_properties = dict(retry=retry)
self.assertFalse(self.filter.host_passes(host, filter_properties))

View File

@ -26,7 +26,7 @@ from six import moves
from manila import db
from manila import exception
from manila.openstack.common.scheduler import filters
from manila.scheduler.filters import base_host
from manila.scheduler import host_manager
from manila import test
from manila.tests.scheduler import fakes
@ -36,12 +36,12 @@ from manila import utils
CONF = cfg.CONF
class FakeFilterClass1(filters.BaseHostFilter):
class FakeFilterClass1(base_host.BaseHostFilter):
def host_passes(self, host_state, filter_properties):
pass
class FakeFilterClass2(filters.BaseHostFilter):
class FakeFilterClass2(base_host.BaseHostFilter):
def host_passes(self, host_state, filter_properties):
pass

View File

@ -0,0 +1,245 @@
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# 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 Manager
"""
import ddt
import mock
from oslo_config import cfg
from manila import context
from manila import db
from manila import exception
from manila.scheduler.drivers import base
from manila.scheduler.drivers import filter
from manila.scheduler import manager
from manila.share import rpcapi as share_rpcapi
from manila import test
from manila.tests import db_utils
CONF = cfg.CONF
@ddt.ddt
class SchedulerManagerTestCase(test.TestCase):
"""Test case for scheduler manager."""
manager_cls = manager.SchedulerManager
driver_cls = base.Scheduler
driver_cls_name = 'manila.scheduler.drivers.base.Scheduler'
def setUp(self):
super(SchedulerManagerTestCase, self).setUp()
self.flags(scheduler_driver=self.driver_cls_name)
self.manager = self.manager_cls()
self.context = context.RequestContext('fake_user', 'fake_project')
self.topic = 'fake_topic'
self.fake_args = (1, 2, 3)
self.fake_kwargs = {'cat': 'meow', 'dog': 'woof'}
def test_1_correct_init(self):
# Correct scheduler driver
manager = self.manager
self.assertTrue(isinstance(manager.driver,
self.driver_cls))
@ddt.data('manila.scheduler.filter_scheduler.FilterScheduler',
'manila.scheduler.drivers.filter.FilterScheduler')
def test_scheduler_driver_mapper(self, driver_class):
test_manager = manager.SchedulerManager(scheduler_driver=driver_class)
self.assertTrue(isinstance(test_manager.driver,
filter.FilterScheduler))
def test_init_host(self):
self.mock_object(context,
'get_admin_context',
mock.Mock(return_value='fake_admin_context'))
self.mock_object(self.manager, 'request_service_capabilities')
self.manager.init_host()
self.manager.request_service_capabilities.assert_called_once_with(
'fake_admin_context')
def test_get_host_list(self):
self.mock_object(self.manager.driver, 'get_host_list')
self.manager.get_host_list(context)
self.manager.driver.get_host_list.assert_called_once_with()
def test_get_service_capabilities(self):
self.mock_object(self.manager.driver, 'get_service_capabilities')
self.manager.get_service_capabilities(context)
self.manager.driver.get_service_capabilities.assert_called_once_with()
def test_update_service_capabilities(self):
service_name = 'fake_service'
host = 'fake_host'
with mock.patch.object(self.manager.driver,
'update_service_capabilities', mock.Mock()):
self.manager.update_service_capabilities(
self.context, service_name=service_name, host=host)
(self.manager.driver.update_service_capabilities.
assert_called_once_with(service_name, host, {}))
with mock.patch.object(self.manager.driver,
'update_service_capabilities', mock.Mock()):
capabilities = {'fake_capability': 'fake_value'}
self.manager.update_service_capabilities(
self.context, service_name=service_name, host=host,
capabilities=capabilities)
(self.manager.driver.update_service_capabilities.
assert_called_once_with(service_name, host, capabilities))
@mock.patch.object(db, 'share_update', mock.Mock())
def test_create_share_exception_puts_share_in_error_state(self):
"""Test NoValidHost exception for create_share.
Puts the share in 'error' state and eats the exception.
"""
def raise_no_valid_host(*args, **kwargs):
raise exception.NoValidHost(reason="")
fake_share_id = 1
request_spec = {'share_id': fake_share_id}
with mock.patch.object(self.manager.driver,
'schedule_create_share',
mock.Mock(side_effect=raise_no_valid_host)):
self.mock_object(manager.LOG, 'error')
self.manager.create_share_instance(
self.context, request_spec=request_spec, filter_properties={})
db.share_update.assert_called_once_with(
self.context, fake_share_id, {'status': 'error'})
(self.manager.driver.schedule_create_share.
assert_called_once_with(self.context, request_spec, {}))
manager.LOG.error.assert_called_once_with(mock.ANY, mock.ANY)
@mock.patch.object(db, 'share_update', mock.Mock())
def test_create_share_other_exception_puts_share_in_error_state(self):
"""Test any exception except NoValidHost for create_share.
Puts the share in 'error' state and re-raises the exception.
"""
fake_share_id = 1
request_spec = {'share_id': fake_share_id}
with mock.patch.object(self.manager.driver,
'schedule_create_share',
mock.Mock(side_effect=exception.QuotaError)):
self.mock_object(manager.LOG, 'error')
self.assertRaises(exception.QuotaError,
self.manager.create_share_instance,
self.context,
request_spec=request_spec,
filter_properties={})
db.share_update.assert_called_once_with(
self.context, fake_share_id, {'status': 'error'})
(self.manager.driver.schedule_create_share.
assert_called_once_with(self.context, request_spec, {}))
manager.LOG.error.assert_called_once_with(mock.ANY, mock.ANY)
def test_get_pools(self):
"""Ensure get_pools exists and calls base_scheduler.get_pools."""
mock_get_pools = self.mock_object(self.manager.driver,
'get_pools',
mock.Mock(return_value='fake_pools'))
result = self.manager.get_pools(self.context, filters='fake_filters')
mock_get_pools.assert_called_once_with(self.context, 'fake_filters')
self.assertEqual('fake_pools', result)
@mock.patch.object(db, 'consistency_group_update', mock.Mock())
def test_create_cg_no_valid_host_puts_cg_in_error_state(self):
"""Test that NoValidHost is raised for create_consistency_group.
Puts the share in 'error' state and eats the exception.
"""
def raise_no_valid_host(*args, **kwargs):
raise exception.NoValidHost(reason="")
fake_cg_id = 1
cg_id = fake_cg_id
request_spec = {"consistency_group_id": cg_id}
with mock.patch.object(self.manager.driver,
'schedule_create_consistency_group',
mock.Mock(side_effect=raise_no_valid_host)):
self.manager.create_consistency_group(self.context,
fake_cg_id,
request_spec=request_spec,
filter_properties={})
db.consistency_group_update.assert_called_once_with(
self.context, fake_cg_id, {'status': 'error'})
(self.manager.driver.schedule_create_consistency_group.
assert_called_once_with(self.context, cg_id, request_spec, {}))
@mock.patch.object(db, 'consistency_group_update', mock.Mock())
def test_create_cg_exception_puts_cg_in_error_state(self):
"""Test that exceptions for create_consistency_group.
Puts the share in 'error' state and raises the exception.
"""
fake_cg_id = 1
cg_id = fake_cg_id
request_spec = {"consistency_group_id": cg_id}
with mock.patch.object(self.manager.driver,
'schedule_create_consistency_group',
mock.Mock(side_effect=exception.NotFound)):
self.assertRaises(exception.NotFound,
self.manager.create_consistency_group,
self.context, fake_cg_id,
request_spec=request_spec,
filter_properties={})
def test_migrate_share_to_host(self):
share = db_utils.create_share()
host = 'fake@backend#pool'
self.mock_object(db, 'share_get', mock.Mock(return_value=share))
self.mock_object(share_rpcapi.ShareAPI, 'migrate_share')
self.mock_object(base.Scheduler,
'host_passes_filters',
mock.Mock(return_value=host))
self.manager.migrate_share_to_host(self.context, share['id'], host,
False, {}, None)
def test_migrate_share_to_host_no_valid_host(self):
share = db_utils.create_share()
host = 'fake@backend#pool'
self.mock_object(
base.Scheduler, 'host_passes_filters',
mock.Mock(side_effect=[exception.NoValidHost('fake')]))
self.manager.migrate_share_to_host(self.context, share['id'], host,
False, {}, None)

View File

@ -1,389 +0,0 @@
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# 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
"""
import mock
from oslo_config import cfg
from oslo_utils import timeutils
from manila import context
from manila import db
from manila import exception
from manila.scheduler import driver
from manila.scheduler import manager
from manila.scheduler import simple
from manila.share import rpcapi as share_rpcapi
from manila import test
from manila.tests import db_utils
from manila import utils
CONF = cfg.CONF
class SchedulerManagerTestCase(test.TestCase):
"""Test case for scheduler manager."""
manager_cls = manager.SchedulerManager
driver_cls = driver.Scheduler
driver_cls_name = 'manila.scheduler.driver.Scheduler'
def setUp(self):
super(SchedulerManagerTestCase, self).setUp()
self.flags(scheduler_driver=self.driver_cls_name)
self.manager = self.manager_cls()
self.context = context.RequestContext('fake_user', 'fake_project')
self.topic = 'fake_topic'
self.fake_args = (1, 2, 3)
self.fake_kwargs = {'cat': 'meow', 'dog': 'woof'}
def test_1_correct_init(self):
# Correct scheduler driver
manager = self.manager
self.assertTrue(isinstance(manager.driver, self.driver_cls))
def test_update_service_capabilities(self):
service_name = 'fake_service'
host = 'fake_host'
with mock.patch.object(self.manager.driver,
'update_service_capabilities', mock.Mock()):
self.manager.update_service_capabilities(
self.context, service_name=service_name, host=host)
self.manager.driver.update_service_capabilities.\
assert_called_once_with(service_name, host, {})
with mock.patch.object(self.manager.driver,
'update_service_capabilities', mock.Mock()):
capabilities = {'fake_capability': 'fake_value'}
self.manager.update_service_capabilities(
self.context, service_name=service_name, host=host,
capabilities=capabilities)
self.manager.driver.update_service_capabilities.\
assert_called_once_with(service_name, host, capabilities)
@mock.patch.object(db, 'share_update', mock.Mock())
def test_create_share_exception_puts_share_in_error_state(self):
"""Test that a NoValideHost exception for create_share.
Puts the share in 'error' state and eats the exception.
"""
def raise_no_valid_host(*args, **kwargs):
raise exception.NoValidHost(reason="")
fake_share_id = 1
request_spec = {'share_id': fake_share_id}
with mock.patch.object(self.manager.driver,
'schedule_create_share',
mock.Mock(side_effect=raise_no_valid_host)):
self.mock_object(manager.LOG, 'error')
self.manager.create_share_instance(
self.context, request_spec=request_spec, filter_properties={})
db.share_update.assert_called_once_with(
self.context, fake_share_id, {'status': 'error'})
self.manager.driver.schedule_create_share.assert_called_once_with(
self.context, request_spec, {})
manager.LOG.error.assert_called_once_with(mock.ANY, mock.ANY)
def test_get_pools(self):
"""Ensure get_pools exists and calls driver.get_pools."""
mock_get_pools = self.mock_object(self.manager.driver, 'get_pools',
mock.Mock(return_value='fake_pools'))
result = self.manager.get_pools(self.context, filters='fake_filters')
mock_get_pools.assert_called_once_with(self.context, 'fake_filters')
self.assertEqual('fake_pools', result)
@mock.patch.object(db, 'consistency_group_update', mock.Mock())
def test_create_cg_no_valid_host_puts_cg_in_error_state(self):
"""Test that NoValidHost is raised for create_consistency_group.
Puts the share in 'error' state and eats the exception.
"""
def raise_no_valid_host(*args, **kwargs):
raise exception.NoValidHost(reason="")
fake_cg_id = 1
cg_id = fake_cg_id
request_spec = {"consistency_group_id": cg_id}
with mock.patch.object(self.manager.driver,
'schedule_create_consistency_group',
mock.Mock(side_effect=raise_no_valid_host)):
self.manager.create_consistency_group(self.context,
fake_cg_id,
request_spec=request_spec,
filter_properties={})
db.consistency_group_update.assert_called_once_with(
self.context, fake_cg_id, {'status': 'error'})
self.manager.driver.schedule_create_consistency_group\
.assert_called_once_with(self.context, cg_id,
request_spec, {})
@mock.patch.object(db, 'consistency_group_update', mock.Mock())
def test_create_cg_exception_puts_cg_in_error_state(self):
"""Test that exceptions for create_consistency_group.
Puts the share in 'error' state and raises the exception.
"""
fake_cg_id = 1
cg_id = fake_cg_id
request_spec = {"consistency_group_id": cg_id}
with mock.patch.object(self.manager.driver,
'schedule_create_consistency_group',
mock.Mock(side_effect=exception.NotFound)):
self.assertRaises(exception.NotFound,
self.manager.create_consistency_group,
self.context, fake_cg_id,
request_spec=request_spec,
filter_properties={})
def test_migrate_share_to_host(self):
share = db_utils.create_share()
host = 'fake@backend#pool'
self.mock_object(db, 'share_get', mock.Mock(return_value=share))
self.mock_object(share_rpcapi.ShareAPI, 'migrate_share')
self.mock_object(driver.Scheduler, 'host_passes_filters',
mock.Mock(return_value=host))
self.manager.migrate_share_to_host(self.context, share['id'], host,
False, {}, None)
def test_migrate_share_to_host_no_valid_host(self):
share = db_utils.create_share()
host = 'fake@backend#pool'
self.mock_object(
driver.Scheduler, 'host_passes_filters',
mock.Mock(side_effect=[exception.NoValidHost('fake')]))
self.manager.migrate_share_to_host(self.context, share['id'], host,
False, {}, None)
class SchedulerTestCase(test.TestCase):
"""Test case for base scheduler driver class."""
# So we can subclass this test and re-use tests if we need.
driver_cls = driver.Scheduler
def setUp(self):
super(SchedulerTestCase, self).setUp()
self.driver = self.driver_cls()
self.context = context.RequestContext('fake_user', 'fake_project')
self.topic = 'fake_topic'
def test_update_service_capabilities(self):
service_name = 'fake_service'
host = 'fake_host'
capabilities = {'fake_capability': 'fake_value'}
with mock.patch.object(self.driver.host_manager,
'update_service_capabilities', mock.Mock()):
self.driver.update_service_capabilities(
service_name, host, capabilities)
self.driver.host_manager.update_service_capabilities.\
assert_called_once_with(service_name, host, capabilities)
def test_hosts_up(self):
service1 = {'host': 'host1'}
service2 = {'host': 'host2'}
services = [service1, service2]
def fake_service_is_up(*args, **kwargs):
if args[0]['host'] == 'host1':
return False
return True
with mock.patch.object(db, 'service_get_all_by_topic',
mock.Mock(return_value=services)):
with mock.patch.object(utils, 'service_is_up',
mock.Mock(side_effect=fake_service_is_up)):
result = self.driver.hosts_up(self.context, self.topic)
self.assertEqual(['host2'], result)
db.service_get_all_by_topic.assert_called_once_with(
self.context, self.topic)
class SchedulerDriverBaseTestCase(SchedulerTestCase):
"""Test cases for base scheduler driver class methods.
These can't fail if the driver is changed.
"""
def test_unimplemented_schedule(self):
fake_args = (1, 2, 3)
fake_kwargs = {'cat': 'meow'}
self.assertRaises(NotImplementedError, self.driver.schedule,
self.context, self.topic, 'schedule_something',
*fake_args, **fake_kwargs)
class SchedulerDriverModuleTestCase(test.TestCase):
"""Test case for scheduler driver module methods."""
def setUp(self):
super(SchedulerDriverModuleTestCase, self).setUp()
self.context = context.RequestContext('fake_user', 'fake_project')
@mock.patch.object(db, 'share_update', mock.Mock())
def test_share_host_update_db(self):
with mock.patch.object(timeutils, 'utcnow',
mock.Mock(return_value='fake-now')):
driver.share_update_db(self.context, 31337, 'fake_host')
db.share_update.assert_called_once_with(
self.context, 31337,
{'host': 'fake_host', 'scheduled_at': 'fake-now'})
class SimpleSchedulerSharesTestCase(test.TestCase):
"""Test case for simple scheduler create share method."""
def setUp(self):
super(SimpleSchedulerSharesTestCase, self).setUp()
self.mock_object(share_rpcapi, 'ShareAPI')
self.driver = simple.SimpleScheduler()
self.context = context.RequestContext('fake_user', 'fake_project')
self.admin_context = context.RequestContext('fake_admin_user',
'fake_project')
self.admin_context.is_admin = True
@mock.patch.object(utils, 'service_is_up', mock.Mock(return_value=True))
def test_create_share_if_two_services_up(self):
share_id = 'fake'
fake_share = {'id': share_id, 'size': 1}
fake_service_1 = {'disabled': False, 'host': 'fake_host1'}
fake_service_2 = {'disabled': False, 'host': 'fake_host2'}
fake_result = [(fake_service_1, 2), (fake_service_2, 1)]
fake_request_spec = {
'share_id': share_id,
'share_properties': fake_share,
}
self.mock_object(db, 'service_get_all_share_sorted',
mock.Mock(return_value=fake_result))
self.mock_object(driver, 'share_update_db',
mock.Mock(return_value=db_utils.create_share()))
self.driver.schedule_create_share(self.context,
fake_request_spec, {})
utils.service_is_up.assert_called_once_with(utils.IsAMatcher(dict))
db.service_get_all_share_sorted.assert_called_once_with(
utils.IsAMatcher(context.RequestContext))
driver.share_update_db.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share_id, 'fake_host1')
def test_create_share_if_services_not_available(self):
share_id = 'fake'
fake_share = {'id': share_id, 'size': 1}
fake_result = []
fake_request_spec = {
'share_id': share_id,
'share_properties': fake_share,
}
with mock.patch.object(db, 'service_get_all_share_sorted',
mock.Mock(return_value=fake_result)):
self.assertRaises(exception.NoValidHost,
self.driver.schedule_create_share,
self.context, fake_request_spec, {})
db.service_get_all_share_sorted.assert_called_once_with(
utils.IsAMatcher(context.RequestContext))
def test_create_share_if_max_gigabytes_exceeded(self):
share_id = 'fake'
fake_share = {'id': share_id, 'size': 10001}
fake_service_1 = {'disabled': False, 'host': 'fake_host1'}
fake_service_2 = {'disabled': False, 'host': 'fake_host2'}
fake_result = [(fake_service_1, 5), (fake_service_2, 7)]
fake_request_spec = {
'share_id': share_id,
'share_properties': fake_share,
}
with mock.patch.object(db, 'service_get_all_share_sorted',
mock.Mock(return_value=fake_result)):
self.assertRaises(exception.NoValidHost,
self.driver.schedule_create_share,
self.context, fake_request_spec, {})
db.service_get_all_share_sorted.assert_called_once_with(
utils.IsAMatcher(context.RequestContext))
@mock.patch.object(utils, 'service_is_up', mock.Mock(return_value=True))
def test_create_share_availability_zone(self):
share_id = 'fake'
fake_share = {
'id': share_id,
'size': 1,
}
fake_instance = {
'availability_zone_id': 'fake',
}
fake_service_1 = {
'disabled': False, 'host': 'fake_host1',
'availability_zone_id': 'fake',
}
fake_service_2 = {
'disabled': False, 'host': 'fake_host2',
'availability_zone_id': 'super_fake',
}
fake_result = [(fake_service_1, 0), (fake_service_2, 1)]
fake_request_spec = {
'share_id': share_id,
'share_properties': fake_share,
'share_instance_properties': fake_instance,
}
self.mock_object(db, 'service_get_all_share_sorted',
mock.Mock(return_value=fake_result))
self.mock_object(driver, 'share_update_db',
mock.Mock(return_value=db_utils.create_share()))
self.driver.schedule_create_share(self.context,
fake_request_spec, {})
utils.service_is_up.assert_called_once_with(fake_service_1)
driver.share_update_db.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share_id,
fake_service_1['host'])
db.service_get_all_share_sorted.assert_called_once_with(
utils.IsAMatcher(context.RequestContext))
@mock.patch.object(utils, 'service_is_up', mock.Mock(return_value=True))
def test_create_share_availability_zone_on_host(self):
share_id = 'fake'
fake_share = {
'id': share_id,
'availability_zone': 'fake:fake',
'size': 1,
}
fake_service = {'disabled': False, 'host': 'fake'}
fake_request_spec = {
'share_id': share_id,
'share_properties': fake_share,
}
self.mock_object(db, 'service_get_all_share_sorted',
mock.Mock(return_value=[(fake_service, 1)]))
self.mock_object(driver, 'share_update_db',
mock.Mock(return_value=db_utils.create_share()))
self.driver.schedule_create_share(self.admin_context,
fake_request_spec, {})
utils.service_is_up.assert_called_once_with(fake_service)
db.service_get_all_share_sorted.assert_called_once_with(
utils.IsAMatcher(context.RequestContext))
driver.share_update_db.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share_id, 'fake')

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
"""
Tests For PickledScheduler.
Tests For scheduler options.
"""
import datetime

View File

@ -0,0 +1,64 @@
# Copyright 2011-2012 OpenStack Foundation.
# 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 weighers.
"""
from manila.scheduler.weighers import base
from manila import test
from manila.tests.scheduler import fakes
class TestWeightHandler(test.TestCase):
def test_get_all_classes(self):
namespace = "manila.tests.scheduler.fakes"
handler = base.BaseWeightHandler(
base.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)
def test_no_multiplier(self):
class FakeWeigher(base.BaseWeigher):
def _weigh_object(self, *args, **kwargs):
pass
self.assertEqual(1.0,
FakeWeigher().weight_multiplier())
def test_no_weight_object(self):
class FakeWeigher(base.BaseWeigher):
def weight_multiplier(self, *args, **kwargs):
pass
self.assertRaises(TypeError,
FakeWeigher)
def test_normalization(self):
# weight_list, expected_result, minval, maxval
map_ = (
((), (), None, None),
((0.0, 0.0), (0.0, 0.0), None, None),
((1.0, 1.0), (0.0, 0.0), None, None),
((20.0, 50.0), (0.0, 1.0), None, None),
((20.0, 50.0), (0.0, 0.375), None, 100.0),
((20.0, 50.0), (0.4, 1.0), 0.0, None),
((20.0, 50.0), (0.2, 0.5), 0.0, 100.0),
)
for seq, result, minval, maxval in map_:
ret = base.normalize(seq, minval=minval, maxval=maxval)
self.assertEqual(result, tuple(ret))

View File

@ -20,8 +20,8 @@ import mock
from oslo_config import cfg
from manila import context
from manila.openstack.common.scheduler import weights
from manila.scheduler.weights import capacity
from manila.scheduler.weighers import base_host
from manila.scheduler.weighers import capacity
from manila.share import utils
from manila import test
from manila.tests.scheduler import fakes
@ -33,8 +33,8 @@ class CapacityWeigherTestCase(test.TestCase):
def setUp(self):
super(CapacityWeigherTestCase, self).setUp()
self.host_manager = fakes.FakeHostManager()
self.weight_handler = weights.HostWeightHandler(
'manila.scheduler.weights')
self.weight_handler = base_host.HostWeightHandler(
'manila.scheduler.weighers')
def _get_weighed_host(self, hosts, weight_properties=None, index=0):
if weight_properties is None:

View File

@ -12,6 +12,9 @@
# 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 Pool Weigher.
"""
import mock
from oslo_config import cfg
@ -19,8 +22,8 @@ from oslo_utils import timeutils
from manila import context
from manila.db import api as db_api
from manila.openstack.common.scheduler import weights
from manila.scheduler.weights import pool
from manila.scheduler.weighers import base_host
from manila.scheduler.weighers import pool
from manila.share import utils
from manila import test
from manila.tests.scheduler import fakes
@ -32,8 +35,8 @@ class PoolWeigherTestCase(test.TestCase):
def setUp(self):
super(PoolWeigherTestCase, self).setUp()
self.host_manager = fakes.FakeHostManager()
self.weight_handler = weights.HostWeightHandler(
'manila.scheduler.weights')
self.weight_handler = base_host.HostWeightHandler(
'manila.scheduler.weighers')
share_servers = [
{'id': 'fake_server_id0'},
{'id': 'fake_server_id1'},
@ -170,7 +173,7 @@ class PoolWeigherTestCase(test.TestCase):
# host4: weight = 1*(1.0)
# host5: weight = 1*(1.0)
# But after normalization all weights will be 0
# But after normalization all weighers will be 0
weighed_host = self._get_weighed_host(self._get_all_hosts(),
weight_properties)

View File

@ -34,15 +34,16 @@ console_scripts =
manila-scheduler = manila.cmd.scheduler:main
manila-share = manila.cmd.share:main
manila.scheduler.filters =
AvailabilityZoneFilter = manila.openstack.common.scheduler.filters.availability_zone_filter:AvailabilityZoneFilter
CapabilitiesFilter = manila.openstack.common.scheduler.filters.capabilities_filter:CapabilitiesFilter
CapacityFilter = manila.scheduler.filters.capacity_filter:CapacityFilter
ConsistencyGroupFilter = manila.scheduler.filters.consistency_group_filter:ConsistencyGroupFilter
JsonFilter = manila.openstack.common.scheduler.filters.json_filter:JsonFilter
RetryFilter = manila.scheduler.filters.retry_filter:RetryFilter
manila.scheduler.weights =
CapacityWeigher = manila.scheduler.weights.capacity:CapacityWeigher
PoolWeigher = manila.scheduler.weights.pool:PoolWeigher
AvailabilityZoneFilter = manila.scheduler.filters.availability_zone:AvailabilityZoneFilter
CapabilitiesFilter = manila.scheduler.filters.capabilities:CapabilitiesFilter
CapacityFilter = manila.scheduler.filters.capacity:CapacityFilter
ConsistencyGroupFilter = manila.scheduler.filters.consistency_group:ConsistencyGroupFilter
IgnoreAttemptedHostsFilter = manila.scheduler.filters.ignore_attempted_hosts:IgnoreAttemptedHostsFilter
JsonFilter = manila.scheduler.filters.json:JsonFilter
RetryFilter = manila.scheduler.filters.retry:RetryFilter
manila.scheduler.weighers =
CapacityWeigher = manila.scheduler.weighers.capacity:CapacityWeigher
PoolWeigher = manila.scheduler.weighers.pool:PoolWeigher
# These are for backwards compat with Havana notification_driver configuration values
oslo_messaging.notify.drivers =
manila.openstack.common.notifier.log_notifier = oslo_messaging.notify._impl_log:LogDriver
@ -55,6 +56,9 @@ oslo.config.opts =
manila.share.drivers.emc.plugins =
vnx = manila.share.drivers.emc.plugins.vnx.connection:VNXStorageConnection
isilon = manila.share.drivers.emc.plugins.isilon.isilon:IsilonStorageConnection
manila.tests.scheduler.fakes =
FakeWeigher1 = manila.tests.scheduler.fakes:FakeWeigher1
FakeWeigher2 = manila.tests.scheduler.fakes:FakeWeigher2
tempest.test_plugins =
manila_tests = manila_tempest_tests.plugin:ManilaTempestPlugin