commit 1390eecf8dec4c3b022a9b1e259a908197566738 Author: Balazs Gibizer Date: Mon Sep 21 17:21:18 2020 +0200 Use cell targeted context to query BDMs for metadata The metadata service supports a multicell deployment in a configuration where the nova-api service implements the metadata API. In this case the metadata query needs to be cell targeted. This was partly implemented already. The instance itself is queried from the cell DB properly. However the BDM data used the non targeted context resulting in an empty BDM returned by the metadata service. Functional reproduction test is not added as I did not find a way to have a cell setup in the functional test that reproduce the problem. I reproduced the bug and tested the fix in a devstack. Change-Id: I48f57082edaef3ec4722bd31ce29a90b94d32523 Closes-Bug: #1881944 diff --git a/nova/api/metadata/base.py b/nova/api/metadata/base.py index a069301..164d0ff 100644 --- a/nova/api/metadata/base.py +++ b/nova/api/metadata/base.py @@ -124,8 +124,13 @@ class InstanceMetadata(object): if not content: content = [] + # NOTE(gibi): this is not a cell targeted context even if we are called + # in a situation when the instance is in a different cell than the + # metadata service itself. ctxt = context.get_admin_context() + self.mappings = _format_instance_mapping(instance) + # NOTE(danms): Sanitize the instance to limit the amount of stuff # inside that may not pickle well (i.e. context). We also touch # some of the things we'll lazy load later to make sure we keep their @@ -147,8 +152,6 @@ class InstanceMetadata(object): self.security_groups = security_group_api.get_instance_security_groups( ctxt, instance) - self.mappings = _format_instance_mapping(ctxt, instance) - if instance.user_data is not None: self.userdata_raw = base64.decode_as_bytes(instance.user_data) else: @@ -696,9 +699,8 @@ def get_metadata_by_instance_id(instance_id, address, ctxt=None): return InstanceMetadata(instance, address) -def _format_instance_mapping(ctxt, instance): - bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( - ctxt, instance.uuid) +def _format_instance_mapping(instance): + bdms = instance.get_bdms() return block_device.instance_block_mapping(instance, bdms) diff --git a/nova/tests/unit/test_metadata.py b/nova/tests/unit/test_metadata.py index 1dfa5ee..45c2b6a 100644 --- a/nova/tests/unit/test_metadata.py +++ b/nova/tests/unit/test_metadata.py @@ -322,12 +322,14 @@ class MetadataTestCase(test.TestCase): 'uuid': 'e5fe5518-0288-4fa3-b0c4-c79764101b85', 'root_device_name': None, 'default_ephemeral_device': None, - 'default_swap_device': None}) + 'default_swap_device': None, + 'context': self.context}) instance_ref1 = objects.Instance(**{'id': 0, 'uuid': 'b65cee2f-8c69-4aeb-be2f-f79742548fc2', 'root_device_name': '/dev/sda1', 'default_ephemeral_device': None, - 'default_swap_device': None}) + 'default_swap_device': None, + 'context': self.context}) def fake_bdm_get(ctxt, uuid): return [fake_block_device.FakeDbBlockDeviceDict( @@ -366,10 +368,12 @@ class MetadataTestCase(test.TestCase): 'swap': '/dev/sdc', 'ebs0': '/dev/sdh'} - self.assertEqual(base._format_instance_mapping(self.context, - instance_ref0), block_device._DEFAULT_MAPPINGS) - self.assertEqual(base._format_instance_mapping(self.context, - instance_ref1), expected) + self.assertEqual( + base._format_instance_mapping(instance_ref0), + block_device._DEFAULT_MAPPINGS) + self.assertEqual( + base._format_instance_mapping(instance_ref1), + expected) def test_pubkey(self): md = fake_InstanceMetadata(self, self.instance.obj_clone())