[Share groups] Add scheduler filter ConsistentSnapshotFilter

That will be used for scheduling share groups based on their possibility
to create consistent snapshots.

Also apply following tempest plugin changes:
- Add new 'capability_sg_consistent_snapshot_support' tempest config
option, that will be used for creation of new share group types and used
to prove that scheduling works as expected.
- Fix some share group test attributes from 'only API involved' to
  'API and Backend are involved', because it is so indeed.

Change-Id: I05553c308ae40c4ddc2c6469ff1c1a3da36a87da
Partially-Implements BP manila-share-groups
This commit is contained in:
Valeriy Ponomaryov 2017-03-15 19:06:23 +03:00 committed by vponomaryov
parent ded53681cb
commit 21699451f1
23 changed files with 271 additions and 54 deletions

View File

@ -232,6 +232,7 @@ elif [[ "$DRIVER" == "dummy" ]]; then
iniset $TEMPEST_CONFIG share build_timeout 180
iniset $TEMPEST_CONFIG share share_creation_retry_number 0
iniset $TEMPEST_CONFIG share capability_storage_protocol 'NFS_CIFS'
iniset $TEMPEST_CONFIG share capability_sg_consistent_snapshot_support 'pool'
iniset $TEMPEST_CONFIG share enable_protocols 'nfs,cifs'
iniset $TEMPEST_CONFIG share suppress_errors_in_cleanup False
iniset $TEMPEST_CONFIG share multitenancy_enabled True

View File

@ -15,9 +15,9 @@
# under the License.
"""
The FilterScheduler is for creating shares.
You can customize this scheduler by specifying your own share Filters and
Weighing Functions.
The FilterScheduler is for scheduling of share and share group creation.
You can customize this scheduler by specifying your own share/share group
filters and weighing functions.
"""
from oslo_config import cfg
@ -392,7 +392,9 @@ class FilterScheduler(base.Scheduler):
}
hosts = self.host_manager.get_filtered_hosts(
all_hosts, filter_properties)
all_hosts,
filter_properties,
CONF.scheduler_default_share_group_filters)
if not hosts:
return []

View File

@ -0,0 +1,31 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from manila.scheduler.filters import base_host
class ConsistentSnapshotFilter(base_host.BaseHostFilter):
"""Filters hosts based on possibility to create consistent SG snapshots."""
def host_passes(self, host_state, filter_properties):
"""Return True if host will work with desired share group."""
cs_group_spec = filter_properties['share_group_type'].get(
'group_specs', {}).get('consistent_snapshot_support')
# NOTE(vpoomaryov): if 'consistent_snapshot_support' group spec
# is not set, then we assume that share group owner do not care about
# it, which means any host should pass this filter.
if cs_group_spec is None:
return True
return cs_group_spec == host_state.sg_consistent_snapshot_support

View File

@ -56,7 +56,14 @@ host_manager_opts = [
'CapacityWeigher',
'GoodnessWeigher',
],
help='Which weigher class names to use for weighing hosts.')
help='Which weigher class names to use for weighing hosts.'),
cfg.ListOpt(
'scheduler_default_share_group_filters',
default=[
'ConsistentSnapshotFilter',
],
help='Which filter class names to use for filtering hosts '
'creating share group when not specified in the request.'),
]
CONF = cfg.CONF
@ -140,6 +147,9 @@ class HostState(object):
self.pools = {}
self.updated = None
# Share Group capabilities
self.sg_consistent_snapshot_support = None
def update_capabilities(self, capabilities=None, service=None):
# Read-only capability dicts
@ -317,6 +327,10 @@ class HostState(object):
if not pool_cap.get('replication_domain'):
pool_cap['replication_domain'] = self.replication_domain
if 'sg_consistent_snapshot_support' not in pool_cap:
pool_cap['sg_consistent_snapshot_support'] = (
self.sg_consistent_snapshot_support)
def update_backend(self, capability):
self.share_backend_name = capability.get('share_backend_name')
self.vendor_name = capability.get('vendor_name')
@ -334,6 +348,8 @@ class HostState(object):
self.updated = capability['timestamp']
self.replication_type = capability.get('replication_type')
self.replication_domain = capability.get('replication_domain')
self.sg_consistent_snapshot_support = capability.get(
'share_group_stats', {}).get('consistent_snapshot_support')
def consume_from_share(self, share):
"""Incrementally update host state from an share."""
@ -419,6 +435,8 @@ class PoolState(HostState):
'replication_type', self.replication_type)
self.replication_domain = capability.get(
'replication_domain')
self.sg_consistent_snapshot_support = capability.get(
'sg_consistent_snapshot_support')
def update_pools(self, capability):
# Do nothing, since we don't have pools within pool, yet

View File

@ -53,6 +53,8 @@ def generate_stats(host_state, properties):
'pools': host_state.pools,
'max_over_subscription_ratio':
host_state.max_over_subscription_ratio,
'sg_consistent_snapshot_support': (
host_state.sg_consistent_snapshot_support),
}
host_caps = host_state.capabilities
@ -60,15 +62,20 @@ def generate_stats(host_state, properties):
share_type = properties.get('share_type', {})
extra_specs = share_type.get('extra_specs', {})
share_group_type = properties.get('share_group_type', {})
group_specs = share_group_type.get('group_specs', {})
request_spec = properties.get('request_spec', {})
share_stats = request_spec.get('resource_properties', {})
stats = {
'host_stats': host_stats,
'host_caps': host_caps,
'share_type': share_type,
'extra_specs': extra_specs,
'share_stats': share_stats,
'share_type': share_type,
'share_group_type': share_group_type,
'group_specs': group_specs,
}
return stats

View File

@ -1112,7 +1112,6 @@ class ShareDriver(object):
create_share_from_snapshot_support=(
self.creating_shares_from_snapshots_is_supported),
revert_to_snapshot_support=False,
share_group_snapshot_support=self.snapshots_are_supported,
mount_snapshot_support=False,
replication_domain=self.replication_domain,
filter_function=self.get_filter_function(),
@ -1120,6 +1119,13 @@ class ShareDriver(object):
)
if isinstance(data, dict):
common.update(data)
sg_stats = data.get('share_group_stats', {}) if data else {}
common['share_group_stats'] = {
'consistent_snapshot_support': sg_stats.get(
'consistent_snapshot_support'),
}
self._stats = common
def get_share_server_pools(self, share_server):
@ -1357,7 +1363,7 @@ class ShareDriver(object):
snap_dict['id'])
snapshot_members = snap_dict.get('share_group_snapshot_members', [])
if not self._stats.get('share_group_snapshot_support'):
if not self._stats.get('snapshot_support'):
raise exception.ShareGroupSnapshotNotSupported(
share_group=snap_dict['share_group_id'])
elif not snapshot_members:

View File

@ -3522,7 +3522,10 @@ class ShareManager(manager.SchedulerDependentManager):
self.db.share_group_update(
context,
share_group_ref['id'],
{'status': constants.STATUS_ERROR})
{'status': constants.STATUS_ERROR,
'consistent_snapshot_support': self.driver._stats[
'share_group_stats'].get(
'consistent_snapshot_support')})
for share in shares:
self.db.share_instance_update(
context, share['id'],
@ -3533,10 +3536,13 @@ class ShareManager(manager.SchedulerDependentManager):
for share in shares:
self.db.share_instance_update(
context, share['id'], {'status': constants.STATUS_AVAILABLE})
self.db.share_group_update(context,
share_group_ref['id'],
{'status': status,
'created_at': now})
self.db.share_group_update(
context,
share_group_ref['id'],
{'status': status,
'created_at': now,
'consistent_snapshot_support': self.driver._stats[
'share_group_stats'].get('consistent_snapshot_support')})
LOG.info("Share group %s: created successfully", share_group_id)
# TODO(ameade): Add notification for create.end

View File

@ -217,6 +217,7 @@ class HostManagerTestCase(test.TestCase):
'compression': False,
'replication_type': None,
'replication_domain': None,
'sg_consistent_snapshot_support': None,
},
}, {
'name': 'host2@back1#BBB',
@ -244,6 +245,7 @@ class HostManagerTestCase(test.TestCase):
'compression': False,
'replication_type': None,
'replication_domain': None,
'sg_consistent_snapshot_support': None,
},
}, {
'name': 'host2@back2#CCC',
@ -271,6 +273,7 @@ class HostManagerTestCase(test.TestCase):
'compression': False,
'replication_type': None,
'replication_domain': None,
'sg_consistent_snapshot_support': None,
},
},
]
@ -320,6 +323,7 @@ class HostManagerTestCase(test.TestCase):
'compression': False,
'replication_type': None,
'replication_domain': None,
'sg_consistent_snapshot_support': None,
},
}, {
'name': 'host2@BBB#pool2',
@ -348,6 +352,7 @@ class HostManagerTestCase(test.TestCase):
'compression': False,
'replication_type': None,
'replication_domain': None,
'sg_consistent_snapshot_support': None,
},
}, {
'name': 'host3@CCC#pool3',
@ -376,6 +381,7 @@ class HostManagerTestCase(test.TestCase):
'compression': False,
'replication_type': None,
'replication_domain': None,
'sg_consistent_snapshot_support': None,
},
}, {
'name': 'host4@DDD#pool4a',
@ -404,6 +410,7 @@ class HostManagerTestCase(test.TestCase):
'compression': False,
'replication_type': None,
'replication_domain': None,
'sg_consistent_snapshot_support': None,
},
}, {
'name': 'host4@DDD#pool4b',
@ -432,6 +439,7 @@ class HostManagerTestCase(test.TestCase):
'compression': False,
'replication_type': None,
'replication_domain': None,
'sg_consistent_snapshot_support': None,
},
},
]
@ -493,6 +501,7 @@ class HostManagerTestCase(test.TestCase):
'compression': False,
'replication_type': None,
'replication_domain': None,
'sg_consistent_snapshot_support': None,
},
}, {
'name': 'host2@back1#BBB',
@ -520,6 +529,7 @@ class HostManagerTestCase(test.TestCase):
'compression': False,
'replication_type': None,
'replication_domain': None,
'sg_consistent_snapshot_support': None,
},
},
]
@ -575,6 +585,7 @@ class HostManagerTestCase(test.TestCase):
'compression': False,
'replication_type': None,
'replication_domain': None,
'sg_consistent_snapshot_support': None,
},
},
]

View File

@ -126,7 +126,7 @@ class EMCShareFrameworkTestCase(test.TestCase):
data['snapshot_support'] = True
data['create_share_from_snapshot_support'] = True
data['revert_to_snapshot_support'] = False
data['share_group_snapshot_support'] = True
data['share_group_stats'] = {'consistent_snapshot_support': None}
data['mount_snapshot_support'] = False
data['replication_domain'] = None
data['filter_function'] = None

View File

@ -380,13 +380,15 @@ class DummyDriver(driver.ShareDriver):
"storage_protocol": "NFS_CIFS",
"reserved_percentage":
self.configuration.reserved_share_percentage,
"consistency_group_support": "pool",
"snapshot_support": True,
"create_share_from_snapshot_support": True,
"revert_to_snapshot_support": True,
"mount_snapshot_support": True,
"driver_name": "Dummy",
"pools": self._get_pools_info(),
"share_group_stats": {
"consistent_snapshot_support": "pool",
}
}
if self.configuration.replication_domain:
data["replication_type"] = "readable"

View File

@ -258,8 +258,10 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
'snapshot_support': True,
'create_share_from_snapshot_support': True,
'revert_to_snapshot_support': False,
'share_group_snapshot_support': True,
'mount_snapshot_support': False,
'share_group_stats': {
'consistent_snapshot_support': None,
},
'replication_domain': None,
'filter_function': None,
'goodness_function': None,

View File

@ -735,8 +735,10 @@ class HPE3ParDriverTestCase(test.TestCase):
'snapshot_support': True,
'create_share_from_snapshot_support': True,
'revert_to_snapshot_support': False,
'share_group_snapshot_support': True,
'mount_snapshot_support': False,
'share_group_stats': {
'consistent_snapshot_support': None,
},
'storage_protocol': 'NFS_CIFS',
'thin_provisioning': True,
'total_capacity_gb': 0,
@ -813,8 +815,10 @@ class HPE3ParDriverTestCase(test.TestCase):
'snapshot_support': True,
'create_share_from_snapshot_support': True,
'revert_to_snapshot_support': False,
'share_group_snapshot_support': True,
'mount_snapshot_support': False,
'share_group_stats': {
'consistent_snapshot_support': None,
},
'replication_domain': None,
'filter_function': None,
'goodness_function': None,
@ -853,8 +857,10 @@ class HPE3ParDriverTestCase(test.TestCase):
'snapshot_support': True,
'create_share_from_snapshot_support': True,
'revert_to_snapshot_support': False,
'share_group_snapshot_support': True,
'mount_snapshot_support': False,
'share_group_stats': {
'consistent_snapshot_support': None,
},
'replication_domain': None,
'filter_function': None,
'goodness_function': None,

View File

@ -2425,12 +2425,12 @@ class HuaweiShareDriverTestCase(test.TestCase):
"snapshot_support": snapshot_support,
"create_share_from_snapshot_support": snapshot_support,
"revert_to_snapshot_support": False,
"share_group_snapshot_support": True,
"mount_snapshot_support": False,
"replication_domain": None,
"filter_function": None,
"goodness_function": None,
"pools": [],
"share_group_stats": {"consistent_snapshot_support": None},
}
if replication_support:

View File

@ -352,10 +352,10 @@ class ZFSonLinuxShareDriverTestCase(test.TestCase):
'replication_domain': replication_domain,
'reserved_percentage': 0,
'share_backend_name': self.driver.backend_name,
'share_group_stats': {'consistent_snapshot_support': None},
'snapshot_support': True,
'create_share_from_snapshot_support': True,
'revert_to_snapshot_support': False,
'share_group_snapshot_support': True,
'mount_snapshot_support': False,
'storage_protocol': 'NFS',
'total_capacity_gb': 'unknown',

View File

@ -690,9 +690,6 @@ class ShareDriverTestCase(test.TestCase):
self.assertEqual(
snapshots_are_supported,
child_class_instance._stats["snapshot_support"])
self.assertEqual(
snapshots_are_supported,
child_class_instance._stats["share_group_snapshot_support"])
self.assertTrue(child_class_instance.configuration.safe_get.called)
def test_create_share_group_from_share_group_snapshot(self):
@ -843,7 +840,7 @@ class ShareDriverTestCase(test.TestCase):
'name': None
}
share_driver = self._instantiate_share_driver(None, False)
share_driver._stats['share_group_snapshot_support'] = True
share_driver._stats['snapshot_support'] = True
mock_create_snap = self.mock_object(
share_driver, 'create_snapshot',
mock.Mock(side_effect=lambda *args, **kwargs: {
@ -917,7 +914,7 @@ class ShareDriverTestCase(test.TestCase):
expected_exception = exception.ManilaException
share_driver = self._instantiate_share_driver(None, False)
share_driver._stats['share_group_snapshot_support'] = True
share_driver._stats['snapshot_support'] = True
mock_create_snap = self.mock_object(
share_driver, 'create_snapshot',
mock.Mock(side_effect=[None, expected_exception]))
@ -985,7 +982,7 @@ class ShareDriverTestCase(test.TestCase):
'name': None
}
share_driver = self._instantiate_share_driver(None, False)
share_driver._stats['share_group_snapshot_support'] = False
share_driver._stats['snapshot_support'] = False
self.assertRaises(
exception.ShareGroupSnapshotNotSupported,
@ -1006,7 +1003,7 @@ class ShareDriverTestCase(test.TestCase):
'name': None
}
share_driver = self._instantiate_share_driver(None, False)
share_driver._stats['share_group_snapshot_support'] = True
share_driver._stats['snapshot_support'] = True
share_group_snapshot_update, member_update_list = (
share_driver.create_share_group_snapshot(

View File

@ -89,6 +89,9 @@ class ShareManagerTestCase(test.TestCase):
"manila.share.manager.ShareManager")
self.mock_object(self.share_manager.driver, 'do_setup')
self.mock_object(self.share_manager.driver, 'check_for_setup_error')
self.share_manager.driver._stats = {
'share_group_stats': {'consistent_snapshot_support': None},
}
self.context = context.get_admin_context()
self.share_manager.driver.initialized = True
mock.patch.object(
@ -3226,10 +3229,13 @@ class ShareManagerTestCase(test.TestCase):
self.share_manager.create_share_group(self.context, "fake_id")
self.share_manager.db.share_group_update.\
assert_called_once_with(mock.ANY, 'fake_id',
{'status': constants.STATUS_AVAILABLE,
'created_at': mock.ANY})
self.share_manager.db.share_group_update.assert_called_once_with(
mock.ANY, 'fake_id', {
'status': constants.STATUS_AVAILABLE,
'created_at': mock.ANY,
'consistent_snapshot_support': None,
}
)
def test_create_cg_with_share_network_driver_not_handles_servers(self):
manager.CONF.set_default('driver_handles_share_servers', False)
@ -3281,8 +3287,12 @@ class ShareManagerTestCase(test.TestCase):
self.share_manager.create_share_group(self.context, "fake_id")
self.share_manager.db.share_group_update.assert_called_once_with(
mock.ANY, 'fake_id',
{'status': constants.STATUS_AVAILABLE, 'created_at': mock.ANY})
mock.ANY, 'fake_id', {
'status': constants.STATUS_AVAILABLE,
'created_at': mock.ANY,
'consistent_snapshot_support': None,
}
)
def test_create_share_group_with_update(self):
fake_group = {'id': 'fake_id'}
@ -3298,10 +3308,13 @@ class ShareManagerTestCase(test.TestCase):
self.share_manager.db.share_group_update.\
assert_any_call(mock.ANY, 'fake_id', {'foo': 'bar'})
self.share_manager.db.share_group_update.\
assert_any_call(mock.ANY, 'fake_id',
{'status': constants.STATUS_AVAILABLE,
'created_at': mock.ANY})
self.share_manager.db.share_group_update.assert_any_call(
mock.ANY, 'fake_id', {
'status': constants.STATUS_AVAILABLE,
'created_at': mock.ANY,
'consistent_snapshot_support': None,
}
)
def test_create_share_group_with_error(self):
fake_group = {'id': 'fake_id'}
@ -3318,7 +3331,11 @@ class ShareManagerTestCase(test.TestCase):
self.context, "fake_id")
self.share_manager.db.share_group_update.assert_called_once_with(
mock.ANY, 'fake_id', {'status': constants.STATUS_ERROR})
mock.ANY, 'fake_id', {
'status': constants.STATUS_ERROR,
'consistent_snapshot_support': None,
}
)
def test_create_share_group_from_sg_snapshot(self):
fake_group = {
@ -3348,7 +3365,9 @@ class ShareManagerTestCase(test.TestCase):
self.share_manager.db.share_group_update.assert_called_once_with(
mock.ANY, 'fake_id',
{'status': constants.STATUS_AVAILABLE, 'created_at': mock.ANY})
{'status': constants.STATUS_AVAILABLE,
'created_at': mock.ANY,
'consistent_snapshot_support': None})
self.share_manager.db.share_server_get(mock.ANY, 'fake_ss_id')
mock_create_sg_from_sg_snap.assert_called_once_with(
mock.ANY, fake_group, fake_snap, share_server=fake_ss)
@ -3415,7 +3434,9 @@ class ShareManagerTestCase(test.TestCase):
self.share_manager.db.share_group_update.assert_called_once_with(
mock.ANY, 'fake_id',
{'status': constants.STATUS_AVAILABLE, 'created_at': mock.ANY})
{'status': constants.STATUS_AVAILABLE,
'created_at': mock.ANY,
'consistent_snapshot_support': None})
def test_create_share_group_from_share_group_snapshot_with_update(self):
fake_group = {
@ -3439,8 +3460,12 @@ class ShareManagerTestCase(test.TestCase):
self.share_manager.db.share_group_update.assert_any_call(
mock.ANY, 'fake_id', {'foo': 'bar'})
self.share_manager.db.share_group_update.assert_any_call(
mock.ANY, 'fake_id',
{'status': constants.STATUS_AVAILABLE, 'created_at': mock.ANY})
mock.ANY, 'fake_id', {
'status': constants.STATUS_AVAILABLE,
'created_at': mock.ANY,
'consistent_snapshot_support': None,
}
)
def test_create_share_group_from_sg_snapshot_with_share_update(self):
fake_share = {'id': 'fake_share_id'}
@ -3474,8 +3499,12 @@ class ShareManagerTestCase(test.TestCase):
self.share_manager.db.share_export_locations_update.assert_any_call(
mock.ANY, 'fake_share_id', fake_export_locations)
self.share_manager.db.share_group_update.assert_any_call(
mock.ANY, 'fake_id',
{'status': constants.STATUS_AVAILABLE, 'created_at': mock.ANY})
mock.ANY, 'fake_id', {
'status': constants.STATUS_AVAILABLE,
'created_at': mock.ANY,
'consistent_snapshot_support': None,
}
)
def test_create_share_group_from_sg_snapshot_with_error(self):
fake_group = {
@ -3502,7 +3531,11 @@ class ShareManagerTestCase(test.TestCase):
self.context, "fake_id")
self.share_manager.db.share_group_update.assert_called_once_with(
mock.ANY, 'fake_id', {'status': constants.STATUS_ERROR})
mock.ANY, 'fake_id', {
'status': constants.STATUS_ERROR,
'consistent_snapshot_support': None,
}
)
def test_create_share_group_from_sg_snapshot_with_share_error(self):
fake_share = {'id': 'fake_share_id'}
@ -3532,7 +3565,11 @@ class ShareManagerTestCase(test.TestCase):
self.share_manager.db.share_instance_update.assert_any_call(
mock.ANY, 'fake_share_id', {'status': constants.STATUS_ERROR})
self.share_manager.db.share_group_update.assert_called_once_with(
mock.ANY, 'fake_id', {'status': constants.STATUS_ERROR})
mock.ANY, 'fake_id', {
'status': constants.STATUS_ERROR,
'consistent_snapshot_support': None,
}
)
def test_delete_share_group(self):
fake_group = {'id': 'fake_id'}

View File

@ -112,6 +112,11 @@ ShareGroup = [
"capability called 'revert_to_snapshot_support' "
"and will be used for setting up custom share type. "
"Defaults to the value of run_revert_to_snapshot_tests."),
cfg.StrOpt("capability_sg_consistent_snapshot_support",
choices=["host", "pool", None],
help="Backend capability to create consistent snapshots of "
"share group members. Will be used with creation "
"of new share group types as group spec."),
cfg.StrOpt("share_network_id",
default="",
help="Some backend drivers requires share network "

View File

@ -136,13 +136,16 @@ class ShareGroupTypesTest(base.BaseSharesAdminTest):
self.assertDictMatch(group_specs, sg_type['group_specs'])
group_specs = {'key1': 'value3', 'key2': 'value2'}
group_specs = {'key1': 'value1', 'key2': 'value2'}
self.shares_v2_client.update_share_group_type_spec(
sg_type['id'], 'key1', 'value3')
sg_type = self.shares_v2_client.get_share_group_type(sg_type['id'])
self.assertDictMatch(group_specs, sg_type['group_specs'])
self.assertIn('key1', sg_type['group_specs'])
self.assertIn('key2', sg_type['group_specs'])
self.assertEqual('value3', sg_type['group_specs']['key1'])
self.assertEqual(group_specs['key2'], sg_type['group_specs']['key2'])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_update_all_share_group_type_specs_min(self):
@ -164,7 +167,9 @@ class ShareGroupTypesTest(base.BaseSharesAdminTest):
sg_type['id'], group_specs)
sg_type = self.shares_v2_client.get_share_group_type(sg_type['id'])
self.assertDictMatch(group_specs, sg_type['group_specs'])
for k, v in group_specs.items():
self.assertIn(k, sg_type['group_specs'])
self.assertEqual(v, sg_type['group_specs'][k])
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
def test_delete_single_share_group_type_spec_min(self):

View File

@ -48,7 +48,7 @@ class ShareGroupsTest(base.BaseSharesAdminTest):
cleanup_in_class=True,
version=constants.MIN_SHARE_GROUP_MICROVERSION)
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_create_share_group_with_single_share_type_min(self):
share_group = self.create_share_group(
share_group_type_id=self.sg_type['id'],
@ -81,7 +81,7 @@ class ShareGroupsTest(base.BaseSharesAdminTest):
'Expected %s, got %s' % (
share_group['id'], expected_share_types, actual_share_types))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_create_share_group_with_multiple_share_types_min(self):
share_group = self.create_share_group(
share_group_type_id=self.sg_type['id'],
@ -114,7 +114,7 @@ class ShareGroupsTest(base.BaseSharesAdminTest):
'Expected %s, got %s' % (
share_group['id'], expected_share_types, actual_share_types))
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_default_share_group_type_applied(self):
default_type = self.shares_v2_client.get_default_share_group_type()
default_share_types = default_type['share_types']
@ -142,7 +142,7 @@ class ShareGroupsTest(base.BaseSharesAdminTest):
@testtools.skipUnless(
CONF.share.multitenancy_enabled, "Only for multitenancy.")
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_create_sg_from_snapshot_verify_share_server_information_min(self):
# Create a share group
orig_sg = self.create_share_group(
@ -173,3 +173,19 @@ class ShareGroupsTest(base.BaseSharesAdminTest):
orig_sg['share_network_id'], new_sg['share_network_id'])
self.assertEqual(
orig_sg['share_server_id'], new_sg['share_server_id'])
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_create_sg_with_sg_type_but_without_any_group_specs(self):
# Create share group type not specifying any group specs
sg_type = self.create_share_group_type(
name=data_utils.rand_name("tempest-manila"),
share_types=[self.share_type['id']],
group_specs={},
cleanup_in_class=False)
# Create share group, it should be created always, because we do not
# restrict choice anyhow.
self.create_share_group(
share_type_ids=[self.share_type['id']],
share_group_type_id=sg_type['id'],
cleanup_in_class=False)

View File

@ -0,0 +1,56 @@
# Copyright 2017 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import config
from tempest.lib.common.utils import data_utils
import testtools
from testtools import testcase as tc
from manila_tempest_tests.common import constants
from manila_tempest_tests import share_exceptions
from manila_tempest_tests.tests.api import base
CONF = config.CONF
@testtools.skipUnless(
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
class ShareGroupsNegativeTest(base.BaseSharesAdminTest):
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_create_share_group_with_wrong_consistent_snapshot_spec(self):
# Create valid share type for share group type
name = data_utils.rand_name("tempest-manila")
extra_specs = self.add_extra_specs_to_dict()
st = self.create_share_type(name, extra_specs=extra_specs)
share_type = st['share_type'] if 'share_type' in st else st
# Create share group type with wrong value for
# 'consistent_snapshot_support' capability, we always expect
# NoValidHostFound using this SG type.
sg_type = self.create_share_group_type(
name=name,
share_types=[share_type['id']],
group_specs={"consistent_snapshot_support": "fake"},
cleanup_in_class=False)
# Try create share group
self.assertRaises(
share_exceptions.ShareGroupBuildErrorException,
self.create_share_group,
share_type_ids=[share_type['id']],
share_group_type_id=sg_type['id'],
cleanup_in_class=False)

View File

@ -595,6 +595,11 @@ class BaseSharesTest(test.BaseTestCase):
group_specs=None, client=None,
cleanup_in_class=True, **kwargs):
client = client or cls.shares_v2_client
if group_specs is None:
group_specs = {
'consistent_snapshot_support': (
CONF.share.capability_sg_consistent_snapshot_support),
}
share_group_type = client.create_share_group_type(
name=name,
share_types=share_types,

View File

@ -45,10 +45,14 @@ manila.scheduler.filters =
JsonFilter = manila.scheduler.filters.json:JsonFilter
RetryFilter = manila.scheduler.filters.retry:RetryFilter
ShareReplicationFilter = manila.scheduler.filters.share_replication:ShareReplicationFilter
# Share Group filters
ConsistentSnapshotFilter = manila.scheduler.filters.share_group_filters.consistent_snapshot:ConsistentSnapshotFilter
manila.scheduler.weighers =
CapacityWeigher = manila.scheduler.weighers.capacity:CapacityWeigher
GoodnessWeigher = manila.scheduler.weighers.goodness:GoodnessWeigher
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