Added isolinux bootloader support

This commit is contained in:
Marcus Schäfer 2015-12-09 10:39:21 +01:00
parent 48a96d6528
commit 61ea327a4c
No known key found for this signature in database
GPG Key ID: AD11DD02B44996EF
21 changed files with 1065 additions and 61 deletions

View File

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

View File

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

View File

@ -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 <http://www.gnu.org/licenses/>
#
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

View File

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

View File

@ -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 <http://www.gnu.org/licenses/>
#
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)

View File

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

View File

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

41
kiwi/filesystem_isofs.py Normal file
View File

@ -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 <http://www.gnu.org/licenses/>
#
# 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
]
)

View File

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

View File

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

114
kiwi/iso.py Normal file
View File

@ -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 <http://www.gnu.org/licenses/>
#
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))

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

110
test/unit/iso_test.py Normal file
View File

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