Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resource UUID context #286

Open
wants to merge 2 commits into
base: stable/rocky-m3
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion nova/compute/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2454,7 +2454,8 @@ def get(self, context, instance_id, expected_attrs=None):
except exception.InvalidID:
LOG.debug("Invalid instance id %s", instance_id)
raise exception.InstanceNotFound(instance_id=instance_id)

context.resource_id = instance.uuid
context.update_store()
return instance

def get_all(self, context, search_opts=None, limit=None, marker=None,
Expand Down
52 changes: 36 additions & 16 deletions nova/compute/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -697,9 +697,10 @@ def _destroy_evacuated_instances(self, context):
if inst.uuid in evacuations}

for instance in evacuated_local_instances.values():
context.resource_id = instance.uuid
context.update_store()
LOG.info('Destroying instance as it has been evacuated from '
'this host but still exists in the hypervisor',
instance=instance)
'this host but still exists in the hypervisor')
try:
network_info = self.network_api.get_instance_nw_info(
context, instance)
Expand All @@ -711,8 +712,7 @@ def _destroy_evacuated_instances(self, context):
network_info = network_model.NetworkInfo()
bdi = {}
LOG.info('Instance has been marked deleted already, '
'removing it from the hypervisor.',
instance=instance)
'removing it from the hypervisor.')
# always destroy disks if the instance was deleted
destroy_disks = True
self.driver.destroy(context, instance,
Expand All @@ -725,6 +725,8 @@ def _destroy_evacuated_instances(self, context):
compute_nodes = {}

for instance_uuid, migration in evacuations.items():
context.resource_id = instance_uuid
context.update_store()
try:
if instance_uuid in evacuated_local_instances:
# Avoid the db call if we already have the instance loaded
Expand All @@ -739,8 +741,7 @@ def _destroy_evacuated_instances(self, context):
continue

LOG.info('Cleaning up allocations of the instance as it has been '
'evacuated from this host',
instance=instance)
'evacuated from this host')
if migration.source_node not in compute_nodes:
try:
cn_uuid = objects.ComputeNode.get_by_host_and_nodename(
Expand All @@ -749,7 +750,7 @@ def _destroy_evacuated_instances(self, context):
except exception.ComputeHostNotFound:
LOG.error("Failed to clean allocation of evacuated "
"instance as the source node %s is not found",
migration.source_node, instance=instance)
migration.source_node)
continue
cn_uuid = compute_nodes[migration.source_node]

Expand All @@ -761,7 +762,7 @@ def _destroy_evacuated_instances(self, context):
context, instance, cn_uuid, self.reportclient)):
LOG.error("Failed to clean allocation of evacuated instance "
"on the source node %s",
cn_uuid, instance=instance)
cn_uuid)

migration.status = 'completed'
migration.save()
Expand Down Expand Up @@ -833,6 +834,8 @@ def _init_instance(self, context, instance):
'host': instance.host})
return

context.resource_id = instance.uuid
context.update_store()
# Instances that are shut down, or in an error state can not be
# initialized and are not attempted to be recovered. The exception
# to this are instances that are in RESIZE_MIGRATING or DELETING,
Expand Down Expand Up @@ -1955,6 +1958,9 @@ def build_and_run_instance(self, context, instance, image, request_spec,

@utils.synchronized(instance.uuid)
def _locked_do_build_and_run_instance(*args, **kwargs):
# NOTE(fwiesel): Spawned in a different thread, store the context
context.update_store()

# NOTE(danms): We grab the semaphore with the instance uuid
# locked because we could wait in line to build this instance
# for a while and we want to make sure that nothing else tries
Expand Down Expand Up @@ -7604,6 +7610,8 @@ def _poll_rescued_instances(self, context):
to_unrescue.append(instance)

for instance in to_unrescue:
context.resource_id = instance.uuid
context.update_store()
self.compute_api.unrescue(context, instance)

@periodic_task.periodic_task
Expand Down Expand Up @@ -7653,6 +7661,9 @@ def _set_migration_to_error(migration, reason, **kwargs):
_set_migration_to_error(migration, reason,
instance=instance)
continue

context.resource_id = instance.uuid
context.update_store()
# race condition: The instance in DELETING state should not be
# set the migration state to error, otherwise the instance in
# to be deleted which is in RESIZED state
Expand All @@ -7661,7 +7672,7 @@ def _set_migration_to_error(migration, reason, **kwargs):
task_states.SOFT_DELETING]:
msg = ("Instance being deleted or soft deleted during resize "
"confirmation. Skipping.")
LOG.debug(msg, instance=instance)
LOG.debug(msg)
continue

# race condition: This condition is hit when this method is
Expand All @@ -7671,7 +7682,7 @@ def _set_migration_to_error(migration, reason, **kwargs):
if instance.task_state == task_states.RESIZE_FINISH:
msg = ("Instance still resizing during resize "
"confirmation. Skipping.")
LOG.debug(msg, instance=instance)
LOG.debug(msg)
continue

vm_state = instance.vm_state
Expand All @@ -7689,7 +7700,7 @@ def _set_migration_to_error(migration, reason, **kwargs):
migration=migration)
except Exception as e:
LOG.info("Error auto-confirming resize: %s. "
"Will retry later.", e, instance=instance)
"Will retry later.", e)

@periodic_task.periodic_task(spacing=CONF.shelved_poll_interval)
def _poll_shelved_instances(self, context):
Expand All @@ -7712,6 +7723,8 @@ def _poll_shelved_instances(self, context):
to_gc.append(instance)

for instance in to_gc:
context.resource_id = instance.uuid
context.update_store()
try:
instance.task_state = task_states.SHELVING_OFFLOADING
instance.save(expected_task_state=(None,))
Expand Down Expand Up @@ -7948,6 +7961,9 @@ def _sync_power_states(self, context):
'num_vm_instances': num_vm_instances})

def _sync(db_instance):
context.resource_uuid = db_instance.uuid
context.update_store()

# NOTE(melwitt): This must be synchronized as we query state from
# two separate sources, the driver and the database.
# They are set (in stop_instance) and read, in sync.
Expand Down Expand Up @@ -8278,13 +8294,14 @@ def _reclaim_queued_deletes(self, context):
if self._deleted_old_enough(instance, interval):
bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
context, instance.uuid)
LOG.info('Reclaiming deleted instance', instance=instance)
context.resource_id = instance.uuid
context.update_store()
LOG.info('Reclaiming deleted instance')
try:
self._delete_instance(context, instance, bdms)
except Exception as e:
LOG.warning("Periodic reclaim failed to delete "
"instance: %s",
e, instance=instance)
"instance: %s", e)

def _get_nodename(self, instance, refresh=False):
"""Helper method to get the name of the first available node
Expand Down Expand Up @@ -8739,11 +8756,12 @@ def _run_pending_deletes(self, context):

for instance in instances:
attempts = int(instance.system_metadata.get('clean_attempts', '0'))
context.resource_id = instance.uuid
context.update_store()
LOG.debug('Instance has had %(attempts)s of %(max)s '
'cleanup attempts',
{'attempts': attempts,
'max': CONF.maximum_instance_delete_attempts},
instance=instance)
'max': CONF.maximum_instance_delete_attempts})
if attempts < CONF.maximum_instance_delete_attempts:
success = self.driver.delete_instance_files(instance)

Expand Down Expand Up @@ -8784,6 +8802,8 @@ def _cleanup_incomplete_migrations(self, context):
if instance.host != CONF.host:
for migration in migrations:
if instance.uuid == migration.instance_uuid:
context.resource_id = instance.uuid
context.update_store()
# Delete instance files if not cleanup properly either
# from the source or destination compute nodes when
# the instance is deleted during resizing.
Expand Down
8 changes: 6 additions & 2 deletions nova/conductor/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,8 @@ def build_instances(self, context, instances, image, filter_properties,

elevated = context.elevated()
for (instance, host_list) in six.moves.zip(instances, host_lists):
context.resource_uuid = instance.uuid
context.update_store()
host = host_list.pop(0)
if is_reschedule:
# If this runs in the superconductor, the first instance will
Expand Down Expand Up @@ -775,7 +777,7 @@ def build_instances(self, context, instances, image, filter_properties,

alts = [(alt.service_host, alt.nodename) for alt in host_list]
LOG.debug("Selected host: %s; Selected node: %s; Alternates: %s",
host.service_host, host.nodename, alts, instance=instance)
joker-at-work marked this conversation as resolved.
Show resolved Hide resolved
host.service_host, host.nodename, alts)

self.compute_rpcapi.build_and_run_instance(context,
instance=instance, host=host.service_host, image=image,
Expand Down Expand Up @@ -1375,13 +1377,15 @@ def schedule_and_build_instances(self, context, build_requests,
# Skip placeholders that were buried in cell0 or had their
# build requests deleted by the user before instance create.
continue
context.resource_uuid = instance.uuid
context.update_store()
cell = cell_mapping_cache[instance.uuid]
# host_list is a list of one or more Selection objects, the first
# of which has been selected and its resources claimed.
host = host_list.pop(0)
alts = [(alt.service_host, alt.nodename) for alt in host_list]
LOG.debug("Selected host: %s; Selected node: %s; Alternates: %s",
host.service_host, host.nodename, alts, instance=instance)
fwiesel marked this conversation as resolved.
Show resolved Hide resolved
host.service_host, host.nodename, alts)
filter_props = request_spec.to_legacy_filter_properties_dict()
scheduler_utils.populate_retry(filter_props, instance.uuid)
scheduler_utils.populate_filter_properties(filter_props,
Expand Down
1 change: 1 addition & 0 deletions nova/tests/unit/compute/test_compute.py
Original file line number Diff line number Diff line change
Expand Up @@ -7882,6 +7882,7 @@ def test_init_instance_for_partial_deletion(self):
admin_context = context.get_admin_context()
instance = objects.Instance(admin_context)
instance.id = 1
instance.uuid = uuids.fake
instance.vm_state = vm_states.DELETED
instance.deleted = False
instance.host = self.compute.host
Expand Down
27 changes: 23 additions & 4 deletions nova/tests/unit/compute/test_compute_mgr.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,23 @@
fake_host_list = [mock.sentinel.host1]


class _PropertiesChanged(object):
def __init__(self, obj, properties):
self._obj = obj
self._properties = properties

def __eq__(self, other):
if self._obj is not other:
return False
try:
for key, value in six.iteritems(self._properties):
if getattr(other, key) != value:
return False
return True
except KeyError:
return False


@ddt.ddt
class ComputeManagerUnitTestCase(test.NoDBTestCase):
def setUp(self):
Expand Down Expand Up @@ -1193,7 +1210,7 @@ def test_init_instance_failed_resume_sets_error(self, mock_set_inst,
power_state.SHUTDOWN)
mock_get_inst.return_value = 'fake-bdm'
mock_resume.side_effect = test.TestingException
self.compute._init_instance('fake-context', instance)
self.compute._init_instance(self.context, instance)
mock_get_power.assert_has_calls([mock.call(mock.ANY, instance),
mock.call(mock.ANY, instance)])
mock_plug.assert_called_once_with(instance, mock.ANY)
Expand Down Expand Up @@ -1271,7 +1288,7 @@ def test_init_instance_complete_partial_deletion_raises_exception(
with mock.patch.object(self.compute,
'_complete_partial_deletion') as mock_deletion:
mock_deletion.side_effect = test.TestingException()
self.compute._init_instance(self, instance)
self.compute._init_instance(self.context, instance)
msg = u'Failed to complete a deletion'
mock_log.exception.assert_called_once_with(msg, instance=instance)

Expand Down Expand Up @@ -2148,8 +2165,10 @@ def save(self):
pass

def _fake_get(ctx, filter, expected_attrs, use_slave):
changed_ctx = _PropertiesChanged(ctx, {'read_deleted': 'yes'},)

mock_get.assert_called_once_with(
{'read_deleted': 'yes'},
changed_ctx,
{'deleted': True, 'soft_deleted': False, 'host': 'fake-mini',
'cleaned': False},
expected_attrs=['system_metadata'],
Expand All @@ -2163,7 +2182,7 @@ def _fake_get(ctx, filter, expected_attrs, use_slave):
mock_get.side_effect = _fake_get
mock_delete.side_effect = [True, False]

self.compute._run_pending_deletes({})
self.compute._run_pending_deletes(self.context)

self.assertFalse(a.cleaned)
self.assertEqual('100', a.system_metadata['clean_attempts'])
Expand Down
Loading