Build ISO out of EFI system partition image
When ironic builds UEFI-bootable ISO image, it extracts EFI system partition image (`efiboot.img`) from the `deploy_iso` ISO image. This change allows supplying EFI system partition image to the ISO image building routines in form of a local file or UUID or URI reference. The motivation behind this change is to make UEFI-bootable image building process more efficient and functional. This change is thought of as a prerequisite for the upcoming Redfish-based virtual media boot feature. Story: 1526753 Task: 28098 Change-Id: Idf912ff2146434b666fdb4250dc1ecad39bc5a04
This commit is contained in:
parent
53823d7f93
commit
738d4eafdc
@ -222,27 +222,33 @@ def create_isolinux_image_for_bios(output_file, kernel, ramdisk,
|
||||
raise exception.ImageCreationFailed(image_type='iso', error=e)
|
||||
|
||||
|
||||
def create_isolinux_image_for_uefi(output_file, deploy_iso, kernel, ramdisk,
|
||||
def create_isolinux_image_for_uefi(output_file, kernel, ramdisk,
|
||||
deploy_iso=None, esp_image=None,
|
||||
kernel_params=None):
|
||||
"""Creates an isolinux image on the specified file.
|
||||
|
||||
Copies the provided kernel, ramdisk, efiboot.img to a directory, creates
|
||||
the path for grub config file, generates the isolinux configuration file
|
||||
using the kernel parameters provided, generates the grub configuration
|
||||
file using kernel parameters and then generates a bootable ISO image
|
||||
for uefi.
|
||||
Copies the provided kernel, ramdisk and EFI system partition image to
|
||||
a directory, generates the grub configuration file using kernel parameters
|
||||
and then generates a bootable ISO image for UEFI.
|
||||
|
||||
:param output_file: the path to the file where the iso image needs to be
|
||||
created.
|
||||
:param deploy_iso: deploy iso used to initiate the deploy.
|
||||
:param kernel: the kernel to use.
|
||||
:param ramdisk: the ramdisk to use.
|
||||
:param deploy_iso: deploy ISO image to extract EFI system partition image
|
||||
from. If not specified, the `esp_image` option is required.
|
||||
:param esp_image: FAT12/16/32-formatted EFI system partition image
|
||||
containing the EFI boot loader (e.g. GRUB2) for each hardware
|
||||
architecture to boot. This image will be embedded into the ISO image.
|
||||
If not specified, the `deploy_iso` option is required.
|
||||
:param kernel_params: a list of strings(each element being a string like
|
||||
'K=V' or 'K' or combination of them like 'K1=V1,K2,...') to be added
|
||||
as the kernel cmdline.
|
||||
:raises: ImageCreationFailed, if image creation failed while copying files
|
||||
or while running command to generate iso.
|
||||
"""
|
||||
EFIBOOT_LOCATION = 'boot/grub/efiboot.img'
|
||||
|
||||
grub_options = {'linux': '/vmlinuz', 'initrd': '/initrd'}
|
||||
|
||||
with utils.tempdir() as tmpdir:
|
||||
@ -251,26 +257,48 @@ def create_isolinux_image_for_uefi(output_file, deploy_iso, kernel, ramdisk,
|
||||
ramdisk: 'initrd',
|
||||
}
|
||||
|
||||
# Open the deploy iso used to initiate deploy and copy the
|
||||
# efiboot.img i.e. boot loader to the current temporary
|
||||
# directory.
|
||||
with utils.tempdir() as mountdir:
|
||||
uefi_path_info, e_img_rel_path, grub_rel_path = (
|
||||
_mount_deploy_iso(deploy_iso, mountdir))
|
||||
# Open the deploy iso used to initiate deploy and copy the
|
||||
# efiboot.img i.e. boot loader to the current temporary
|
||||
# directory.
|
||||
if deploy_iso:
|
||||
uefi_path_info, e_img_rel_path, grub_rel_path = (
|
||||
_mount_deploy_iso(deploy_iso, mountdir))
|
||||
|
||||
grub_cfg = os.path.join(tmpdir, grub_rel_path)
|
||||
|
||||
# Use ELF boot loader provided
|
||||
elif esp_image:
|
||||
e_img_rel_path = EFIBOOT_LOCATION
|
||||
grub_rel_path = CONF.grub_config_path.strip()
|
||||
while grub_rel_path.startswith(os.sep):
|
||||
grub_rel_path = grub_rel_path[1:]
|
||||
grub_cfg = os.path.join(tmpdir, grub_rel_path)
|
||||
|
||||
uefi_path_info = {
|
||||
esp_image: e_img_rel_path,
|
||||
grub_cfg: grub_rel_path
|
||||
}
|
||||
|
||||
else:
|
||||
raise exception.ImageCreationFailed(
|
||||
image_type='iso',
|
||||
error='Neither `deploy_iso` nor `esp_image` configured')
|
||||
|
||||
# if either of these variables are not initialized then the
|
||||
# uefi efiboot.img cannot be created.
|
||||
files_info.update(uefi_path_info)
|
||||
|
||||
try:
|
||||
_create_root_fs(tmpdir, files_info)
|
||||
|
||||
except (OSError, IOError) as e:
|
||||
LOG.exception("Creating the filesystem root failed.")
|
||||
raise exception.ImageCreationFailed(image_type='iso', error=e)
|
||||
|
||||
finally:
|
||||
_umount_without_raise(mountdir)
|
||||
if deploy_iso:
|
||||
_umount_without_raise(mountdir)
|
||||
|
||||
# Generate and copy grub config file.
|
||||
grub_cfg = os.path.join(tmpdir, grub_rel_path)
|
||||
grub_conf = _generate_cfg(kernel_params,
|
||||
CONF.grub_config_template, grub_options)
|
||||
utils.write_to_file(grub_cfg, grub_conf)
|
||||
@ -401,8 +429,8 @@ def get_temp_url_for_glance_image(context, image_uuid):
|
||||
|
||||
|
||||
def create_boot_iso(context, output_filename, kernel_href,
|
||||
ramdisk_href, deploy_iso_href, root_uuid=None,
|
||||
kernel_params=None, boot_mode=None):
|
||||
ramdisk_href, deploy_iso_href=None, esp_image_href=None,
|
||||
root_uuid=None, kernel_params=None, boot_mode=None):
|
||||
"""Creates a bootable ISO image for a node.
|
||||
|
||||
Given the hrefs for kernel, ramdisk, root partition's UUID and
|
||||
@ -414,8 +442,15 @@ def create_boot_iso(context, output_filename, kernel_href,
|
||||
:param output_filename: the absolute path of the output ISO file
|
||||
:param kernel_href: URL or glance uuid of the kernel to use
|
||||
:param ramdisk_href: URL or glance uuid of the ramdisk to use
|
||||
:param deploy_iso_href: URL or glance uuid of the deploy iso used
|
||||
:param root_uuid: uuid of the root filesystem (optional)
|
||||
:param deploy_iso_href: URL or glance UUID of the deploy ISO image
|
||||
to extract EFI system partition image. If not specified,
|
||||
the `esp_image_href` option must be present if UEFI-bootable
|
||||
ISO is desired.
|
||||
:param esp_image_href: URL or glance UUID of FAT12/16/32-formatted EFI
|
||||
system partition image containing the EFI boot loader (e.g. GRUB2)
|
||||
for each hardware architecture to boot. This image will be embedded
|
||||
into the ISO image. If not specified, the `deploy_iso_href` option
|
||||
is only required for building UEFI-bootable ISO.
|
||||
:param kernel_params: a string containing whitespace separated values
|
||||
kernel cmdline arguments of the form K=V or K (optional).
|
||||
:boot_mode: the boot mode in which the deploy is to happen.
|
||||
@ -424,6 +459,7 @@ def create_boot_iso(context, output_filename, kernel_href,
|
||||
with utils.tempdir() as tmpdir:
|
||||
kernel_path = os.path.join(tmpdir, kernel_href.split('/')[-1])
|
||||
ramdisk_path = os.path.join(tmpdir, ramdisk_href.split('/')[-1])
|
||||
|
||||
fetch(context, kernel_href, kernel_path)
|
||||
fetch(context, ramdisk_href, ramdisk_path)
|
||||
|
||||
@ -434,13 +470,28 @@ def create_boot_iso(context, output_filename, kernel_href,
|
||||
params.append(kernel_params)
|
||||
|
||||
if boot_mode == 'uefi':
|
||||
deploy_iso = os.path.join(tmpdir, deploy_iso_href.split('/')[-1])
|
||||
fetch(context, deploy_iso_href, deploy_iso)
|
||||
|
||||
deploy_iso_path = esp_image_path = None
|
||||
|
||||
if deploy_iso_href:
|
||||
deploy_iso_path = os.path.join(
|
||||
tmpdir, deploy_iso_href.split('/')[-1])
|
||||
fetch(context, deploy_iso_href, deploy_iso_path)
|
||||
|
||||
elif esp_image_href:
|
||||
esp_image_path = os.path.join(
|
||||
tmpdir, esp_image_href.split('/')[-1])
|
||||
fetch(context, esp_image_href, esp_image_path)
|
||||
|
||||
elif CONF.esp_image:
|
||||
esp_image_path = CONF.esp_image
|
||||
|
||||
create_isolinux_image_for_uefi(output_filename,
|
||||
deploy_iso,
|
||||
kernel_path,
|
||||
ramdisk_path,
|
||||
params)
|
||||
deploy_iso=deploy_iso_path,
|
||||
esp_image=esp_image_path,
|
||||
kernel_params=params)
|
||||
else:
|
||||
create_isolinux_image_for_bios(output_filename,
|
||||
kernel_path,
|
||||
|
@ -210,6 +210,10 @@ image_opts = [
|
||||
default=os.path.join('$pybasedir',
|
||||
'common/isolinux_config.template'),
|
||||
help=_('Template file for isolinux configuration file.')),
|
||||
cfg.StrOpt('grub_config_path',
|
||||
default='/boot/grub/grub.cfg',
|
||||
help=_('GRUB2 configuration file location on the UEFI ISO '
|
||||
'images produced by ironic.')),
|
||||
cfg.StrOpt('grub_config_template',
|
||||
default=os.path.join('$pybasedir',
|
||||
'common/grub_conf.template'),
|
||||
@ -220,6 +224,17 @@ image_opts = [
|
||||
'looked for in '
|
||||
'"/usr/lib/syslinux/modules/bios/ldlinux.c32" and '
|
||||
'"/usr/share/syslinux/ldlinux.c32".')),
|
||||
cfg.StrOpt('esp_image',
|
||||
help=_('Path to EFI System Partition image file. This file is '
|
||||
'recommended for creating UEFI bootable ISO images '
|
||||
'efficiently. ESP image should contain a '
|
||||
'FAT12/16/32-formatted file system holding EFI boot '
|
||||
'loaders (e.g. GRUB2) for each hardware architecture '
|
||||
'ironic needs to boot. If not configured, ironic '
|
||||
'will attempt to fetch ESP image from some remote '
|
||||
'store (if configured) or extract ESP image from '
|
||||
'UEFI-bootable deploy ISO image.')),
|
||||
|
||||
]
|
||||
|
||||
img_cache_opts = [
|
||||
|
@ -198,8 +198,10 @@ def _get_boot_iso(task, root_uuid):
|
||||
boot_iso_tmp_file = fileobj.name
|
||||
images.create_boot_iso(task.context, boot_iso_tmp_file,
|
||||
kernel_href, ramdisk_href,
|
||||
deploy_iso_uuid, root_uuid,
|
||||
kernel_params, boot_mode)
|
||||
deploy_iso_href=deploy_iso_uuid,
|
||||
root_uuid=root_uuid,
|
||||
kernel_params=kernel_params,
|
||||
boot_mode=boot_mode)
|
||||
|
||||
if CONF.ilo.use_web_server_for_images:
|
||||
boot_iso_url = (
|
||||
|
@ -314,8 +314,10 @@ def _prepare_boot_iso(task, root_uuid):
|
||||
|
||||
images.create_boot_iso(task.context, boot_iso_fullpathname,
|
||||
kernel_href, ramdisk_href,
|
||||
deploy_iso_href, root_uuid,
|
||||
kernel_params, boot_mode)
|
||||
deploy_iso_href=deploy_iso_href,
|
||||
root_uuid=root_uuid,
|
||||
kernel_params=kernel_params,
|
||||
boot_mode=boot_mode)
|
||||
|
||||
driver_internal_info['irmc_boot_iso'] = boot_iso_filename
|
||||
|
||||
|
@ -438,9 +438,9 @@ class FsImageTestCase(base.TestCase):
|
||||
@mock.patch.object(os.path, 'relpath', autospec=True)
|
||||
@mock.patch.object(os, 'walk', autospec=True)
|
||||
@mock.patch.object(utils, 'mount', autospec=True)
|
||||
def test__mount_deploy_iso_fail_no_efibootimg(self, mount_mock,
|
||||
walk_mock, relpath_mock,
|
||||
umount_mock):
|
||||
def test__mount_deploy_iso_fail_no_esp_imageimg(self, mount_mock,
|
||||
walk_mock, relpath_mock,
|
||||
umount_mock):
|
||||
walk_mock.return_value = [('/tmpdir1/EFI/ubuntu', [], ['grub.cfg']),
|
||||
('/tmpdir1/isolinux', [],
|
||||
['isolinux.bin', 'isolinux.cfg'])]
|
||||
@ -489,16 +489,17 @@ class FsImageTestCase(base.TestCase):
|
||||
@mock.patch.object(images, '_mount_deploy_iso', autospec=True)
|
||||
@mock.patch.object(utils, 'tempdir', autospec=True)
|
||||
@mock.patch.object(images, '_generate_cfg', autospec=True)
|
||||
def test_create_isolinux_image_for_uefi(
|
||||
def test_create_isolinux_image_for_uefi_with_deploy_iso(
|
||||
self, gen_cfg_mock, tempdir_mock, mount_mock, execute_mock,
|
||||
write_to_file_mock, create_root_fs_mock, umount_mock):
|
||||
|
||||
files_info = {
|
||||
'path/to/kernel': 'vmlinuz',
|
||||
'path/to/ramdisk': 'initrd',
|
||||
'path/to/grub': 'relpath/to/grub.cfg',
|
||||
'sourceabspath/to/efiboot.img': 'path/to/efiboot.img'
|
||||
'sourceabspath/to/efiboot.img': 'path/to/efiboot.img',
|
||||
'path/to/grub': 'relpath/to/grub.cfg'
|
||||
}
|
||||
|
||||
grubcfg = "grubcfg"
|
||||
grub_file = 'tmpdir/relpath/to/grub.cfg'
|
||||
gen_cfg_mock.side_effect = (grubcfg,)
|
||||
@ -520,9 +521,10 @@ class FsImageTestCase(base.TestCase):
|
||||
mount_mock.return_value = (uefi_path_info,
|
||||
e_img_rel_path, grub_rel_path)
|
||||
|
||||
images.create_isolinux_image_for_uefi('tgt_file', 'path/to/deploy_iso',
|
||||
images.create_isolinux_image_for_uefi('tgt_file',
|
||||
'path/to/kernel',
|
||||
'path/to/ramdisk',
|
||||
deploy_iso='path/to/deploy_iso',
|
||||
kernel_params=params)
|
||||
mount_mock.assert_called_once_with('path/to/deploy_iso', 'mountdir')
|
||||
create_root_fs_mock.assert_called_once_with('tmpdir', files_info)
|
||||
@ -534,6 +536,49 @@ class FsImageTestCase(base.TestCase):
|
||||
'path/to/efiboot.img', '-no-emul-boot', '-o', 'tgt_file', 'tmpdir')
|
||||
umount_mock.assert_called_once_with('mountdir')
|
||||
|
||||
@mock.patch.object(images, '_create_root_fs', autospec=True)
|
||||
@mock.patch.object(utils, 'write_to_file', autospec=True)
|
||||
@mock.patch.object(utils, 'execute', autospec=True)
|
||||
@mock.patch.object(utils, 'tempdir', autospec=True)
|
||||
@mock.patch.object(images, '_generate_cfg', autospec=True)
|
||||
def test_create_isolinux_image_for_uefi_with_esp_image(
|
||||
self, gen_cfg_mock, tempdir_mock, execute_mock,
|
||||
write_to_file_mock, create_root_fs_mock):
|
||||
|
||||
files_info = {
|
||||
'path/to/kernel': 'vmlinuz',
|
||||
'path/to/ramdisk': 'initrd',
|
||||
'sourceabspath/to/efiboot.img': 'boot/grub/efiboot.img',
|
||||
'tmpdir/boot/grub/grub.cfg': 'boot/grub/grub.cfg'
|
||||
}
|
||||
|
||||
grubcfg = "grubcfg"
|
||||
grub_file = 'tmpdir/boot/grub/grub.cfg'
|
||||
gen_cfg_mock.side_effect = (grubcfg,)
|
||||
|
||||
params = ['a=b', 'c']
|
||||
grub_options = {'linux': '/vmlinuz',
|
||||
'initrd': '/initrd'}
|
||||
|
||||
mock_file_handle = mock.MagicMock(spec=file)
|
||||
mock_file_handle.__enter__.return_value = 'tmpdir'
|
||||
mock_file_handle1 = mock.MagicMock(spec=file)
|
||||
mock_file_handle1.__enter__.return_value = 'mountdir'
|
||||
tempdir_mock.side_effect = mock_file_handle, mock_file_handle1
|
||||
|
||||
images.create_isolinux_image_for_uefi(
|
||||
'tgt_file', 'path/to/kernel', 'path/to/ramdisk',
|
||||
esp_image='sourceabspath/to/efiboot.img',
|
||||
kernel_params=params)
|
||||
create_root_fs_mock.assert_called_once_with('tmpdir', files_info)
|
||||
gen_cfg_mock.assert_any_call(params, CONF.grub_config_template,
|
||||
grub_options)
|
||||
write_to_file_mock.assert_any_call(grub_file, grubcfg)
|
||||
execute_mock.assert_called_once_with(
|
||||
'mkisofs', '-r', '-V', 'VMEDIA_BOOT_ISO', '-l', '-e',
|
||||
'boot/grub/efiboot.img', '-no-emul-boot', '-o', 'tgt_file',
|
||||
'tmpdir')
|
||||
|
||||
@mock.patch.object(images, '_create_root_fs', autospec=True)
|
||||
@mock.patch.object(utils, 'write_to_file', autospec=True)
|
||||
@mock.patch.object(utils, 'tempdir', autospec=True)
|
||||
@ -615,9 +660,10 @@ class FsImageTestCase(base.TestCase):
|
||||
|
||||
self.assertRaises(exception.ImageCreationFailed,
|
||||
images.create_isolinux_image_for_uefi,
|
||||
'tgt_file', 'path/to/deployiso',
|
||||
'tgt_file',
|
||||
'path/to/kernel',
|
||||
'path/to/ramdisk')
|
||||
'path/to/ramdisk',
|
||||
deploy_iso='path/to/deployiso')
|
||||
umount_mock.assert_called_once_with('mountdir')
|
||||
|
||||
@mock.patch.object(images, '_create_root_fs', autospec=True)
|
||||
@ -660,9 +706,10 @@ class FsImageTestCase(base.TestCase):
|
||||
|
||||
self.assertRaises(exception.ImageCreationFailed,
|
||||
images.create_isolinux_image_for_uefi,
|
||||
'tgt_file', 'path/to/deployiso',
|
||||
'tgt_file',
|
||||
'path/to/kernel',
|
||||
'path/to/ramdisk')
|
||||
'path/to/ramdisk',
|
||||
deploy_iso='path/to/deployiso')
|
||||
umount_mock.assert_called_once_with('mountdir')
|
||||
|
||||
@mock.patch.object(images, '_create_root_fs', autospec=True)
|
||||
@ -689,15 +736,17 @@ class FsImageTestCase(base.TestCase):
|
||||
@mock.patch.object(images, 'create_isolinux_image_for_uefi', autospec=True)
|
||||
@mock.patch.object(images, 'fetch', autospec=True)
|
||||
@mock.patch.object(utils, 'tempdir', autospec=True)
|
||||
def test_create_boot_iso_for_uefi(
|
||||
def test_create_boot_iso_for_uefi_deploy_iso(
|
||||
self, tempdir_mock, fetch_images_mock, create_isolinux_mock):
|
||||
mock_file_handle = mock.MagicMock(spec=file)
|
||||
mock_file_handle.__enter__.return_value = 'tmpdir'
|
||||
tempdir_mock.return_value = mock_file_handle
|
||||
|
||||
images.create_boot_iso('ctx', 'output_file', 'kernel-uuid',
|
||||
'ramdisk-uuid', 'deploy_iso-uuid',
|
||||
'root-uuid', 'kernel-params', 'uefi')
|
||||
images.create_boot_iso(
|
||||
'ctx', 'output_file', 'kernel-uuid',
|
||||
'ramdisk-uuid', deploy_iso_href='deploy_iso-uuid',
|
||||
root_uuid='root-uuid', kernel_params='kernel-params',
|
||||
boot_mode='uefi')
|
||||
|
||||
fetch_images_mock.assert_any_call(
|
||||
'ctx', 'kernel-uuid', 'tmpdir/kernel-uuid')
|
||||
@ -708,21 +757,53 @@ class FsImageTestCase(base.TestCase):
|
||||
|
||||
params = ['root=UUID=root-uuid', 'kernel-params']
|
||||
create_isolinux_mock.assert_called_once_with(
|
||||
'output_file', 'tmpdir/deploy_iso-uuid', 'tmpdir/kernel-uuid',
|
||||
'tmpdir/ramdisk-uuid', params)
|
||||
'output_file', 'tmpdir/kernel-uuid', 'tmpdir/ramdisk-uuid',
|
||||
deploy_iso='tmpdir/deploy_iso-uuid', esp_image=None,
|
||||
kernel_params=params)
|
||||
|
||||
@mock.patch.object(images, 'create_isolinux_image_for_uefi', autospec=True)
|
||||
@mock.patch.object(images, 'fetch', autospec=True)
|
||||
@mock.patch.object(utils, 'tempdir', autospec=True)
|
||||
def test_create_boot_iso_for_uefi_for_hrefs(
|
||||
def test_create_boot_iso_for_uefi_esp_image(
|
||||
self, tempdir_mock, fetch_images_mock, create_isolinux_mock):
|
||||
mock_file_handle = mock.MagicMock(spec=file)
|
||||
mock_file_handle.__enter__.return_value = 'tmpdir'
|
||||
tempdir_mock.return_value = mock_file_handle
|
||||
|
||||
images.create_boot_iso('ctx', 'output_file', 'http://kernel-href',
|
||||
'http://ramdisk-href', 'http://deploy_iso-href',
|
||||
'root-uuid', 'kernel-params', 'uefi')
|
||||
images.create_boot_iso(
|
||||
'ctx', 'output_file', 'kernel-uuid',
|
||||
'ramdisk-uuid', esp_image_href='efiboot-uuid',
|
||||
root_uuid='root-uuid', kernel_params='kernel-params',
|
||||
boot_mode='uefi')
|
||||
|
||||
fetch_images_mock.assert_any_call(
|
||||
'ctx', 'kernel-uuid', 'tmpdir/kernel-uuid')
|
||||
fetch_images_mock.assert_any_call(
|
||||
'ctx', 'ramdisk-uuid', 'tmpdir/ramdisk-uuid')
|
||||
fetch_images_mock.assert_any_call(
|
||||
'ctx', 'efiboot-uuid', 'tmpdir/efiboot-uuid')
|
||||
|
||||
params = ['root=UUID=root-uuid', 'kernel-params']
|
||||
create_isolinux_mock.assert_called_once_with(
|
||||
'output_file', 'tmpdir/kernel-uuid', 'tmpdir/ramdisk-uuid',
|
||||
deploy_iso=None, esp_image='tmpdir/efiboot-uuid',
|
||||
kernel_params=params)
|
||||
|
||||
@mock.patch.object(images, 'create_isolinux_image_for_uefi', autospec=True)
|
||||
@mock.patch.object(images, 'fetch', autospec=True)
|
||||
@mock.patch.object(utils, 'tempdir', autospec=True)
|
||||
def test_create_boot_iso_for_uefi_deploy_iso_for_hrefs(
|
||||
self, tempdir_mock, fetch_images_mock, create_isolinux_mock):
|
||||
mock_file_handle = mock.MagicMock(spec=file)
|
||||
mock_file_handle.__enter__.return_value = 'tmpdir'
|
||||
tempdir_mock.return_value = mock_file_handle
|
||||
|
||||
images.create_boot_iso(
|
||||
'ctx', 'output_file', 'http://kernel-href', 'http://ramdisk-href',
|
||||
deploy_iso_href='http://deploy_iso-href',
|
||||
root_uuid='root-uuid', kernel_params='kernel-params',
|
||||
boot_mode='uefi')
|
||||
|
||||
expected_calls = [mock.call('ctx', 'http://kernel-href',
|
||||
'tmpdir/kernel-href'),
|
||||
mock.call('ctx', 'http://ramdisk-href',
|
||||
@ -732,8 +813,37 @@ class FsImageTestCase(base.TestCase):
|
||||
fetch_images_mock.assert_has_calls(expected_calls)
|
||||
params = ['root=UUID=root-uuid', 'kernel-params']
|
||||
create_isolinux_mock.assert_called_once_with(
|
||||
'output_file', 'tmpdir/deploy_iso-href', 'tmpdir/kernel-href',
|
||||
'tmpdir/ramdisk-href', params)
|
||||
'output_file', 'tmpdir/kernel-href', 'tmpdir/ramdisk-href',
|
||||
deploy_iso='tmpdir/deploy_iso-href', esp_image=None,
|
||||
kernel_params=params)
|
||||
|
||||
@mock.patch.object(images, 'create_isolinux_image_for_uefi', autospec=True)
|
||||
@mock.patch.object(images, 'fetch', autospec=True)
|
||||
@mock.patch.object(utils, 'tempdir', autospec=True)
|
||||
def test_create_boot_iso_for_uefi_esp_image_for_hrefs(
|
||||
self, tempdir_mock, fetch_images_mock, create_isolinux_mock):
|
||||
mock_file_handle = mock.MagicMock(spec=file)
|
||||
mock_file_handle.__enter__.return_value = 'tmpdir'
|
||||
tempdir_mock.return_value = mock_file_handle
|
||||
|
||||
images.create_boot_iso(
|
||||
'ctx', 'output_file', 'http://kernel-href', 'http://ramdisk-href',
|
||||
esp_image_href='http://efiboot-href',
|
||||
root_uuid='root-uuid', kernel_params='kernel-params',
|
||||
boot_mode='uefi')
|
||||
|
||||
expected_calls = [mock.call('ctx', 'http://kernel-href',
|
||||
'tmpdir/kernel-href'),
|
||||
mock.call('ctx', 'http://ramdisk-href',
|
||||
'tmpdir/ramdisk-href'),
|
||||
mock.call('ctx', 'http://efiboot-href',
|
||||
'tmpdir/efiboot-href')]
|
||||
fetch_images_mock.assert_has_calls(expected_calls)
|
||||
params = ['root=UUID=root-uuid', 'kernel-params']
|
||||
create_isolinux_mock.assert_called_once_with(
|
||||
'output_file', 'tmpdir/kernel-href', 'tmpdir/ramdisk-href',
|
||||
deploy_iso=None, esp_image='tmpdir/efiboot-href',
|
||||
kernel_params=params)
|
||||
|
||||
@mock.patch.object(images, 'create_isolinux_image_for_bios', autospec=True)
|
||||
@mock.patch.object(images, 'fetch', autospec=True)
|
||||
@ -746,7 +856,8 @@ class FsImageTestCase(base.TestCase):
|
||||
|
||||
images.create_boot_iso('ctx', 'output_file', 'kernel-uuid',
|
||||
'ramdisk-uuid', 'deploy_iso-uuid',
|
||||
'root-uuid', 'kernel-params', 'bios')
|
||||
'efiboot-uuid', 'root-uuid', 'kernel-params',
|
||||
'bios')
|
||||
|
||||
fetch_images_mock.assert_any_call(
|
||||
'ctx', 'kernel-uuid', 'tmpdir/kernel-uuid')
|
||||
@ -777,7 +888,8 @@ class FsImageTestCase(base.TestCase):
|
||||
|
||||
images.create_boot_iso('ctx', 'output_file', 'kernel-uuid',
|
||||
'ramdisk-uuid', 'deploy_iso-uuid',
|
||||
'root-uuid', 'kernel-params', None)
|
||||
'efiboot-uuid', 'root-uuid', 'kernel-params',
|
||||
None)
|
||||
|
||||
fetch_images_mock.assert_any_call(
|
||||
'ctx', 'kernel-uuid', 'tmpdir/kernel-uuid')
|
||||
|
@ -204,14 +204,12 @@ class IloBootPrivateMethodsTestCase(test_common.BaseIloTest):
|
||||
task.context, 'image-uuid',
|
||||
['boot_iso', 'kernel_id', 'ramdisk_id'])
|
||||
boot_object_name_mock.assert_called_once_with(task.node)
|
||||
create_boot_iso_mock.assert_called_once_with(task.context,
|
||||
'tmpfile',
|
||||
'kernel_uuid',
|
||||
'ramdisk_uuid',
|
||||
'deploy_iso_uuid',
|
||||
'root-uuid',
|
||||
'kernel-params',
|
||||
'uefi')
|
||||
create_boot_iso_mock.assert_called_once_with(
|
||||
task.context, 'tmpfile', 'kernel_uuid', 'ramdisk_uuid',
|
||||
deploy_iso_href='deploy_iso_uuid',
|
||||
root_uuid='root-uuid',
|
||||
kernel_params='kernel-params',
|
||||
boot_mode='uefi')
|
||||
swift_obj_mock.create_object.assert_called_once_with('ilo-cont',
|
||||
'abcdef',
|
||||
'tmpfile')
|
||||
@ -273,14 +271,12 @@ class IloBootPrivateMethodsTestCase(test_common.BaseIloTest):
|
||||
task.context, 'image-uuid',
|
||||
['boot_iso', 'kernel_id', 'ramdisk_id'])
|
||||
boot_object_name_mock.assert_called_once_with(task.node)
|
||||
create_boot_iso_mock.assert_called_once_with(task.context,
|
||||
'tmpfile',
|
||||
kernel_href,
|
||||
ramdisk_href,
|
||||
'deploy_iso_uuid',
|
||||
'root-uuid',
|
||||
'kernel-params',
|
||||
'uefi')
|
||||
create_boot_iso_mock.assert_called_once_with(
|
||||
task.context, 'tmpfile', kernel_href, ramdisk_href,
|
||||
deploy_iso_href='deploy_iso_uuid',
|
||||
root_uuid='root-uuid',
|
||||
kernel_params='kernel-params',
|
||||
boot_mode='uefi')
|
||||
boot_iso_expected = 'http://10.10.1.30/httpboot/new_boot_iso'
|
||||
self.assertEqual(boot_iso_expected, boot_iso_actual)
|
||||
copy_file_mock.assert_called_once_with(fileobj_mock.name,
|
||||
@ -336,14 +332,12 @@ class IloBootPrivateMethodsTestCase(test_common.BaseIloTest):
|
||||
task.context, 'image-uuid',
|
||||
['boot_iso', 'kernel_id', 'ramdisk_id'])
|
||||
boot_object_name_mock.assert_called_once_with(task.node)
|
||||
create_boot_iso_mock.assert_called_once_with(task.context,
|
||||
'tmpfile',
|
||||
kernel_href,
|
||||
ramdisk_href,
|
||||
'deploy_iso_uuid',
|
||||
'root-uuid',
|
||||
'kernel-params',
|
||||
'uefi')
|
||||
create_boot_iso_mock.assert_called_once_with(
|
||||
task.context, 'tmpfile', kernel_href, ramdisk_href,
|
||||
deploy_iso_href='deploy_iso_uuid',
|
||||
root_uuid='root-uuid',
|
||||
kernel_params='kernel-params',
|
||||
boot_mode='uefi')
|
||||
boot_iso_expected = 'http://10.10.1.30/httpboot/abcdef'
|
||||
self.assertEqual(boot_iso_expected, boot_iso_actual)
|
||||
copy_file_mock.assert_called_once_with(fileobj_mock.name,
|
||||
|
@ -498,8 +498,9 @@ class IRMCDeployPrivateMethodsTestCase(test_common.BaseIRMCTest):
|
||||
'/remote_image_share_root/'
|
||||
"boot-%s.iso" % self.node.uuid,
|
||||
'kernel_uuid', 'ramdisk_uuid',
|
||||
'02f9d414-2ce0-4cf5-b48f-dbc1bf678f55',
|
||||
'root-uuid', 'kernel-params', 'uefi')
|
||||
deploy_iso_href='02f9d414-2ce0-4cf5-b48f-dbc1bf678f55',
|
||||
root_uuid='root-uuid', kernel_params='kernel-params',
|
||||
boot_mode='uefi')
|
||||
task.node.refresh()
|
||||
self.assertEqual("boot-%s.iso" % self.node.uuid,
|
||||
task.node.driver_internal_info['irmc_boot_iso'])
|
||||
|
12
releasenotes/notes/build-iso-from-esp-d156036aa8ef85fb.yaml
Normal file
12
releasenotes/notes/build-iso-from-esp-d156036aa8ef85fb.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Allows the user to supply EFI system partition image to ironic, for
|
||||
building UEFI-bootable ISO images, in form of a local file or UUID
|
||||
or URI reference. The new ``[conductor]esp_image`` option can be used
|
||||
to configure ironic to use local file.
|
||||
other:
|
||||
- |
|
||||
Makes ironic building UEFI-only bootable ISO image (when being asked to
|
||||
build a UEFI-bootable image) rather than building a hybrid
|
||||
BIOS/UEFI-bootable ISO.
|
Loading…
Reference in New Issue
Block a user