Set cluster name for volume groups
In Active/Active HA mode we need to store not only worker hostname but cluster name too. This patch saves cluster name for groups created from other groups or snaphshots. Change-Id: I6f160cc44350f0d378fdddb7943e8cdcc15be1b8 Closes-Bug: #1867906
This commit is contained in:
parent
8bf454b0b5
commit
8d67562831
@ -6129,15 +6129,18 @@ def group_create(context, values, group_snapshot_id=None,
|
|||||||
values.pop('group_type_id', None)
|
values.pop('group_type_id', None)
|
||||||
values.pop('availability_zone', None)
|
values.pop('availability_zone', None)
|
||||||
values.pop('host', None)
|
values.pop('host', None)
|
||||||
|
values.pop('cluster_name', None)
|
||||||
# NOTE(xyang): Save volume_type_ids to update later.
|
# NOTE(xyang): Save volume_type_ids to update later.
|
||||||
volume_type_ids = values.pop('volume_type_ids', [])
|
volume_type_ids = values.pop('volume_type_ids', [])
|
||||||
|
|
||||||
sel = session.query(group_model.group_type_id,
|
sel = session.query(group_model.group_type_id,
|
||||||
group_model.availability_zone,
|
group_model.availability_zone,
|
||||||
group_model.host,
|
group_model.host,
|
||||||
|
group_model.cluster_name,
|
||||||
*(bindparam(k, v) for k, v in values.items())
|
*(bindparam(k, v) for k, v in values.items())
|
||||||
).filter(*conditions)
|
).filter(*conditions)
|
||||||
names = ['group_type_id', 'availability_zone', 'host']
|
names = ['group_type_id', 'availability_zone', 'host',
|
||||||
|
'cluster_name']
|
||||||
names.extend(values.keys())
|
names.extend(values.keys())
|
||||||
insert_stmt = group_model.__table__.insert().from_select(
|
insert_stmt = group_model.__table__.insert().from_select(
|
||||||
names, sel)
|
names, sel)
|
||||||
|
@ -97,6 +97,15 @@ class API(base.Base):
|
|||||||
|
|
||||||
return availability_zone
|
return availability_zone
|
||||||
|
|
||||||
|
def _update_volumes_host(self, context, group):
|
||||||
|
volumes = objects.VolumeList.get_all_by_generic_group(context,
|
||||||
|
group.id)
|
||||||
|
for vol in volumes:
|
||||||
|
# Update the host field for the volume.
|
||||||
|
vol.host = group.host
|
||||||
|
vol.cluster_name = group.cluster_name
|
||||||
|
vol.save()
|
||||||
|
|
||||||
def create(self, context, name, description, group_type,
|
def create(self, context, name, description, group_type,
|
||||||
volume_types, availability_zone=None):
|
volume_types, availability_zone=None):
|
||||||
context.authorize(group_policy.CREATE_POLICY)
|
context.authorize(group_policy.CREATE_POLICY)
|
||||||
@ -247,8 +256,9 @@ class API(base.Base):
|
|||||||
kwargs = {'group_id': group.id,
|
kwargs = {'group_id': group.id,
|
||||||
'volume_properties': objects.VolumeProperties(size=size)}
|
'volume_properties': objects.VolumeProperties(size=size)}
|
||||||
|
|
||||||
if not group.host or not self.scheduler_rpcapi.validate_host_capacity(
|
host = group.resource_backend
|
||||||
context, group.host, objects.RequestSpec(**kwargs)):
|
if not host or not self.scheduler_rpcapi.validate_host_capacity(
|
||||||
|
context, host, objects.RequestSpec(**kwargs)):
|
||||||
msg = _("No valid host to create group %s.") % group.id
|
msg = _("No valid host to create group %s.") % group.id
|
||||||
LOG.error(msg)
|
LOG.error(msg)
|
||||||
raise exception.InvalidGroup(reason=msg)
|
raise exception.InvalidGroup(reason=msg)
|
||||||
@ -335,12 +345,7 @@ class API(base.Base):
|
|||||||
{'group': group.id,
|
{'group': group.id,
|
||||||
'group_snap': group_snapshot.id})
|
'group_snap': group_snapshot.id})
|
||||||
|
|
||||||
volumes = objects.VolumeList.get_all_by_generic_group(context,
|
self._update_volumes_host(context, group)
|
||||||
group.id)
|
|
||||||
for vol in volumes:
|
|
||||||
# Update the host field for the volume.
|
|
||||||
vol.host = group.host
|
|
||||||
vol.save()
|
|
||||||
|
|
||||||
self.volume_rpcapi.create_group_from_src(
|
self.volume_rpcapi.create_group_from_src(
|
||||||
context, group, group_snapshot)
|
context, group, group_snapshot)
|
||||||
@ -418,12 +423,7 @@ class API(base.Base):
|
|||||||
{'group': group.id,
|
{'group': group.id,
|
||||||
'source_group': source_group.id})
|
'source_group': source_group.id})
|
||||||
|
|
||||||
volumes = objects.VolumeList.get_all_by_generic_group(context,
|
self._update_volumes_host(context, group)
|
||||||
group.id)
|
|
||||||
for vol in volumes:
|
|
||||||
# Update the host field for the volume.
|
|
||||||
vol.host = group.host
|
|
||||||
vol.save()
|
|
||||||
|
|
||||||
self.volume_rpcapi.create_group_from_src(context, group,
|
self.volume_rpcapi.create_group_from_src(context, group,
|
||||||
None, source_group)
|
None, source_group)
|
||||||
|
@ -500,6 +500,7 @@ class GroupAPITestCase(test.TestCase):
|
|||||||
vol1.destroy()
|
vol1.destroy()
|
||||||
grp_snap.destroy()
|
grp_snap.destroy()
|
||||||
|
|
||||||
|
@mock.patch('cinder.group.api.API._update_volumes_host')
|
||||||
@mock.patch('cinder.objects.VolumeType.get_by_name_or_id')
|
@mock.patch('cinder.objects.VolumeType.get_by_name_or_id')
|
||||||
@mock.patch('cinder.db.group_volume_type_mapping_create')
|
@mock.patch('cinder.db.group_volume_type_mapping_create')
|
||||||
@mock.patch('cinder.volume.api.API.create')
|
@mock.patch('cinder.volume.api.API.create')
|
||||||
@ -512,7 +513,8 @@ class GroupAPITestCase(test.TestCase):
|
|||||||
mock_snap_get_all, mock_group_snap_get,
|
mock_snap_get_all, mock_group_snap_get,
|
||||||
mock_volume_api_create,
|
mock_volume_api_create,
|
||||||
mock_mapping_create,
|
mock_mapping_create,
|
||||||
mock_get_volume_type):
|
mock_get_volume_type,
|
||||||
|
mock_update_volumes_host):
|
||||||
vol_type = fake_volume.fake_volume_type_obj(
|
vol_type = fake_volume.fake_volume_type_obj(
|
||||||
self.ctxt,
|
self.ctxt,
|
||||||
id=fake.VOLUME_TYPE_ID,
|
id=fake.VOLUME_TYPE_ID,
|
||||||
@ -566,12 +568,17 @@ class GroupAPITestCase(test.TestCase):
|
|||||||
mock_rpc_create_group_from_src.assert_called_once_with(
|
mock_rpc_create_group_from_src.assert_called_once_with(
|
||||||
self.ctxt, grp, grp_snap)
|
self.ctxt, grp, grp_snap)
|
||||||
|
|
||||||
|
mock_update_volumes_host.assert_called_once_with(
|
||||||
|
self.ctxt, grp
|
||||||
|
)
|
||||||
|
|
||||||
vol2.destroy()
|
vol2.destroy()
|
||||||
grp.destroy()
|
grp.destroy()
|
||||||
snap.destroy()
|
snap.destroy()
|
||||||
vol1.destroy()
|
vol1.destroy()
|
||||||
grp_snap.destroy()
|
grp_snap.destroy()
|
||||||
|
|
||||||
|
@mock.patch('cinder.group.api.API._update_volumes_host')
|
||||||
@mock.patch('cinder.objects.VolumeType.get_by_name_or_id')
|
@mock.patch('cinder.objects.VolumeType.get_by_name_or_id')
|
||||||
@mock.patch('cinder.db.group_volume_type_mapping_create')
|
@mock.patch('cinder.db.group_volume_type_mapping_create')
|
||||||
@mock.patch('cinder.volume.api.API.create')
|
@mock.patch('cinder.volume.api.API.create')
|
||||||
@ -583,7 +590,8 @@ class GroupAPITestCase(test.TestCase):
|
|||||||
mock_group_get,
|
mock_group_get,
|
||||||
mock_volume_api_create,
|
mock_volume_api_create,
|
||||||
mock_mapping_create,
|
mock_mapping_create,
|
||||||
mock_get_volume_type):
|
mock_get_volume_type,
|
||||||
|
mock_update_volumes_host):
|
||||||
vol_type = fake_volume.fake_volume_type_obj(
|
vol_type = fake_volume.fake_volume_type_obj(
|
||||||
self.ctxt,
|
self.ctxt,
|
||||||
id=fake.VOLUME_TYPE_ID,
|
id=fake.VOLUME_TYPE_ID,
|
||||||
@ -631,6 +639,10 @@ class GroupAPITestCase(test.TestCase):
|
|||||||
mock_rpc_create_group_from_src.assert_called_once_with(
|
mock_rpc_create_group_from_src.assert_called_once_with(
|
||||||
self.ctxt, grp2, None, grp)
|
self.ctxt, grp2, None, grp)
|
||||||
|
|
||||||
|
mock_update_volumes_host.assert_called_once_with(
|
||||||
|
self.ctxt, grp2
|
||||||
|
)
|
||||||
|
|
||||||
vol2.destroy()
|
vol2.destroy()
|
||||||
grp2.destroy()
|
grp2.destroy()
|
||||||
vol.destroy()
|
vol.destroy()
|
||||||
@ -781,6 +793,42 @@ class GroupAPITestCase(test.TestCase):
|
|||||||
self.ctxt, 'group', 'desc',
|
self.ctxt, 'group', 'desc',
|
||||||
group_snapshot_id=None, source_group_id=group.id)
|
group_snapshot_id=None, source_group_id=group.id)
|
||||||
|
|
||||||
|
@mock.patch('cinder.objects.volume.Volume.host',
|
||||||
|
new_callable=mock.PropertyMock)
|
||||||
|
@mock.patch('cinder.objects.volume.Volume.cluster_name',
|
||||||
|
new_callable=mock.PropertyMock)
|
||||||
|
@mock.patch('cinder.objects.VolumeList.get_all_by_generic_group')
|
||||||
|
def test_update_volumes_host(self, mock_volume_get_all, mock_cluster_name,
|
||||||
|
mock_host):
|
||||||
|
vol_type = utils.create_volume_type(self.ctxt, name='test_vol_type')
|
||||||
|
grp = utils.create_group(self.ctxt, group_type_id=fake.GROUP_TYPE_ID,
|
||||||
|
volume_type_ids=[vol_type['id']],
|
||||||
|
availability_zone='nova',
|
||||||
|
status=fields.GroupStatus.CREATING,
|
||||||
|
cluster_name='fake_cluster')
|
||||||
|
|
||||||
|
vol1 = utils.create_volume(
|
||||||
|
self.ctxt,
|
||||||
|
availability_zone=grp.availability_zone,
|
||||||
|
volume_type_id=fake.VOLUME_TYPE_ID,
|
||||||
|
group_id=grp.id)
|
||||||
|
|
||||||
|
mock_volume = mock.Mock()
|
||||||
|
mock_volume_get_all.return_value = [mock_volume]
|
||||||
|
group_api = cinder.group.api.API()
|
||||||
|
group_api._update_volumes_host(None, grp)
|
||||||
|
|
||||||
|
mock_cluster_name.assert_called()
|
||||||
|
mock_host.assert_called()
|
||||||
|
|
||||||
|
self.assertEqual(grp.host, mock_volume.host)
|
||||||
|
self.assertEqual(grp.cluster_name, mock_volume.cluster_name)
|
||||||
|
mock_volume.save.assert_called_once_with()
|
||||||
|
|
||||||
|
vol1.destroy()
|
||||||
|
|
||||||
|
grp.destroy()
|
||||||
|
|
||||||
def test_delete_group_frozen(self):
|
def test_delete_group_frozen(self):
|
||||||
service = utils.create_service(self.ctxt, {'frozen': True})
|
service = utils.create_service(self.ctxt, {'frozen': True})
|
||||||
group = utils.create_group(self.ctxt, host=service.host,
|
group = utils.create_group(self.ctxt, host=service.host,
|
||||||
|
Loading…
Reference in New Issue
Block a user