From cf412bc81e4182a7c332545cfeb6e154015e3dc3 Mon Sep 17 00:00:00 2001 From: Julia Kreger Date: Fri, 20 Mar 2020 12:57:47 -0700 Subject: "dual stack" support for PXE/iPXE Adds functionality for dual stack capabilities and automatic population to neutron with the correct response based upon the IP version of the provisioning/cleaning/rescue or tenant ports. This was origianlly intended to be separated from removing the need for [pxe]ip_version, however the resulting code changes from doing both this and making ironic support dual stacks touched the same tests and some of the same code, so combined is simpler. Change-Id: If7a296001e204ae0c9a49495731052ab33379628 --- ironic/tests/unit/dhcp/test_neutron.py | 66 +++++++++++++++++++++++++- ironic/tests/unit/drivers/modules/test_ipxe.py | 19 ++++++-- ironic/tests/unit/drivers/modules/test_pxe.py | 17 ++++++- 3 files changed, 96 insertions(+), 6 deletions(-) (limited to 'ironic/tests') diff --git a/ironic/tests/unit/dhcp/test_neutron.py b/ironic/tests/unit/dhcp/test_neutron.py index 29983e7d3..391b1cf74 100644 --- a/ironic/tests/unit/dhcp/test_neutron.py +++ b/ironic/tests/unit/dhcp/test_neutron.py @@ -48,8 +48,9 @@ class TestNeutron(db_base.DbTestCase): dhcp_factory.DHCPFactory._dhcp_provider = None + @mock.patch('ironic.common.neutron.get_client', autospec=True) @mock.patch('ironic.common.neutron.update_neutron_port', autospec=True) - def test_update_port_dhcp_opts(self, update_mock): + def test_update_port_dhcp_opts(self, update_mock, client_mock): opts = [{'opt_name': 'bootfile-name', 'opt_value': 'pxelinux.0'}, {'opt_name': 'tftp-server', @@ -58,6 +59,56 @@ class TestNeutron(db_base.DbTestCase): 'opt_value': '1.1.1.1'}] port_id = 'fake-port-id' expected = {'port': {'extra_dhcp_opts': opts}} + port_data = { + "id": port_id, + "fixed_ips": [ + { + "ip_address": "192.168.1.3", + } + ], + } + client_mock.return_value.show_port.return_value = {'port': port_data} + + api = dhcp_factory.DHCPFactory() + with task_manager.acquire(self.context, self.node.uuid) as task: + api.provider.update_port_dhcp_opts(port_id, opts, + context=task.context) + update_mock.assert_called_once_with( + self.context, port_id, expected) + + @mock.patch('ironic.common.neutron.get_client', autospec=True) + @mock.patch('ironic.common.neutron.update_neutron_port', autospec=True) + def test_update_port_dhcp_opts_v6(self, update_mock, client_mock): + opts = [{'opt_name': 'bootfile-name', + 'opt_value': 'pxelinux.0', + 'ip_version': 4}, + {'opt_name': 'tftp-server', + 'opt_value': '1.1.1.1', + 'ip_version': 4}, + {'opt_name': 'server-ip-address', + 'opt_value': '1.1.1.1', + 'ip_version': 4}, + {'opt_name': 'bootfile-url', + 'opt_value': 'tftp://::1/file.name', + 'ip_version': 6}] + port_id = 'fake-port-id' + expected = { + 'port': { + 'extra_dhcp_opts': [{ + 'opt_name': 'bootfile-url', + 'opt_value': 'tftp://::1/file.name', + 'ip_version': 6}] + } + } + port_data = { + "id": port_id, + "fixed_ips": [ + { + "ip_address": "2001:db8::201", + } + ], + } + client_mock.return_value.show_port.return_value = {'port': port_data} api = dhcp_factory.DHCPFactory() with task_manager.acquire(self.context, self.node.uuid) as task: @@ -66,10 +117,21 @@ class TestNeutron(db_base.DbTestCase): update_mock.assert_called_once_with( task.context, port_id, expected) + @mock.patch('ironic.common.neutron.get_client', autospec=True) @mock.patch('ironic.common.neutron.update_neutron_port', autospec=True) - def test_update_port_dhcp_opts_with_exception(self, update_mock): + def test_update_port_dhcp_opts_with_exception(self, update_mock, + client_mock): opts = [{}] port_id = 'fake-port-id' + port_data = { + "id": port_id, + "fixed_ips": [ + { + "ip_address": "192.168.1.3", + } + ], + } + client_mock.return_value.show_port.return_value = {'port': port_data} update_mock.side_effect = ( neutron_client_exc.NeutronClientException()) diff --git a/ironic/tests/unit/drivers/modules/test_ipxe.py b/ironic/tests/unit/drivers/modules/test_ipxe.py index 2c78a7550..4b1d81670 100644 --- a/ironic/tests/unit/drivers/modules/test_ipxe.py +++ b/ironic/tests/unit/drivers/modules/test_ipxe.py @@ -270,11 +270,14 @@ class iPXEBootTestCase(db_base.DbTestCase): self.node.save() with task_manager.acquire(self.context, self.node.uuid) as task: dhcp_opts = pxe_utils.dhcp_options_for_instance( - task, ipxe_enabled=True) + task, ipxe_enabled=True, ip_version=4) + dhcp_opts += pxe_utils.dhcp_options_for_instance( + task, ipxe_enabled=True, ip_version=6) task.driver.boot.prepare_ramdisk(task, {'foo': 'bar'}) mock_deploy_img_info.assert_called_once_with(task.node, mode=mode, ipxe_enabled=True) - provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts) + provider_mock.update_dhcp.assert_called_once_with( + task, dhcp_opts) if self.node.provision_state == states.DEPLOYING: get_boot_mode_mock.assert_called_once_with(task) set_boot_device_mock.assert_called_once_with(task, @@ -630,6 +633,8 @@ class iPXEBootTestCase(db_base.DbTestCase): with task_manager.acquire(self.context, self.node.uuid) as task: dhcp_opts = pxe_utils.dhcp_options_for_instance( task, ipxe_enabled=True) + dhcp_opts += pxe_utils.dhcp_options_for_instance( + task, ipxe_enabled=True, ip_version=6) pxe_config_path = pxe_utils.get_pxe_config_file_path( task.node.uuid, ipxe_enabled=True) task.node.properties['capabilities'] = 'boot_mode:bios' @@ -672,6 +677,8 @@ class iPXEBootTestCase(db_base.DbTestCase): with task_manager.acquire(self.context, self.node.uuid) as task: dhcp_opts = pxe_utils.dhcp_options_for_instance( task, ipxe_enabled=True) + dhcp_opts += pxe_utils.dhcp_options_for_instance( + task, ipxe_enabled=True, ip_version=6) pxe_config_path = pxe_utils.get_pxe_config_file_path( task.node.uuid, ipxe_enabled=True) task.node.properties['capabilities'] = 'boot_mode:bios' @@ -710,7 +717,9 @@ class iPXEBootTestCase(db_base.DbTestCase): get_image_info_mock.return_value = image_info with task_manager.acquire(self.context, self.node.uuid) as task: dhcp_opts = pxe_utils.dhcp_options_for_instance( - task, ipxe_enabled=True) + task, ipxe_enabled=True, ip_version=4) + dhcp_opts += pxe_utils.dhcp_options_for_instance( + task, ipxe_enabled=True, ip_version=6) task.node.properties['capabilities'] = 'boot_mode:bios' task.node.driver_internal_info['is_whole_disk_image'] = False @@ -742,6 +751,8 @@ class iPXEBootTestCase(db_base.DbTestCase): with task_manager.acquire(self.context, self.node.uuid) as task: dhcp_opts = pxe_utils.dhcp_options_for_instance( task, ipxe_enabled=True) + dhcp_opts += pxe_utils.dhcp_options_for_instance( + task, ipxe_enabled=True, ip_version=6) task.node.properties['capabilities'] = 'boot_mode:bios' task.node.driver_internal_info['is_whole_disk_image'] = True task.driver.boot.prepare_instance(task) @@ -786,6 +797,8 @@ class iPXEBootTestCase(db_base.DbTestCase): 'boot_from_volume': vol_id} dhcp_opts = pxe_utils.dhcp_options_for_instance(task, ipxe_enabled=True) + dhcp_opts += pxe_utils.dhcp_options_for_instance( + task, ipxe_enabled=True, ip_version=6) pxe_config_path = pxe_utils.get_pxe_config_file_path( task.node.uuid, ipxe_enabled=True) task.node.properties['capabilities'] = 'boot_mode:bios' diff --git a/ironic/tests/unit/drivers/modules/test_pxe.py b/ironic/tests/unit/drivers/modules/test_pxe.py index 33b487db2..f5ef8cd26 100644 --- a/ironic/tests/unit/drivers/modules/test_pxe.py +++ b/ironic/tests/unit/drivers/modules/test_pxe.py @@ -86,6 +86,7 @@ class PXEBootTestCase(db_base.DbTestCase): self.port = obj_utils.create_test_port(self.context, node_id=self.node.id) self.config(group='conductor', api_url='http://127.0.0.1:1234/') + self.config(my_ipv6='2001:db8::1') def test_get_properties(self): expected = pxe_base.COMMON_PROPERTIES @@ -267,6 +268,8 @@ class PXEBootTestCase(db_base.DbTestCase): with task_manager.acquire(self.context, self.node.uuid) as task: dhcp_opts = pxe_utils.dhcp_options_for_instance( task, ipxe_enabled=False) + dhcp_opts += pxe_utils.dhcp_options_for_instance( + task, ipxe_enabled=False, ip_version=6) task.driver.boot.prepare_ramdisk(task, {'foo': 'bar'}) mock_deploy_img_info.assert_called_once_with(task.node, mode=mode, @@ -552,7 +555,9 @@ class PXEBootTestCase(db_base.DbTestCase): get_image_info_mock.return_value = image_info with task_manager.acquire(self.context, self.node.uuid) as task: dhcp_opts = pxe_utils.dhcp_options_for_instance( - task, ipxe_enabled=False) + task, ipxe_enabled=False, ip_version=4) + dhcp_opts += pxe_utils.dhcp_options_for_instance( + task, ipxe_enabled=False, ip_version=6) pxe_config_path = pxe_utils.get_pxe_config_file_path( task.node.uuid) task.node.properties['capabilities'] = 'boot_mode:bios' @@ -595,6 +600,8 @@ class PXEBootTestCase(db_base.DbTestCase): with task_manager.acquire(self.context, self.node.uuid) as task: dhcp_opts = pxe_utils.dhcp_options_for_instance( task, ipxe_enabled=False) + dhcp_opts += pxe_utils.dhcp_options_for_instance( + task, ipxe_enabled=False, ip_version=6) pxe_config_path = pxe_utils.get_pxe_config_file_path( task.node.uuid) task.node.properties['capabilities'] = 'boot_mode:bios' @@ -634,6 +641,8 @@ class PXEBootTestCase(db_base.DbTestCase): with task_manager.acquire(self.context, self.node.uuid) as task: dhcp_opts = pxe_utils.dhcp_options_for_instance( task, ipxe_enabled=False) + dhcp_opts += pxe_utils.dhcp_options_for_instance( + task, ipxe_enabled=False, ip_version=6) task.node.properties['capabilities'] = 'boot_mode:bios' task.node.driver_internal_info['is_whole_disk_image'] = False @@ -663,6 +672,8 @@ class PXEBootTestCase(db_base.DbTestCase): with task_manager.acquire(self.context, self.node.uuid) as task: dhcp_opts = pxe_utils.dhcp_options_for_instance( task, ipxe_enabled=False) + dhcp_opts += pxe_utils.dhcp_options_for_instance( + task, ipxe_enabled=False, ip_version=6) task.node.properties['capabilities'] = 'boot_mode:bios' task.node.driver_internal_info['is_whole_disk_image'] = True task.driver.boot.prepare_instance(task) @@ -734,6 +745,8 @@ class PXEBootTestCase(db_base.DbTestCase): task.node.save() dhcp_opts = pxe_utils.dhcp_options_for_instance( task, ipxe_enabled=False) + dhcp_opts += pxe_utils.dhcp_options_for_instance( + task, ipxe_enabled=False, ip_version=6) pxe_config_path = pxe_utils.get_pxe_config_file_path( task.node.uuid) task.driver.boot.prepare_instance(task) @@ -830,6 +843,8 @@ class PXERamdiskDeployTestCase(db_base.DbTestCase): with task_manager.acquire(self.context, self.node.uuid) as task: dhcp_opts = pxe_utils.dhcp_options_for_instance( task, ipxe_enabled=False) + dhcp_opts += pxe_utils.dhcp_options_for_instance( + task, ipxe_enabled=False, ip_version=6) pxe_config_path = pxe_utils.get_pxe_config_file_path( task.node.uuid) task.node.properties['capabilities'] = 'boot_option:netboot' -- cgit v1.2.1