ipxe: add --timeout parameter to kernel and initrd
In case of network issue during the download of the ramdisk or the kernel, ipxe can freeze. The default timeout value is "unlimited" [0] [1]. If force_power_state_during_sync is False, ironic will just ignore the node until someone do an human intervention. By setting a timeout, we ensure ipxe will just give up. Depending on the BIOS configuration, a new boot attempt may be done immedialey without the hassle of a hard reboot. https://bugzilla.redhat.com/show_bug.cgi?id=1310778 [0] http://ipxe.org/cmd/kernel [1] http://lists.ipxe.org/pipermail/ipxe-devel/2014-October/003829.html Closes-Bug: 1550417 Change-Id: I472dfb73044df50849c9cf72de90e59151698376
This commit is contained in:
parent
cc66d0b711
commit
404bfda982
@ -1943,6 +1943,10 @@
|
|||||||
# file. (string value)
|
# file. (string value)
|
||||||
#ipxe_boot_script=$pybasedir/drivers/modules/boot.ipxe
|
#ipxe_boot_script=$pybasedir/drivers/modules/boot.ipxe
|
||||||
|
|
||||||
|
# Timeout value (in seconds) for downloading an image via
|
||||||
|
# iPXE. Defaults to 0 (no timeout) (integer value)
|
||||||
|
#ipxe_timeout=0
|
||||||
|
|
||||||
# The IP version that will be used for PXE booting. Can be
|
# The IP version that will be used for PXE booting. Can be
|
||||||
# either 4 or 6. Defaults to 4. EXPERIMENTAL (string value)
|
# either 4 or 6. Defaults to 4. EXPERIMENTAL (string value)
|
||||||
#ip_version=4
|
#ip_version=4
|
||||||
|
@ -5,14 +5,14 @@ dhcp
|
|||||||
goto deploy
|
goto deploy
|
||||||
|
|
||||||
:deploy
|
:deploy
|
||||||
kernel {{ pxe_options.deployment_aki_path }} selinux=0 disk={{ pxe_options.disk }} iscsi_target_iqn={{ pxe_options.iscsi_target_iqn }} deployment_id={{ pxe_options.deployment_id }} deployment_key={{ pxe_options.deployment_key }} ironic_api_url={{ pxe_options.ironic_api_url }} troubleshoot=0 text {{ pxe_options.pxe_append_params|default("", true) }} boot_option={{ pxe_options.boot_option }} ip=${ip}:${next-server}:${gateway}:${netmask} BOOTIF=${mac} {% if pxe_options.root_device %}root_device={{ pxe_options.root_device }}{% endif %} ipa-api-url={{ pxe_options['ipa-api-url'] }} ipa-driver-name={{ pxe_options['ipa-driver-name'] }} boot_mode={{ pxe_options['boot_mode'] }} initrd=deploy_ramdisk coreos.configdrive=0
|
kernel {% if pxe_options.ipxe_timeout > 0 %}--timeout {{ pxe_options.ipxe_timeout }} {% endif %}{{ pxe_options.deployment_aki_path }} selinux=0 disk={{ pxe_options.disk }} iscsi_target_iqn={{ pxe_options.iscsi_target_iqn }} deployment_id={{ pxe_options.deployment_id }} deployment_key={{ pxe_options.deployment_key }} ironic_api_url={{ pxe_options.ironic_api_url }} troubleshoot=0 text {{ pxe_options.pxe_append_params|default("", true) }} boot_option={{ pxe_options.boot_option }} ip=${ip}:${next-server}:${gateway}:${netmask} BOOTIF=${mac} {% if pxe_options.root_device %}root_device={{ pxe_options.root_device }}{% endif %} ipa-api-url={{ pxe_options['ipa-api-url'] }} ipa-driver-name={{ pxe_options['ipa-driver-name'] }} boot_mode={{ pxe_options['boot_mode'] }} initrd=deploy_ramdisk coreos.configdrive=0
|
||||||
|
|
||||||
initrd {{ pxe_options.deployment_ari_path }}
|
initrd {% if pxe_options.ipxe_timeout > 0 %}--timeout {{ pxe_options.ipxe_timeout }} {% endif %}{{ pxe_options.deployment_ari_path }}
|
||||||
boot
|
boot
|
||||||
|
|
||||||
:boot_partition
|
:boot_partition
|
||||||
kernel {{ pxe_options.aki_path }} root={{ ROOT }} ro text {{ pxe_options.pxe_append_params|default("", true) }} initrd=ramdisk
|
kernel {% if pxe_options.ipxe_timeout > 0 %}--timeout {{ pxe_options.ipxe_timeout }} {% endif %}{{ pxe_options.aki_path }} root={{ ROOT }} ro text {{ pxe_options.pxe_append_params|default("", true) }} initrd=ramdisk
|
||||||
initrd {{ pxe_options.ari_path }}
|
initrd {% if pxe_options.ipxe_timeout > 0 %}--timeout {{ pxe_options.ipxe_timeout }} {% endif %}{{ pxe_options.ari_path }}
|
||||||
boot
|
boot
|
||||||
|
|
||||||
:boot_whole_disk
|
:boot_whole_disk
|
||||||
|
@ -81,6 +81,10 @@ pxe_opts = [
|
|||||||
'drivers/modules/boot.ipxe'),
|
'drivers/modules/boot.ipxe'),
|
||||||
help=_('On ironic-conductor node, the path to the main iPXE '
|
help=_('On ironic-conductor node, the path to the main iPXE '
|
||||||
'script file.')),
|
'script file.')),
|
||||||
|
cfg.IntOpt('ipxe_timeout',
|
||||||
|
default=0,
|
||||||
|
help=_('Timeout value (in seconds) for downloading an image '
|
||||||
|
'via iPXE. Defaults to 0 (no timeout)')),
|
||||||
cfg.StrOpt('ip_version',
|
cfg.StrOpt('ip_version',
|
||||||
default='4',
|
default='4',
|
||||||
choices=['4', '6'],
|
choices=['4', '6'],
|
||||||
@ -274,7 +278,8 @@ def _build_pxe_config_options(task, pxe_info):
|
|||||||
'pxe_append_params': _get_pxe_conf_option(task, 'pxe_append_params'),
|
'pxe_append_params': _get_pxe_conf_option(task, 'pxe_append_params'),
|
||||||
'tftp_server': CONF.pxe.tftp_server,
|
'tftp_server': CONF.pxe.tftp_server,
|
||||||
'aki_path': kernel,
|
'aki_path': kernel,
|
||||||
'ari_path': ramdisk
|
'ari_path': ramdisk,
|
||||||
|
'ipxe_timeout': CONF.pxe.ipxe_timeout * 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
return pxe_options
|
return pxe_options
|
||||||
|
@ -45,6 +45,7 @@ class TestPXEUtils(db_base.DbTestCase):
|
|||||||
u'f33c123/deploy_ramdisk',
|
u'f33c123/deploy_ramdisk',
|
||||||
'root_device': 'vendor=fake,size=123',
|
'root_device': 'vendor=fake,size=123',
|
||||||
'ipa-api-url': 'http://192.168.122.184:6385',
|
'ipa-api-url': 'http://192.168.122.184:6385',
|
||||||
|
'ipxe_timeout': 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pxe_options = {
|
self.pxe_options = {
|
||||||
@ -89,6 +90,11 @@ class TestPXEUtils(db_base.DbTestCase):
|
|||||||
}
|
}
|
||||||
self.ipxe_options_bios.update(self.ipxe_options)
|
self.ipxe_options_bios.update(self.ipxe_options)
|
||||||
|
|
||||||
|
self.ipxe_options_timeout = self.ipxe_options_bios.copy()
|
||||||
|
self.ipxe_options_timeout.update({
|
||||||
|
'ipxe_timeout': 120
|
||||||
|
})
|
||||||
|
|
||||||
self.ipxe_options_uefi = {
|
self.ipxe_options_uefi = {
|
||||||
'boot_mode': 'uefi',
|
'boot_mode': 'uefi',
|
||||||
}
|
}
|
||||||
@ -137,6 +143,25 @@ class TestPXEUtils(db_base.DbTestCase):
|
|||||||
|
|
||||||
self.assertEqual(six.text_type(expected_template), rendered_template)
|
self.assertEqual(six.text_type(expected_template), rendered_template)
|
||||||
|
|
||||||
|
def test__build_ipxe_timeout_config(self):
|
||||||
|
# NOTE(lucasagomes): iPXE is just an extension of the PXE driver,
|
||||||
|
# it doesn't have it's own configuration option for template.
|
||||||
|
# More info:
|
||||||
|
# http://docs.openstack.org/developer/ironic/deploy/install-guide.html
|
||||||
|
self.config(
|
||||||
|
pxe_config_template='ironic/drivers/modules/ipxe_config.template',
|
||||||
|
group='pxe'
|
||||||
|
)
|
||||||
|
self.config(http_url='http://1.2.3.4:1234', group='deploy')
|
||||||
|
rendered_template = pxe_utils._build_pxe_config(
|
||||||
|
self.ipxe_options_timeout, CONF.pxe.pxe_config_template,
|
||||||
|
'{{ ROOT }}', '{{ DISK_IDENTIFIER }}')
|
||||||
|
|
||||||
|
tpl_file = 'ironic/tests/unit/drivers/ipxe_config_timeout.template'
|
||||||
|
expected_template = open(tpl_file).read().rstrip()
|
||||||
|
|
||||||
|
self.assertEqual(six.text_type(expected_template), rendered_template)
|
||||||
|
|
||||||
def test__build_ipxe_uefi_config(self):
|
def test__build_ipxe_uefi_config(self):
|
||||||
# NOTE(lucasagomes): iPXE is just an extension of the PXE driver,
|
# NOTE(lucasagomes): iPXE is just an extension of the PXE driver,
|
||||||
# it doesn't have it's own configuration option for template.
|
# it doesn't have it's own configuration option for template.
|
||||||
|
19
ironic/tests/unit/drivers/ipxe_config_timeout.template
Normal file
19
ironic/tests/unit/drivers/ipxe_config_timeout.template
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#!ipxe
|
||||||
|
|
||||||
|
dhcp
|
||||||
|
|
||||||
|
goto deploy
|
||||||
|
|
||||||
|
:deploy
|
||||||
|
kernel --timeout 120 http://1.2.3.4:1234/deploy_kernel selinux=0 disk=cciss/c0d0,sda,hda,vda iscsi_target_iqn=iqn-1be26c0b-03f2-4d2e-ae87-c02d7f33c123 deployment_id=1be26c0b-03f2-4d2e-ae87-c02d7f33c123 deployment_key=0123456789ABCDEFGHIJKLMNOPQRSTUV ironic_api_url=http://192.168.122.184:6385 troubleshoot=0 text test_param boot_option=netboot ip=${ip}:${next-server}:${gateway}:${netmask} BOOTIF=${mac} root_device=vendor=fake,size=123 ipa-api-url=http://192.168.122.184:6385 ipa-driver-name=pxe_ssh boot_mode=bios initrd=deploy_ramdisk coreos.configdrive=0
|
||||||
|
|
||||||
|
initrd --timeout 120 http://1.2.3.4:1234/deploy_ramdisk
|
||||||
|
boot
|
||||||
|
|
||||||
|
:boot_partition
|
||||||
|
kernel --timeout 120 http://1.2.3.4:1234/kernel root={{ ROOT }} ro text test_param initrd=ramdisk
|
||||||
|
initrd --timeout 120 http://1.2.3.4:1234/ramdisk
|
||||||
|
boot
|
||||||
|
|
||||||
|
:boot_whole_disk
|
||||||
|
sanboot --no-describe
|
@ -183,11 +183,13 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
|||||||
@mock.patch.object(pxe_utils, '_build_pxe_config', autospec=True)
|
@mock.patch.object(pxe_utils, '_build_pxe_config', autospec=True)
|
||||||
def _test_build_pxe_config_options(self, build_pxe_mock,
|
def _test_build_pxe_config_options(self, build_pxe_mock,
|
||||||
whle_dsk_img=False,
|
whle_dsk_img=False,
|
||||||
ipxe_enabled=False):
|
ipxe_enabled=False,
|
||||||
|
ipxe_timeout=0):
|
||||||
self.config(pxe_append_params='test_param', group='pxe')
|
self.config(pxe_append_params='test_param', group='pxe')
|
||||||
# NOTE: right '/' should be removed from url string
|
# NOTE: right '/' should be removed from url string
|
||||||
self.config(api_url='http://192.168.122.184:6385', group='conductor')
|
self.config(api_url='http://192.168.122.184:6385', group='conductor')
|
||||||
self.config(disk_devices='sda', group='pxe')
|
self.config(disk_devices='sda', group='pxe')
|
||||||
|
self.config(ipxe_timeout=ipxe_timeout, group='pxe')
|
||||||
|
|
||||||
driver_internal_info = self.node.driver_internal_info
|
driver_internal_info = self.node.driver_internal_info
|
||||||
driver_internal_info['is_whole_disk_image'] = whle_dsk_img
|
driver_internal_info['is_whole_disk_image'] = whle_dsk_img
|
||||||
@ -223,6 +225,8 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
|||||||
ramdisk = 'no_ramdisk'
|
ramdisk = 'no_ramdisk'
|
||||||
kernel = 'no_kernel'
|
kernel = 'no_kernel'
|
||||||
|
|
||||||
|
ipxe_timeout_in_ms = ipxe_timeout * 1000
|
||||||
|
|
||||||
expected_options = {
|
expected_options = {
|
||||||
'ari_path': ramdisk,
|
'ari_path': ramdisk,
|
||||||
'deployment_ari_path': deploy_ramdisk,
|
'deployment_ari_path': deploy_ramdisk,
|
||||||
@ -230,6 +234,7 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
|||||||
'aki_path': kernel,
|
'aki_path': kernel,
|
||||||
'deployment_aki_path': deploy_kernel,
|
'deployment_aki_path': deploy_kernel,
|
||||||
'tftp_server': tftp_server,
|
'tftp_server': tftp_server,
|
||||||
|
'ipxe_timeout': ipxe_timeout_in_ms,
|
||||||
}
|
}
|
||||||
|
|
||||||
image_info = {'deploy_kernel': ('deploy_kernel',
|
image_info = {'deploy_kernel': ('deploy_kernel',
|
||||||
@ -268,6 +273,11 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
|||||||
self._test_build_pxe_config_options(whle_dsk_img=False,
|
self._test_build_pxe_config_options(whle_dsk_img=False,
|
||||||
ipxe_enabled=False)
|
ipxe_enabled=False)
|
||||||
|
|
||||||
|
def test__build_pxe_config_options_ipxe_and_ipxe_timeout(self):
|
||||||
|
self._test_build_pxe_config_options(whle_dsk_img=True,
|
||||||
|
ipxe_enabled=True,
|
||||||
|
ipxe_timeout=120)
|
||||||
|
|
||||||
@mock.patch.object(pxe_utils, '_build_pxe_config', autospec=True)
|
@mock.patch.object(pxe_utils, '_build_pxe_config', autospec=True)
|
||||||
def test__build_pxe_config_options_whole_disk_image(self,
|
def test__build_pxe_config_options_whole_disk_image(self,
|
||||||
build_pxe_mock,
|
build_pxe_mock,
|
||||||
@ -303,6 +313,7 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
|||||||
'tftp_server': tftp_server,
|
'tftp_server': tftp_server,
|
||||||
'aki_path': 'no_kernel',
|
'aki_path': 'no_kernel',
|
||||||
'ari_path': 'no_ramdisk',
|
'ari_path': 'no_ramdisk',
|
||||||
|
'ipxe_timeout': 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
image_info = {'deploy_kernel': ('deploy_kernel',
|
image_info = {'deploy_kernel': ('deploy_kernel',
|
||||||
@ -345,7 +356,8 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
|||||||
'pxe_append_params': 'my-pxe-append-params',
|
'pxe_append_params': 'my-pxe-append-params',
|
||||||
'tftp_server': 'my-tftp-server',
|
'tftp_server': 'my-tftp-server',
|
||||||
'aki_path': 'no_kernel',
|
'aki_path': 'no_kernel',
|
||||||
'ari_path': 'no_ramdisk'}
|
'ari_path': 'no_ramdisk',
|
||||||
|
'ipxe_timeout': 0}
|
||||||
self.assertEqual(expected_options, options)
|
self.assertEqual(expected_options, options)
|
||||||
|
|
||||||
@mock.patch.object(deploy_utils, 'fetch_images', autospec=True)
|
@mock.patch.object(deploy_utils, 'fetch_images', autospec=True)
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Add the ability to adjust ipxe timeout during image downloading, default is
|
||||||
|
still unlimited (0).
|
Loading…
Reference in New Issue
Block a user