From f66bd7369a86b1833cd146de67c4337ea150f087 Mon Sep 17 00:00:00 2001 From: Takashi NATSUME Date: Fri, 5 Jan 2018 10:18:47 +0900 Subject: [PATCH] [placement] Add sending global request ID in put (3) Add the 'X-Openstack-Request-Id' header in the request of PUT in SchedulerReportClient. When removing a resource provider from an instance allocation and putting allocations to a resource provider, the header is added. Subsequent patches will add the header in the other cases. Change-Id: I7891b98f225f97ad47f189afb9110ef31c810717 Partial-Bug: #1734625 --- nova/compute/manager.py | 11 ++- nova/compute/resource_tracker.py | 21 +++-- nova/conductor/tasks/live_migrate.py | 4 +- nova/scheduler/client/report.py | 45 +++++---- nova/scheduler/utils.py | 7 +- .../openstack/placement/test_report_client.py | 24 +++-- nova/tests/unit/compute/test_compute_mgr.py | 27 +++--- .../unit/compute/test_resource_tracker.py | 7 +- .../unit/scheduler/client/test_report.py | 92 ++++++++++++------- 9 files changed, 146 insertions(+), 92 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index cb26c41ef21c..4a83b7440f6e 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -697,7 +697,7 @@ class ComputeManager(manager.Manager): cn_uuid = compute_nodes[migration.source_node] if not scheduler_utils.remove_allocation_from_compute( - instance, cn_uuid, self.reportclient): + context, instance, cn_uuid, self.reportclient): LOG.error("Failed to clean allocation of evacuated instance " "on the source node %s", cn_uuid, instance=instance) @@ -2901,7 +2901,7 @@ class ComputeManager(manager.Manager): # on the same host (not evacuate) uses the NopClaim which will # not raise ComputeResourcesUnavailable. rt.delete_allocation_for_evacuated_instance( - instance, scheduled_node, node_type='destination') + context, instance, scheduled_node, node_type='destination') self._notify_instance_rebuild_error(context, instance, e, bdms) raise exception.BuildAbortException( instance_uuid=instance.uuid, reason=e.format_message()) @@ -2915,7 +2915,8 @@ class ComputeManager(manager.Manager): self._set_migration_status(migration, 'failed') if recreate or scheduled_node is not None: rt.delete_allocation_for_evacuated_instance( - instance, scheduled_node, node_type='destination') + context, instance, scheduled_node, + node_type='destination') self._notify_instance_rebuild_error(context, instance, e, bdms) raise else: @@ -3829,7 +3830,7 @@ class ComputeManager(manager.Manager): # any shared providers in the case of a confirm_resize operation and # the source host and shared providers for a revert_resize operation.. if not scheduler_utils.remove_allocation_from_compute( - instance, cn_uuid, self.reportclient, flavor): + context, instance, cn_uuid, self.reportclient, flavor): LOG.error("Failed to save manipulated allocation", instance=instance) @@ -6288,7 +6289,7 @@ class ComputeManager(manager.Manager): # attempt to clean up any doubled per-instance allocation rt = self._get_resource_tracker() rt.delete_allocation_for_migrated_instance( - instance, source_node) + ctxt, instance, source_node) def _consoles_enabled(self): """Returns whether a console is enable.""" diff --git a/nova/compute/resource_tracker.py b/nova/compute/resource_tracker.py index ef2b26b44b30..bedcc546052a 100644 --- a/nova/compute/resource_tracker.py +++ b/nova/compute/resource_tracker.py @@ -894,7 +894,7 @@ class ResourceTracker(object): # that the resource provider exists in the tree and has had its # cached traits refreshed. self.reportclient.set_traits_for_provider( - compute_node.uuid, traits) + context, compute_node.uuid, traits) if self.pci_tracker: self.pci_tracker.save(context) @@ -1316,27 +1316,30 @@ class ResourceTracker(object): "host that might need to be removed: %s.", instance_uuid, instance.host, instance.node, alloc) - def delete_allocation_for_evacuated_instance(self, instance, node, + def delete_allocation_for_evacuated_instance(self, context, instance, node, node_type='source'): self._delete_allocation_for_moved_instance( - instance, node, 'evacuated', node_type) + context, instance, node, 'evacuated', node_type) - def delete_allocation_for_migrated_instance(self, instance, node): - self._delete_allocation_for_moved_instance(instance, node, 'migrated') + def delete_allocation_for_migrated_instance(self, context, instance, node): + self._delete_allocation_for_moved_instance(context, instance, node, + 'migrated') def _delete_allocation_for_moved_instance( - self, instance, node, move_type, node_type='source'): + self, context, instance, node, move_type, node_type='source'): # Clean up the instance allocation from this node in placement cn_uuid = self.compute_nodes[node].uuid if not scheduler_utils.remove_allocation_from_compute( - instance, cn_uuid, self.reportclient): + context, instance, cn_uuid, self.reportclient): LOG.error("Failed to clean allocation of %s " "instance on the %s node %s", move_type, node_type, cn_uuid, instance=instance) - def delete_allocation_for_failed_resize(self, instance, node, flavor): + def delete_allocation_for_failed_resize(self, context, instance, node, + flavor): """Delete instance allocations for the node during a failed resize + :param context: The request context. :param instance: The instance being resized/migrated. :param node: The node provider on which the instance should have allocations to remove. If this is a resize to the same host, then @@ -1345,7 +1348,7 @@ class ResourceTracker(object): """ cn = self.compute_nodes[node] if not scheduler_utils.remove_allocation_from_compute( - instance, cn.uuid, self.reportclient, flavor): + context, instance, cn.uuid, self.reportclient, flavor): if instance.instance_type_id == flavor.id: operation = 'migration' else: diff --git a/nova/conductor/tasks/live_migrate.py b/nova/conductor/tasks/live_migrate.py index 77400ea7a95f..52383acd736b 100644 --- a/nova/conductor/tasks/live_migrate.py +++ b/nova/conductor/tasks/live_migrate.py @@ -376,8 +376,8 @@ class LiveMigrationTask(base.TaskBase): # allocated for the given (destination) node. self.scheduler_client.reportclient.\ remove_provider_from_instance_allocation( - self.instance.uuid, compute_node.uuid, self.instance.user_id, - self.instance.project_id, resources) + self.context, self.instance.uuid, compute_node.uuid, + self.instance.user_id, self.instance.project_id, resources) def _check_not_over_max_retries(self, attempted_hosts): if CONF.migrate_max_retries == -1: diff --git a/nova/scheduler/client/report.py b/nova/scheduler/client/report.py index 4e29fc6963ea..40f5014a9d11 100644 --- a/nova/scheduler/client/report.py +++ b/nova/scheduler/client/report.py @@ -1054,9 +1054,10 @@ class SchedulerReportClient(object): self._delete_inventory(context, rp_uuid) @safe_connect - def _ensure_traits(self, traits): + def _ensure_traits(self, context, traits): """Make sure all specified traits exist in the placement service. + :param context: The security context :param traits: Iterable of trait strings to ensure exist. :raises: TraitCreationFailed if traits contains a trait that did not exist in placement, and couldn't be created. When this @@ -1082,7 +1083,8 @@ class SchedulerReportClient(object): # Might be neat to have a batch create. But creating multiple # traits will generally happen once, at initial startup, if at all. for trait in traits_to_create: - resp = self.put('/traits/' + trait, None, version='1.6') + resp = self.put('/traits/' + trait, None, version='1.6', + global_request_id=context.global_id) if not resp: raise exception.TraitCreationFailed(name=trait, error=resp.text) @@ -1100,11 +1102,12 @@ class SchedulerReportClient(object): raise exception.TraitRetrievalFailed(error=resp.text) @safe_connect - def set_traits_for_provider(self, rp_uuid, traits): + def set_traits_for_provider(self, context, rp_uuid, traits): """Replace a provider's traits with those specified. The provider must exist - this method does not attempt to create it. + :param context: The security context :param rp_uuid: The UUID of the provider whose traits are to be updated :param traits: Iterable of traits to set on the provider :raises: ResourceProviderUpdateConflict if the provider's generation @@ -1122,7 +1125,7 @@ class SchedulerReportClient(object): if not self._provider_tree.have_traits_changed(rp_uuid, traits): return - self._ensure_traits(traits) + self._ensure_traits(context, traits) url = '/resource_providers/%s/traits' % rp_uuid # NOTE(efried): Don't use the DELETE API when traits is empty, because @@ -1134,7 +1137,8 @@ class SchedulerReportClient(object): 'resource_provider_generation': generation, 'traits': traits, } - resp = self.put(url, payload, version='1.6') + resp = self.put(url, payload, version='1.6', + global_request_id=context.global_id) if resp.status_code == 200: json = resp.json() @@ -1165,11 +1169,12 @@ class SchedulerReportClient(object): raise exception.ResourceProviderUpdateFailed(url=url, error=resp.text) @safe_connect - def set_aggregates_for_provider(self, rp_uuid, aggregates): + def set_aggregates_for_provider(self, context, rp_uuid, aggregates): """Replace a provider's aggregates with those specified. The provider must exist - this method does not attempt to create it. + :param context: The security context :param rp_uuid: The UUID of the provider whose aggregates are to be updated. :param aggregates: Iterable of aggregates to set on the provider. @@ -1178,7 +1183,8 @@ class SchedulerReportClient(object): # TODO(efried): Handle generation conflicts when supported by placement url = '/resource_providers/%s/aggregates' % rp_uuid aggregates = list(aggregates) if aggregates else [] - resp = self.put(url, aggregates, version='1.1') + resp = self.put(url, aggregates, version='1.1', + global_request_id=context.global_id) if resp.status_code == 200: placement_aggs = resp.json()['aggregates'] @@ -1268,7 +1274,7 @@ class SchedulerReportClient(object): return allocations.get( rp_uuid, {}).get('resources', {}) - def _allocate_for_instance(self, rp_uuid, instance): + def _allocate_for_instance(self, context, rp_uuid, instance): my_allocations = _instance_to_allocations_dict(instance) current_allocations = self.get_allocations_for_consumer_by_provider( rp_uuid, instance.uuid) @@ -1282,8 +1288,9 @@ class SchedulerReportClient(object): LOG.debug('Sending allocation for instance %s', my_allocations, instance=instance) - res = self.put_allocations(rp_uuid, instance.uuid, my_allocations, - instance.project_id, instance.user_id) + res = self.put_allocations(context, rp_uuid, instance.uuid, + my_allocations, instance.project_id, + instance.user_id) if res: LOG.info('Submitted allocation for instance', instance=instance) @@ -1383,8 +1390,8 @@ class SchedulerReportClient(object): return r.status_code == 204 @safe_connect - def remove_provider_from_instance_allocation(self, consumer_uuid, rp_uuid, - user_id, project_id, + def remove_provider_from_instance_allocation(self, context, consumer_uuid, + rp_uuid, user_id, project_id, resources): """Grabs an allocation for a particular consumer UUID, strips parts of the allocation that refer to a supplied resource provider UUID, and @@ -1400,6 +1407,7 @@ class SchedulerReportClient(object): subtract resources from the single allocation to ensure we do not exceed the reserved or max_unit amounts for the resource on the host. + :param context: The security context :param consumer_uuid: The instance/consumer UUID :param rp_uuid: The UUID of the provider whose resources we wish to remove from the consumer's allocation @@ -1472,7 +1480,8 @@ class SchedulerReportClient(object): LOG.debug("Sending updated allocation %s for instance %s after " "removing resources for %s.", new_allocs, consumer_uuid, rp_uuid) - r = self.put(url, payload, version='1.10') + r = self.put(url, payload, version='1.10', + global_request_id=context.global_id) if r.status_code != 204: LOG.warning("Failed to save allocation for %s. Got HTTP %s: %s", consumer_uuid, r.status_code, r.text) @@ -1548,8 +1557,8 @@ class SchedulerReportClient(object): @safe_connect @retries - def put_allocations(self, rp_uuid, consumer_uuid, alloc_data, project_id, - user_id): + def put_allocations(self, context, rp_uuid, consumer_uuid, alloc_data, + project_id, user_id): """Creates allocation records for the supplied instance UUID against the supplied resource provider. @@ -1557,6 +1566,7 @@ class SchedulerReportClient(object): Once shared storage and things like NUMA allocations are a reality, this will change to allocate against multiple providers. + :param context: The security context :param rp_uuid: The UUID of the resource provider to allocate against. :param consumer_uuid: The instance's UUID. :param alloc_data: Dict, keyed by resource class, of amounts to @@ -1580,7 +1590,8 @@ class SchedulerReportClient(object): 'user_id': user_id, } url = '/allocations/%s' % consumer_uuid - r = self.put(url, payload, version='1.8') + r = self.put(url, payload, version='1.8', + global_request_id=context.global_id) if r.status_code != 204: # NOTE(jaypipes): Yes, it sucks doing string comparison like this # but we have no error codes, only error messages. @@ -1619,7 +1630,7 @@ class SchedulerReportClient(object): def update_instance_allocation(self, context, compute_node, instance, sign): if sign > 0: - self._allocate_for_instance(compute_node.uuid, instance) + self._allocate_for_instance(context, compute_node.uuid, instance) else: self.delete_allocation_for_instance(context, instance.uuid) diff --git a/nova/scheduler/utils.py b/nova/scheduler/utils.py index 01591c5d6432..190d8dd87bd9 100644 --- a/nova/scheduler/utils.py +++ b/nova/scheduler/utils.py @@ -797,10 +797,11 @@ def claim_resources(ctx, client, spec_obj, instance_uuid, alloc_req, user_id, allocation_request_version=allocation_request_version) -def remove_allocation_from_compute(instance, compute_node_uuid, reportclient, - flavor=None): +def remove_allocation_from_compute(context, instance, compute_node_uuid, + reportclient, flavor=None): """Removes the instance allocation from the compute host. + :param context: The request context :param instance: the instance object owning the allocation :param compute_node_uuid: the UUID of the compute node where the allocation needs to be removed @@ -817,5 +818,5 @@ def remove_allocation_from_compute(instance, compute_node_uuid, reportclient, my_resources = resources_from_flavor(instance, flavor) return reportclient.remove_provider_from_instance_allocation( - instance.uuid, compute_node_uuid, instance.user_id, + context, instance.uuid, compute_node_uuid, instance.user_id, instance.project_id, my_resources) diff --git a/nova/tests/functional/api/openstack/placement/test_report_client.py b/nova/tests/functional/api/openstack/placement/test_report_client.py index 93b925c79a7a..a1f321db0132 100644 --- a/nova/tests/functional/api/openstack/placement/test_report_client.py +++ b/nova/tests/functional/api/openstack/placement/test_report_client.py @@ -331,7 +331,8 @@ class SchedulerReportClientTests(test.TestCase): self.client.update_compute_node(self.context, self.compute_node) # The compute node is associated with two of the shared storages self.client.set_aggregates_for_provider( - self.compute_uuid, set([uuids.agg_disk_1, uuids.agg_disk_2])) + self.context, self.compute_uuid, + set([uuids.agg_disk_1, uuids.agg_disk_2])) # Register two SR-IOV PFs with VF and bandwidth inventory for x in (1, 2): @@ -357,10 +358,11 @@ class SchedulerReportClientTests(test.TestCase): }, }, parent_provider_uuid=self.compute_uuid) # They're associated with an IP address aggregate - self.client.set_aggregates_for_provider(uuid, [uuids.agg_ip]) + self.client.set_aggregates_for_provider(self.context, uuid, + [uuids.agg_ip]) # Set some traits on 'em self.client.set_traits_for_provider( - uuid, ['CUSTOM_PHYSNET_%d' % x]) + self.context, uuid, ['CUSTOM_PHYSNET_%d' % x]) # Register three shared storage pools with disk inventory for x in (1, 2, 3): @@ -379,11 +381,12 @@ class SchedulerReportClientTests(test.TestCase): }) # Mark as a sharing provider self.client.set_traits_for_provider( - uuid, ['MISC_SHARES_VIA_AGGREGATE']) + self.context, uuid, ['MISC_SHARES_VIA_AGGREGATE']) # Associate each with its own aggregate. The compute node is # associated with the first two (agg_disk_1 and agg_disk_2). agg = getattr(uuids, 'agg_disk_%d' % x) - self.client.set_aggregates_for_provider(uuid, [agg]) + self.client.set_aggregates_for_provider(self.context, uuid, + [agg]) # Register a shared IP address provider with IP address inventory self.client.set_inventory_for_provider( @@ -399,9 +402,11 @@ class SchedulerReportClientTests(test.TestCase): }) # Mark as a sharing provider, and add another trait self.client.set_traits_for_provider( - uuids.sip, set(['MISC_SHARES_VIA_AGGREGATE', 'CUSTOM_FOO'])) + self.context, uuids.sip, + set(['MISC_SHARES_VIA_AGGREGATE', 'CUSTOM_FOO'])) # It's associated with the same aggregate as both PFs - self.client.set_aggregates_for_provider(uuids.sip, [uuids.agg_ip]) + self.client.set_aggregates_for_provider(self.context, uuids.sip, + [uuids.agg_ip]) # Register a shared network bandwidth provider self.client.set_inventory_for_provider( @@ -417,9 +422,10 @@ class SchedulerReportClientTests(test.TestCase): }) # Mark as a sharing provider self.client.set_traits_for_provider( - uuids.sbw, ['MISC_SHARES_VIA_AGGREGATE']) + self.context, uuids.sbw, ['MISC_SHARES_VIA_AGGREGATE']) # It's associated with some other aggregate. - self.client.set_aggregates_for_provider(uuids.sbw, [uuids.agg_bw]) + self.client.set_aggregates_for_provider(self.context, uuids.sbw, + [uuids.agg_bw]) # Setup is done. Grab the ProviderTree prov_tree = self.client.get_provider_tree_and_ensure_root( diff --git a/nova/tests/unit/compute/test_compute_mgr.py b/nova/tests/unit/compute/test_compute_mgr.py index d026bfd9e44f..c24328db549c 100644 --- a/nova/tests/unit/compute/test_compute_mgr.py +++ b/nova/tests/unit/compute/test_compute_mgr.py @@ -725,7 +725,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): self.compute.init_host() mock_remove_allocation.assert_called_once_with( - deleted_instance.uuid, uuids.our_node_uuid, + self.context, deleted_instance.uuid, uuids.our_node_uuid, deleted_instance.user_id, deleted_instance.project_id, mock.sentinel.my_resources) @@ -3592,8 +3592,8 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): get_node.assert_called_once_with( self.context, our_host, migration.source_node) remove_allocation.assert_called_once_with( - instance_2.uuid, uuids.our_node_uuid, uuids.user_id, - uuids.project_id, mock.sentinel.resources) + self.context, instance_2.uuid, uuids.our_node_uuid, + uuids.user_id, uuids.project_id, mock.sentinel.resources) def test_destroy_evacuated_instances_node_deleted(self): our_host = self.compute.host @@ -3669,8 +3669,8 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): # but only instance_2 is deallocated as the compute node for # instance_1 is already deleted remove_allocation.assert_called_once_with( - instance_2.uuid, uuids.our_node_uuid, uuids.user_id, - uuids.project_id, mock.sentinel.resources) + self.context, instance_2.uuid, uuids.our_node_uuid, + uuids.user_id, uuids.project_id, mock.sentinel.resources) self.assertEqual(2, get_node.call_count) @@ -3920,10 +3920,13 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): self.assertFalse( rt.delete_allocation_for_evacuated_instance.called) + @mock.patch('nova.context.RequestContext.elevated') @mock.patch('nova.compute.utils.add_instance_fault_from_exc') @mock.patch.object(manager.ComputeManager, '_error_out_instance_on_exception') - def test_rebuild_driver_error_evacuate(self, mock_error, mock_aiffe): + def test_rebuild_driver_error_evacuate(self, mock_error, mock_aiffe, + mock_elevated): + mock_elevated.return_value = self.context instance = fake_instance.fake_instance_obj(self.context) ex = test.TestingException('foo') with mock.patch.object(self.compute, '_get_resource_tracker') as mrt: @@ -3932,7 +3935,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): recreate=True, scheduled_node='foo') rt = mrt.return_value delete_alloc = rt.delete_allocation_for_evacuated_instance - delete_alloc.assert_called_once_with(instance, 'foo', + delete_alloc.assert_called_once_with(self.context, instance, 'foo', node_type='destination') @mock.patch('nova.context.RequestContext.elevated') @@ -4015,7 +4018,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): mock_validate_policy.assert_called_once_with( elevated_context, instance, {'group': [uuids.group]}) mock_delete_allocation.assert_called_once_with( - instance, 'fake-node', node_type='destination') + elevated_context, instance, 'fake-node', node_type='destination') mock_notify.assert_called_once_with( elevated_context, instance, 'fake-mini', action='rebuild', bdms=None, exception=exc, phase='error') @@ -6390,7 +6393,7 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase): rt.get_node_uuid.assert_called_once_with(mock.sentinel.node) remove = mock_rc.remove_provider_from_instance_allocation remove.assert_called_once_with( - instance.uuid, rt.get_node_uuid.return_value, + self.context, instance.uuid, rt.get_node_uuid.return_value, instance.user_id, instance.project_id, mock_resources.return_value) do_it() @@ -7019,7 +7022,8 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase): # ...so we should have called the old style delete mock_delete.assert_not_called() fn = mock_rt.return_value.delete_allocation_for_migrated_instance - fn.assert_called_once_with(self.instance, self.instance.node) + fn.assert_called_once_with(self.context, self.instance, + self.instance.node) def test_post_live_migration_legacy(self): # We have no migrate_data... @@ -7041,7 +7045,8 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase): # ...so we should have called the old style delete mock_delete.assert_not_called() fn = mock_rt.return_value.delete_allocation_for_migrated_instance - fn.assert_called_once_with(self.instance, self.instance.node) + fn.assert_called_once_with(self.context, self.instance, + self.instance.node) def test_post_live_migration_cinder_v3_api(self): # Because live migration has succeeded, _post_live_migration diff --git a/nova/tests/unit/compute/test_resource_tracker.py b/nova/tests/unit/compute/test_resource_tracker.py index 9b957b3fa4ff..f57d4c10a13c 100644 --- a/nova/tests/unit/compute/test_resource_tracker.py +++ b/nova/tests/unit/compute/test_resource_tracker.py @@ -1315,6 +1315,7 @@ class TestUpdateComputeNode(BaseTestCase): self.rt._update(mock.sentinel.ctx, new_compute) rc.set_traits_for_provider.assert_called_once_with( + mock.sentinel.ctx, new_compute.uuid, mock.sentinel.traits, ) @@ -2842,13 +2843,15 @@ class TestUpdateUsageFromInstance(BaseTestCase): mock_resource_from_flavor.return_value = mock_resource instance = _INSTANCE_FIXTURES[0].obj_clone() instance.uuid = uuids.inst0 + ctxt = context.get_admin_context() - self.rt.delete_allocation_for_evacuated_instance(instance, _NODENAME) + self.rt.delete_allocation_for_evacuated_instance( + ctxt, instance, _NODENAME) rc = self.rt.reportclient mock_remove_allocation = rc.remove_provider_from_instance_allocation mock_remove_allocation.assert_called_once_with( - instance.uuid, self.rt.compute_nodes[_NODENAME].uuid, + ctxt, instance.uuid, self.rt.compute_nodes[_NODENAME].uuid, instance.user_id, instance.project_id, mock_resource) diff --git a/nova/tests/unit/scheduler/client/test_report.py b/nova/tests/unit/scheduler/client/test_report.py index 6e2e3c1b6cdc..b3ee77c05bf1 100644 --- a/nova/tests/unit/scheduler/client/test_report.py +++ b/nova/tests/unit/scheduler/client/test_report.py @@ -266,11 +266,14 @@ class TestPutAllocations(SchedulerReportClientTestCase): consumer_uuid = mock.sentinel.consumer data = {"MEMORY_MB": 1024} expected_url = "/allocations/%s" % consumer_uuid - resp = self.client.put_allocations(rp_uuid, consumer_uuid, data, + resp = self.client.put_allocations(self.context, rp_uuid, + consumer_uuid, data, mock.sentinel.project_id, mock.sentinel.user_id) self.assertTrue(resp) - mock_put.assert_called_once_with(expected_url, mock.ANY, version='1.8') + mock_put.assert_called_once_with( + expected_url, mock.ANY, version='1.8', + global_request_id=self.context.global_id) @mock.patch.object(report.LOG, 'warning') @mock.patch('nova.scheduler.client.report.SchedulerReportClient.put') @@ -281,11 +284,14 @@ class TestPutAllocations(SchedulerReportClientTestCase): consumer_uuid = mock.sentinel.consumer data = {"MEMORY_MB": 1024} expected_url = "/allocations/%s" % consumer_uuid - resp = self.client.put_allocations(rp_uuid, consumer_uuid, data, + resp = self.client.put_allocations(self.context, rp_uuid, + consumer_uuid, data, mock.sentinel.project_id, mock.sentinel.user_id) self.assertFalse(resp) - mock_put.assert_called_once_with(expected_url, mock.ANY, version='1.8') + mock_put.assert_called_once_with( + expected_url, mock.ANY, version='1.8', + global_request_id=self.context.global_id) log_msg = mock_warn.call_args[0][0] self.assertIn("Unable to submit allocation for instance", log_msg) @@ -305,13 +311,14 @@ class TestPutAllocations(SchedulerReportClientTestCase): consumer_uuid = mock.sentinel.consumer data = {"MEMORY_MB": 1024} expected_url = "/allocations/%s" % consumer_uuid - resp = self.client.put_allocations(rp_uuid, consumer_uuid, data, + resp = self.client.put_allocations(self.context, rp_uuid, + consumer_uuid, data, mock.sentinel.project_id, mock.sentinel.user_id) self.assertTrue(resp) mock_put.assert_has_calls([ - mock.call(expected_url, mock.ANY, version='1.8'), - mock.call(expected_url, mock.ANY, version='1.8')]) + mock.call(expected_url, mock.ANY, version='1.8', + global_request_id=self.context.global_id)] * 2) @mock.patch('nova.scheduler.client.report.SchedulerReportClient.put') def test_put_allocations_retry_gives_up(self, mock_put): @@ -326,14 +333,14 @@ class TestPutAllocations(SchedulerReportClientTestCase): consumer_uuid = mock.sentinel.consumer data = {"MEMORY_MB": 1024} expected_url = "/allocations/%s" % consumer_uuid - resp = self.client.put_allocations(rp_uuid, consumer_uuid, data, + resp = self.client.put_allocations(self.context, rp_uuid, + consumer_uuid, data, mock.sentinel.project_id, mock.sentinel.user_id) self.assertFalse(resp) mock_put.assert_has_calls([ - mock.call(expected_url, mock.ANY, version='1.8'), - mock.call(expected_url, mock.ANY, version='1.8'), - mock.call(expected_url, mock.ANY, version='1.8')]) + mock.call(expected_url, mock.ANY, version='1.8', + global_request_id=self.context.global_id)] * 3) def test_claim_resources_success_with_old_version(self): get_resp_mock = mock.Mock(status_code=200) @@ -875,7 +882,8 @@ class TestPutAllocations(SchedulerReportClientTestCase): project_id = uuids.project_id user_id = uuids.user_id res = self.client.remove_provider_from_instance_allocation( - consumer_uuid, uuids.source, user_id, project_id, mock.Mock()) + self.context, consumer_uuid, uuids.source, user_id, project_id, + mock.Mock()) expected_url = "/allocations/%s" % consumer_uuid # New allocations should only include the destination... @@ -905,7 +913,7 @@ class TestPutAllocations(SchedulerReportClientTestCase): self.assertEqual(expected_allocations, actual_allocations) self.ks_adap_mock.put.assert_called_once_with( expected_url, microversion='1.10', json=mock.ANY, raise_exc=False, - headers={}) + headers={'X-Openstack-Request-Id': self.context.global_id}) self.assertTrue(res) @@ -948,7 +956,8 @@ class TestPutAllocations(SchedulerReportClientTestCase): project_id = uuids.project_id user_id = uuids.user_id res = self.client.remove_provider_from_instance_allocation( - consumer_uuid, uuids.source, user_id, project_id, mock.Mock()) + self.context, consumer_uuid, uuids.source, user_id, project_id, + mock.Mock()) expected_url = "/allocations/%s" % consumer_uuid # New allocations should only include the destination... @@ -986,7 +995,7 @@ class TestPutAllocations(SchedulerReportClientTestCase): self.assertEqual(expected_allocations, actual_allocations) self.ks_adap_mock.put.assert_called_once_with( expected_url, microversion='1.10', json=mock.ANY, raise_exc=False, - headers={}) + headers={'X-Openstack-Request-Id': self.context.global_id}) self.assertTrue(res) @@ -1020,7 +1029,8 @@ class TestPutAllocations(SchedulerReportClientTestCase): project_id = uuids.project_id user_id = uuids.user_id res = self.client.remove_provider_from_instance_allocation( - consumer_uuid, uuids.source, user_id, project_id, mock.Mock()) + self.context, consumer_uuid, uuids.source, user_id, project_id, + mock.Mock()) self.ks_adap_mock.get.assert_called() self.ks_adap_mock.put.assert_not_called() @@ -1038,7 +1048,8 @@ class TestPutAllocations(SchedulerReportClientTestCase): project_id = uuids.project_id user_id = uuids.user_id res = self.client.remove_provider_from_instance_allocation( - consumer_uuid, uuids.source, user_id, project_id, mock.Mock()) + self.context, consumer_uuid, uuids.source, user_id, project_id, + mock.Mock()) self.ks_adap_mock.get.assert_called() self.ks_adap_mock.put.assert_not_called() @@ -1960,11 +1971,12 @@ class TestProviderOperations(SchedulerReportClientTestCase): self.assertEqual(set(), self.client._provider_tree.data(uuids.rp).aggregates) - self.client.set_aggregates_for_provider(uuids.rp, aggs) + self.client.set_aggregates_for_provider(self.context, uuids.rp, aggs) self.ks_adap_mock.put.assert_called_once_with( '/resource_providers/%s/aggregates' % uuids.rp, json=aggs, - raise_exc=False, microversion='1.1', headers={}) + raise_exc=False, microversion='1.1', + headers={'X-Openstack-Request-Id': self.context.global_id}) # Cache was updated self.assertEqual(set(aggs), self.client._provider_tree.data(uuids.rp).aggregates) @@ -1973,7 +1985,8 @@ class TestProviderOperations(SchedulerReportClientTestCase): self.ks_adap_mock.put.return_value = mock.Mock(status_code=503) self.assertRaises( exception.ResourceProviderUpdateFailed, - self.client.set_aggregates_for_provider, uuids.rp, []) + self.client.set_aggregates_for_provider, + self.context, uuids.rp, []) class TestAggregates(SchedulerReportClientTestCase): @@ -2078,18 +2091,20 @@ class TestTraits(SchedulerReportClientTestCase): # Request all traits; custom traits need to be created get_mock.json.return_value = {'traits': standard_traits} - self.client._ensure_traits(all_traits) + self.client._ensure_traits(self.context, all_traits) self.ks_adap_mock.get.assert_called_once_with( '/traits?name=in:' + ','.join(all_traits), **self.trait_api_kwargs) self.ks_adap_mock.put.assert_has_calls( - [mock.call('/traits/' + trait, headers={}, **self.trait_api_kwargs) + [mock.call('/traits/' + trait, + headers={'X-Openstack-Request-Id': self.context.global_id}, + **self.trait_api_kwargs) for trait in custom_traits], any_order=True) self.ks_adap_mock.reset_mock() # Request standard traits; no traits need to be created get_mock.json.return_value = {'traits': standard_traits} - self.client._ensure_traits(standard_traits) + self.client._ensure_traits(self.context, standard_traits) self.ks_adap_mock.get.assert_called_once_with( '/traits?name=in:' + ','.join(standard_traits), **self.trait_api_kwargs) @@ -2098,8 +2113,8 @@ class TestTraits(SchedulerReportClientTestCase): self.ks_adap_mock.reset_mock() # Request no traits - short circuit - self.client._ensure_traits(None) - self.client._ensure_traits([]) + self.client._ensure_traits(self.context, None) + self.client._ensure_traits(self.context, []) self.ks_adap_mock.get.assert_not_called() self.ks_adap_mock.put.assert_not_called() @@ -2107,7 +2122,8 @@ class TestTraits(SchedulerReportClientTestCase): self.ks_adap_mock.get.return_value = mock.Mock(status_code=400) self.assertRaises(exception.TraitRetrievalFailed, - self.client._ensure_traits, ['FOO']) + self.client._ensure_traits, + self.context, ['FOO']) self.ks_adap_mock.get.assert_called_once_with( '/traits?name=in:FOO', **self.trait_api_kwargs) @@ -2122,12 +2138,15 @@ class TestTraits(SchedulerReportClientTestCase): self.ks_adap_mock.put.return_value = put_mock self.assertRaises(exception.TraitCreationFailed, - self.client._ensure_traits, ['FOO']) + self.client._ensure_traits, + self.context, ['FOO']) self.ks_adap_mock.get.assert_called_once_with( '/traits?name=in:FOO', **self.trait_api_kwargs) self.ks_adap_mock.put.assert_called_once_with( - '/traits/FOO', headers={}, **self.trait_api_kwargs) + '/traits/FOO', + headers={'X-Openstack-Request-Id': self.context.global_id}, + **self.trait_api_kwargs) def test_set_traits_for_provider(self): traits = ['HW_NIC_OFFLOAD_UCS', 'HW_NIC_OFFLOAD_RDMA'] @@ -2147,7 +2166,7 @@ class TestTraits(SchedulerReportClientTestCase): self.ks_adap_mock.put.return_value = put_mock # Invoke - self.client.set_traits_for_provider(uuids.rp, traits) + self.client.set_traits_for_provider(self.context, uuids.rp, traits) # Verify API calls self.ks_adap_mock.get.assert_called_once_with( @@ -2155,7 +2174,8 @@ class TestTraits(SchedulerReportClientTestCase): self.ks_adap_mock.put.assert_called_once_with( '/resource_providers/%s/traits' % uuids.rp, json={'traits': traits, 'resource_provider_generation': 0}, - headers={}, **self.trait_api_kwargs) + headers={'X-Openstack-Request-Id': self.context.global_id}, + **self.trait_api_kwargs) # And ensure the provider tree cache was updated appropriately self.assertFalse( @@ -2176,7 +2196,8 @@ class TestTraits(SchedulerReportClientTestCase): get_mock.status_code = 400 self.assertRaises( exception.TraitRetrievalFailed, - self.client.set_traits_for_provider, uuids.rp, traits) + self.client.set_traits_for_provider, + self.context, uuids.rp, traits) self.ks_adap_mock.put.assert_not_called() get_mock.status_code = 200 @@ -2186,13 +2207,15 @@ class TestTraits(SchedulerReportClientTestCase): self.ks_adap_mock.put.return_value = mock.Mock(status_code=409) self.assertRaises( exception.ResourceProviderUpdateConflict, - self.client.set_traits_for_provider, uuids.rp, traits) + self.client.set_traits_for_provider, + self.context, uuids.rp, traits) # Other error self.ks_adap_mock.put.return_value = mock.Mock(status_code=503) self.assertRaises( exception.ResourceProviderUpdateFailed, - self.client.set_traits_for_provider, uuids.rp, traits) + self.client.set_traits_for_provider, + self.context, uuids.rp, traits) class TestAssociations(SchedulerReportClientTestCase): @@ -3342,7 +3365,8 @@ class TestAllocations(SchedulerReportClientTestCase): self.client.update_instance_allocation(self.context, cn, inst, 1) mock_put.assert_called_once_with( '/allocations/%s' % inst.uuid, - expected, version='1.8') + expected, version='1.8', + global_request_id=self.context.global_id) self.assertTrue(mock_get.called) @mock.patch('nova.scheduler.client.report.SchedulerReportClient.'