def create(self): """ Build a bootable hybrid live ISO image Image types which triggers this builder are: * image="iso" :raises KiwiLiveBootImageError: if no kernel or hipervisor is found in boot image tree :return: result :rtype: instance of :class:`Result` """ # media dir to store CD contents self.media_dir = mkdtemp(prefix='live-media.', dir=self.target_dir) # unpack cdroot user files to media dir self.system_setup.import_cdroot_files(self.media_dir) rootsize = SystemSize(self.media_dir) # custom iso metadata log.info('Using following live ISO metadata:') log.info('--> Application id: {0}'.format(self.mbrid.get_id())) log.info('--> Publisher: {0}'.format(Defaults.get_publisher())) log.info('--> Volume id: {0}'.format(self.volume_id)) custom_iso_args = { 'meta_data': { 'publisher': self.publisher, 'preparer': Defaults.get_preparer(), 'volume_id': self.volume_id, 'mbr_id': self.mbrid.get_id(), 'efi_mode': self.firmware.efi_mode() } } log.info('Setting up live image bootloader configuration') if self.firmware.efi_mode(): # setup bootloader config to boot the ISO via EFI # This also embedds an MBR and the respective BIOS modules # for compat boot. The complete bootloader setup will be # based on grub bootloader_config = BootLoaderConfig( 'grub2', self.xml_state, root_dir=self.root_dir, boot_dir=self.media_dir, custom_args={ 'grub_directory_name': Defaults.get_grub_boot_directory_name(self.root_dir) }) bootloader_config.setup_live_boot_images(mbrid=self.mbrid, lookup_path=self.root_dir) else: # setup bootloader config to boot the ISO via isolinux. # This allows for booting on x86 platforms in BIOS mode # only. bootloader_config = BootLoaderConfig('isolinux', self.xml_state, root_dir=self.root_dir, boot_dir=self.media_dir) IsoToolsBase.setup_media_loader_directory( self.boot_image.boot_root_directory, self.media_dir, bootloader_config.get_boot_theme()) bootloader_config.write_meta_data() bootloader_config.setup_live_image_config(mbrid=self.mbrid) bootloader_config.write() # call custom editbootconfig script if present self.system_setup.call_edit_boot_config_script( filesystem='iso:{0}'.format(self.media_dir), boot_part_id=1, working_directory=self.root_dir) # prepare dracut initrd call self.boot_image.prepare() # create dracut initrd for live image log.info('Creating live ISO boot image') live_dracut_modules = Defaults.get_live_dracut_modules_from_flag( self.live_type) live_dracut_modules.append('pollcdrom') for dracut_module in live_dracut_modules: self.boot_image.include_module(dracut_module) self.boot_image.omit_module('multipath') self.boot_image.write_system_config_file( config={ 'modules': live_dracut_modules, 'omit_modules': ['multipath'] }, config_file=self.root_dir + '/etc/dracut.conf.d/02-livecd.conf') self.boot_image.create_initrd(self.mbrid) # setup kernel file(s) and initrd in ISO boot layout log.info('Setting up kernel file(s) and boot image in ISO boot layout') self._setup_live_iso_kernel_and_initrd() # calculate size and decide if we need UDF if rootsize.accumulate_mbyte_file_sizes() > 4096: log.info('ISO exceeds 4G size, using UDF filesystem') custom_iso_args['meta_data']['udf'] = True # pack system into live boot structure as expected by dracut log.info('Packing system into dracut live ISO type: {0}'.format( self.live_type)) root_filesystem = Defaults.get_default_live_iso_root_filesystem() filesystem_custom_parameters = { 'mount_options': self.xml_state.get_fs_mount_option_list(), 'create_options': self.xml_state.get_fs_create_option_list() } filesystem_setup = FileSystemSetup(self.xml_state, self.root_dir) root_image = NamedTemporaryFile() loop_provider = LoopDevice( root_image.name, filesystem_setup.get_size_mbytes(root_filesystem), self.xml_state.build_type.get_target_blocksize()) loop_provider.create() live_filesystem = FileSystem(name=root_filesystem, device_provider=loop_provider, root_dir=self.root_dir + os.sep, custom_args=filesystem_custom_parameters) live_filesystem.create_on_device() log.info('--> Syncing data to {0} root image'.format(root_filesystem)) live_filesystem.sync_data( Defaults.get_exclude_list_for_root_data_sync()) log.info('--> Creating squashfs container for root image') self.live_container_dir = mkdtemp(prefix='live-container.', dir=self.target_dir) Path.create(self.live_container_dir + '/LiveOS') shutil.copy(root_image.name, self.live_container_dir + '/LiveOS/rootfs.img') live_container_image = FileSystem( name='squashfs', device_provider=None, root_dir=self.live_container_dir, custom_args={ 'compression': self.xml_state.build_type.get_squashfscompression() }) container_image = NamedTemporaryFile() live_container_image.create_on_file(container_image.name) Path.create(self.media_dir + '/LiveOS') shutil.copy(container_image.name, self.media_dir + '/LiveOS/squashfs.img') # create iso filesystem from media_dir log.info('Creating live ISO image') iso_image = FileSystemIsoFs(device_provider=None, root_dir=self.media_dir, custom_args=custom_iso_args) iso_image.create_on_file(self.isoname) # include metadata for checkmedia tool if self.xml_state.build_type.get_mediacheck() is True: Iso.set_media_tag(self.isoname) self.result.verify_image_size( self.runtime_config.get_max_size_constraint(), self.isoname) self.result.add(key='live_image', filename=self.isoname, use_for_bundle=True, compress=False, shasum=True) self.result.add(key='image_packages', filename=self.system_setup.export_package_list( self.target_dir), use_for_bundle=True, compress=False, shasum=False) self.result.add(key='image_verified', filename=self.system_setup.export_package_verification( self.target_dir), use_for_bundle=True, compress=False, shasum=False) return self.result
def create_install_iso(self): """ Create an install ISO from the disk_image as hybrid ISO bootable via legacy BIOS, EFI and as disk from Stick Image types which triggers this builder are: * installiso="true|false" * installstick="true|false" """ self.media_dir = mkdtemp( prefix='kiwi_install_media.', dir=self.target_dir ) # unpack cdroot user files to media dir self.setup.import_cdroot_files(self.media_dir) # custom iso metadata self.custom_iso_args = { 'meta_data': { 'volume_id': self.iso_volume_id, 'mbr_id': self.mbrid.get_id(), 'efi_mode': self.firmware.efi_mode() } } # the system image transfer is checked against a checksum log.info('Creating disk image checksum') self.squashed_contents = mkdtemp( prefix='kiwi_install_squashfs.', dir=self.target_dir ) checksum = Checksum(self.diskname) checksum.md5(self.squashed_contents + '/' + self.md5name) # the system image name is stored in a config file self._write_install_image_info_to_iso_image() if self.initrd_system == 'kiwi': self._write_install_image_info_to_boot_image() # the system image is stored as squashfs embedded file log.info('Creating squashfs embedded disk image') Command.run( [ 'cp', '-l', self.diskname, self.squashed_contents + '/' + self.squashed_diskname ] ) squashed_image_file = ''.join( [ self.target_dir, '/', self.squashed_diskname, '.squashfs' ] ) squashed_image = FileSystemSquashFs( device_provider=None, root_dir=self.squashed_contents, custom_args={ 'create_options': self.xml_state.get_fs_create_option_list() } ) squashed_image.create_on_file(squashed_image_file) Command.run( ['mv', squashed_image_file, self.media_dir] ) log.info( 'Setting up install image bootloader configuration' ) if self.firmware.efi_mode(): # setup bootloader config to boot the ISO via EFI # This also embedds an MBR and the respective BIOS modules # for compat boot. The complete bootloader setup will be # based on grub bootloader_config = BootLoaderConfig( 'grub2', self.xml_state, root_dir=self.root_dir, boot_dir=self.media_dir, custom_args={ 'grub_directory_name': Defaults.get_grub_boot_directory_name(self.root_dir) } ) bootloader_config.setup_install_boot_images( mbrid=self.mbrid, lookup_path=self.boot_image_task.boot_root_directory ) else: # setup bootloader config to boot the ISO via isolinux. # This allows for booting on x86 platforms in BIOS mode # only. bootloader_config = BootLoaderConfig( 'isolinux', self.xml_state, root_dir=self.root_dir, boot_dir=self.media_dir ) IsoToolsBase.setup_media_loader_directory( self.boot_image_task.boot_root_directory, self.media_dir, bootloader_config.get_boot_theme() ) bootloader_config.write_meta_data() bootloader_config.setup_install_image_config( mbrid=self.mbrid ) bootloader_config.write() # create initrd for install image log.info('Creating install image boot image') self._create_iso_install_kernel_and_initrd() # the system image initrd is stored to allow kexec self._copy_system_image_initrd_to_iso_image() # create iso filesystem from media_dir log.info('Creating ISO filesystem') iso_image = FileSystemIsoFs( device_provider=None, root_dir=self.media_dir, custom_args=self.custom_iso_args ) iso_image.create_on_file(self.isoname)
class TestIsoToolsBase: @patch('platform.machine') def setup(self, mock_machine): mock_machine.return_value = 'x86_64' self.iso_tool = IsoToolsBase('source-dir') def test_create_iso(self): with raises(NotImplementedError): self.iso_tool.create_iso('filename') def test_list_iso(self): with raises(NotImplementedError): self.iso_tool.list_iso('isofile') def test_get_tool_name(self): with raises(NotImplementedError): self.iso_tool.get_tool_name() def test_init_iso_creation_parameters(self): with raises(NotImplementedError): self.iso_tool.init_iso_creation_parameters() def test_add_efi_loader_parameters(self): with raises(NotImplementedError): self.iso_tool.add_efi_loader_parameters() def test_has_iso_hybrid_capability(self): with raises(NotImplementedError): self.iso_tool.has_iso_hybrid_capability() @patch('kiwi.iso_tools.base.DataSync') @patch('kiwi.iso_tools.base.shutil') @patch('kiwi.iso_tools.base.Command.run') @patch('kiwi.iso_tools.base.Path') @patch('os.path.exists') def test_setup_media_loader_directory(self, mock_exists, mock_Path, mock_command, mock_shutil, mock_sync): mock_exists.return_value = True data = Mock() mock_sync.return_value = data self.iso_tool.setup_media_loader_directory('root_dir', 'media_dir', 'openSUSE') assert mock_shutil.copy.call_args_list == [ call('root_dir/usr/share/grub2/i386-pc/eltorito.img', 'root_dir/image/loader/'), call('root_dir/usr/share/grub2/i386-pc/boot_hybrid.img', 'root_dir/image/loader/'), call('root_dir/usr/share/syslinux/isolinux.bin', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/bios/isolinux.bin', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/modules/bios/isolinux.bin', 'root_dir/image/loader/'), call('root_dir/usr/lib/ISOLINUX/isolinux.bin', 'root_dir/image/loader/'), call('root_dir/usr/share/syslinux/ldlinux.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/bios/ldlinux.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/modules/bios/ldlinux.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/ISOLINUX/ldlinux.c32', 'root_dir/image/loader/'), call('root_dir/usr/share/syslinux/libcom32.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/bios/libcom32.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/modules/bios/libcom32.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/ISOLINUX/libcom32.c32', 'root_dir/image/loader/'), call('root_dir/usr/share/syslinux/libutil.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/bios/libutil.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/modules/bios/libutil.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/ISOLINUX/libutil.c32', 'root_dir/image/loader/'), call('root_dir/usr/share/syslinux/gfxboot.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/bios/gfxboot.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/modules/bios/gfxboot.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/ISOLINUX/gfxboot.c32', 'root_dir/image/loader/'), call('root_dir/usr/share/syslinux/gfxboot.com', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/bios/gfxboot.com', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/modules/bios/gfxboot.com', 'root_dir/image/loader/'), call('root_dir/usr/lib/ISOLINUX/gfxboot.com', 'root_dir/image/loader/'), call('root_dir/usr/share/syslinux/menu.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/bios/menu.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/modules/bios/menu.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/ISOLINUX/menu.c32', 'root_dir/image/loader/'), call('root_dir/usr/share/syslinux/chain.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/bios/chain.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/modules/bios/chain.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/ISOLINUX/chain.c32', 'root_dir/image/loader/'), call('root_dir/usr/share/syslinux/mboot.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/bios/mboot.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/syslinux/modules/bios/mboot.c32', 'root_dir/image/loader/'), call('root_dir/usr/lib/ISOLINUX/mboot.c32', 'root_dir/image/loader/') ] assert mock_command.call_args_list == [ call(command=[ 'bash', '-c', 'cp root_dir/boot/memtest* ' 'root_dir/image/loader//memtest' ], raise_on_error=False), call([ 'bash', '-c', 'cp root_dir/etc/bootsplash/themes/openSUSE/' 'cdrom/* root_dir/image/loader/' ]), call([ 'gfxboot', '--config-file', 'root_dir/image/loader//gfxboot.cfg', '--change-config', 'install::autodown=0' ]), call([ 'cp', 'root_dir/etc/bootsplash/themes/openSUSE/' 'bootloader/message', 'root_dir/image/loader/' ]) ] mock_sync.assert_called_once_with('root_dir/image/loader/', 'media_dir/boot/x86_64/loader') data.sync_data.assert_called_once_with(options=['-a'])