Don't persist RequestSpec.retry

During a resize, the RequestSpec.flavor is updated
to the new flavor. If the resize failed on one host
and was rescheduled, the RequestSpec.retry is updated
for that failed host and mistakenly persisted, which
can affect later move operations, like if an admin
targets one of those previously failed hosts for a
live migration or evacuate operation.

This change fixes the problem by not ever persisting
the RequestSpec.retry field to the database, since
retries are per-request/operation and not something
that needs to be persisted.

Alternative to this, we could reset the retry field
in the RequestSpec.reset_forced_destinations method
but that would be slightly overloading the meaning
of that method, and the approach taken in this patch
is arguably cleaner since retries shouldn't ever be
persisted. It should be noted, however, that one
advantage to resetting the 'retry' field in the
RequestSpec.reset_forced_destinations method would
be to avoid this issue for any existing DB entries
that have this problem.

The related functional regression test is updated
to show the bug is now fixed.

Change-Id: Iadbf8ec935565a6d4ccf6f36ef630ab6bf1bea5d
Closes-Bug: #1718512
This commit is contained in:
Matt Riedemann 2018-04-06 20:28:53 -04:00
parent 89448bea57
commit 6647f11dc1
3 changed files with 8 additions and 9 deletions

View File

@ -510,6 +510,9 @@ class RequestSpec(base.NovaObject):
if 'instance_group' in spec and spec.instance_group:
spec.instance_group.members = None
spec.instance_group.hosts = None
# NOTE(mriedem): Don't persist retries since those are per-request
if 'retry' in spec and spec.retry:
spec.retry = None
db_updates = {'spec': jsonutils.dumps(spec.obj_to_primitive())}
if 'instance_uuid' in updates:

View File

@ -142,17 +142,12 @@ class TestRequestSpecRetryReschedule(test.TestCase,
data = {'os-migrateLive': {'host': 'host2', 'block_migration': 'auto'}}
self.admin_api.post_server_action(server['id'], data)
server = self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
# FIXME(mriedem): This is bug 1718512 where the failed resize left
# host2 in the RequestSpec.retry field and it affects the live migrate
# to host2 because the scheduler RetryFilter kicks it out.
self.assertEqual('host3', server['OS-EXT-SRV-ATTR:host'])
self.assertEqual('host2', server['OS-EXT-SRV-ATTR:host'])
migrations = self.admin_api.api_get(
'os-migrations?instance_uuid=%s&migration_type=live-migration' %
server['id']).body['migrations']
self.assertEqual(1, len(migrations))
self.assertEqual('error', migrations[0]['status'])
self.assertEqual('completed', migrations[0]['status'])
reqspec = objects.RequestSpec.get_by_instance_uuid(
nova_context.get_admin_context(), server['id'])
self.assertIsNotNone(reqspec.retry)
self.assertEqual(1, reqspec.retry.num_attempts)
self.assertEqual('host2', reqspec.retry.hosts[0].host)
self.assertIsNone(reqspec.retry)

View File

@ -535,13 +535,14 @@ class _TestRequestSpecObject(object):
# object fields
for field in ['image', 'numa_topology', 'pci_requests', 'flavor',
'retry', 'limits']:
'limits']:
self.assertEqual(
getattr(req_obj, field).obj_to_primitive(),
getattr(serialized_obj, field).obj_to_primitive())
self.assertIsNone(serialized_obj.instance_group.members)
self.assertIsNone(serialized_obj.instance_group.hosts)
self.assertIsNone(serialized_obj.retry)
def test_create(self):
req_obj = fake_request_spec.fake_spec_obj(remove_id=True)