Pre-load instance.device_metadata in InstanceMetadata

Change Ie7d97ce5c62c8fb9da5822590a64210521f8ae7a orphans
the Instance object so that we can pickle it. However,
this means we can't lazy-load any attributes that we need
when building up metadata, like when building the config
drive during server create. We need to pre-load the
device_metadata field so it's available when building
the config drive.

This isn't a problem for the libvirt driver since it
loads device_metadata before building the config drive,
but the hyperv driver doesn't do that, so the change
above breaks hyperv when there are device tags without
this fix.

Change-Id: I08b905d2734ff9d484b373369f36d48c4d056fd8
Closes-Bug: #1702150
This commit is contained in:
Matt Riedemann 2017-07-06 16:56:02 -04:00
parent e2d0442b5e
commit 004d5ed1f3
2 changed files with 25 additions and 1 deletions

View File

@ -130,6 +130,7 @@ class InstanceMetadata(object):
# values in what we cache.
instance.ec2_ids
instance.keypairs
instance.device_metadata
instance = objects.Instance.obj_from_primitive(
instance.obj_to_primitive())

View File

@ -391,9 +391,32 @@ class MetadataTestCase(test.TestCase):
def test_instance_is_sanitized(self):
inst = self.instance.obj_clone()
# The instance already has some fake device_metadata stored on it,
# and we want to test to see it gets lazy-loaded, so save off the
# original attribute value and delete the attribute from the instance,
# then we can assert it gets loaded up later.
original_device_meta = inst.device_metadata
delattr(inst, 'device_metadata')
def fake_obj_load_attr(attrname):
if attrname == 'device_metadata':
inst.device_metadata = original_device_meta
elif attrname == 'ec2_ids':
inst.ec2_ids = objects.EC2Ids()
else:
self.fail('Unexpected instance lazy-load: %s' % attrname)
inst._will_not_pass = True
md = fake_InstanceMetadata(self, inst)
with mock.patch.object(
inst, 'obj_load_attr',
side_effect=fake_obj_load_attr) as mock_obj_load_attr:
md = fake_InstanceMetadata(self, inst)
self.assertFalse(hasattr(md.instance, '_will_not_pass'))
self.assertEqual(2, mock_obj_load_attr.call_count)
mock_obj_load_attr.assert_has_calls(
[mock.call('device_metadata'), mock.call('ec2_ids')],
any_order=True)
self.assertIs(original_device_meta, inst.device_metadata)
def test_check_version(self):
inst = self.instance.obj_clone()