From 93b90d2b6a58df26f6fbf0ff0fe20cf37fcbf8af Mon Sep 17 00:00:00 2001 From: Jay Faulkner Date: Wed, 10 Jul 2024 16:02:46 -0700 Subject: [PATCH] [ironic] Factor out metadata and send to ironic This change migrates the code currently written only to serve libvirt driver to be generally useful, adding driver-neutral data structures and a method to build them. The libvirt driver is reworked to use get_instance_driver_metadata instead of it's current code. The ironic driver is reworked, per the blueprint, to send along some of this additional metadata to the Ironic node.instance_info. blueprint ironic-guest-metadata Needed-By: https://review.opendev.org/c/openstack/ironic/+/924887 Change-Id: I2b23c8463f66c38e64625486157f245cd74cec61 --- nova/tests/unit/virt/ironic/test_driver.py | 113 +++++++++++++++++--- nova/tests/unit/virt/ironic/test_patcher.py | 50 ++++++--- nova/tests/unit/virt/ironic/utils.py | 75 ++++++++++--- nova/tests/unit/virt/libvirt/test_driver.py | 82 +++++++------- nova/virt/driver.py | 103 +++++++++++++++++- nova/virt/ironic/driver.py | 10 +- nova/virt/ironic/patcher.py | 18 +++- nova/virt/libvirt/driver.py | 51 ++++----- 8 files changed, 387 insertions(+), 115 deletions(-) diff --git a/nova/tests/unit/virt/ironic/test_driver.py b/nova/tests/unit/virt/ironic/test_driver.py index 204ed522889d..0118c721d7a9 100644 --- a/nova/tests/unit/virt/ironic/test_driver.py +++ b/nova/tests/unit/virt/ironic/test_driver.py @@ -1263,6 +1263,8 @@ class IronicDriverTestCase(test.NoDBTestCase): instance_id=instance.uuid, fields=ironic_driver._NODE_FIELDS)]) + @mock.patch.object(ironic_driver.IronicDriver, + 'get_instance_driver_metadata') @mock.patch.object(objects.Instance, 'save') @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall') @mock.patch.object(ironic_driver.IronicDriver, '_add_volume_target_info') @@ -1271,11 +1273,15 @@ class IronicDriverTestCase(test.NoDBTestCase): '_add_instance_info_to_node') def _test_spawn(self, mock_aiitn, mock_wait_active, mock_avti, mock_looping, mock_save, - config_drive_value=None): + mock_metadata, config_drive_value=None): node_id = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' node = _get_cached_node(driver='fake', id=node_id) instance = fake_instance.fake_instance_obj(self.ctx, node=node_id) fake_flavor = objects.Flavor(ephemeral_gb=0) + mock_metadata.return_value = ( + ironic_utils.get_test_instance_driver_metadata( + flavor_ephemeralgb=0) + ) instance.flavor = fake_flavor self.mock_conn.get_node.return_value = node @@ -1295,9 +1301,10 @@ class IronicDriverTestCase(test.NoDBTestCase): self.mock_conn.validate_node.assert_called_once_with( node_id, required=None, ) - mock_aiitn.assert_called_once_with(node, instance, - test.MatchType(objects.ImageMeta), - fake_flavor, block_device_info=None) + mock_aiitn.assert_called_once_with( + node, instance, test.MatchType(objects.ImageMeta), + fake_flavor, test.MatchType(driver.InstanceDriverMetadata), + block_device_info=None) mock_avti.assert_called_once_with(self.ctx, instance, None) self.mock_conn.set_node_provision_state.assert_called_once_with( node_id, 'active', config_drive=config_drive_value, @@ -1331,6 +1338,8 @@ class IronicDriverTestCase(test.NoDBTestCase): mock.ANY, extra_md={}, files=[]) + @mock.patch.object(ironic_driver.IronicDriver, + 'get_instance_driver_metadata') @mock.patch.object(configdrive, 'required_by') @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall') @mock.patch.object(ironic_driver.IronicDriver, 'destroy') @@ -1341,13 +1350,18 @@ class IronicDriverTestCase(test.NoDBTestCase): def test_spawn_destroyed_after_failure(self, mock_aiitn, mock_wait_active, mock_avti, mock_destroy, - mock_looping, mock_required_by): + mock_looping, mock_required_by, + mock_metadata): mock_required_by.return_value = False node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' node = _get_cached_node(driver='fake', id=node_uuid) fake_flavor = objects.Flavor(ephemeral_gb=0) instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid) instance.flavor = fake_flavor + mock_metadata.return_value = ( + ironic_utils.get_test_instance_driver_metadata( + flavor_ephemeralgb=0 + )) self.mock_conn.get_node.return_value = node self.mock_conn.validate_node.return_value = \ @@ -1368,6 +1382,7 @@ class IronicDriverTestCase(test.NoDBTestCase): instance = fake_instance.fake_instance_obj(self.ctx, node=node.id) image_meta = ironic_utils.get_test_image_meta() flavor = ironic_utils.get_test_flavor() + metadata = ironic_utils.get_test_instance_driver_metadata() instance.flavor = flavor expected_patch = [{'path': '/instance_info/image_source', 'op': 'add', 'value': image_meta.id}, @@ -1384,10 +1399,25 @@ class IronicDriverTestCase(test.NoDBTestCase): {'path': '/instance_info/memory_mb', 'op': 'add', 'value': str(instance.flavor.memory_mb)}, {'path': '/instance_info/local_gb', 'op': 'add', - 'value': str(node.properties.get('local_gb', 0))}] + 'value': str(node.properties.get('local_gb', 0))}, + {'path': '/instance_info/project_id', 'op': 'add', + 'value': 'ppppppp-pppp-pppp-pppp-pppppppppppp'}, + {'path': '/instance_info/project_name', 'op': 'add', + 'value': 'testproject'}, + {'path': '/instance_info/user_id', 'op': 'add', + 'value': 'uuuuuuu-uuuu-uuuu-uuuu-uuuuuuuuuuuu'}, + {'op': 'add', 'path': '/instance_info/user_name', + 'value': 'testuser'}, + {'path': '/instance_info/flavor_name', + 'op': 'add', 'value': 'fake.flavor'}, + {'path': '/instance_info/fixed_ips', + 'op': 'add', 'value': '[]'}, + {'path': '/instance_info/floating_ips', + 'op': 'add', 'value': '[]'}, + ] self.driver._add_instance_info_to_node(node, instance, - image_meta, flavor) + image_meta, flavor, metadata) # TODO(dustinc): Add check for call to patcher.create self.mock_conn.patch_node.assert_called_once_with(node, expected_patch) @@ -1533,16 +1563,22 @@ class IronicDriverTestCase(test.NoDBTestCase): ] ) + @mock.patch.object(ironic_driver.IronicDriver, + 'get_instance_driver_metadata') @mock.patch.object(configdrive, 'required_by') @mock.patch.object(ironic_driver.IronicDriver, '_add_volume_target_info') def test_spawn_node_driver_validation_fail(self, mock_avti, - mock_required_by): + mock_required_by, + mock_metadata): mock_required_by.return_value = False node_id = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' node = _get_cached_node(driver='fake', id=node_id) flavor = ironic_utils.get_test_flavor() instance = fake_instance.fake_instance_obj(self.ctx, node=node_id) instance.flavor = flavor + mock_metadata.return_value = ( + ironic_utils.get_test_instance_driver_metadata() + ) self.mock_conn.validate_node.return_value = \ ironic_utils.get_test_validation( @@ -1562,20 +1598,23 @@ class IronicDriverTestCase(test.NoDBTestCase): node_id, required=None, ) + @mock.patch.object(ironic_driver.IronicDriver, + 'get_instance_driver_metadata') @mock.patch.object(configdrive, 'required_by') @mock.patch.object(objects.Instance, 'save') @mock.patch.object(ironic_driver.IronicDriver, '_add_volume_target_info') @mock.patch.object(ironic_driver.IronicDriver, '_generate_configdrive') - def test_spawn_node_configdrive_fail(self, - mock_configdrive, - mock_avti, mock_save, - mock_required_by): + def test_spawn_node_configdrive_fail(self, mock_configdrive, mock_avti, + mock_save, mock_required_by, + mock_metadata): mock_required_by.return_value = True node_id = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' node = _get_cached_node(driver='fake', id=node_id) flavor = ironic_utils.get_test_flavor() instance = fake_instance.fake_instance_obj(self.ctx, node=node_id) instance.flavor = flavor + mock_metadata.return_value = ( + ironic_utils.get_test_instance_driver_metadata()) self.mock_conn.get_node.return_value = node self.mock_conn.validate_node.return_value = \ ironic_utils.get_test_validation() @@ -1594,12 +1633,14 @@ class IronicDriverTestCase(test.NoDBTestCase): ) mock_cleanup_deploy.assert_called_with(node, instance, None) + @mock.patch.object(ironic_driver.IronicDriver, + 'get_instance_driver_metadata') @mock.patch.object(configdrive, 'required_by') @mock.patch.object(ironic_driver.IronicDriver, '_add_volume_target_info') @mock.patch.object(ironic_driver.IronicDriver, '_cleanup_deploy') def test_spawn_node_trigger_deploy_fail(self, mock_cleanup_deploy, mock_avti, - mock_required_by): + mock_required_by, mock_metadata): mock_required_by.return_value = False node_id = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' node = _get_cached_node(driver='fake', id=node_id) @@ -1607,6 +1648,9 @@ class IronicDriverTestCase(test.NoDBTestCase): instance = fake_instance.fake_instance_obj(self.ctx, node=node_id) instance.flavor = flavor image_meta = ironic_utils.get_test_image_meta() + mock_metadata.return_value = ( + ironic_utils.get_test_instance_driver_metadata() + ) self.mock_conn.get_node.return_value = node self.mock_conn.validate_node.return_value = \ @@ -1627,6 +1671,8 @@ class IronicDriverTestCase(test.NoDBTestCase): ) mock_cleanup_deploy.assert_called_once_with(node, instance, None) + @mock.patch.object(ironic_driver.IronicDriver, + 'get_instance_driver_metadata') @mock.patch.object(configdrive, 'required_by') @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall') @mock.patch.object(objects.Instance, 'save') @@ -1636,12 +1682,18 @@ class IronicDriverTestCase(test.NoDBTestCase): mock_wait, mock_avti, mock_save, mock_looping, - mock_required_by): + mock_required_by, + mock_metadata): mock_required_by.return_value = False node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' flavor = ironic_utils.get_test_flavor(ephemeral_gb=1) instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid) instance.flavor = flavor + mock_metadata.return_value = ( + ironic_utils.get_test_instance_driver_metadata( + flavor_ephemeralgb=1) + ) + image_meta = ironic_utils.get_test_image_meta() self.driver.spawn(self.ctx, instance, image_meta, [], None, {}) @@ -2148,13 +2200,16 @@ class IronicDriverTestCase(test.NoDBTestCase): 'fake_vif') mock_uv.assert_called_once_with('fake_instance', ['fake_vif']) + @mock.patch.object(ironic_driver.IronicDriver, + 'get_instance_driver_metadata') @mock.patch.object(ironic_driver.IronicDriver, '_wait_for_active') @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall') @mock.patch.object(ironic_driver.IronicDriver, '_add_instance_info_to_node') @mock.patch.object(objects.Instance, 'save') def _test_rebuild(self, mock_save, mock_add_instance_info, - mock_looping, mock_wait_active, preserve=False): + mock_looping, mock_wait_active, mock_metadata, + preserve=False): node_uuid = uuidutils.generate_uuid() node = _get_cached_node(id=node_uuid, instance_id=self.instance_id) self.mock_conn.get_node.return_value = node @@ -2165,6 +2220,13 @@ class IronicDriverTestCase(test.NoDBTestCase): instance = fake_instance.fake_instance_obj( self.ctx, uuid=self.instance_uuid, node=node_uuid, flavor=flavor) + mock_metadata.return_value = ( + ironic_utils.get_test_instance_driver_metadata( + flavor_id=5, + flavor_name='baremetal', + instance_uuid=self.instance_uuid, + )) + fake_looping_call = FakeLoopingCall() mock_looping.return_value = fake_looping_call @@ -2179,6 +2241,7 @@ class IronicDriverTestCase(test.NoDBTestCase): mock_add_instance_info.assert_called_once_with( node, instance, test.MatchType(objects.ImageMeta), + test.MatchType(driver.InstanceDriverMetadata), flavor, preserve) self.mock_conn.set_node_provision_state.assert_called_once_with( node_uuid, ironic_states.REBUILD, config_drive=mock.ANY, @@ -2214,6 +2277,8 @@ class IronicDriverTestCase(test.NoDBTestCase): mock_configdrive.assert_called_once_with( self.ctx, mock.ANY, mock.ANY, mock.ANY, extra_md={}, files=None) + @mock.patch.object(ironic_driver.IronicDriver, + 'get_instance_driver_metadata') @mock.patch.object(ironic_driver.IronicDriver, '_generate_configdrive') @mock.patch.object(configdrive, 'required_by') @mock.patch.object(ironic_driver.IronicDriver, @@ -2222,13 +2287,18 @@ class IronicDriverTestCase(test.NoDBTestCase): def test_rebuild_with_configdrive_failure(self, mock_save, mock_add_instance_info, mock_required_by, - mock_configdrive): + mock_configdrive, + mock_metadata): node_uuid = uuidutils.generate_uuid() node = _get_cached_node( id=node_uuid, instance_id=self.instance_uuid) self.mock_conn.get_node.return_value = node mock_required_by.return_value = True mock_configdrive.side_effect = exception.NovaException() + mock_metadata.return_value = ( + ironic_utils.get_test_instance_driver_metadata( + flavor_id=5, flavor_name='baremetal') + ) image_meta = ironic_utils.get_test_image_meta() flavor = objects.Flavor(flavor_id=5, name='baremetal') @@ -2243,6 +2313,8 @@ class IronicDriverTestCase(test.NoDBTestCase): bdms=None, detach_block_devices=None, attach_block_devices=None) + @mock.patch.object(ironic_driver.IronicDriver, + 'get_instance_driver_metadata') @mock.patch.object(ironic_driver.IronicDriver, '_generate_configdrive') @mock.patch.object(configdrive, 'required_by') @mock.patch.object(ironic_driver.IronicDriver, @@ -2250,7 +2322,8 @@ class IronicDriverTestCase(test.NoDBTestCase): @mock.patch.object(objects.Instance, 'save') def test_rebuild_failures(self, mock_save, mock_add_instance_info, - mock_required_by, mock_configdrive): + mock_required_by, mock_configdrive, + mock_metadata): node_uuid = uuidutils.generate_uuid() node = _get_cached_node( id=node_uuid, instance_id=self.instance_uuid) @@ -2259,6 +2332,12 @@ class IronicDriverTestCase(test.NoDBTestCase): image_meta = ironic_utils.get_test_image_meta() flavor = objects.Flavor(flavor_id=5, name='baremetal') + mock_metadata.return_value = ( + ironic_utils.get_test_instance_driver_metadata( + flavor_id=5, + flavor_name='baremetal', + instance_uuid=self.instance_uuid, + )) instance = fake_instance.fake_instance_obj( self.ctx, uuid=self.instance_uuid, node=node_uuid, flavor=flavor) diff --git a/nova/tests/unit/virt/ironic/test_patcher.py b/nova/tests/unit/virt/ironic/test_patcher.py index 228672b8d64e..b28f4909eceb 100644 --- a/nova/tests/unit/virt/ironic/test_patcher.py +++ b/nova/tests/unit/virt/ironic/test_patcher.py @@ -37,6 +37,7 @@ class IronicDriverFieldsTestCase(test.NoDBTestCase): self.instance = fake_instance.fake_instance_obj(self.ctx) self.instance.flavor = self.flavor self.node = ironic_utils.get_test_node(driver='fake') + self.metadata = ironic_utils.get_test_instance_driver_metadata() # Generic expected patches self._expected_deploy_patch = [ {'path': '/instance_info/image_source', @@ -60,9 +61,24 @@ class IronicDriverFieldsTestCase(test.NoDBTestCase): {'path': '/instance_info/local_gb', 'value': str(self.node.properties.get('local_gb', 0)), 'op': 'add'}, - {'path': '/instance_info/nova_host_id', - 'value': u'fake-host', - 'op': 'add'}, + {'op': 'add', 'path': '/instance_info/fixed_ips', + 'value': '[]'}, + {'op': 'add', 'path': '/instance_info/floating_ips', + 'value': '[]'}, + {'op': 'add', 'path': '/instance_info/flavor_name', + 'value': str(self.flavor.name)}, + {'op': 'add', 'path': '/instance_info/nova_host_id', + 'value': 'fake-host'}, + {'op': 'add', + 'path': '/instance_info/project_id', + 'value': 'ppppppp-pppp-pppp-pppp-pppppppppppp'}, + {'op': 'add', 'path': '/instance_info/project_name', + 'value': 'testproject'}, + {'op': 'add', 'path': '/instance_info/user_name', + 'value': 'testuser'}, + {'op': 'add', + 'path': '/instance_info/user_id', + 'value': 'uuuuuuu-uuuu-uuuu-uuuu-uuuuuuuuuuuu'}, ] def assertPatchEqual(self, expected, observed): @@ -79,7 +95,7 @@ class IronicDriverFieldsTestCase(test.NoDBTestCase): def test_generic_get_deploy_patch(self): node = ironic_utils.get_test_node(driver='fake') patch = patcher.create(node).get_deploy_patch( - self.instance, self.image_meta, self.flavor) + self.instance, self.image_meta, self.flavor, self.metadata) self.assertPatchEqual(self._expected_deploy_patch, patch) def test_generic_get_deploy_patch_capabilities(self): @@ -90,7 +106,7 @@ class IronicDriverFieldsTestCase(test.NoDBTestCase): 'op': 'add'}] expected += self._expected_deploy_patch patch = patcher.create(node).get_deploy_patch( - self.instance, self.image_meta, self.flavor) + self.instance, self.image_meta, self.flavor, self.metadata) self.assertPatchEqual(expected, patch) def test_generic_get_deploy_patch_capabilities_op(self): @@ -101,7 +117,7 @@ class IronicDriverFieldsTestCase(test.NoDBTestCase): 'op': 'add'}] expected += self._expected_deploy_patch patch = patcher.create(node).get_deploy_patch( - self.instance, self.image_meta, self.flavor) + self.instance, self.image_meta, self.flavor, self.metadata) self.assertPatchEqual(expected, patch) def test_generic_get_deploy_patch_capabilities_nested_key(self): @@ -112,7 +128,7 @@ class IronicDriverFieldsTestCase(test.NoDBTestCase): 'op': 'add'}] expected += self._expected_deploy_patch patch = patcher.create(node).get_deploy_patch( - self.instance, self.image_meta, self.flavor) + self.instance, self.image_meta, self.flavor, self.metadata) self.assertPatchEqual(expected, patch) def test_generic_get_deploy_patch_traits(self): @@ -123,7 +139,7 @@ class IronicDriverFieldsTestCase(test.NoDBTestCase): 'op': 'add'}] expected += self._expected_deploy_patch patch = patcher.create(node).get_deploy_patch( - self.instance, self.image_meta, self.flavor) + self.instance, self.image_meta, self.flavor, self.metadata) self.assertPatchEqual(expected, patch) def test_generic_get_deploy_patch_traits_granular(self): @@ -134,7 +150,7 @@ class IronicDriverFieldsTestCase(test.NoDBTestCase): 'op': 'add'}] expected += self._expected_deploy_patch patch = patcher.create(node).get_deploy_patch( - self.instance, self.image_meta, self.flavor) + self.instance, self.image_meta, self.flavor, self.metadata) self.assertPatchEqual(expected, patch) def test_generic_get_deploy_patch_traits_ignores_not_required(self): @@ -142,7 +158,7 @@ class IronicDriverFieldsTestCase(test.NoDBTestCase): self.flavor['extra_specs']['trait:CUSTOM_FOO'] = 'invalid' expected = self._expected_deploy_patch patch = patcher.create(node).get_deploy_patch( - self.instance, self.image_meta, self.flavor) + self.instance, self.image_meta, self.flavor, self.metadata) self.assertPatchEqual(expected, patch) def test_generic_get_deploy_patch_image_traits_required(self): @@ -154,7 +170,7 @@ class IronicDriverFieldsTestCase(test.NoDBTestCase): 'op': 'add'}] expected += self._expected_deploy_patch patch = patcher.create(node).get_deploy_patch( - self.instance, self.image_meta, self.flavor) + self.instance, self.image_meta, self.flavor, self.metadata) self.assertPatchEqual(expected, patch) def test_generic_get_deploy_patch_image_flavor_traits_required(self): @@ -167,7 +183,7 @@ class IronicDriverFieldsTestCase(test.NoDBTestCase): 'op': 'add'}] expected += self._expected_deploy_patch patch = patcher.create(node).get_deploy_patch( - self.instance, self.image_meta, self.flavor) + self.instance, self.image_meta, self.flavor, self.metadata) self.assertPatchEqual(expected, patch) def test_generic_get_deploy_patch_image_flavor_traits_none(self): @@ -175,7 +191,7 @@ class IronicDriverFieldsTestCase(test.NoDBTestCase): self.image_meta.properties = objects.ImageMetaProps() expected = self._expected_deploy_patch patch = patcher.create(node).get_deploy_patch( - self.instance, self.image_meta, self.flavor) + self.instance, self.image_meta, self.flavor, self.metadata) self.assertPatchEqual(expected, patch) def test_generic_get_deploy_patch_boot_from_volume_image_traits_required( @@ -192,7 +208,7 @@ class IronicDriverFieldsTestCase(test.NoDBTestCase): 'op': 'add'}] expected += expected_deploy_patch_volume patch = patcher.create(node).get_deploy_patch( - self.instance, self.image_meta, self.flavor, + self.instance, self.image_meta, self.flavor, self.metadata, boot_from_volume=True) self.assertPatchEqual(expected, patch) @@ -204,7 +220,7 @@ class IronicDriverFieldsTestCase(test.NoDBTestCase): flavor=objects.Flavor(root_gb=1, vcpus=1, memory_mb=1, ephemeral_gb=10)) patch = patcher.create(node).get_deploy_patch( - instance, self.image_meta, self.flavor) + instance, self.image_meta, self.flavor, self.metadata) expected = [{'path': '/instance_info/ephemeral_gb', 'value': str(instance.flavor.ephemeral_gb), 'op': 'add'}, @@ -218,7 +234,7 @@ class IronicDriverFieldsTestCase(test.NoDBTestCase): node = ironic_utils.get_test_node(driver='fake') for preserve in [True, False]: patch = patcher.create(node).get_deploy_patch( - self.instance, self.image_meta, self.flavor, + self.instance, self.image_meta, self.flavor, self.metadata, preserve_ephemeral=preserve) expected = [{'path': '/instance_info/preserve_ephemeral', 'value': str(preserve), 'op': 'add', }] @@ -230,6 +246,6 @@ class IronicDriverFieldsTestCase(test.NoDBTestCase): expected = [patch for patch in self._expected_deploy_patch if patch['path'] != '/instance_info/image_source'] patch = patcher.create(node).get_deploy_patch( - self.instance, self.image_meta, self.flavor, + self.instance, self.image_meta, self.flavor, self.metadata, boot_from_volume=True) self.assertPatchEqual(expected, patch) diff --git a/nova/tests/unit/virt/ironic/utils.py b/nova/tests/unit/virt/ironic/utils.py index 11bb00898593..5d5fd8429458 100644 --- a/nova/tests/unit/virt/ironic/utils.py +++ b/nova/tests/unit/virt/ironic/utils.py @@ -19,9 +19,27 @@ from openstack.baremetal.v1 import port_group as _port_group from openstack.baremetal.v1 import volume_connector as _volume_connector from openstack.baremetal.v1 import volume_target as _volume_target +from nova.network import model as network_model from nova import objects +from nova.virt import driver from nova.virt.ironic import ironic_states +# NOTE(JayF): These exist to make it trivial to unify test data +# between both the driver_metadata generators and the generated +# objects. +TEST_IMAGE_UUID = "cccccccc-cccc-cccc-cccc-cccccccccccc" +TEST_IMAGE_NAME = "test-image" +TEST_FLAVOR_ID = "1" +TEST_FLAVOR_NAME = "fake.flavor" +TEST_FLAVOR_EXTRA_SPECS = { + 'baremetal:deploy_kernel_id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', + 'baremetal:deploy_ramdisk_id': 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb'} +TEST_FLAVOR_SWAP = 1 +TEST_FLAVOR_ROOTGB = 1 +TEST_FLAVOR_MEMORYMB = 1 +TEST_FLAVOR_VCPUS = 1 +TEST_FLAVOR_EPHEMERALGB = 0 + def get_test_validation(**kw): result = { @@ -174,18 +192,15 @@ def get_test_volume_target(**kw): def get_test_flavor(**kw): - default_extra_specs = { - 'baremetal:deploy_kernel_id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', - 'baremetal:deploy_ramdisk_id': 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', - } flavor = { - 'name': kw.get('name', 'fake.flavor'), - 'extra_specs': kw.get('extra_specs', default_extra_specs), - 'swap': kw.get('swap', 0), - 'root_gb': 1, - 'memory_mb': 1, - 'vcpus': 1, - 'ephemeral_gb': kw.get('ephemeral_gb', 0), + 'id': kw.get('id', TEST_FLAVOR_ID), + 'name': kw.get('name', TEST_FLAVOR_NAME), + 'extra_specs': kw.get('extra_specs', TEST_FLAVOR_EXTRA_SPECS), + 'swap': kw.get('swap', TEST_FLAVOR_SWAP), + 'root_gb': TEST_FLAVOR_ROOTGB, + 'memory_mb': TEST_FLAVOR_MEMORYMB, + 'vcpus': TEST_FLAVOR_VCPUS, + 'ephemeral_gb': kw.get('ephemeral_gb', TEST_FLAVOR_EPHEMERALGB), } return objects.Flavor(**flavor) @@ -193,5 +208,41 @@ def get_test_flavor(**kw): def get_test_image_meta(**kw): return objects.ImageMeta.from_dict( - {'id': kw.get('id', 'cccccccc-cccc-cccc-cccc-cccccccccccc')}, + {'id': kw.get('id', TEST_IMAGE_UUID)}, + ) + + +def get_test_instance_driver_metadata(**kw): + default_instance_meta = driver.NovaInstanceMeta( + name=kw.get('instance_name', 'testinstance'), + uuid=kw.get('instance_uuid', 'iiiiiii-iiii-iiii-iiii-iiiiiiiiiiii')) + default_owner_meta = driver.OwnerMeta( + userid='uuuuuuu-uuuu-uuuu-uuuu-uuuuuuuuuuuu', + username='testuser', + projectid='ppppppp-pppp-pppp-pppp-pppppppppppp', + projectname='testproject') + default_image_meta = driver.ImageMeta(id=TEST_IMAGE_UUID, + name=TEST_IMAGE_NAME, + properties={}) + default_flavor_meta = driver.FlavorMeta( + name=kw.get('flavor_name', TEST_FLAVOR_NAME), + memory_mb=kw.get('flavor_memorymb', + TEST_FLAVOR_MEMORYMB), + vcpus=kw.get('flavor_vcpus', TEST_FLAVOR_VCPUS), + root_gb=kw.get('flavor_rootgb', + TEST_FLAVOR_ROOTGB), + ephemeral_gb=kw.get('flavor_ephemeralgb', + TEST_FLAVOR_EPHEMERALGB), + extra_specs=kw.get('flavor_extra_specs', + TEST_FLAVOR_EXTRA_SPECS), + swap=kw.get('flavor_swap', TEST_FLAVOR_SWAP)) + + return driver.InstanceDriverMetadata( + root_type=kw.get('root_type', 'roottype'), + root_id=kw.get('root_id', 'rootid'), + instance_meta=kw.get('instance_meta', default_instance_meta), + owner=kw.get('owner_meta', default_owner_meta), + image=kw.get('image_meta', default_image_meta), + flavor=kw.get('flavor_meta', default_flavor_meta), + network_info=kw.get('network_info', network_model.NetworkInfo()) ) diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 660b671f2ec3..7748650dd6f6 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -2591,17 +2591,19 @@ class LibvirtConnTestCase(test.NoDBTestCase, def test_get_guest_config_meta_with_no_port(self): drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) - meta = drvr._get_guest_config_meta( - objects.Instance(**self.test_instance), - _fake_network_info(self, num_networks=0)) + idm = drvr.get_instance_driver_metadata( + objects.Instance(**self.test_instance), + _fake_network_info(self, num_networks=0)) + meta = drvr._get_guest_config_meta(idm) self.assertEqual(len(meta.ports.ports), 0) def test_get_guest_config_meta_with_multiple_ports(self): drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) - meta = drvr._get_guest_config_meta( - objects.Instance(**self.test_instance), - _fake_network_info(self, num_networks=2)) + idm = drvr.get_instance_driver_metadata( + objects.Instance(**self.test_instance), + _fake_network_info(self, num_networks=2)) + meta = drvr._get_guest_config_meta(idm) self.assertEqual(len(meta.ports.ports), 2) @@ -2649,6 +2651,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, user_name="pie", ) flavor = objects.Flavor( + id=1, name='m1.small', memory_mb=6, vcpus=28, @@ -2775,6 +2778,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, ephemeral_gb=8128, swap=33550336, extra_specs={}, + id=42 ) instance_ref = objects.Instance(**test_instance) instance_ref.flavor = flavor @@ -2927,13 +2931,10 @@ class LibvirtConnTestCase(test.NoDBTestCase, user_id=456, user_name="pie") - flavor = objects.Flavor(name='m1.small', - memory_mb=6, - vcpus=28, - root_gb=496, - ephemeral_gb=8128, - swap=33550336, - extra_specs={}) + flavor = objects.Flavor( + id=42, name='m1.small', memory_mb=6, + vcpus=28, root_gb=496, ephemeral_gb=8128, + swap=33550336, extra_specs={}) instance_ref = objects.Instance(**test_instance) instance_ref.flavor = flavor image_meta = objects.ImageMeta.from_dict(self.test_image_meta) @@ -3106,7 +3107,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, image_meta = objects.ImageMeta.from_dict(self.test_image_meta) flavor = objects.Flavor(memory_mb=1, vcpus=2, root_gb=496, ephemeral_gb=8128, swap=33550336, name='fake', - extra_specs={}) + extra_specs={}, id=42) instance_ref.flavor = flavor caps = vconfig.LibvirtConfigCaps() @@ -3140,9 +3141,10 @@ class LibvirtConnTestCase(test.NoDBTestCase, def test_get_guest_config_numa_host_instance_no_fit(self): instance_ref = objects.Instance(**self.test_instance) image_meta = objects.ImageMeta.from_dict(self.test_image_meta) - flavor = objects.Flavor(memory_mb=4096, vcpus=4, root_gb=496, - ephemeral_gb=8128, swap=33550336, name='fake', - extra_specs={}) + flavor = objects.Flavor( + id=42, memory_mb=4096, vcpus=4, root_gb=496, + ephemeral_gb=8128, swap=33550336, name='fake', + extra_specs={}) instance_ref.flavor = flavor caps = vconfig.LibvirtConfigCaps() @@ -3475,13 +3477,10 @@ class LibvirtConnTestCase(test.NoDBTestCase, extra_specs = { "hw:mem_encryption": True, } - flavor = objects.Flavor(name='m1.small', - memory_mb=6, - vcpus=28, - root_gb=496, - ephemeral_gb=8128, - swap=33550336, - extra_specs=extra_specs) + flavor = objects.Flavor( + id=42, name='m1.small', memory_mb=6, + vcpus=28, root_gb=496, ephemeral_gb=8128, + swap=33550336, extra_specs=extra_specs) instance_ref = objects.Instance(**self.test_instance) instance_ref.flavor = flavor @@ -3573,7 +3572,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, image_meta = objects.ImageMeta.from_dict(self.test_image_meta) flavor = objects.Flavor(memory_mb=1, vcpus=2, root_gb=496, ephemeral_gb=8128, swap=33550336, name='fake', - extra_specs={}) + extra_specs={}, id=42) instance_ref.flavor = flavor caps = vconfig.LibvirtConfigCaps() @@ -3626,7 +3625,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, image_meta = objects.ImageMeta.from_dict(self.test_image_meta) flavor = objects.Flavor(memory_mb=4096, vcpus=4, root_gb=496, ephemeral_gb=8128, swap=33550336, name='fake', - extra_specs={}) + extra_specs={}, id=42) instance_ref.flavor = flavor caps = vconfig.LibvirtConfigCaps() @@ -3744,7 +3743,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, image_meta = objects.ImageMeta.from_dict(self.test_image_meta) flavor = objects.Flavor(memory_mb=1024, vcpus=2, root_gb=496, ephemeral_gb=8128, swap=33550336, name='fake', - extra_specs={}) + extra_specs={}, id=42) instance_ref.flavor = flavor caps = vconfig.LibvirtConfigCaps() @@ -3787,7 +3786,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, image_meta = objects.ImageMeta.from_dict(self.test_image_meta) flavor = objects.Flavor(memory_mb=2048, vcpus=2, root_gb=496, ephemeral_gb=8128, swap=33550336, name='fake', - extra_specs={}) + extra_specs={}, id=42) instance_ref.flavor = flavor caps = vconfig.LibvirtConfigCaps() @@ -3840,7 +3839,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, image_meta = objects.ImageMeta.from_dict(self.test_image_meta) flavor = objects.Flavor(memory_mb=2048, vcpus=4, root_gb=496, ephemeral_gb=8128, swap=33550336, name='fake', - extra_specs={}) + extra_specs={}, id=42) instance_ref.flavor = flavor caps = vconfig.LibvirtConfigCaps() @@ -3917,7 +3916,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, image_meta = objects.ImageMeta.from_dict(self.test_image_meta) flavor = objects.Flavor(memory_mb=2048, vcpus=4, root_gb=496, ephemeral_gb=8128, swap=33550336, name='fake', - extra_specs={}) + extra_specs={}, id=42) instance_ref.flavor = flavor caps = vconfig.LibvirtConfigCaps() @@ -3995,7 +3994,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, image_meta = objects.ImageMeta.from_dict(self.test_image_meta) flavor = objects.Flavor(memory_mb=2048, vcpus=2, root_gb=496, ephemeral_gb=8128, swap=33550336, name='fake', - extra_specs={}) + extra_specs={}, id=42) instance_ref.flavor = flavor caps = vconfig.LibvirtConfigCaps() @@ -4084,7 +4083,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, image_meta = objects.ImageMeta.from_dict(self.test_image_meta) flavor = objects.Flavor(memory_mb=2048, vcpus=8, root_gb=496, ephemeral_gb=8128, swap=33550336, name='fake', - extra_specs={}) + extra_specs={}, id=42) instance_ref.flavor = flavor caps = vconfig.LibvirtConfigCaps() @@ -4198,7 +4197,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, image_meta = objects.ImageMeta.from_dict(self.test_image_meta) flavor = objects.Flavor(memory_mb=2048, vcpus=8, root_gb=496, ephemeral_gb=8128, swap=33550336, name='fake', - extra_specs={}) + extra_specs={}, id=42) instance_ref.flavor = flavor caps = vconfig.LibvirtConfigCaps() @@ -4301,7 +4300,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, "hw:cpu_realtime": "yes", "hw:cpu_policy": "mixed", "hw:cpu_realtime_mask": "^2-3" - }) + }, id=42) instance_ref.flavor = flavor caps = vconfig.LibvirtConfigCaps() @@ -4410,7 +4409,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, image_meta = objects.ImageMeta.from_dict(self.test_image_meta) flavor = objects.Flavor(memory_mb=2048, vcpus=4, root_gb=496, ephemeral_gb=8128, swap=33550336, name='fake', - extra_specs={}) + extra_specs={}, id=42) instance_ref.flavor = flavor caps = vconfig.LibvirtConfigCaps() @@ -4494,7 +4493,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, "hw:cpu_realtime": "yes", "hw:cpu_policy": "dedicated", "hw:cpu_realtime_mask": "^0-1" - }) + }, id=42) instance_ref.flavor = flavor caps = vconfig.LibvirtConfigCaps() @@ -22933,6 +22932,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin): inst = {} inst['id'] = 1 inst['uuid'] = uuids.fake_instance_id + inst['display_name'] = 'fake-instance' inst['os_type'] = 'linux' inst['image_ref'] = uuids.fake_image_ref inst['reservation_id'] = 'r-fakeres' @@ -25002,13 +25002,16 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin): instance, 'get_network_info', return_value=network_info), mock.patch.object( self.drvr, '_detach_with_retry'), + mock.patch.object( + self.drvr, 'get_instance_driver_metadata' + ), mock.patch.object( self.drvr, '_get_guest_config_meta', return_value=config_meta), mock.patch.object(guest, 'set_metadata') ) as ( mock_get_guest, mock_get_config, mock_get_network_info, - mock_detach_with_retry, mock_get_guest_config_meta, - mock_set_metadata + mock_detach_with_retry, mock_get_instance_driver_metadata, + mock_get_guest_config_meta, mock_set_metadata ): self.drvr.detach_interface(self.context, instance, vif) mock_get_guest.assert_called_once_with(instance) @@ -25018,8 +25021,9 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin): mock_detach_with_retry.assert_called_once_with( guest, instance.uuid, mock.ANY, device_name=None) mock_get_network_info.assert_called_once_with() - mock_get_guest_config_meta.assert_called_once_with( + mock_get_instance_driver_metadata.assert_called_once_with( instance, network_info[1:]) + mock_get_guest_config_meta.assert_called_once() mock_set_metadata.assert_called_once_with(config_meta) def test__detach_with_retry_persistent_success(self): diff --git a/nova/virt/driver.py b/nova/virt/driver.py index f7f3530c638f..d2eef4e21938 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -20,26 +20,78 @@ Driver base-classes: types that support that contract """ +import dataclasses import itertools import sys +import time import typing as ty import os_resource_classes as orc import os_traits + from oslo_log import log as logging from oslo_utils import importutils import nova.conf +import nova.virt.node + from nova import context as nova_context from nova.i18n import _ +from nova.network import model as network_model from nova import objects +from nova import version from nova.virt import event as virtevent -import nova.virt.node CONF = nova.conf.CONF LOG = logging.getLogger(__name__) +@dataclasses.dataclass +class FlavorMeta: + name: str + memory_mb: int + vcpus: int + root_gb: int + ephemeral_gb: int + extra_specs: dict + swap: int + + +@dataclasses.dataclass +class ImageMeta: + id: str + name: str + properties: dict + + +@dataclasses.dataclass +class NovaInstanceMeta: + name: str + uuid: str + + +@dataclasses.dataclass +class OwnerMeta: + userid: str + username: str + projectid: str + projectname: str + + +@dataclasses.dataclass +class InstanceDriverMetadata: + root_type: str + root_id: str + instance_meta: NovaInstanceMeta + owner: OwnerMeta + image: ImageMeta + flavor: FlavorMeta + network_info: network_model.NetworkInfo + nova_package: str = dataclasses.field( + default_factory=version.version_string_with_package) + creation_time: float = dataclasses.field(default_factory=time.time) + + def get_block_device_info(instance, block_device_mapping): """Converts block device mappings for an instance to driver format. @@ -294,6 +346,55 @@ class ComputeDriver(object): # TODO(Vek): Need to pass context in for access to auth_token raise NotImplementedError() + @classmethod + def get_instance_driver_metadata( + cls, instance: 'nova.objects.instance.Instance', + network_info: network_model.NetworkInfo + ) -> InstanceDriverMetadata: + """Get driver metadata from instance and network info + + :param instance: nova.objects.instance.Instance + :param network_info: instance network information + :returns: InstanceDriverMetadata + """ + + instance_name = instance.display_name or instance.uuid + system_meta = instance.system_metadata + instance_meta = NovaInstanceMeta( + str(instance_name), str(instance.uuid)) + owner = OwnerMeta( + userid=instance.user_id, + username=system_meta.get('owner_user_name', 'N/A'), + projectid=instance.project_id, + projectname=system_meta.get('owner_project_name', 'N/A') + ) + flavor = FlavorMeta( + name=instance.flavor.name, + memory_mb=instance.flavor.memory_mb, + vcpus=instance.flavor.vcpus, + ephemeral_gb=instance.flavor.ephemeral_gb, + root_gb=instance.flavor.root_gb, + swap=instance.flavor.swap, + extra_specs=instance.flavor.extra_specs, + ) + image = ImageMeta( + id=instance.image_ref, + name=system_meta.get('image_name'), + properties=instance.image_meta.properties + ) + meta = InstanceDriverMetadata( + instance_meta=instance_meta, + owner=owner, + flavor=flavor, + image=image, + root_type = 'image' if instance.image_ref else 'volume', + root_id = instance.image_ref, + creation_time = time.time(), + network_info=network_info + ) + LOG.debug('InstanceDriverMetadata: %s', meta) + return meta + def get_num_instances(self): """Return the total number of virtual machines. diff --git a/nova/virt/ironic/driver.py b/nova/virt/ironic/driver.py index c99021866962..135422c66014 100644 --- a/nova/virt/ironic/driver.py +++ b/nova/virt/ironic/driver.py @@ -404,7 +404,7 @@ class IronicDriver(virt_driver.ComputeDriver): self._cleanup_deploy(node, instance) def _add_instance_info_to_node(self, node, instance, image_meta, flavor, - preserve_ephemeral=None, + metadata, preserve_ephemeral=None, block_device_info=None): root_bdm = block_device.get_root_bdm( @@ -413,6 +413,7 @@ class IronicDriver(virt_driver.ComputeDriver): patch = patcher.create(node).get_deploy_patch(instance, image_meta, flavor, + metadata, preserve_ephemeral, boot_from_volume) @@ -1157,7 +1158,7 @@ class IronicDriver(virt_driver.ComputeDriver): :param network_info: Instance network information. :param block_device_info: Instance block device information. - :param arqs: Accelerator requests for this instance. + :param accel_info: Accelerator requests for this instance. :param power_on: True if the instance should be powered on, False otherwise """ @@ -1175,7 +1176,9 @@ class IronicDriver(virt_driver.ComputeDriver): node = self._get_node(node_id) flavor = instance.flavor + metadata = self.get_instance_driver_metadata(instance, network_info) self._add_instance_info_to_node(node, instance, image_meta, flavor, + metadata, block_device_info=block_device_info) try: @@ -1739,7 +1742,8 @@ class IronicDriver(virt_driver.ComputeDriver): node_id = instance.node node = self._get_node(node_id) - self._add_instance_info_to_node(node, instance, image_meta, + metadata = self.get_instance_driver_metadata(instance, network_info) + self._add_instance_info_to_node(node, instance, image_meta, metadata, instance.flavor, preserve_ephemeral) # Config drive diff --git a/nova/virt/ironic/patcher.py b/nova/virt/ironic/patcher.py index e1f9a6256c78..8384c23484a4 100644 --- a/nova/virt/ironic/patcher.py +++ b/nova/virt/ironic/patcher.py @@ -40,13 +40,14 @@ class GenericDriverFields(object): def __init__(self, node): self.node = node - def get_deploy_patch(self, instance, image_meta, flavor, + def get_deploy_patch(self, instance, image_meta, flavor, metadata, preserve_ephemeral=None, boot_from_volume=False): """Build a patch to add the required fields to deploy a node. :param instance: the instance object. :param image_meta: the nova.objects.ImageMeta object instance :param flavor: the flavor object. + :param metadata: nova.virt.driver.InstanceDriverMetadata dataclass :param preserve_ephemeral: preserve_ephemeral status (bool) to be specified during rebuild. :param boot_from_volume: True if node boots from volume. Then, @@ -73,6 +74,21 @@ class GenericDriverFields(object): patch.append({'path': '/instance_info/local_gb', 'op': 'add', 'value': str(self.node.properties.get('local_gb', 0))}) + patch.append({'path': '/instance_info/project_id', 'op': 'add', + 'value': str(metadata.owner.projectid)}) + patch.append({'path': '/instance_info/project_name', 'op': 'add', + 'value': str(metadata.owner.projectname)}) + patch.append({'path': '/instance_info/user_id', 'op': 'add', + 'value': str(metadata.owner.userid)}) + patch.append({'path': '/instance_info/user_name', 'op': 'add', + 'value': str(metadata.owner.username)}) + patch.append({'path': '/instance_info/flavor_name', 'op': 'add', + 'value': str(metadata.flavor.name)}) + patch.append({'path': '/instance_info/fixed_ips', 'op': 'add', + 'value': str(metadata.network_info.fixed_ips())}) + patch.append({'path': '/instance_info/floating_ips', 'op': 'add', + 'value': str(metadata.network_info.floating_ips())}) + if instance.flavor.ephemeral_gb: patch.append({'path': '/instance_info/ephemeral_gb', 'op': 'add', diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 37613eb2c61f..60dd39a7b25b 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -3052,7 +3052,8 @@ class LibvirtDriver(driver.ComputeDriver): try: guest.set_metadata( self._get_guest_config_meta( - instance, instance.get_network_info())) + self.get_instance_driver_metadata( + instance, instance.get_network_info()))) except libvirt.libvirtError: LOG.warning('updating libvirt metadata failed.', instance=instance) @@ -3091,7 +3092,9 @@ class LibvirtDriver(driver.ComputeDriver): network_info = list(filter(lambda info: info['id'] != vif['id'], instance.get_network_info())) guest.set_metadata( - self._get_guest_config_meta(instance, network_info)) + self._get_guest_config_meta( + self.get_instance_driver_metadata( + instance, network_info))) except libvirt.libvirtError: LOG.warning('updating libvirt metadata failed.', instance=instance) @@ -6073,39 +6076,35 @@ class LibvirtDriver(driver.ComputeDriver): return dev - def _get_guest_config_meta(self, instance, network_info): + def _get_guest_config_meta(self, dmeta: driver.InstanceDriverMetadata): """Get metadata config for guest.""" meta = vconfig.LibvirtConfigGuestMetaNovaInstance() - meta.package = version.version_string_with_package() - meta.name = instance.display_name - meta.creationTime = time.time() + meta.package = dmeta.nova_package + meta.name = dmeta.instance_meta.name + meta.creationTime = dmeta.creation_time + meta.roottype = dmeta.root_type + meta.rootid = dmeta.root_id - if instance.image_ref not in ("", None): - meta.roottype = "image" - meta.rootid = instance.image_ref - - system_meta = instance.system_metadata ometa = vconfig.LibvirtConfigGuestMetaNovaOwner() - ometa.userid = instance.user_id - ometa.username = system_meta.get('owner_user_name', 'N/A') - ometa.projectid = instance.project_id - ometa.projectname = system_meta.get('owner_project_name', 'N/A') + ometa.userid = dmeta.owner.userid + ometa.username = dmeta.owner.username + ometa.projectid = dmeta.owner.projectid + ometa.projectname = dmeta.owner.projectname meta.owner = ometa fmeta = vconfig.LibvirtConfigGuestMetaNovaFlavor() - flavor = instance.flavor - fmeta.name = flavor.name - fmeta.memory = flavor.memory_mb - fmeta.vcpus = flavor.vcpus - fmeta.ephemeral = flavor.ephemeral_gb - fmeta.disk = flavor.root_gb - fmeta.swap = flavor.swap + fmeta.name = dmeta.flavor.name + fmeta.memory = dmeta.flavor.memory_mb + fmeta.vcpus = dmeta.flavor.vcpus + fmeta.ephemeral = dmeta.flavor.ephemeral_gb + fmeta.disk = dmeta.flavor.root_gb + fmeta.swap = dmeta.flavor.swap meta.flavor = fmeta ports = [] - for vif in network_info: + for vif in dmeta.network_info: ips = [] for subnet in vif.get('network', {}).get('subnets', []): for ip in subnet.get('ips', []): @@ -7353,8 +7352,10 @@ class LibvirtDriver(driver.ComputeDriver): guest_numa_config.numatune, flavor, image_meta) - guest.metadata.append(self._get_guest_config_meta( - instance, network_info)) + guest.metadata.append( + self._get_guest_config_meta( + self.get_instance_driver_metadata( + instance, network_info))) guest.idmaps = self._get_guest_idmaps() for event in self._supported_perf_events: