From b34809dfae862e37b1362b73fd258af8d12adae5 Mon Sep 17 00:00:00 2001 From: Sam Betts Date: Tue, 17 Jan 2017 12:45:21 +0000 Subject: [PATCH] Ensure we mark baremetal links as phy links In the Ironic multi-tenant case, the neutron ports will remain unbound until later in the deploy process. Nova generates the network_data.json file with all the links marked as unbound, which we need to correct as these links will be bound after the config drive is generated and written to the node. This patch updates the Ironic virt driver to correct the network metadata. Change-Id: I1881f4a9bca6a6d6a3b4e0e89a82b0765ae09eee Closes-Bug: #1656854 --- nova/tests/unit/virt/ironic/test_driver.py | 32 +++++++++++++++++++--- nova/virt/ironic/driver.py | 23 ++++++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/nova/tests/unit/virt/ironic/test_driver.py b/nova/tests/unit/virt/ironic/test_driver.py index 23e1e23814cd..a266f2dd1728 100644 --- a/nova/tests/unit/virt/ironic/test_driver.py +++ b/nova/tests/unit/virt/ironic/test_driver.py @@ -1748,11 +1748,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, @@ -1762,16 +1766,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): diff --git a/nova/virt/ironic/driver.py b/nova/virt/ironic/driver.py index dfcd067240a3..30fe42e35455 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 @@ -700,6 +701,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. @@ -718,6 +740,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: