diff --git a/etc/ironic/ironic.conf.sample b/etc/ironic/ironic.conf.sample index 12f434b83a..9b46eff25f 100644 --- a/etc/ironic/ironic.conf.sample +++ b/etc/ironic/ironic.conf.sample @@ -314,6 +314,12 @@ # Template file for grub configuration file. (string value) #grub_config_template = $pybasedir/common/grub_conf.template +# Path to ldlinux.c32 file. This file is required for syslinux +# 5.0 or later. If not specified, the file is searched in +# general paths, "/usr/lib/syslinux/modules/bios/ldlinux.c32" +# and "/usr/share/syslinux/ldlinux.c32". (string value) +#ldlinux_c32 = + # Run image downloads and raw format conversions in parallel. # (boolean value) #parallel_image_downloads = false diff --git a/ironic/common/images.py b/ironic/common/images.py index ff6bf3b8c1..766cffcf3a 100644 --- a/ironic/common/images.py +++ b/ironic/common/images.py @@ -184,6 +184,9 @@ def create_isolinux_image_for_bios(output_file, kernel, ramdisk, """ ISOLINUX_BIN = 'isolinux/isolinux.bin' ISOLINUX_CFG = 'isolinux/isolinux.cfg' + LDLINUX_SRC_DIRS = ['/usr/lib/syslinux/modules/bios', + '/usr/share/syslinux'] + LDLINUX_BIN = 'isolinux/ldlinux.c32' options = {'kernel': '/vmlinuz', 'ramdisk': '/initrd'} @@ -193,6 +196,20 @@ def create_isolinux_image_for_bios(output_file, kernel, ramdisk, ramdisk: 'initrd', CONF.isolinux_bin: ISOLINUX_BIN, } + + # ldlinux.c32 is required for syslinux 5.0 or later. + if CONF.ldlinux_c32: + ldlinux_src = CONF.ldlinux_c32 + else: + for directory in LDLINUX_SRC_DIRS: + ldlinux_src = os.path.join(directory, 'ldlinux.c32') + if os.path.isfile(ldlinux_src): + break + else: + ldlinux_src = None + if ldlinux_src: + files_info[ldlinux_src] = LDLINUX_BIN + try: _create_root_fs(tmpdir, files_info) except (OSError, IOError) as e: diff --git a/ironic/conf/default.py b/ironic/conf/default.py index a669493a1e..0eebb898fd 100644 --- a/ironic/conf/default.py +++ b/ironic/conf/default.py @@ -199,6 +199,12 @@ image_opts = [ default=os.path.join('$pybasedir', 'common/grub_conf.template'), help=_('Template file for grub configuration file.')), + cfg.StrOpt('ldlinux_c32', + help=_('Path to ldlinux.c32 file. This file is required for ' + 'syslinux 5.0 or later. If not specified, the file is ' + 'searched in general paths, ' + '"/usr/lib/syslinux/modules/bios/ldlinux.c32" and ' + '"/usr/share/syslinux/ldlinux.c32".')), ] img_cache_opts = [ diff --git a/ironic/tests/unit/common/test_images.py b/ironic/tests/unit/common/test_images.py index 1fd71211b6..44975e16ef 100644 --- a/ironic/tests/unit/common/test_images.py +++ b/ironic/tests/unit/common/test_images.py @@ -549,9 +549,9 @@ class FsImageTestCase(base.TestCase): @mock.patch.object(utils, 'tempdir', autospec=True) @mock.patch.object(utils, 'execute', autospec=True) @mock.patch.object(images, '_generate_cfg', autospec=True) - def test_create_isolinux_image_for_bios( + def _test_create_isolinux_image_for_bios( self, gen_cfg_mock, execute_mock, tempdir_mock, - write_to_file_mock, create_root_fs_mock): + write_to_file_mock, create_root_fs_mock, ldlinux_path=None): mock_file_handle = mock.MagicMock(spec=file) mock_file_handle.__enter__.return_value = 'tmpdir' @@ -575,6 +575,8 @@ class FsImageTestCase(base.TestCase): 'path/to/ramdisk': 'initrd', CONF.isolinux_bin: 'isolinux/isolinux.bin' } + if ldlinux_path: + files_info[ldlinux_path] = 'isolinux/ldlinux.c32' create_root_fs_mock.assert_called_once_with('tmpdir', files_info) gen_cfg_mock.assert_called_once_with(params, CONF.isolinux_config_template, @@ -587,6 +589,22 @@ class FsImageTestCase(base.TestCase): '4', '-boot-info-table', '-b', 'isolinux/isolinux.bin', '-o', 'tgt_file', 'tmpdir') + @mock.patch.object(os.path, 'isfile', autspec=True) + def test_create_isolinux_image_for_bios(self, mock_isfile): + mock_isfile.return_value = False + self._test_create_isolinux_image_for_bios() + + def test_create_isolinux_image_for_bios_conf_ldlinux(self): + CONF.set_override('ldlinux_c32', 'path/to/ldlinux.c32') + self._test_create_isolinux_image_for_bios( + ldlinux_path='path/to/ldlinux.c32') + + @mock.patch.object(os.path, 'isfile', autspec=True) + def test_create_isolinux_image_for_bios_default_ldlinux(self, mock_isfile): + mock_isfile.side_effect = [False, True] + self._test_create_isolinux_image_for_bios( + ldlinux_path='/usr/share/syslinux/ldlinux.c32') + @mock.patch.object(images, '_umount_without_raise', autospec=True) @mock.patch.object(images, '_create_root_fs', autospec=True) @mock.patch.object(utils, 'tempdir', autospec=True) diff --git a/releasenotes/notes/bug-1694645-57289200e35bd883.yaml b/releasenotes/notes/bug-1694645-57289200e35bd883.yaml new file mode 100644 index 0000000000..496e3a9c4b --- /dev/null +++ b/releasenotes/notes/bug-1694645-57289200e35bd883.yaml @@ -0,0 +1,14 @@ +--- +fixes: + - | + Fix a bug that netboot is unavailable with virtual media boot in an + environment using syslinux 5.00 or later such as Ubuntu 16.04. This is + caused by a change in syslinux that ldlinux.c32 is required for creating + boot ISO. This file is searched in the following general paths: + + * /usr/lib/syslinux/modules/bios/ldlinux.c32 + * /usr/share/syslinux/ldlinux.c32 + + This path can be set with the configuration parameter + ``[DEFAULT]/ldlinux_c32`` for another distribution or for a case where the + path is changed with future update.