diff --git a/nova/tests/unit/virt/ironic/test_driver.py b/nova/tests/unit/virt/ironic/test_driver.py index 18cc374ab9f7..f9e7d265d727 100644 --- a/nova/tests/unit/virt/ironic/test_driver.py +++ b/nova/tests/unit/virt/ironic/test_driver.py @@ -1723,11 +1723,15 @@ class IronicDriverGenerateConfigDriveTestCase(test.NoDBTestCase): mock_instance_meta.return_value = 'fake-instance' mock_make_drive = mock.MagicMock(make_drive=lambda *_: None) mock_cd_builder.return_value.__enter__.return_value = mock_make_drive + network_metadata_mock = mock.Mock() + self.driver._get_network_metadata = network_metadata_mock self.driver._generate_configdrive(None, self.instance, self.node, self.network_info) mock_cd_builder.assert_called_once_with(instance_md='fake-instance') - mock_instance_meta.assert_called_once_with(self.instance, - network_info=self.network_info, extra_md={}, content=None, + mock_instance_meta.assert_called_once_with( + self.instance, content=None, extra_md={}, + network_info=self.network_info, + network_metadata=network_metadata_mock.return_value, request_context=None) def test_generate_configdrive_fail(self, mock_cd_builder, @@ -1737,16 +1741,36 @@ class IronicDriverGenerateConfigDriveTestCase(test.NoDBTestCase): mock_instance_meta.return_value = 'fake-instance' mock_make_drive = mock.MagicMock(make_drive=lambda *_: None) mock_cd_builder.return_value.__enter__.return_value = mock_make_drive + network_metadata_mock = mock.Mock() + self.driver._get_network_metadata = network_metadata_mock self.assertRaises(exception.ConfigDriveMountFailed, self.driver._generate_configdrive, None, self.instance, self.node, self.network_info) mock_cd_builder.assert_called_once_with(instance_md='fake-instance') - mock_instance_meta.assert_called_once_with(self.instance, - network_info=self.network_info, extra_md={}, content=None, + mock_instance_meta.assert_called_once_with( + self.instance, content=None, extra_md={}, + network_info=self.network_info, + network_metadata=network_metadata_mock.return_value, request_context=None) + @mock.patch.object(FAKE_CLIENT.node, 'list_ports') + def test_generate_network_metadata_ports_only( + self, mock_ports, mock_cd_builder, mock_instance_meta): + address = self.network_info[0]['address'] + port = ironic_utils.get_test_port( + node_uuid=self.node.uuid, address=address, + internal_info={'tenant_vif_port_id': utils.FAKE_VIF_UUID}) + mock_ports.return_value = [port] + + metadata = self.driver._get_network_metadata(self.node, + self.network_info) + + self.assertEqual(port.address, + metadata['links'][0]['ethernet_mac_address']) + self.assertEqual('phy', metadata['links'][0]['type']) + class HashRingTestCase(test.NoDBTestCase): @mock.patch.object(servicegroup, 'API', autospec=True) diff --git a/nova/virt/ironic/driver.py b/nova/virt/ironic/driver.py index 5ef3394d9eec..78f548eb87c3 100644 --- a/nova/virt/ironic/driver.py +++ b/nova/virt/ironic/driver.py @@ -56,6 +56,7 @@ from nova.virt import hardware from nova.virt.ironic import client_wrapper from nova.virt.ironic import ironic_states from nova.virt.ironic import patcher +from nova.virt import netutils ironic = None @@ -684,6 +685,27 @@ class IronicDriver(virt_driver.ComputeDriver): ports = self.ironicclient.call("node.list_ports", node.uuid) return set([p.address for p in ports]) + def _get_network_metadata(self, node, network_info): + """Gets a more complete representation of the instance network info. + + This data is exposed as network_data.json in the metadata service and + the config drive. + + :param node: The node object. + :param network_info: Instance network information. + """ + base_metadata = netutils.get_network_metadata(network_info) + + ports = self.ironicclient.call("node.list_ports", + node.uuid, detail=True) + + for port in ports: + for link in base_metadata['links']: + if link['ethernet_mac_address'] == port.address: + link['type'] = 'phy' + + return base_metadata + def _generate_configdrive(self, context, instance, node, network_info, extra_md=None, files=None): """Generate a config drive. @@ -702,6 +724,7 @@ class IronicDriver(virt_driver.ComputeDriver): i_meta = instance_metadata.InstanceMetadata(instance, content=files, extra_md=extra_md, network_info=network_info, + network_metadata=self._get_network_metadata(node, network_info), request_context=context) with tempfile.NamedTemporaryFile() as uncompressed: