diff --git a/kiwi/bootloader_config.py b/kiwi/bootloader_config.py index 3a18113c..f91805ad 100644 --- a/kiwi/bootloader_config.py +++ b/kiwi/bootloader_config.py @@ -17,6 +17,7 @@ # # project from bootloader_config_grub2 import BootLoaderConfigGrub2 +from bootloader_config_isolinux import BootLoaderConfigIsoLinux from exceptions import ( KiwiBootLoaderConfigSetupError @@ -33,6 +34,10 @@ class BootLoaderConfig(object): return BootLoaderConfigGrub2( xml_state, source_dir ) + elif name == 'isolinux': + return BootLoaderConfigIsoLinux( + xml_state, source_dir + ) else: raise KiwiBootLoaderConfigSetupError( 'Support for %s bootloader config not implemented' % name diff --git a/kiwi/bootloader_config_grub2.py b/kiwi/bootloader_config_grub2.py index fac4f97e..ff0ac4a8 100644 --- a/kiwi/bootloader_config_grub2.py +++ b/kiwi/bootloader_config_grub2.py @@ -200,7 +200,7 @@ class BootLoaderConfigGrub2(BootLoaderConfigBase): self.source_dir + '/boot/mbrid' ) - self.__copy_unicode_font_to_boot_directory(lookup_path) + self.__copy_theme_data_to_boot_directory(lookup_path) if self.firmware.efi_mode() == 'uefi': log.info('--> Using signed secure boot efi image') @@ -226,7 +226,7 @@ class BootLoaderConfigGrub2(BootLoaderConfigBase): if self.firmware.efi_mode(): self.efi_boot_path = self.create_efi_path() - self.__copy_unicode_font_to_boot_directory(lookup_path) + self.__copy_theme_data_to_boot_directory(lookup_path) if self.firmware.efi_mode() == 'efi': log.info('--> Creating unsigned efi image') @@ -468,11 +468,11 @@ class BootLoaderConfigGrub2(BootLoaderConfigBase): selected_gfxmode = gfxmode[requested_gfxmode] return selected_gfxmode - def __copy_unicode_font_to_boot_directory(self, lookup_path): + def __copy_theme_data_to_boot_directory(self, lookup_path): + if not lookup_path: + lookup_path = self.source_dir boot_unicode_font = self.source_dir + '/boot/unicode.pf2' if not os.path.exists(boot_unicode_font): - if not lookup_path: - lookup_path = self.source_dir unicode_font = lookup_path + '/usr/share/grub2/unicode.pf2' try: Command.run( @@ -483,6 +483,18 @@ class BootLoaderConfigGrub2(BootLoaderConfigBase): 'Unicode font %s not found' % unicode_font ) + boot_theme_dir = self.source_dir + '/boot/grub2/themes' + if self.theme and not os.path.exists(boot_theme_dir): + Path.create(boot_theme_dir) + theme_dir = \ + lookup_path + '/usr/share/grub2/themes/' + self.theme + if os.path.exists(theme_dir): + Command.run( + ['rsync', '-zav', theme_dir, boot_theme_dir], + ) + else: + log.warning('Theme %s not found', theme_dir) + def __copy_efi_modules_to_boot_directory(self, lookup_path): self.__copy_modules_to_boot_directory_from( self.__get_efi_modules_path(lookup_path) diff --git a/kiwi/bootloader_config_isolinux.py b/kiwi/bootloader_config_isolinux.py new file mode 100644 index 00000000..f4779302 --- /dev/null +++ b/kiwi/bootloader_config_isolinux.py @@ -0,0 +1,155 @@ +# Copyright (c) 2015 SUSE Linux GmbH. All rights reserved. +# +# This file is part of kiwi. +# +# kiwi is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# kiwi is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with kiwi. If not, see +# +import os +import platform + +# project +from logger import log +from bootloader_config_base import BootLoaderConfigBase +from bootloader_template_isolinux import BootLoaderTemplateIsoLinux +from command import Command +from path import Path + +from exceptions import ( + KiwiTemplateError, + KiwiBootLoaderIsoLinuxPlatformError +) + + +class BootLoaderConfigIsoLinux(BootLoaderConfigBase): + """ + isolinux bootloader configuration. + """ + def post_init(self): + arch = platform.machine() + if arch == 'x86_64': + self.arch = arch + else: + raise KiwiBootLoaderIsoLinuxPlatformError( + 'host architecture %s not supported for isolinux setup' % arch + ) + + self.gfxmode = self.xml_state.build_type.get_vga() + self.timeout = self.get_boot_timeout_seconds() + self.cmdline = self.get_boot_cmdline() + self.cmdline_failsafe = self.get_failsafe_boot_cmdline() + self.failsafe_boot = self.failsafe_boot_entry_requested() + self.hypervisor_domain = self.get_hypervisor_domain() + + self.multiboot = False + if self.hypervisor_domain: + if self.hypervisor_domain == 'dom0': + self.multiboot = True + elif self.hypervisor_domain == 'domU': + self.multiboot = False + + self.isolinux = BootLoaderTemplateIsoLinux() + self.config = None + self.config_message = None + + def write(self): + """ + Write isolinux.cfg and isolinux.msg file + """ + log.info('Writing isolinux.cfg file') + config_dir = self.__get_iso_boot_path() + config_file = config_dir + '/isolinux.cfg' + if self.config: + Path.create(config_dir) + with open(config_file, 'w') as config: + config.write(self.config) + + config_file_message = config_dir + '/isolinux.msg' + if self.config_message: + with open(config_file_message, 'w') as config: + config.write(self.config_message) + + def setup_install_image_config( + self, mbrid, hypervisor='xen.gz', kernel='linux', initrd='initrd' + ): + """ + Create isolinux.cfg in memory from a template suitable to boot + from an ISO image in BIOS boot mode + """ + # mbrid parameter is not used, the information is placed as the + # application id when creating the iso filesystem. Thus not part + # of the configuration file + log.info('Creating install config file from template') + parameters = { + 'default_boot': 'Boot_from_Hard_Disk', + 'kernel_file': kernel, + 'initrd_file': initrd, + 'boot_options': self.cmdline, + 'failsafe_boot_options': self.cmdline_failsafe, + 'gfxmode': self.gfxmode, + 'boot_timeout': self.timeout, + 'title': self.get_menu_entry_install_title() + } + if self.multiboot: + log.info('--> Using multiboot install template') + parameters['hypervisor'] = hypervisor + template = self.isolinux.get_multiboot_install_template( + self.failsafe_boot, self.__have_theme() + ) + else: + log.info('--> Using install template') + template = self.isolinux.get_install_template( + self.failsafe_boot, self.__have_theme() + ) + try: + self.config = template.substitute(parameters) + template = self.isolinux.get_install_message_template() + self.config_message = template.substitute(parameters) + except Exception as e: + raise KiwiTemplateError( + '%s: %s' % (type(e).__name__, format(e)) + ) + + def setup_live_image_config( + self, mbrid, hypervisor='xen.gz', kernel='linux', initrd='initrd' + ): + # TODO + pass + + def setup_install_boot_images(self, mbrid, lookup_path=None): + # mbrid parameter is not used, because only isolinux loader + # binary and possible theming files are copied + self.__copy_loader_data_to_boot_directory(lookup_path) + + def setup_live_boot_images(self, mbrid, lookup_path=None): + # same action as for install media + self.setup_install_boot_images(None, lookup_path) + + def __copy_loader_data_to_boot_directory(self, lookup_path): + if not lookup_path: + lookup_path = self.source_dir + loader_data = lookup_path + '/image/loader/' + Path.create(self.__get_iso_boot_path()) + Command.run( + [ + 'rsync', '-zav', loader_data, self.__get_iso_boot_path() + ] + ) + + def __get_iso_boot_path(self): + return self.source_dir + '/boot/' + self.arch + '/loader' + + def __have_theme(self): + if os.path.exists(self.__get_iso_boot_path() + '/bootlogo'): + return True + return False diff --git a/kiwi/bootloader_template_grub2.py b/kiwi/bootloader_template_grub2.py index 09ac4f66..59027189 100644 --- a/kiwi/bootloader_template_grub2.py +++ b/kiwi/bootloader_template_grub2.py @@ -45,25 +45,20 @@ class BootLoaderTemplateGrub2(object): ''').strip() + self.cr self.header_gfxterm = dedent(''' - set font=($$root)${bootpath}/unicode.pf2 - if loadfont $$font ;then - set gfxmode=${gfxmode} - insmod all_video - insmod gfxterm - terminal_output gfxterm - fi + set gfxmode=${gfxmode} + insmod all_video + insmod gfxterm + terminal_output gfxterm ''').strip() + self.cr self.header_serial = dedent(''' - set font=${bootpath}/unicode.pf2 - if loadfont $$font ;then - serial --speed=9600 --unit=0 --word=8 --parity=no --stop=1 - terminal_input serial - terminal_output serial - fi + serial --speed=9600 --unit=0 --word=8 --parity=no --stop=1 + terminal_input serial + terminal_output serial ''').strip() + self.cr self.header_theme = dedent(''' + set font=($$root)${bootpath}/unicode.pf2 if loadfont ($$root)${bootpath}/grub2/themes/${theme}/ascii.pf2;then loadfont ($$root)${bootpath}/grub2/themes/${theme}/DejaVuSans-Bold14.pf2 loadfont ($$root)${bootpath}/grub2/themes/${theme}/DejaVuSans10.pf2 @@ -73,6 +68,17 @@ class BootLoaderTemplateGrub2(object): fi ''').strip() + self.cr + self.header_theme_iso = dedent(''' + set font=($$root)/boot/unicode.pf2 + if loadfont ($$root)/boot/grub2/themes/${theme}/ascii.pf2;then + loadfont ($$root)/boot/grub2/themes/${theme}/DejaVuSans-Bold14.pf2 + loadfont ($$root)/boot/grub2/themes/${theme}/DejaVuSans10.pf2 + loadfont ($$root)/boot/grub2/themes/${theme}/DejaVuSans12.pf2 + loadfont ($$root)/boot/grub2/themes/${theme}/ascii.pf2 + set theme=($$root)/boot/grub2/themes/${theme}/theme.txt + fi + ''').strip() + self.cr + self.menu_entry_hybrid = dedent(''' menuentry "${title}" --class os { echo Loading kernel... @@ -263,7 +269,7 @@ class BootLoaderTemplateGrub2(object): template_data += self.header_gfxterm else: template_data += self.header_serial - template_data += self.header_theme + template_data += self.header_theme_iso template_data += self.menu_install_harddisk_entry if hybrid: template_data += self.menu_install_entry_hybrid @@ -287,7 +293,7 @@ class BootLoaderTemplateGrub2(object): template_data += self.header_gfxterm else: template_data += self.header_serial - template_data += self.header_theme + template_data += self.header_theme_iso template_data += self.menu_install_harddisk_entry template_data += self.menu_install_entry_multiboot if failsafe: diff --git a/kiwi/bootloader_template_isolinux.py b/kiwi/bootloader_template_isolinux.py new file mode 100644 index 00000000..d54edebd --- /dev/null +++ b/kiwi/bootloader_template_isolinux.py @@ -0,0 +1,165 @@ +# Copyright (c) 2015 SUSE Linux GmbH. All rights reserved. +# +# This file is part of kiwi. +# +# kiwi is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# kiwi is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with kiwi. If not, see +# +from string import Template +from textwrap import dedent + + +class BootLoaderTemplateIsoLinux(object): + """ + isolinux configuraton file templates + """ + def __init__(self): + self.cr = '\n' + + self.install_message = dedent(''' + Welcome ! + + Boot_from_Hard_Disk + Install_${title} + Failsafe_--_Install_${title} + + + Have a lot of fun... + ''').strip() + self.cr + + self.message = dedent(''' + Welcome ! + + ${title} + Failsafe_${title} + + + Have a lot of fun... + ''').strip() + self.cr + + self.header = dedent(''' + # kiwi generated isolinux config file + implicit 1 + prompt 1 + timeout ${boot_timeout} + display isolinux.msg + default ${default_boot} + ui gfxboot bootlogo isolinux.msg + ''').strip() + self.cr + + self.ui_theme = dedent(''' + ui gfxboot bootlogo isolinux.msg + ''').strip() + self.cr + + self.ui_plain = dedent(''' + ui menu.c32 + ''').strip() + self.cr + + self.menu_install_harddisk_entry = dedent(''' + label Boot_from_Hard_Disk + localboot 0x80 + ''').strip() + self.cr + + self.menu_install_entry_multiboot = dedent(''' + label Install_${title} + kernel mboot.c32 + append ${hypervisor} --- ${kernel_file} vga=${gfxmode} ${boot_options} cdinst=1 kiwi_hybrid=1 showopts --- ${initrd_file} showopts + ''').strip() + self.cr + + self.menu_install_entry_failsafe_multiboot = dedent(''' + label Failsafe_--_Install_${title} + kernel mboot.c32 + append ${hypervisor} --- ${kernel_file} vga=${gfxmode} ${failsafe_boot_options} cdinst=1 kiwi_hybrid=1 showopts --- ${initrd_file} showopts + ''').strip() + self.cr + + self.menu_entry_multiboot = dedent(''' + label ${title} + kernel mboot.c32 + append ${hypervisor} --- ${kernel_file} vga=${gfxmode} ${boot_options} cdinst=1 kiwi_hybrid=1 showopts --- ${initrd_file} showopts + ''').strip() + self.cr + + self.menu_entry_failsafe_multiboot = dedent(''' + label Failsafe_--_${title} + kernel mboot.c32 + append ${hypervisor} --- ${kernel_file} vga=${gfxmode} ${failsafe_boot_options} cdinst=1 kiwi_hybrid=1 showopts --- ${initrd_file} showopts + ''').strip() + self.cr + + self.menu_install_entry = dedent(''' + label Install_${title} + kernel ${kernel_file} + append initrd=${initrd_file} vga=${gfxmode} ${boot_options} cdinst=1 kiwi_hybrid=1 showopts + ''').strip() + self.cr + + self.menu_install_entry_failsafe = dedent(''' + label Failsafe_--_Install_${title} + kernel ${kernel_file} + append initrd=${initrd_file} vga=${gfxmode} ${failsafe_boot_options} cdinst=1 kiwi_hybrid=1 showopts + ''').strip() + self.cr + + self.menu_entry = dedent(''' + label ${title} + kernel ${kernel_file} + append initrd=${initrd_file} vga=${gfxmode} ${boot_options} cdinst=1 kiwi_hybrid=1 showopts + ''').strip() + self.cr + + self.menu_entry_failsafe = dedent(''' + label Failsafe_--_${title} + kernel ${kernel_file} + append initrd=${initrd_file} vga=${gfxmode} ${failsafe_boot_options} cdinst=1 kiwi_hybrid=1 showopts + ''').strip() + self.cr + + def get_install_message_template(self): + """ + bootloader template for text message file in install mode. + isolinux displays this as menu if no graphics mode can be + initialized + """ + return Template(self.install_message) + + def get_message_template(self): + """ + bootloader template for text message file. isolinux + displays this as menu if no graphics mode can be initialized + """ + return Template(self.message) + + def get_install_template(self, failsafe=True, with_theme=True): + """ + bootloader configuration template for install media + """ + template_data = self.header + if with_theme: + self.ui_theme + else: + self.ui_plain + template_data += self.menu_install_harddisk_entry + template_data += self.menu_install_entry + if failsafe: + template_data += self.menu_install_entry_failsafe + return Template(template_data) + + def get_multiboot_install_template(self, failsafe=True, with_theme=True): + """ + bootloader configuration template for install media with + hypervisor, e.g Xen dom0 + """ + template_data = self.header + if with_theme: + self.ui_theme + else: + self.ui_plain + template_data += self.menu_install_harddisk_entry + template_data += self.menu_install_entry_multiboot + if failsafe: + template_data += self.menu_install_entry_failsafe_multiboot + return Template(template_data) diff --git a/kiwi/command_process.py b/kiwi/command_process.py index b3007014..00621b69 100644 --- a/kiwi/command_process.py +++ b/kiwi/command_process.py @@ -121,6 +121,10 @@ class CommandProcess(object): result = namedtuple( 'result', ['stderr', 'returncode'] ) + if watch: + log.debug(command_error_output) + else: + log.debug('%s: %s', self.log_topic, command_error_output) return result( stderr=command_error_output, returncode=self.command.process.returncode diff --git a/kiwi/exceptions.py b/kiwi/exceptions.py index 5d4704fc..ea6c31a2 100644 --- a/kiwi/exceptions.py +++ b/kiwi/exceptions.py @@ -29,10 +29,6 @@ class KiwiError(Exception): return format(self.message) -class KiwiBootLoaderTargetError(KiwiError): - pass - - class KiwiBootLoaderConfigSetupError(KiwiError): pass @@ -57,6 +53,14 @@ class KiwiBootLoaderInstallSetupError(KiwiError): pass +class KiwiBootLoaderIsoLinuxPlatformError(KiwiError): + pass + + +class KiwiBootLoaderTargetError(KiwiError): + pass + + class KiwiBootStrapPhaseFailed(KiwiError): pass @@ -129,6 +133,10 @@ class KiwiInvalidVolumeName(KiwiError): pass +class KiwiIsoLoaderError(KiwiError): + pass + + class KiwiLoadCommandUndefined(KiwiError): pass diff --git a/kiwi/filesystem_isofs.py b/kiwi/filesystem_isofs.py new file mode 100644 index 00000000..023394be --- /dev/null +++ b/kiwi/filesystem_isofs.py @@ -0,0 +1,41 @@ +# Copyright (c) 2015 SUSE Linux GmbH. All rights reserved. +# +# This file is part of kiwi. +# +# kiwi is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# kiwi is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with kiwi. If not, see +# +# project +from iso import Iso +from command import Command +from filesystem_base import FileSystemBase + + +class FileSystemIsoFs(FileSystemBase): + """ + Implements creation of iso filesystem + """ + def post_init(self, custom_args): + self.custom_args = custom_args + + def create_on_file(self, filename, label=None): + # there is no label which could be set for an iso filesystem + # thus this parameter is not used + iso = Iso(self.source_dir) + iso.init_iso_creation_parameters(self.custom_args) + iso.add_efi_loader_parameters() + Command.run( + ['genisoimage'] + iso.get_iso_creation_parameters() + [ + '-o', filename, self.source_dir + ] + ) diff --git a/kiwi/install_image_builder.py b/kiwi/install_image_builder.py index 1873a317..3b70a6e4 100644 --- a/kiwi/install_image_builder.py +++ b/kiwi/install_image_builder.py @@ -22,6 +22,7 @@ import os from command import Command from bootloader_config import BootLoaderConfig from filesystem_squashfs import FileSystemSquashFs +from filesystem_isofs import FileSystemIsoFs from image_identifier import ImageIdentifier from path import Path from checksum import Checksum @@ -42,11 +43,21 @@ class InstallImageBuilder(object): ): self.target_dir = target_dir self.disk_image = disk_image + self.machine = xml_state.get_build_type_machine_section() self.boot_image_task = boot_image_task self.xml_state = xml_state + self.isoname = ''.join( + [ + target_dir, '/', + xml_state.xml_data.get_name(), '.install.iso' + ] + ) + self.mbrid = ImageIdentifier() self.mbrid.calculate_id() + self.media_dir = None + self.custom_iso_args = None def create_install_iso(self): """ @@ -56,6 +67,12 @@ class InstallImageBuilder(object): self.media_dir = mkdtemp( prefix='install-media.', dir=self.target_dir ) + # custom iso metadata + self.custom_iso_args = [ + '-V', '"KIWI Installation System"', + '-A', self.mbrid.get_id() + ] + # the install image transfer is checked against a checksum log.info('Creating disk image checksum') checksum = Checksum(self.disk_image) @@ -77,26 +94,43 @@ class InstallImageBuilder(object): ['mv', squashed_image_file, self.media_dir] ) + # setup bootloader config to boot the ISO via isolinux + bootloader_config_isolinux = BootLoaderConfig.new( + 'isolinux', self.xml_state, self.media_dir + ) + bootloader_config_isolinux.setup_install_boot_images( + mbrid=None, + lookup_path=self.boot_image_task.boot_root_directory + ) + bootloader_config_isolinux.setup_install_image_config( + mbrid=None + ) + bootloader_config_isolinux.write() + # setup bootloader config to boot the ISO via EFI - self.bootloader_config_grub = BootLoaderConfig.new( + bootloader_config_grub = BootLoaderConfig.new( 'grub2', self.xml_state, self.media_dir ) - self.bootloader_config_grub.setup_install_boot_images( + bootloader_config_grub.setup_install_boot_images( mbrid=self.mbrid, lookup_path=self.boot_image_task.boot_root_directory ) - self.bootloader_config_grub.setup_install_image_config( - self.mbrid + bootloader_config_grub.setup_install_image_config( + mbrid=self.mbrid ) - self.bootloader_config_grub.write() - - # setup bootloader config to boot the ISO via isolinux - # TODO + bootloader_config_grub.write() + # create initrd for install image self.__create_iso_install_kernel_and_initrd() # TODO # create iso filesystem from self.media_dir and make it hybrid + iso_image = FileSystemIsoFs( + device_provider=None, + source_dir=self.media_dir, + custom_args=self.custom_iso_args + ) + iso_image.create_on_file(self.isoname) def create_install_pxe_archive(self): # TODO @@ -113,7 +147,14 @@ class InstallImageBuilder(object): 'No kernel in boot image tree %s found' % self.boot_image_task.boot_root_directory ) - # TODO: for xen dom0 boot the hypervisor needs to be copied too + if self.machine and self.machine.get_domain() == 'dom0': + if kernel.get_xen_hypervisor(): + kernel.copy_xen_hypervisor(boot_path, '/xen.gz') + else: + raise KiwiInstallBootImageError( + 'No hypervisor in boot image tree %s found' % + self.boot_image_task.boot_root_directory + ) self.boot_image_task.create_initrd(self.mbrid) Command.run( [ @@ -133,6 +174,6 @@ class InstallImageBuilder(object): iso_system.write('IMAGE="%s"\n' % diskname) def __del__(self): - # if self.media_dir: - # Path.wipe(self.media_dir) - pass + if self.media_dir: + log.info('Cleaning up %s instance', type(self).__name__) + Path.wipe(self.media_dir) diff --git a/kiwi/internal_boot_image_task.py b/kiwi/internal_boot_image_task.py index 7a848b1a..e47a6b2f 100644 --- a/kiwi/internal_boot_image_task.py +++ b/kiwi/internal_boot_image_task.py @@ -157,9 +157,6 @@ class BootImageTask(object): compress = Compress(initrd_file_name) compress.xz() self.initrd_filename = compress.compressed_filename - log.info( - '--> created %s', self.initrd_filename - ) def __import_system_description_elements(self): self.xml_state.copy_displayname( diff --git a/kiwi/iso.py b/kiwi/iso.py new file mode 100644 index 00000000..535eefed --- /dev/null +++ b/kiwi/iso.py @@ -0,0 +1,114 @@ +# Copyright (c) 2015 SUSE Linux GmbH. All rights reserved. +# +# This file is part of kiwi. +# +# kiwi is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# kiwi is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with kiwi. If not, see +# +import os +import platform +from tempfile import NamedTemporaryFile + +# project +from command import Command +from exceptions import ( + KiwiIsoLoaderError +) + + +class Iso(object): + """ + Implements helper methods around the creation of an iso filesystem + """ + def __init__(self, source_dir): + self.header_id = '7984fc91-a43f-4e45-bf27-6d3aa08b24cf' + self.header_end_name = 'header_end' + self.arch = platform.machine() + self.source_dir = source_dir + self.boot_path = 'boot/' + self.arch + self.iso_sortfile = NamedTemporaryFile() + self.iso_parameters = [] + self.iso_loaders = [] + + def init_iso_creation_parameters(self, custom_args=None): + loader_file = self.boot_path + '/loader/isolinux.bin' + catalog_file = self.boot_path + '/boot.catalog' + with open(self.source_dir + '/' + self.header_end_name, 'w') as marker: + marker.write('%s\n' % self.header_id) + if not os.path.exists(self.source_dir + '/' + loader_file): + raise KiwiIsoLoaderError( + 'No isolinux loader found in %s' % + self.source_dir + '/loader' + ) + if custom_args: + self.iso_parameters = custom_args + self.iso_parameters += [ + '-R', '-J', '-f', '-pad', '-joliet-long', + '-sort', self.iso_sortfile.name, + '-no-emul-boot', '-boot-load-size', '4', '-boot-info-table', + '-hide', catalog_file, + '-hide-joliet', catalog_file, + ] + self.iso_loaders += [ + '-b', loader_file, '-c', catalog_file + ] + Command.run( + [ + 'isolinux-config', '--base', self.boot_path + '/loader', + self.source_dir + '/' + loader_file + ] + ) + self.__create_sortfile() + + def add_efi_loader_parameters(self): + loader_file = self.boot_path + '/efi' + if os.path.exists(self.source_dir + '/' + loader_file): + self.iso_loaders += [ + '-eltorito-alt-boot', '-b', loader_file, + '-no-emul-boot', '-joliet-long' + ] + + def get_iso_creation_parameters(self): + return self.iso_parameters + self.iso_loaders + + def add_iso_header_end_marker(self): + # TODO: see the glump file creation in the old kiwi + pass + + def relocate_boot_catalog(self, isofile): + # TODO + pass + + def fix_boot_catalog(self, isofile): + # TODO + pass + + def __create_sortfile(self): + catalog_file = \ + self.source_dir + '/' + self.boot_path + '/boot.catalog' + loader_file = \ + self.source_dir + '/' + self.boot_path + '/loader/isolinux.bin' + with open(self.iso_sortfile.name, 'w') as sortfile: + sortfile.write('%s 3\n' % catalog_file) + sortfile.write('%s 2\n' % loader_file) + + for basedir, dirnames, filenames in os.walk(self.source_dir): + for filename in filenames: + if filename == 'efi': + sortfile.write('%s/%s 1000001\n' % (basedir, filename)) + elif filename == self.header_end_name: + sortfile.write('%s/%s 1000000\n' % (basedir, filename)) + else: + sortfile.write('%s/%s 1\n' % (basedir, filename)) + for dirname in dirnames: + sortfile.write('%s/%s 1\n' % (basedir, dirname)) diff --git a/kiwi/system.py b/kiwi/system.py index fe985eca..ad774274 100644 --- a/kiwi/system.py +++ b/kiwi/system.py @@ -300,15 +300,15 @@ class System(object): self, manager, packages, collections=None, products=None ): if packages: - for package in packages: + for package in sorted(packages): log.info('--> package: %s', package) manager.request_package(package) if collections: - for collection in collections: + for collection in sorted(collections): log.info('--> collection: %s', collection) manager.request_collection(collection) if products: - for product in products: + for product in sorted(products): log.info('--> product: %s', product) manager.request_product(product) return \ diff --git a/kiwi/system_create_task.py b/kiwi/system_create_task.py index f7a73a71..646524aa 100644 --- a/kiwi/system_create_task.py +++ b/kiwi/system_create_task.py @@ -90,6 +90,10 @@ class SystemCreateTask(CliTask): result.add( 'disk_image', disk.diskname ) + if disk.install_image.media_dir: + result.add( + 'installation_image', disk.install_image.isoname + ) elif requested_image_type in Defaults.get_live_image_types(): # TODO raise KiwiNotImplementedError( diff --git a/test/unit/bootloader_config_grub2_test.py b/test/unit/bootloader_config_grub2_test.py index f8080a42..b8c6bbec 100644 --- a/test/unit/bootloader_config_grub2_test.py +++ b/test/unit/bootloader_config_grub2_test.py @@ -49,6 +49,10 @@ class TestBootLoaderConfigGrub2(object): self.bootloader = BootLoaderConfigGrub2( self.state, 'source_dir' ) + self.bootloader.get_hypervisor_domain = mock.Mock( + return_value='domU' + ) + self.bootloader.theme = None @raises(KiwiBootLoaderGrubPlatformError) @patch('platform.machine') @@ -56,13 +60,12 @@ class TestBootLoaderConfigGrub2(object): mock_machine.return_value = 'unsupported-arch' BootLoaderConfigGrub2(mock.Mock(), 'source_dir') - @patch('kiwi.bootloader_config_base.BootLoaderConfigBase.get_hypervisor_domain') @patch('os.path.exists') - def test_post_init_dom0(self, mock_exists, mock_domain): - mock_domain.return_value = 'dom0' + def test_post_init_dom0(self, mock_exists): + self.bootloader.get_hypervisor_domain.return_value = 'dom0' mock_exists.return_value = True self.bootloader.post_init() - assert self.bootloader.hypervisor_domain == 'dom0' + assert self.bootloader.multiboot is True @patch('__builtin__.open') @patch('os.path.exists') @@ -423,6 +426,39 @@ class TestBootLoaderConfigGrub2(object): 'source_dir//EFI/BOOT' ]) + @patch('kiwi.bootloader_config_grub2.Command.run') + @patch('__builtin__.open') + @patch('os.path.exists') + @patch('kiwi.logger.log.warning') + def test_setup_install_boot_images_with_theme( + self, mock_warn, mock_exists, mock_open, mock_command + ): + self.bootloader.theme = 'some-theme' + exists_results = [False, True, False, False] + + def side_effect(arg): + return exists_results.pop() + + mock_exists.side_effect = side_effect + self.bootloader.setup_install_boot_images(self.mbrid) + assert mock_command.call_args_list[1] == call([ + 'rsync', '-zav', + 'source_dir/usr/share/grub2/themes/some-theme', + 'source_dir/boot/grub2/themes' + ]) + + @patch('kiwi.bootloader_config_grub2.Command.run') + @patch('__builtin__.open') + @patch('os.path.exists') + @patch('kiwi.logger.log.warning') + def test_setup_install_boot_images_with_theme_not_existing( + self, mock_warn, mock_exists, mock_open, mock_command + ): + self.bootloader.theme = 'some-theme' + mock_exists.return_value = False + self.bootloader.setup_install_boot_images(self.mbrid) + assert mock_warn.called + def test_setup_live_image_config(self): # TODO self.bootloader.setup_live_image_config('mbrid') diff --git a/test/unit/bootloader_config_isolinux_test.py b/test/unit/bootloader_config_isolinux_test.py new file mode 100644 index 00000000..f806e42d --- /dev/null +++ b/test/unit/bootloader_config_isolinux_test.py @@ -0,0 +1,139 @@ +from nose.tools import * +from mock import patch +from mock import call + +import mock + +import kiwi + +import nose_helper + +from kiwi.xml_state import XMLState +from kiwi.xml_description import XMLDescription +from kiwi.exceptions import * +from kiwi.bootloader_config_isolinux import BootLoaderConfigIsoLinux + + +class TestBootLoaderConfigIsoLinux(object): + @patch('os.path.exists') + @patch('platform.machine') + def setup(self, mock_machine, mock_exists): + mock_machine.return_value = 'x86_64' + mock_exists.return_value = True + description = XMLDescription( + '../data/example_config.xml' + ) + self.state = XMLState( + description.load() + ) + kiwi.bootloader_config_isolinux.Path = mock.Mock() + kiwi.bootloader_config_base.Path = mock.Mock() + self.isolinux = mock.Mock() + kiwi.bootloader_config_isolinux.BootLoaderTemplateIsoLinux = mock.Mock( + return_value=self.isolinux + ) + self.bootloader = BootLoaderConfigIsoLinux( + self.state, 'source_dir' + ) + self.bootloader.get_hypervisor_domain = mock.Mock( + return_value='domU' + ) + + @raises(KiwiBootLoaderIsoLinuxPlatformError) + @patch('platform.machine') + def test_post_init_invalid_platform(self, mock_machine): + mock_machine.return_value = 'unsupported-arch' + BootLoaderConfigIsoLinux(mock.Mock(), 'source_dir') + + @patch('os.path.exists') + def test_post_init_dom0(self, mock_exists): + self.bootloader.get_hypervisor_domain.return_value = 'dom0' + mock_exists.return_value = True + + self.bootloader.post_init() + assert self.bootloader.multiboot is True + + @patch('__builtin__.open') + @patch('os.path.exists') + def test_write(self, mock_exists, mock_open): + mock_exists.return_value = True + context_manager_mock = mock.Mock() + mock_open.return_value = context_manager_mock + file_mock = mock.Mock() + enter_mock = mock.Mock() + exit_mock = mock.Mock() + enter_mock.return_value = file_mock + setattr(context_manager_mock, '__enter__', enter_mock) + setattr(context_manager_mock, '__exit__', exit_mock) + self.bootloader.config = 'some-data' + self.bootloader.config_message = 'some-message-data' + + self.bootloader.write() + assert mock_open.call_args_list == [ + call('source_dir/boot/x86_64/loader/isolinux.cfg', 'w'), + call('source_dir/boot/x86_64/loader/isolinux.msg', 'w') + ] + assert file_mock.write.call_args_list == [ + call('some-data'), + call('some-message-data') + ] + + def test_setup_install_image_config(self): + template_cfg = mock.Mock() + template_msg = mock.Mock() + self.isolinux.get_install_template.return_value = template_cfg + self.isolinux.get_install_message_template.return_value = template_msg + + self.bootloader.setup_install_image_config(mbrid=None) + self.isolinux.get_install_template.assert_called_once_with(True, False) + self.isolinux.get_install_message_template.assert_called_once_with() + assert template_cfg.substitute.called + assert template_msg.substitute.called + + def test_setup_install_image_config_multiboot(self): + self.bootloader.multiboot = True + + self.bootloader.setup_install_image_config(mbrid=None) + self.isolinux.get_multiboot_install_template.assert_called_once_with( + True, False + ) + + @patch('os.path.exists') + def test_setup_install_image_config_with_theme(self, mock_exists): + mock_exists.return_value = True + + self.bootloader.setup_install_image_config(mbrid=None) + self.isolinux.get_install_template.assert_called_once_with(True, True) + + @raises(KiwiTemplateError) + def test_setup_install_image_config_invalid_template(self): + self.isolinux.get_install_message_template.side_effect = Exception + self.bootloader.setup_install_image_config(mbrid=None) + + @patch('kiwi.bootloader_config_isolinux.Command.run') + def test_setup_install_boot_images(self, mock_command): + self.bootloader.setup_install_boot_images( + mbrid=None, lookup_path='lookup_dir' + ) + mock_command.assert_called_once_with( + [ + 'rsync', '-zav', 'lookup_dir/image/loader/', + 'source_dir/boot/x86_64/loader' + ] + ) + + @patch('kiwi.bootloader_config_isolinux.Command.run') + def test_setup_live_boot_images(self, mock_command): + self.bootloader.setup_live_boot_images( + mbrid=None + ) + mock_command.assert_called_once_with( + [ + 'rsync', '-zav', 'source_dir/image/loader/', + 'source_dir/boot/x86_64/loader' + ] + ) + + def test_setup_live_image_config(self): + # TODO + self.bootloader.setup_live_image_config(mbrid=None) diff --git a/test/unit/bootloader_config_test.py b/test/unit/bootloader_config_test.py index bf1896d3..7f43e573 100644 --- a/test/unit/bootloader_config_test.py +++ b/test/unit/bootloader_config_test.py @@ -19,3 +19,9 @@ class TestBootLoaderConfig(object): xml_state = mock.Mock() BootLoaderConfig.new('grub2', xml_state, 'source_dir') mock_grub2.assert_called_once_with(xml_state, 'source_dir') + + @patch('kiwi.bootloader_config.BootLoaderConfigIsoLinux') + def test_bootloader_config_isolinux(self, mock_isolinux): + xml_state = mock.Mock() + BootLoaderConfig.new('isolinux', xml_state, 'source_dir') + mock_isolinux.assert_called_once_with(xml_state, 'source_dir') diff --git a/test/unit/bootloader_template_isolinux_test.py b/test/unit/bootloader_template_isolinux_test.py new file mode 100644 index 00000000..d10019b2 --- /dev/null +++ b/test/unit/bootloader_template_isolinux_test.py @@ -0,0 +1,83 @@ +from nose.tools import * +from mock import patch + +import mock + +import nose_helper + +from kiwi.bootloader_template_isolinux import BootLoaderTemplateIsoLinux + + +class TestBootLoaderTemplateIsoLinux(object): + def setup(self): + self.isolinux = BootLoaderTemplateIsoLinux() + + def test_get_multiboot_install_template(self): + assert self.isolinux.get_multiboot_install_template().substitute( + default_boot='0', + kernel_file='linux.vmx', + initrd_file='initrd.vmx', + boot_options='splash', + failsafe_boot_options='splash', + gfxmode='800x600', + theme='SLE', + boot_timeout='10', + title='LimeJeOS-SLE12-Community [ VMX ]', + bootpath='/boot', + hypervisor='xen.gz' + ) + + def test_get_install_template(self): + assert self.isolinux.get_install_template().substitute( + default_boot='0', + kernel_file='boot/linux.vmx', + initrd_file='boot/initrd.vmx', + boot_options='cdinst=1 splash', + failsafe_boot_options='cdinst=1 splash', + gfxmode='800x600', + theme='SLE', + boot_timeout='10', + title='LimeJeOS-SLE12-Community [ VMX ]', + bootpath='/boot' + ) + + def test_get_multiboot_install_template_plain_ui(self): + assert self.isolinux.get_multiboot_install_template( + with_theme=False + ).substitute( + default_boot='0', + kernel_file='linux.vmx', + initrd_file='initrd.vmx', + boot_options='splash', + failsafe_boot_options='splash', + gfxmode='800x600', + theme='SLE', + boot_timeout='10', + title='LimeJeOS-SLE12-Community [ VMX ]', + bootpath='/boot', + hypervisor='xen.gz' + ) + + def test_get_install_template_plan_ui(self): + assert self.isolinux.get_install_template(with_theme=False).substitute( + default_boot='0', + kernel_file='boot/linux.vmx', + initrd_file='boot/initrd.vmx', + boot_options='cdinst=1 splash', + failsafe_boot_options='cdinst=1 splash', + gfxmode='800x600', + theme='SLE', + boot_timeout='10', + title='LimeJeOS-SLE12-Community [ VMX ]', + bootpath='/boot' + ) + + def test_get_message_template(self): + assert self.isolinux.get_message_template().substitute( + title='LimeJeOS-SLE12-Community [ VMX ]' + ) + + def test_get_install_message_template(self): + assert self.isolinux.get_install_message_template().substitute( + title='LimeJeOS-SLE12-Community [ VMX ]' + ) diff --git a/test/unit/command_process_test.py b/test/unit/command_process_test.py index 839bd060..c29c7075 100644 --- a/test/unit/command_process_test.py +++ b/test/unit/command_process_test.py @@ -1,5 +1,6 @@ from nose.tools import * from mock import patch +from mock import call from collections import namedtuple import mock @@ -60,9 +61,10 @@ class TestCommandProcess(object): process.command.error.read = self.flow_err process.command.process.returncode = 0 process.poll_show_progress(['a', 'b'], match_method) - mock_log_debug.assert_called_once_with( - '%s: %s', 'system', 'data' - ) + assert mock_log_debug.call_args_list == [ + call('%s: %s', 'system', 'data'), + call('%s: %s', 'system', 'error') + ] @raises(KiwiCommandError) @patch('kiwi.command.Command') @@ -90,9 +92,10 @@ class TestCommandProcess(object): process.command.error.read = self.flow_err process.command.process.returncode = 0 process.poll() - mock_log_debug.assert_called_once_with( - '%s: %s', 'system', 'data' - ) + assert mock_log_debug.call_args_list == [ + call('%s: %s', 'system', 'data'), + call('%s: %s', 'system', 'error') + ] @raises(KiwiCommandError) @patch('kiwi.command.Command') diff --git a/test/unit/filesystem_isofs_test.py b/test/unit/filesystem_isofs_test.py new file mode 100644 index 00000000..98d82bb3 --- /dev/null +++ b/test/unit/filesystem_isofs_test.py @@ -0,0 +1,35 @@ +from nose.tools import * +from mock import patch + +import mock + +import nose_helper + +from kiwi.exceptions import * +from kiwi.filesystem_isofs import FileSystemIsoFs + + +class TestFileSystemIsoFs(object): + @patch('os.path.exists') + def setup(self, mock_exists): + mock_exists.return_value = True + self.isofs = FileSystemIsoFs(mock.Mock(), 'source_dir') + + def test_post_init(self): + self.isofs.post_init(['args']) + assert self.isofs.custom_args == ['args'] + + @patch('kiwi.filesystem_isofs.Command.run') + @patch('kiwi.filesystem_isofs.Iso') + def test_create_on_file(self, mock_iso, mock_command): + iso = mock.Mock() + iso.get_iso_creation_parameters = mock.Mock( + return_value=['args'] + ) + mock_iso.return_value = iso + self.isofs.create_on_file('myimage', None) + iso.init_iso_creation_parameters.assert_called_once_with(None) + iso.add_efi_loader_parameters.assert_called_once_with() + mock_command.assert_called_once_with( + ['genisoimage', 'args', '-o', 'myimage', 'source_dir'] + ) diff --git a/test/unit/install_image_builder_test.py b/test/unit/install_image_builder_test.py index 0bdc06e1..30e5beaa 100644 --- a/test/unit/install_image_builder_test.py +++ b/test/unit/install_image_builder_test.py @@ -20,6 +20,10 @@ class TestInstallImageBuilder(object): kiwi.install_image_builder.FileSystemSquashFs = mock.Mock( return_value=self.squashed_image ) + self.iso_image = mock.Mock() + kiwi.install_image_builder.FileSystemIsoFs = mock.Mock( + return_value=self.iso_image + ) self.mbrid = mock.Mock() self.mbrid.get_id = mock.Mock( return_value='0xffffffff' @@ -34,17 +38,26 @@ class TestInstallImageBuilder(object): ) self.kernel = mock.Mock() self.kernel.get_kernel = mock.Mock() + self.kernel.get_xen_hypervisor = mock.Mock() self.kernel.copy_kernel = mock.Mock() + self.kernel.copy_xen_hypervisor = mock.Mock() kiwi.install_image_builder.Kernel = mock.Mock( return_value=self.kernel ) self.xml_state = mock.Mock() + self.xml_state.xml_data.get_name = mock.Mock( + return_value='result-image' + ) self.boot_image_task = mock.Mock() self.boot_image_task.boot_root_directory = 'initrd_dir' self.boot_image_task.initrd_filename = 'initrd' self.install_image = InstallImageBuilder( self.xml_state, 'target_dir', 'some-diskimage', self.boot_image_task ) + self.install_image.machine = mock.Mock() + self.install_image.machine.get_domain = mock.Mock( + return_value='dom0' + ) @patch('kiwi.install_image_builder.mkdtemp') @patch('__builtin__.open') @@ -76,23 +89,37 @@ class TestInstallImageBuilder(object): self.squashed_image.create_on_file.assert_called_once_with( 'some-diskimage.squashfs' ) - self.bootloader.setup_install_boot_images.assert_called_once_with( - lookup_path='initrd_dir', mbrid=self.mbrid - ) - self.bootloader.setup_install_image_config.assert_called_once_with( - self.mbrid - ) - self.bootloader.write.assert_called_once_with() + assert self.bootloader.setup_install_boot_images.call_args_list == [ + call(lookup_path='initrd_dir', mbrid=None), + call(lookup_path='initrd_dir', mbrid=self.mbrid) + ] + assert self.bootloader.setup_install_boot_images.call_args_list == [ + call(lookup_path='initrd_dir', mbrid=None), + call(lookup_path='initrd_dir', mbrid=self.mbrid) + ] + assert self.bootloader.setup_install_image_config.call_args_list == [ + call(mbrid=None), + call(mbrid=self.mbrid) + ] + assert self.bootloader.write.call_args_list == [ + call(), call() + ] self.boot_image_task.create_initrd.assert_called_once_with( self.mbrid ) self.kernel.copy_kernel.assert_called_once_with( 'tmpdir/boot/x86_64/loader', '/linux' ) + self.kernel.copy_xen_hypervisor.assert_called_once_with( + 'tmpdir/boot/x86_64/loader', '/xen.gz' + ) assert mock_command.call_args_list == [ call(['mv', 'some-diskimage.squashfs', 'tmpdir']), call(['mv', 'initrd', 'tmpdir/boot/x86_64/loader/initrd']) ] + self.iso_image.create_on_file.assert_called_once_with( + 'target_dir/result-image.install.iso' + ) @patch('kiwi.install_image_builder.mkdtemp') @patch('__builtin__.open') @@ -104,10 +131,23 @@ class TestInstallImageBuilder(object): self.kernel.get_kernel.return_value = False self.install_image.create_install_iso() + @patch('kiwi.install_image_builder.mkdtemp') + @patch('__builtin__.open') + @patch('kiwi.install_image_builder.Command.run') + @raises(KiwiInstallBootImageError) + def test_create_install_iso_no_hypervisor_found( + self, mock_command, mock_open, mock_dtemp + ): + self.kernel.get_xen_hypervisor.return_value = False + self.install_image.create_install_iso() + def test_create_install_pxe_archive(self): # TODO self.install_image.create_install_pxe_archive() - def test_destructor(self): - # TODO + @patch('kiwi.install_image_builder.Path.wipe') + def test_destructor(self, mock_wipe): + self.install_image.media_dir = 'media-dir' self.install_image.__del__() + mock_wipe.assert_called_once_with('media-dir') + self.install_image.media_dir = None diff --git a/test/unit/iso_test.py b/test/unit/iso_test.py new file mode 100644 index 00000000..cebc9298 --- /dev/null +++ b/test/unit/iso_test.py @@ -0,0 +1,110 @@ +from nose.tools import * +from mock import patch +from mock import call +import mock + +import nose_helper + +from kiwi.exceptions import * + +from kiwi.iso import Iso +from collections import namedtuple + + +class TestIso(object): + @patch('kiwi.iso.NamedTemporaryFile') + @patch('platform.machine') + def setup(self, mock_machine, mock_tempfile): + temp_type = namedtuple( + 'temp_type', ['name'] + ) + mock_machine.return_value = 'x86_64' + mock_tempfile.return_value = temp_type( + name='sortfile' + ) + self.iso = Iso('source-dir') + + @patch('__builtin__.open') + @patch('os.path.exists') + @raises(KiwiIsoLoaderError) + def test_init_iso_creation_parameters_no_loader( + self, mock_exists, mock_open + ): + mock_exists.return_value = False + self.iso.init_iso_creation_parameters() + + @patch('__builtin__.open') + @patch('kiwi.iso.Command.run') + @patch('os.path.exists') + @patch('os.walk') + def test_init_iso_creation_parameters( + self, mock_walk, mock_exists, mock_command, mock_open + ): + mock_walk.return_value = [ + ('source-dir', ('bar', 'baz'), ('efi', 'eggs', 'header_end')) + ] + mock_exists.return_value = True + context_manager_mock = mock.Mock() + mock_open.return_value = context_manager_mock + file_mock = mock.Mock() + enter_mock = mock.Mock() + exit_mock = mock.Mock() + enter_mock.return_value = file_mock + setattr(context_manager_mock, '__enter__', enter_mock) + setattr(context_manager_mock, '__exit__', exit_mock) + + self.iso.init_iso_creation_parameters(['custom_arg']) + + assert file_mock.write.call_args_list == [ + call('7984fc91-a43f-4e45-bf27-6d3aa08b24cf\n'), + call('source-dir/boot/x86_64/boot.catalog 3\n'), + call('source-dir/boot/x86_64/loader/isolinux.bin 2\n'), + call('source-dir/efi 1000001\n'), + call('source-dir/eggs 1\n'), + call('source-dir/header_end 1000000\n'), + call('source-dir/bar 1\n'), + call('source-dir/baz 1\n') + ] + assert self.iso.iso_parameters == [ + 'custom_arg', '-R', '-J', '-f', '-pad', '-joliet-long', + '-sort', 'sortfile', '-no-emul-boot', '-boot-load-size', '4', + '-boot-info-table', + '-hide', 'boot/x86_64/boot.catalog', + '-hide-joliet', 'boot/x86_64/boot.catalog', + ] + assert self.iso.iso_loaders == [ + '-b', 'boot/x86_64/loader/isolinux.bin', + '-c', 'boot/x86_64/boot.catalog' + ] + mock_command.assert_called_once_with( + [ + 'isolinux-config', '--base', 'boot/x86_64/loader', + 'source-dir/boot/x86_64/loader/isolinux.bin' + ] + ) + + @patch('os.path.exists') + def test_add_efi_loader_parameters(self, mock_exists): + mock_exists.return_value = True + self.iso.add_efi_loader_parameters() + assert self.iso.iso_loaders == [ + '-eltorito-alt-boot', '-b', 'boot/x86_64/efi', + '-no-emul-boot', '-joliet-long' + ] + + def test_get_iso_creation_parameters(self): + self.iso.iso_parameters = ['a'] + self.iso.iso_loaders = ['b'] + assert self.iso.get_iso_creation_parameters() == ['a', 'b'] + + def test_add_iso_header_end_marker(self): + # TODO + self.iso.add_iso_header_end_marker() + + def test_relocate_boot_catalog(self): + # TODO + self.iso.relocate_boot_catalog('isofile') + + def test_fix_boot_catalog(self): + # TODO + self.iso.fix_boot_catalog('isofile')