Merge "Delete instance_group_member records from API DB during archive" into stable/rocky

This commit is contained in:
Zuul 2018-09-21 12:01:46 +00:00 committed by Gerrit Code Review
commit 1f1482eb7d
4 changed files with 84 additions and 12 deletions

View File

@ -551,12 +551,18 @@ Error: %s""") % six.text_type(e))
if deleted_instance_uuids:
table_to_rows_archived.setdefault('instance_mappings', 0)
table_to_rows_archived.setdefault('request_specs', 0)
table_to_rows_archived.setdefault('instance_group_member', 0)
deleted_mappings = objects.InstanceMappingList.destroy_bulk(
ctxt, deleted_instance_uuids)
table_to_rows_archived['instance_mappings'] += deleted_mappings
deleted_specs = objects.RequestSpec.destroy_bulk(
ctxt, deleted_instance_uuids)
table_to_rows_archived['request_specs'] += deleted_specs
deleted_group_members = (
objects.InstanceGroup.destroy_members_bulk(
ctxt, deleted_instance_uuids))
table_to_rows_archived['instance_group_member'] += (
deleted_group_members)
if not until_complete:
break
elif not run:

View File

@ -337,6 +337,17 @@ class InstanceGroup(base.NovaPersistentObject, base.NovaObject,
in_(set(instance_uuids))).\
delete(synchronize_session=False)
@staticmethod
@db_api.api_context_manager.writer
def _destroy_members_bulk_in_db(context, instance_uuids):
return context.session.query(api_models.InstanceGroupMember).filter(
api_models.InstanceGroupMember.instance_uuid.in_(instance_uuids)).\
delete(synchronize_session=False)
@classmethod
def destroy_members_bulk(cls, context, instance_uuids):
return cls._destroy_members_bulk_in_db(context, instance_uuids)
def obj_load_attr(self, attrname):
# NOTE(sbauza): Only hosts could be lazy-loaded right now
if attrname != 'hosts':

View File

@ -738,3 +738,53 @@ class TestNovaManagePlacementSyncAggregates(
rp_aggregates = self._get_provider_aggregates(rp_uuid)
self.assertEqual(2, len(rp_aggregates),
'%s should be in two provider aggregates' % host)
class TestDBArchiveDeletedRows(integrated_helpers._IntegratedTestBase):
"""Functional tests for the "nova-manage db archive_deleted_rows" CLI."""
USE_NEUTRON = True
api_major_version = 'v2.1'
_image_ref_parameter = 'imageRef'
_flavor_ref_parameter = 'flavorRef'
def setUp(self):
super(TestDBArchiveDeletedRows, self).setUp()
self.cli = manage.DbCommands()
self.output = StringIO()
self.useFixture(fixtures.MonkeyPatch('sys.stdout', self.output))
def test_archive_instance_group_members(self):
"""Tests that instance_group_member records in the API DB are deleted
when a server group member instance is archived.
"""
# Create a server group.
group = self.api.post_server_groups(
{'name': 'test_archive_instance_group_members',
'policies': ['affinity']})
# Create two servers in the group.
server = self._build_minimal_create_server_request()
server['min_count'] = 2
server_req = {
'server': server, 'os:scheduler_hints': {'group': group['id']}}
# Since we don't pass return_reservation_id=True we get the first
# server back in the response. We're also using the CastAsCall fixture
# (from the base class) fixture so we don't have to worry about the
# server being ACTIVE.
server = self.api.post_server(server_req)
# Assert we have two group members.
self.assertEqual(
2, len(self.api.get_server_group(group['id'])['members']))
# Now delete one server and then we can archive.
server = self.api.get_server(server['id'])
self.api.delete_server(server['id'])
helper = integrated_helpers.InstanceHelperMixin()
helper.api = self.api
helper._wait_until_deleted(server)
# Now archive.
self.cli.archive_deleted_rows(verbose=True)
# Assert only one instance_group_member record was deleted.
self.assertRegexpMatches(self.output.getvalue(),
".*instance_group_member.*\| 1.*")
# And that we still have one remaining group member.
self.assertEqual(
1, len(self.api.get_server_group(group['id'])['members']))

View File

@ -510,8 +510,10 @@ Rows were archived, running purge...
@mock.patch.object(db, 'archive_deleted_rows')
@mock.patch.object(objects.RequestSpec, 'destroy_bulk')
def test_archive_deleted_rows_and_instance_mappings_and_request_specs(self,
mock_destroy, mock_db_archive, verbose=True):
@mock.patch.object(objects.InstanceGroup, 'destroy_members_bulk')
def test_archive_deleted_rows_and_api_db_records(
self, mock_members_destroy, mock_reqspec_destroy, mock_db_archive,
verbose=True):
self.useFixture(nova_fixtures.Database())
self.useFixture(nova_fixtures.Database(database='api'))
@ -533,24 +535,27 @@ Rows were archived, running purge...
.create()
mock_db_archive.return_value = (dict(instances=2, consoles=5), uuids)
mock_destroy.return_value = 2
mock_reqspec_destroy.return_value = 2
mock_members_destroy.return_value = 0
result = self.commands.archive_deleted_rows(20, verbose=verbose)
self.assertEqual(1, result)
mock_db_archive.assert_called_once_with(20)
self.assertEqual(1, mock_destroy.call_count)
self.assertEqual(1, mock_reqspec_destroy.call_count)
mock_members_destroy.assert_called_once()
output = self.output.getvalue()
if verbose:
expected = '''\
+-------------------+-------------------------+
| Table | Number of Rows Archived |
+-------------------+-------------------------+
| consoles | 5 |
| instance_mappings | 2 |
| instances | 2 |
| request_specs | 2 |
+-------------------+-------------------------+
+-----------------------+-------------------------+
| Table | Number of Rows Archived |
+-----------------------+-------------------------+
| consoles | 5 |
| instance_group_member | 0 |
| instance_mappings | 2 |
| instances | 2 |
| request_specs | 2 |
+-----------------------+-------------------------+
'''
self.assertEqual(expected, output)
else: