Add group to cluster when init host

If cluster is enabled, the group should be updated with cluster
as well.

Change-Id: I72dc6c61f10417f8382c7c488be27ed5199b75b9
Implements: blueprint cinder-volume-active-active-support
This commit is contained in:
wangxiyuan 2017-04-24 11:21:05 +08:00
parent c7f15a4fa5
commit 48ce34a68e
7 changed files with 143 additions and 4 deletions

View File

@ -1352,6 +1352,23 @@ def consistencygroup_include_in_cluster(context, cluster, partial_rename=True,
**filters)
def group_include_in_cluster(context, cluster, partial_rename=True, **filters):
"""Include all generic groups matching the filters into a cluster.
When partial_rename is set we will not set the cluster_name with cluster
parameter value directly, we'll replace provided cluster_name or host
filter value with cluster instead.
This is useful when we want to replace just the cluster name but leave
the backend and pool information as it is. If we are using cluster_name
to filter, we'll use that same DB field to replace the cluster value and
leave the rest as it is. Likewise if we use the host to filter.
Returns the number of generic groups that have been changed.
"""
return IMPL.group_include_in_cluster(context, cluster, partial_rename,
**filters)
###################

View File

@ -5528,6 +5528,12 @@ def consistencygroup_include_in_cluster(context, cluster,
partial_rename, filters)
@require_admin_context
def group_include_in_cluster(context, cluster, partial_rename=True, **filters):
"""Include all generic groups matching the filters into a cluster."""
return _include_in_cluster(context, cluster, models.Group, partial_rename,
filters)
###############################

View File

@ -231,3 +231,22 @@ class GroupList(base.ObjectListBase, base.CinderObject):
if grp.is_replicated]
return out_groups
@staticmethod
def include_in_cluster(context, cluster, partial_rename=True, **filters):
"""Include all generic groups matching the filters into a cluster.
When partial_rename is set we will not set the cluster_name with
cluster parameter value directly, we'll replace provided cluster_name
or host filter value with cluster instead.
This is useful when we want to replace just the cluster name but leave
the backend and pool information as it is. If we are using
cluster_name to filter, we'll use that same DB field to replace the
cluster value and leave the rest as it is. Likewise if we use the host
to filter.
Returns the number of generic groups that have been changed.
"""
return db.group_include_in_cluster(context, cluster, partial_rename,
**filters)

View File

@ -272,3 +272,24 @@ class TestGroupList(test_objects.BaseObjectsTestCase):
else:
self.assertEqual(fake.GROUP_ID, res[0].id)
self.assertIsNone(res[0].cluster_name)
@mock.patch('cinder.db.group_include_in_cluster')
def test_include_in_cluster(self, include_mock):
filters = {'host': mock.sentinel.host,
'cluster_name': mock.sentinel.cluster_name}
cluster = 'new_cluster'
objects.GroupList.include_in_cluster(self.context, cluster, **filters)
include_mock.assert_called_once_with(self.context, cluster, True,
**filters)
@mock.patch('cinder.db.group_include_in_cluster')
def test_include_in_cluster_specify_partial(self, include_mock):
filters = {'host': mock.sentinel.host,
'cluster_name': mock.sentinel.cluster_name}
cluster = 'new_cluster'
objects.GroupList.include_in_cluster(self.context, cluster,
mock.sentinel.partial_rename,
**filters)
include_mock.assert_called_once_with(self.context, cluster,
mock.sentinel.partial_rename,
**filters)

View File

@ -3095,6 +3095,7 @@ class DBAPIBackendTestCase(BaseTest):
db.is_backend_frozen(self.ctxt, host, cluster))
@ddt.ddt
class DBAPIGroupTestCase(BaseTest):
def test_group_get_all_by_host(self):
grp_type = db.group_type_create(self.ctxt, {'name': 'my_group_type'})
@ -3148,3 +3149,72 @@ class DBAPIGroupTestCase(BaseTest):
db.group_destroy(self.ctxt, grp_foobar['id'])
db.group_type_destroy(self.ctxt, grp_type['id'])
def _create_gs_to_test_include_in(self):
"""Helper method for test_group_include_in_* tests."""
return [
db.group_create(
self.ctxt, {'host': 'host1@backend1#pool1',
'cluster_name': 'cluster1@backend1#pool1'}),
db.group_create(
self.ctxt, {'host': 'host1@backend2#pool2',
'cluster_name': 'cluster1@backend2#pool1'}),
db.group_create(
self.ctxt, {'host': 'host2@backend#poo1',
'cluster_name': 'cluster2@backend#pool'}),
]
@ddt.data('host1@backend1#pool1', 'host1@backend1')
def test_group_include_in_cluster_by_host(self, host):
group = self._create_gs_to_test_include_in()[0]
cluster_name = 'my_cluster'
result = db.group_include_in_cluster(self.ctxt, cluster_name,
partial_rename=False, host=host)
self.assertEqual(1, result)
db_group = db.group_get(self.ctxt, group.id)
self.assertEqual(cluster_name, db_group.cluster_name)
def test_group_include_in_cluster_by_host_multiple(self):
groups = self._create_gs_to_test_include_in()[0:2]
host = 'host1'
cluster_name = 'my_cluster'
result = db.group_include_in_cluster(self.ctxt, cluster_name,
partial_rename=True, host=host)
self.assertEqual(2, result)
db_group = [db.group_get(self.ctxt, groups[0].id),
db.group_get(self.ctxt, groups[1].id)]
for i in range(2):
self.assertEqual(cluster_name + groups[i].host[len(host):],
db_group[i].cluster_name)
@ddt.data('cluster1@backend1#pool1', 'cluster1@backend1')
def test_group_include_in_cluster_by_cluster_name(self, cluster_name):
group = self._create_gs_to_test_include_in()[0]
new_cluster_name = 'cluster_new@backend1#pool'
result = db.group_include_in_cluster(self.ctxt, new_cluster_name,
partial_rename=False,
cluster_name=cluster_name)
self.assertEqual(1, result)
db_group = db.group_get(self.ctxt, group.id)
self.assertEqual(new_cluster_name, db_group.cluster_name)
def test_group_include_in_cluster_by_cluster_multiple(self):
groups = self._create_gs_to_test_include_in()[0:2]
cluster_name = 'cluster1'
new_cluster_name = 'my_cluster'
result = db.group_include_in_cluster(self.ctxt, new_cluster_name,
partial_rename=True,
cluster_name=cluster_name)
self.assertEqual(2, result)
db_groups = [db.group_get(self.ctxt, groups[0].id),
db.group_get(self.ctxt, groups[1].id)]
for i in range(2):
self.assertEqual(
new_cluster_name + groups[i].cluster_name[len(cluster_name):],
db_groups[i].cluster_name)

View File

@ -239,6 +239,7 @@ class VolumeInitHostTestCase(base.BaseVolumeTestCase):
service_id=self.service_id)
include_in_cluster_mock.assert_not_called()
@mock.patch('cinder.objects.group.GroupList.include_in_cluster')
@mock.patch('cinder.objects.snapshot.SnapshotList.get_all',
return_value=[])
@mock.patch('cinder.objects.volume.VolumeList.get_all', return_value=[])
@ -249,7 +250,7 @@ class VolumeInitHostTestCase(base.BaseVolumeTestCase):
def test_init_host_added_to_cluster(self, image_cache_include_mock,
cg_include_mock,
vol_include_mock, vol_get_all_mock,
snap_get_all_mock):
snap_get_all_mock, group_include_mock):
cluster = str(mock.sentinel.cluster)
self.mock_object(self.volume, 'cluster', cluster)
self.volume.init_host(added_to_cluster=True,
@ -261,6 +262,8 @@ class VolumeInitHostTestCase(base.BaseVolumeTestCase):
host=self.volume.host)
image_cache_include_mock.assert_called_once_with(mock.ANY, cluster,
host=self.volume.host)
group_include_mock.assert_called_once_with(mock.ANY, cluster,
host=self.volume.host)
vol_get_all_mock.assert_called_once_with(
mock.ANY, filters={'cluster_name': cluster})
snap_get_all_mock.assert_called_once_with(

View File

@ -412,12 +412,15 @@ class VolumeManager(manager.CleanableManager,
ctxt, self.cluster, host=self.host)
num_cgs = objects.ConsistencyGroupList.include_in_cluster(
ctxt, self.cluster, host=self.host)
num_gs = objects.GroupList.include_in_cluster(
ctxt, self.cluster, host=self.host)
num_cache = db.image_volume_cache_include_in_cluster(
ctxt, self.cluster, host=self.host)
LOG.info('%(num_vols)s volumes, %(num_cgs)s consistency groups, '
'and %(num_cache)s image volume caches from host '
'%(host)s have been included in cluster %(cluster)s.',
{'num_vols': num_vols, 'num_cgs': num_cgs,
'%(num_gs)s generic groups and %(num_cache)s image '
'volume caches from host %(host)s have been included in '
'cluster %(cluster)s.',
{'num_vols': num_vols, 'num_cgs': num_cgs, 'num_gs': num_gs,
'host': self.host, 'cluster': self.cluster,
'num_cache': num_cache})