diff --git a/ironic/common/pxe_utils.py b/ironic/common/pxe_utils.py index 69b52738fa..4eefef24ab 100644 --- a/ironic/common/pxe_utils.py +++ b/ironic/common/pxe_utils.py @@ -319,6 +319,12 @@ def dhcp_options_for_instance(task): else: dhcp_opts.append({'opt_name': 'bootfile-name', 'opt_value': boot_file}) + # 210 == tftp server path-prefix or tftp root, will be used to find + # pxelinux.cfg directory. The pxelinux.0 loader infers this information + # from it's own path, but Petitboot needs it to be specified by this + # option since it doesn't use pxelinux.0 loader. + dhcp_opts.append({'opt_name': '210', + 'opt_value': get_tftp_path_prefix()}) dhcp_opts.append({'opt_name': 'server-ip-address', 'opt_value': CONF.pxe.tftp_server}) @@ -330,3 +336,20 @@ def dhcp_options_for_instance(task): opt.update({'ip_version': int(CONF.pxe.ip_version)}) return dhcp_opts + + +def get_tftp_path_prefix(): + """Adds trailing slash (if needed) necessary for path-prefix + + :return: CONF.pxe.tftp_root ensured to have a trailing slash + """ + return os.path.join(CONF.pxe.tftp_root, '') + + +def get_path_relative_to_tftp_root(file_path): + """Return file relative path to CONF.pxe.tftp_root + + :param file_path: full file path to be made relative path. + :returns: The path relative to CONF.pxe.tftp_root + """ + return os.path.relpath(file_path, get_tftp_path_prefix()) diff --git a/ironic/drivers/modules/pxe.py b/ironic/drivers/modules/pxe.py index ae94378c9f..77ab5190f6 100644 --- a/ironic/drivers/modules/pxe.py +++ b/ironic/drivers/modules/pxe.py @@ -132,16 +132,21 @@ def _get_deploy_image_info(node): def _get_pxe_kernel_ramdisk(pxe_info): pxe_opts = {} - pxe_opts['deployment_aki_path'] = pxe_info['deploy_kernel'][1] - pxe_opts['deployment_ari_path'] = pxe_info['deploy_ramdisk'][1] + pxe_opts['deployment_aki_path'] = pxe_utils.get_path_relative_to_tftp_root( + pxe_info['deploy_kernel'][1]) + pxe_opts['deployment_ari_path'] = pxe_utils.get_path_relative_to_tftp_root( + pxe_info['deploy_ramdisk'][1]) # It is possible that we don't have kernel/ramdisk or even # image_source to determine if it's a whole disk image or not. # For example, when transitioning to 'available' state for first # time from 'manage' state. if 'kernel' in pxe_info: - pxe_opts['aki_path'] = pxe_info['kernel'][1] + pxe_opts['aki_path'] = pxe_utils.get_path_relative_to_tftp_root( + pxe_info['kernel'][1]) if 'ramdisk' in pxe_info: - pxe_opts['ari_path'] = pxe_info['ramdisk'][1] + pxe_opts['ari_path'] = pxe_utils.get_path_relative_to_tftp_root( + pxe_info['ramdisk'][1]) + return pxe_opts diff --git a/ironic/tests/unit/common/test_pxe_utils.py b/ironic/tests/unit/common/test_pxe_utils.py index 781a69b8b9..55fb553da5 100644 --- a/ironic/tests/unit/common/test_pxe_utils.py +++ b/ironic/tests/unit/common/test_pxe_utils.py @@ -424,9 +424,13 @@ class TestPXEUtils(db_base.DbTestCase): self.config(ip_version=ip_version, group='pxe') self.config(tftp_server='192.0.2.1', group='pxe') self.config(pxe_bootfile_name='fake-bootfile', group='pxe') + self.config(tftp_root='/tftp-path/', group='pxe') expected_info = [{'opt_name': 'bootfile-name', 'opt_value': 'fake-bootfile', 'ip_version': ip_version}, + {'opt_name': '210', + 'opt_value': '/tftp-path/', + 'ip_version': ip_version}, {'opt_name': 'server-ip-address', 'opt_value': '192.0.2.1', 'ip_version': ip_version}, @@ -603,3 +607,25 @@ class TestPXEUtils(db_base.DbTestCase): '/httpboot/pxelinux.cfg/aa-aa-aa-aa-aa-aa') rmtree_mock.assert_called_once_with( os.path.join(CONF.deploy.http_root, self.node.uuid)) + + def test_get_tftp_path_prefix_with_trailing_slash(self): + self.config(tftp_root='/tftpboot-path/', group='pxe') + path_prefix = pxe_utils.get_tftp_path_prefix() + self.assertEqual(path_prefix, '/tftpboot-path/') + + def test_get_tftp_path_prefix_without_trailing_slash(self): + self.config(tftp_root='/tftpboot-path', group='pxe') + path_prefix = pxe_utils.get_tftp_path_prefix() + self.assertEqual(path_prefix, '/tftpboot-path/') + + def test_get_path_relative_to_tftp_root_with_trailing_slash(self): + self.config(tftp_root='/tftpboot-path/', group='pxe') + test_file_path = '/tftpboot-path/pxelinux.cfg/test' + relpath = pxe_utils.get_path_relative_to_tftp_root(test_file_path) + self.assertEqual(relpath, 'pxelinux.cfg/test') + + def test_get_path_relative_to_tftp_root_without_trailing_slash(self): + self.config(tftp_root='/tftpboot-path', group='pxe') + test_file_path = '/tftpboot-path/pxelinux.cfg/test' + relpath = pxe_utils.get_path_relative_to_tftp_root(test_file_path) + self.assertEqual(relpath, 'pxelinux.cfg/test') diff --git a/ironic/tests/unit/drivers/modules/test_pxe.py b/ironic/tests/unit/drivers/modules/test_pxe.py index 3aa9ef3b5b..2ad87a4ff8 100644 --- a/ironic/tests/unit/drivers/modules/test_pxe.py +++ b/ironic/tests/unit/drivers/modules/test_pxe.py @@ -178,14 +178,10 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase): tftp_server = CONF.pxe.tftp_server - deploy_kernel = os.path.join(CONF.pxe.tftp_root, self.node.uuid, - 'deploy_kernel') - deploy_ramdisk = os.path.join(CONF.pxe.tftp_root, self.node.uuid, - 'deploy_ramdisk') - kernel = os.path.join(CONF.pxe.tftp_root, self.node.uuid, - 'kernel') - ramdisk = os.path.join(CONF.pxe.tftp_root, self.node.uuid, - 'ramdisk') + deploy_kernel = os.path.join(self.node.uuid, 'deploy_kernel') + deploy_ramdisk = os.path.join(self.node.uuid, 'deploy_ramdisk') + kernel = os.path.join(self.node.uuid, 'kernel') + ramdisk = os.path.join(self.node.uuid, 'ramdisk') root_dir = CONF.pxe.tftp_root image_info = { @@ -251,11 +247,14 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase): self.node.save() self.config(group='pxe', tftp_server='my-tftp-server') self.config(group='pxe', pxe_append_params='my-pxe-append-params') + self.config(group='pxe', tftp_root='/tftp-path/') image_info = { 'deploy_kernel': ('deploy_kernel', - 'path-to-deploy_kernel'), + os.path.join(CONF.pxe.tftp_root, + 'path-to-deploy_kernel')), 'deploy_ramdisk': ('deploy_ramdisk', - 'path-to-deploy_ramdisk')} + os.path.join(CONF.pxe.tftp_root, + 'path-to-deploy_ramdisk'))} with task_manager.acquire(self.context, self.node.uuid, shared=True) as task: diff --git a/releasenotes/notes/add-pxe-support-for-petitboot-50d1fe4e7da4bfba.yaml b/releasenotes/notes/add-pxe-support-for-petitboot-50d1fe4e7da4bfba.yaml new file mode 100644 index 0000000000..2ebcf0abcd --- /dev/null +++ b/releasenotes/notes/add-pxe-support-for-petitboot-50d1fe4e7da4bfba.yaml @@ -0,0 +1,6 @@ +--- +features: + - Adds the use of DHCP option 210 (tftp-path-prefix). This + enables PXE for systems using petitboot, which cannot + infer their tftp-path-prefix from the boot file location + as petitboot does not use a boot file.