686 lines
25 KiB
Python
686 lines
25 KiB
Python
# 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.
|
|
"""
|
|
|
|
import mock
|
|
from oslo_serialization import jsonutils
|
|
from requests import exceptions as request_exceptions
|
|
|
|
from cinder.compute import nova
|
|
from cinder import context
|
|
from cinder import db
|
|
from cinder import exception
|
|
from cinder.openstack.common.scheduler import filters
|
|
from cinder import test
|
|
from cinder.tests.scheduler import fakes
|
|
from cinder.tests import utils
|
|
|
|
|
|
class HostFiltersTestCase(test.TestCase):
|
|
"""Test case for host filters."""
|
|
|
|
def setUp(self):
|
|
super(HostFiltersTestCase, self).setUp()
|
|
self.context = context.RequestContext('fake', 'fake')
|
|
# This has a side effect of testing 'get_filter_classes'
|
|
# when specifying a method (in this case, our standard filters)
|
|
filter_handler = filters.HostFilterHandler('cinder.scheduler.filters')
|
|
classes = filter_handler.get_all_classes()
|
|
self.class_map = {}
|
|
for cls in classes:
|
|
self.class_map[cls.__name__] = cls
|
|
|
|
|
|
class CapacityFilterTestCase(HostFiltersTestCase):
|
|
def setUp(self):
|
|
super(CapacityFilterTestCase, self).setUp()
|
|
self.json_query = jsonutils.dumps(
|
|
['and',
|
|
['>=', '$free_capacity_gb', 1024],
|
|
['>=', '$total_capacity_gb', 10 * 1024]])
|
|
|
|
@mock.patch('cinder.utils.service_is_up')
|
|
def test_filter_passes(self, _mock_serv_is_up):
|
|
_mock_serv_is_up.return_value = True
|
|
filt_cls = self.class_map['CapacityFilter']()
|
|
filter_properties = {'size': 100}
|
|
service = {'disabled': False}
|
|
host = fakes.FakeHostState('host1',
|
|
{'free_capacity_gb': 200,
|
|
'updated_at': None,
|
|
'service': service})
|
|
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
|
|
|
@mock.patch('cinder.utils.service_is_up')
|
|
def test_filter_current_host_passes(self, _mock_serv_is_up):
|
|
_mock_serv_is_up.return_value = True
|
|
filt_cls = self.class_map['CapacityFilter']()
|
|
filter_properties = {'size': 100, 'vol_exists_on': 'host1'}
|
|
service = {'disabled': False}
|
|
host = fakes.FakeHostState('host1',
|
|
{'free_capacity_gb': 10,
|
|
'updated_at': None,
|
|
'service': service})
|
|
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
|
|
|
@mock.patch('cinder.utils.service_is_up')
|
|
def test_filter_fails(self, _mock_serv_is_up):
|
|
_mock_serv_is_up.return_value = True
|
|
filt_cls = self.class_map['CapacityFilter']()
|
|
filter_properties = {'size': 100}
|
|
service = {'disabled': False}
|
|
host = fakes.FakeHostState('host1',
|
|
{'free_capacity_gb': 120,
|
|
'reserved_percentage': 20,
|
|
'updated_at': None,
|
|
'service': service})
|
|
self.assertFalse(filt_cls.host_passes(host, filter_properties))
|
|
|
|
@mock.patch('cinder.utils.service_is_up')
|
|
def test_filter_passes_infinite(self, _mock_serv_is_up):
|
|
_mock_serv_is_up.return_value = True
|
|
filt_cls = self.class_map['CapacityFilter']()
|
|
filter_properties = {'size': 100}
|
|
service = {'disabled': False}
|
|
host = fakes.FakeHostState('host1',
|
|
{'free_capacity_gb': 'infinite',
|
|
'updated_at': None,
|
|
'service': service})
|
|
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
|
|
|
@mock.patch('cinder.utils.service_is_up')
|
|
def test_filter_passes_unknown(self, _mock_serv_is_up):
|
|
_mock_serv_is_up.return_value = True
|
|
filt_cls = self.class_map['CapacityFilter']()
|
|
filter_properties = {'size': 100}
|
|
service = {'disabled': False}
|
|
host = fakes.FakeHostState('host1',
|
|
{'free_capacity_gb': 'unknown',
|
|
'updated_at': None,
|
|
'service': service})
|
|
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
|
|
|
|
|
class AffinityFilterTestCase(HostFiltersTestCase):
|
|
@mock.patch('cinder.utils.service_is_up')
|
|
def test_different_filter_passes(self, _mock_serv_is_up):
|
|
_mock_serv_is_up.return_value = True
|
|
filt_cls = self.class_map['DifferentBackendFilter']()
|
|
service = {'disabled': False}
|
|
host = fakes.FakeHostState('host1:pool0',
|
|
{'free_capacity_gb': '1000',
|
|
'updated_at': None,
|
|
'service': service})
|
|
volume = utils.create_volume(self.context, host='host1:pool1')
|
|
vol_id = volume.id
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': {
|
|
'different_host': [vol_id], }}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
|
|
|
@mock.patch('cinder.utils.service_is_up')
|
|
def test_different_filter_legacy_volume_hint_passes(
|
|
self, _mock_serv_is_up):
|
|
_mock_serv_is_up.return_value = True
|
|
filt_cls = self.class_map['DifferentBackendFilter']()
|
|
service = {'disabled': False}
|
|
host = fakes.FakeHostState('host1:pool0',
|
|
{'free_capacity_gb': '1000',
|
|
'updated_at': None,
|
|
'service': service})
|
|
volume = utils.create_volume(self.context, host='host1')
|
|
vol_id = volume.id
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': {
|
|
'different_host': [vol_id], }}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_different_filter_non_list_fails(self):
|
|
filt_cls = self.class_map['DifferentBackendFilter']()
|
|
host = fakes.FakeHostState('host2', {})
|
|
volume = utils.create_volume(self.context, host='host2')
|
|
vol_id = volume.id
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': {
|
|
'different_host': vol_id}}
|
|
|
|
self.assertFalse(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_different_filter_fails(self):
|
|
filt_cls = self.class_map['DifferentBackendFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
volume = utils.create_volume(self.context, host='host1')
|
|
vol_id = volume.id
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': {
|
|
'different_host': [vol_id], }}
|
|
|
|
self.assertFalse(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_different_filter_handles_none(self):
|
|
filt_cls = self.class_map['DifferentBackendFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': None}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_different_filter_handles_deleted_instance(self):
|
|
filt_cls = self.class_map['DifferentBackendFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
volume = utils.create_volume(self.context, host='host1')
|
|
vol_id = volume.id
|
|
db.volume_destroy(utils.get_test_admin_context(), vol_id)
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': {
|
|
'different_host': [vol_id], }}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_different_filter_fail_nonuuid_hint(self):
|
|
filt_cls = self.class_map['DifferentBackendFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': {
|
|
'different_host': "NOT-a-valid-UUID", }}
|
|
|
|
self.assertFalse(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_different_filter_handles_multiple_uuids(self):
|
|
filt_cls = self.class_map['DifferentBackendFilter']()
|
|
host = fakes.FakeHostState('host1#pool0', {})
|
|
volume1 = utils.create_volume(self.context, host='host1:pool1')
|
|
vol_id1 = volume1.id
|
|
volume2 = utils.create_volume(self.context, host='host1:pool3')
|
|
vol_id2 = volume2.id
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': {
|
|
'different_host': [vol_id1, vol_id2], }}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_different_filter_handles_invalid_uuids(self):
|
|
filt_cls = self.class_map['DifferentBackendFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
volume = utils.create_volume(self.context, host='host2')
|
|
vol_id = volume.id
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': {
|
|
'different_host': [vol_id, "NOT-a-valid-UUID"], }}
|
|
|
|
self.assertFalse(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_same_filter_no_list_passes(self):
|
|
filt_cls = self.class_map['SameBackendFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
volume = utils.create_volume(self.context, host='host1')
|
|
vol_id = volume.id
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': {
|
|
'same_host': vol_id}}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_same_filter_passes(self):
|
|
filt_cls = self.class_map['SameBackendFilter']()
|
|
host = fakes.FakeHostState('host1#pool0', {})
|
|
volume = utils.create_volume(self.context, host='host1#pool0')
|
|
vol_id = volume.id
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': {
|
|
'same_host': [vol_id], }}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_same_filter_legacy_vol_fails(self):
|
|
filt_cls = self.class_map['SameBackendFilter']()
|
|
host = fakes.FakeHostState('host1#pool0', {})
|
|
volume = utils.create_volume(self.context, host='host1')
|
|
vol_id = volume.id
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': {
|
|
'same_host': [vol_id], }}
|
|
|
|
self.assertFalse(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_same_filter_fails(self):
|
|
filt_cls = self.class_map['SameBackendFilter']()
|
|
host = fakes.FakeHostState('host1#pool0', {})
|
|
volume = utils.create_volume(self.context, host='host1#pool1')
|
|
vol_id = volume.id
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': {
|
|
'same_host': [vol_id], }}
|
|
|
|
self.assertFalse(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_same_filter_vol_list_pass(self):
|
|
filt_cls = self.class_map['SameBackendFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
volume1 = utils.create_volume(self.context, host='host1')
|
|
vol_id1 = volume1.id
|
|
volume2 = utils.create_volume(self.context, host='host2')
|
|
vol_id2 = volume2.id
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': {
|
|
'same_host': [vol_id1, vol_id2], }}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_same_filter_handles_none(self):
|
|
filt_cls = self.class_map['SameBackendFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': None}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_same_filter_handles_deleted_instance(self):
|
|
filt_cls = self.class_map['SameBackendFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
volume = utils.create_volume(self.context, host='host2')
|
|
vol_id = volume.id
|
|
db.volume_destroy(utils.get_test_admin_context(), vol_id)
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': {
|
|
'same_host': [vol_id], }}
|
|
|
|
self.assertFalse(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_same_filter_fail_nonuuid_hint(self):
|
|
filt_cls = self.class_map['SameBackendFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
|
|
filter_properties = {'context': self.context.elevated(),
|
|
'scheduler_hints': {
|
|
'same_host': "NOT-a-valid-UUID", }}
|
|
|
|
self.assertFalse(filt_cls.host_passes(host, filter_properties))
|
|
|
|
|
|
class DriverFilterTestCase(HostFiltersTestCase):
|
|
def test_passing_function(self):
|
|
filt_cls = self.class_map['DriverFilter']()
|
|
host1 = fakes.FakeHostState(
|
|
'host1', {
|
|
'volume_backend_name': 'fake',
|
|
'capabilities': {
|
|
'filter_function': '1 == 1',
|
|
}
|
|
})
|
|
|
|
filter_properties = {
|
|
'volume_type': {
|
|
'extra_specs': {
|
|
'volume_backend_name': 'fake',
|
|
}
|
|
}
|
|
}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host1, filter_properties))
|
|
|
|
def test_failing_function(self):
|
|
filt_cls = self.class_map['DriverFilter']()
|
|
host1 = fakes.FakeHostState(
|
|
'host1', {
|
|
'volume_backend_name': 'fake',
|
|
'capabilities': {
|
|
'filter_function': '1 == 2',
|
|
}
|
|
})
|
|
|
|
filter_properties = {
|
|
'volume_type': {
|
|
'extra_specs': {
|
|
'volume_backend_name': 'fake',
|
|
}
|
|
}
|
|
}
|
|
|
|
self.assertFalse(filt_cls.host_passes(host1, filter_properties))
|
|
|
|
def test_no_filter_function(self):
|
|
filt_cls = self.class_map['DriverFilter']()
|
|
host1 = fakes.FakeHostState(
|
|
'host1', {
|
|
'volume_backend_name': 'fake',
|
|
'capabilities': {
|
|
'filter_function': None,
|
|
}
|
|
})
|
|
|
|
filter_properties = {
|
|
'volume_type': {
|
|
'extra_specs': {
|
|
'volume_backend_name': 'fake',
|
|
}
|
|
}
|
|
}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host1, filter_properties))
|
|
|
|
def test_not_implemented(self):
|
|
filt_cls = self.class_map['DriverFilter']()
|
|
host1 = fakes.FakeHostState(
|
|
'host1', {
|
|
'volume_backend_name': 'fake',
|
|
'capabilities': {}
|
|
})
|
|
|
|
filter_properties = {
|
|
'volume_type': {
|
|
'extra_specs': {
|
|
'volume_backend_name': 'fake',
|
|
}
|
|
}
|
|
}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host1, filter_properties))
|
|
|
|
def test_no_volume_extra_specs(self):
|
|
filt_cls = self.class_map['DriverFilter']()
|
|
host1 = fakes.FakeHostState(
|
|
'host1', {
|
|
'volume_backend_name': 'fake',
|
|
'capabilities': {
|
|
'filter_function': '1 == 1',
|
|
}
|
|
})
|
|
|
|
filter_properties = {'volume_type': {}}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host1, filter_properties))
|
|
|
|
def test_volume_backend_name_different(self):
|
|
filt_cls = self.class_map['DriverFilter']()
|
|
host1 = fakes.FakeHostState(
|
|
'host1', {
|
|
'volume_backend_name': 'fake',
|
|
'capabilities': {
|
|
'filter_function': '1 == 1',
|
|
}
|
|
})
|
|
|
|
filter_properties = {
|
|
'volume_type': {
|
|
'extra_specs': {
|
|
'volume_backend_name': 'fake2',
|
|
}
|
|
}
|
|
}
|
|
|
|
self.assertFalse(filt_cls.host_passes(host1, filter_properties))
|
|
|
|
def test_function_extra_spec_replacement(self):
|
|
filt_cls = self.class_map['DriverFilter']()
|
|
host1 = fakes.FakeHostState(
|
|
'host1', {
|
|
'volume_backend_name': 'fake',
|
|
'capabilities': {
|
|
'filter_function': 'extra.var == 1',
|
|
}
|
|
})
|
|
|
|
filter_properties = {
|
|
'volume_type': {
|
|
'extra_specs': {
|
|
'volume_backend_name': 'fake',
|
|
'var': 1,
|
|
}
|
|
}
|
|
}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host1, filter_properties))
|
|
|
|
def test_function_stats_replacement(self):
|
|
filt_cls = self.class_map['DriverFilter']()
|
|
host1 = fakes.FakeHostState(
|
|
'host1', {
|
|
'volume_backend_name': 'fake',
|
|
'total_capacity_gb': 100,
|
|
'capabilities': {
|
|
'filter_function': 'stats.total_capacity_gb < 200',
|
|
}
|
|
})
|
|
|
|
filter_properties = {
|
|
'volume_type': {
|
|
'extra_specs': {
|
|
'volume_backend_name': 'fake',
|
|
}
|
|
}
|
|
}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host1, filter_properties))
|
|
|
|
def test_function_volume_replacement(self):
|
|
filt_cls = self.class_map['DriverFilter']()
|
|
host1 = fakes.FakeHostState(
|
|
'host1', {
|
|
'volume_backend_name': 'fake',
|
|
'capabilities': {
|
|
'filter_function': 'volume.size < 5',
|
|
}
|
|
})
|
|
|
|
filter_properties = {
|
|
'volume_type': {
|
|
'extra_specs': {
|
|
'volume_backend_name': 'fake',
|
|
}
|
|
},
|
|
'request_spec': {
|
|
'volume_properties': {
|
|
'size': 1
|
|
}
|
|
}
|
|
}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host1, filter_properties))
|
|
|
|
def test_function_qos_spec_replacement(self):
|
|
filt_cls = self.class_map['DriverFilter']()
|
|
host1 = fakes.FakeHostState(
|
|
'host1', {
|
|
'volume_backend_name': 'fake',
|
|
'capabilities': {
|
|
'filter_function': 'qos.var == 1',
|
|
}
|
|
})
|
|
|
|
filter_properties = {
|
|
'volume_type': {
|
|
'extra_specs': {
|
|
'volume_backend_name': 'fake',
|
|
}
|
|
},
|
|
'qos_specs': {
|
|
'var': 1
|
|
}
|
|
}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host1, filter_properties))
|
|
|
|
def test_function_exception_caught(self):
|
|
filt_cls = self.class_map['DriverFilter']()
|
|
host1 = fakes.FakeHostState(
|
|
'host1', {
|
|
'volume_backend_name': 'fake',
|
|
'capabilities': {
|
|
'filter_function': '1 / 0 == 0',
|
|
}
|
|
})
|
|
|
|
filter_properties = {
|
|
'volume_type': {
|
|
'extra_specs': {
|
|
'volume_backend_name': 'fake',
|
|
}
|
|
}
|
|
}
|
|
|
|
self.assertFalse(filt_cls.host_passes(host1, filter_properties))
|
|
|
|
def test_function_empty_qos(self):
|
|
filt_cls = self.class_map['DriverFilter']()
|
|
host1 = fakes.FakeHostState(
|
|
'host1', {
|
|
'volume_backend_name': 'fake',
|
|
'capabilities': {
|
|
'filter_function': 'qos.maxiops == 1',
|
|
}
|
|
})
|
|
|
|
filter_properties = {
|
|
'volume_type': {
|
|
'extra_specs': {
|
|
'volume_backend_name': 'fake',
|
|
}
|
|
},
|
|
'qos_specs': None
|
|
}
|
|
|
|
self.assertFalse(filt_cls.host_passes(host1, filter_properties))
|
|
|
|
def test_capabilities(self):
|
|
filt_cls = self.class_map['DriverFilter']()
|
|
host1 = fakes.FakeHostState(
|
|
'host1', {
|
|
'volume_backend_name': 'fake',
|
|
'capabilities': {
|
|
'foo': 10,
|
|
'filter_function': 'capabilities.foo == 10',
|
|
},
|
|
})
|
|
|
|
filter_properties = {
|
|
'volume_type': {
|
|
'extra_specs': {
|
|
'volume_backend_name': 'fake',
|
|
}
|
|
}
|
|
}
|
|
|
|
self.assertTrue(filt_cls.host_passes(host1, filter_properties))
|
|
|
|
|
|
class InstanceLocalityFilterTestCase(HostFiltersTestCase):
|
|
def setUp(self):
|
|
super(InstanceLocalityFilterTestCase, self).setUp()
|
|
self.override_config('nova_endpoint_template',
|
|
'http://novahost:8774/v2/%(project_id)s')
|
|
self.context.service_catalog = \
|
|
[{'type': 'compute', 'name': 'nova', 'endpoints':
|
|
[{'publicURL': 'http://novahost:8774/v2/e3f0833dc08b4cea'}]},
|
|
{'type': 'identity', 'name': 'keystone', 'endpoints':
|
|
[{'publicURL': 'http://keystonehost:5000/v2.0'}]}]
|
|
|
|
@mock.patch('cinder.compute.nova.novaclient')
|
|
def test_same_host(self, _mock_novaclient):
|
|
_mock_novaclient.return_value = fakes.FakeNovaClient()
|
|
filt_cls = self.class_map['InstanceLocalityFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
uuid = nova.novaclient().servers.create('host1')
|
|
|
|
filter_properties = {'context': self.context,
|
|
'scheduler_hints': {'local_to_instance': uuid}}
|
|
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
|
|
|
@mock.patch('cinder.compute.nova.novaclient')
|
|
def test_different_host(self, _mock_novaclient):
|
|
_mock_novaclient.return_value = fakes.FakeNovaClient()
|
|
filt_cls = self.class_map['InstanceLocalityFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
uuid = nova.novaclient().servers.create('host2')
|
|
|
|
filter_properties = {'context': self.context,
|
|
'scheduler_hints': {'local_to_instance': uuid}}
|
|
self.assertFalse(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_handles_none(self):
|
|
filt_cls = self.class_map['InstanceLocalityFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
|
|
filter_properties = {'context': self.context,
|
|
'scheduler_hints': None}
|
|
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
|
|
|
def test_invalid_uuid(self):
|
|
filt_cls = self.class_map['InstanceLocalityFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
|
|
filter_properties = {'context': self.context,
|
|
'scheduler_hints':
|
|
{'local_to_instance': 'e29b11d4-not-valid-a716'}}
|
|
self.assertRaises(exception.InvalidUUID,
|
|
filt_cls.host_passes, host, filter_properties)
|
|
|
|
@mock.patch('cinder.compute.nova.novaclient')
|
|
def test_nova_no_extended_server_attributes(self, _mock_novaclient):
|
|
_mock_novaclient.return_value = fakes.FakeNovaClient(
|
|
ext_srv_attr=False)
|
|
filt_cls = self.class_map['InstanceLocalityFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
uuid = nova.novaclient().servers.create('host1')
|
|
|
|
filter_properties = {'context': self.context,
|
|
'scheduler_hints': {'local_to_instance': uuid}}
|
|
self.assertRaises(exception.CinderException,
|
|
filt_cls.host_passes, host, filter_properties)
|
|
|
|
@mock.patch('cinder.compute.nova.novaclient')
|
|
def test_nova_down_does_not_alter_other_filters(self, _mock_novaclient):
|
|
# Simulate Nova API is not available
|
|
_mock_novaclient.side_effect = Exception
|
|
|
|
filt_cls = self.class_map['InstanceLocalityFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
|
|
filter_properties = {'context': self.context, 'size': 100}
|
|
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
|
|
|
@mock.patch('requests.request')
|
|
def test_nova_timeout(self, _mock_request):
|
|
# Simulate a HTTP timeout
|
|
_mock_request.side_effect = request_exceptions.Timeout
|
|
|
|
filt_cls = self.class_map['InstanceLocalityFilter']()
|
|
host = fakes.FakeHostState('host1', {})
|
|
|
|
filter_properties = \
|
|
{'context': self.context, 'scheduler_hints':
|
|
{'local_to_instance': 'e29b11d4-15ef-34a9-a716-598a6f0b5467'}}
|
|
self.assertRaises(exception.APITimeout,
|
|
filt_cls.host_passes, host, filter_properties)
|