Enable PXE for systems using petitboot

Petitboot systems do not use the pxelinux.0 loader. Instead,
petitboot itself handles pxelinux functionality. A side effect of
this is that petitboot requires DHCP option 210 (tftp path-prefix)
as this information is normally derived from the boot file name.
This patch uses the value of tftp_root as a path prefix and makes
the PXE module honor that prefix.

Change-Id: Ib9e954feea2cec38dd8328ada35005c0311c2a1b
Closes-Bug: #1639187
Co-Authored-By: Michael Turek <mjturek@linux.vnet.ibm.com>
This commit is contained in:
Michael Turek 2016-09-28 14:18:53 +00:00
parent 9eb148ad37
commit f13959c031
5 changed files with 73 additions and 14 deletions

View File

@ -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())

View File

@ -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

View File

@ -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')

View File

@ -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:

View File

@ -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.