Пример #1
0
class LiveImageBuilder(object):
    """
        Live image builder
    """
    def __init__(self, xml_state, target_dir, root_dir):
        self.media_dir = None
        self.arch = platform.machine()
        self.root_dir = root_dir
        self.target_dir = target_dir
        self.xml_state = xml_state
        self.live_type = xml_state.build_type.get_flags()
        self.types = Defaults.get_live_iso_types()
        self.hybrid = xml_state.build_type.get_hybrid()
        self.volume_id = xml_state.build_type.get_volid()
        self.machine = xml_state.get_build_type_machine_section()
        self.mbrid = ImageIdentifier()
        self.mbrid.calculate_id()

        if not self.live_type:
            self.live_type = Defaults.get_default_live_iso_type()

        self.boot_image_task = BootImageTask('kiwi', xml_state, target_dir)
        self.firmware = FirmWare(xml_state)
        self.system_setup = SystemSetup(xml_state=xml_state,
                                        description_dir=None,
                                        root_dir=self.root_dir)
        self.isoname = ''.join([
            target_dir, '/',
            xml_state.xml_data.get_name(), '.' + platform.machine(),
            '-' + xml_state.get_image_version(), '.iso'
        ])
        self.live_image_file = ''.join([
            target_dir, '/',
            xml_state.xml_data.get_name(), '-read-only.', self.arch, '-',
            xml_state.get_image_version()
        ])
        self.result = Result()

    def create(self):
        # media dir to store CD contents
        self.media_dir = mkdtemp(prefix='live-media.', dir=self.target_dir)
        rootsize = SystemSize(self.media_dir)

        # custom iso metadata
        log.info('Using following live ISO metadata:')
        log.info('--> Application id: %s', self.mbrid.get_id())
        log.info('--> Publisher: %s', Defaults.get_publisher())
        custom_iso_args = [
            '-A',
            self.mbrid.get_id(),
            '-p',
            '"' + Defaults.get_preparer() + '"',
            '-publisher',
            '"' + Defaults.get_publisher() + '"',
        ]
        if self.volume_id:
            log.info('--> Volume id: %s', self.volume_id)
            custom_iso_args.append('-V')
            custom_iso_args.append('"' + self.volume_id + '"')

        # prepare boot(initrd) root system
        log.info('Preparing live ISO boot system')
        self.boot_image_task.prepare()

        # export modprobe configuration to boot image
        self.system_setup.export_modprobe_setup(
            self.boot_image_task.boot_root_directory)

        # pack system into live boot structure
        log.info('Packing system into live ISO type: %s', self.live_type)
        if self.live_type in self.types:
            live_type_image = FileSystem(name=self.types[self.live_type],
                                         device_provider=None,
                                         root_dir=self.root_dir)
            live_type_image.create_on_file(self.live_image_file)
            Command.run(['mv', self.live_image_file, self.media_dir])
            self.__create_live_iso_client_config(self.live_type)
        else:
            raise KiwiLiveBootImageError('live ISO type "%s" not supported' %
                                         self.live_type)

        # setup bootloader config to boot the ISO via isolinux
        log.info('Setting up isolinux bootloader configuration')
        bootloader_config_isolinux = BootLoaderConfig('isolinux',
                                                      self.xml_state,
                                                      self.media_dir)
        bootloader_config_isolinux.setup_live_boot_images(
            mbrid=None, lookup_path=self.boot_image_task.boot_root_directory)
        bootloader_config_isolinux.setup_live_image_config(mbrid=None)
        bootloader_config_isolinux.write()

        # setup bootloader config to boot the ISO via EFI
        if self.firmware.efi_mode():
            log.info('Setting up EFI grub bootloader configuration')
            bootloader_config_grub = BootLoaderConfig('grub2', self.xml_state,
                                                      self.media_dir)
            bootloader_config_grub.setup_live_boot_images(
                mbrid=self.mbrid,
                lookup_path=self.boot_image_task.boot_root_directory)
            bootloader_config_grub.setup_live_image_config(mbrid=self.mbrid)
            bootloader_config_grub.write()

        # create initrd for live image
        log.info('Creating live ISO boot image')
        self.__create_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.append('-allow-limited-size')
            custom_iso_args.append('-udf')

        # 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_header_offset = iso_image.create_on_file(self.isoname)

        # make it hybrid
        if self.hybrid:
            Iso.create_hybrid(iso_header_offset, self.mbrid, self.isoname)

        self.result.add('live_image', self.isoname)
        return self.result

    def __create_live_iso_kernel_and_initrd(self):
        boot_path = self.media_dir + '/boot/x86_64/loader'
        Path.create(boot_path)
        kernel = Kernel(self.boot_image_task.boot_root_directory)
        if kernel.get_kernel():
            kernel.copy_kernel(boot_path, '/linux')
        else:
            raise KiwiLiveBootImageError(
                'No kernel in boot image tree %s found' %
                self.boot_image_task.boot_root_directory)
        if self.machine and self.machine.get_domain() == 'dom0':
            if kernel.get_xen_hypervisor():
                kernel.copy_xen_hypervisor(boot_path, '/xen.gz')
            else:
                raise KiwiLiveBootImageError(
                    '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([
            'mv', self.boot_image_task.initrd_filename, boot_path + '/initrd'
        ])

    def __create_live_iso_client_config(self, iso_type):
        """
            Setup IMAGE and UNIONFS_CONFIG variables as they are used in
            the kiwi isoboot code. Variable contents:

            + IMAGE=target_device;live_iso_name_definition
            + UNIONFS_CONFIG=rw_device,ro_device,union_type

            If no real block device is used or can be predefined the
            word 'loop' is set as a placeholder or indicator to use a loop
            device. For more details please refer to the kiwi shell boot
            code
        """
        iso_client_config_file = self.media_dir + '/config.isoclient'
        iso_client_params = Defaults.get_live_iso_client_parameters()
        (system_device, union_device, union_type) = iso_client_params[iso_type]

        with open(iso_client_config_file, 'w') as config:
            config.write('IMAGE="%s;%s.%s;%s"\n' %
                         (system_device, self.xml_state.xml_data.get_name(),
                          self.arch, self.xml_state.get_image_version()))
            config.write('UNIONFS_CONFIG="%s,loop,%s"\n' %
                         (union_device, union_type))

    def __del__(self):
        if self.media_dir:
            log.info('Cleaning up %s instance', type(self).__name__)
            Path.wipe(self.media_dir)
Пример #2
0
class BootLoaderConfigGrub2(BootLoaderConfigBase):
    """
        grub2 bootloader configuration.
    """
    def post_init(self, custom_args):
        self.custom_args = custom_args
        arch = platform.machine()
        if arch == 'x86_64':
            self.arch = arch
        else:
            raise KiwiBootLoaderGrubPlatformError(
                'host architecture %s not supported for grub2 setup' % arch)

        self.terminal = 'gfxterm'
        self.bootpath = self.get_boot_path()
        self.gfxmode = self.__get_gfxmode()
        self.theme = self.get_boot_theme()
        self.timeout = self.get_boot_timeout_seconds()
        self.failsafe_boot = self.failsafe_boot_entry_requested()
        self.hypervisor_domain = self.get_hypervisor_domain()
        self.firmware = FirmWare(self.xml_state)

        self.hybrid_boot = True
        self.multiboot = False
        if self.hypervisor_domain:
            if self.hypervisor_domain == 'dom0':
                self.hybrid_boot = False
                self.multiboot = True
            elif self.hypervisor_domain == 'domU':
                self.hybrid_boot = False
                self.multiboot = False

        self.xen_guest = False
        if self.hypervisor_domain == 'domU' or self.firmware.ec2_mode():
            self.xen_guest = True

        self.grub2 = BootLoaderTemplateGrub2()
        self.config = None
        self.efi_boot_path = None
        self.boot_directory_name = 'grub2'

    def write(self):
        """
            Write grub.cfg file to all required places
        """
        log.info('Writing grub.cfg file')
        config_dir = self.__get_grub_boot_path()
        config_file = config_dir + '/grub.cfg'
        if self.config:
            Path.create(config_dir)
            with open(config_file, 'w') as config:
                config.write(self.config)

            if self.efi_boot_path:
                config_file = self.efi_boot_path + '/grub.cfg'
                with open(config_file, 'w') as config:
                    config.write(self.config)

    def setup_disk_image_config(self,
                                uuid,
                                hypervisor='xen.gz',
                                kernel='linux.vmx',
                                initrd='initrd.vmx'):
        """
            Create the grub.cfg in memory from a template suitable to boot
            from a disk image
        """
        log.info('Creating grub config file from template')
        cmdline = self.get_boot_cmdline(uuid)
        cmdline_failsafe = ' '.join(
            [cmdline, self.get_failsafe_kernel_options()])
        parameters = {
            'search_params': '--fs-uuid --set=root ' + uuid,
            'default_boot': '0',
            'kernel_file': kernel,
            'initrd_file': initrd,
            'boot_options': cmdline,
            'failsafe_boot_options': cmdline_failsafe,
            'gfxmode': self.gfxmode,
            'theme': self.theme,
            'boot_timeout': self.timeout,
            'title': self.get_menu_entry_title(),
            'bootpath': self.bootpath,
        }
        if self.multiboot:
            log.info('--> Using multiboot disk template')
            parameters['hypervisor'] = hypervisor
            template = self.grub2.get_multiboot_disk_template(
                self.failsafe_boot, self.terminal)
        else:
            log.info('--> Using EFI/BIOS hybrid boot disk template')
            template = self.grub2.get_disk_template(self.failsafe_boot,
                                                    self.hybrid_boot,
                                                    self.terminal)
        try:
            self.config = template.substitute(parameters)
        except Exception as e:
            raise KiwiTemplateError('%s: %s' % (type(e).__name__, format(e)))

    def setup_install_image_config(self,
                                   mbrid,
                                   hypervisor='xen.gz',
                                   kernel='linux',
                                   initrd='initrd'):
        """
            Create the grub.cfg in memory from a template suitable to boot
            from an ISO image in EFI boot mode
        """
        log.info('Creating grub install config file from template')
        cmdline = self.get_boot_cmdline()
        cmdline_failsafe = ' '.join(
            [cmdline, self.get_failsafe_kernel_options()])
        parameters = {
            'search_params': '--file --set=root /boot/' + mbrid.get_id(),
            'default_boot': '0',
            'kernel_file': kernel,
            'initrd_file': initrd,
            'boot_options': cmdline,
            'failsafe_boot_options': cmdline_failsafe,
            'gfxmode': self.gfxmode,
            'theme': self.theme,
            'boot_timeout': self.timeout,
            'title': self.get_menu_entry_install_title(),
            'bootpath': '/boot/x86_64/loader',
        }
        if self.multiboot:
            log.info('--> Using EFI multiboot install template')
            parameters['hypervisor'] = hypervisor
            template = self.grub2.get_multiboot_install_template(
                self.failsafe_boot, self.terminal)
        else:
            log.info('--> Using EFI boot install template')
            hybrid_boot = True
            template = self.grub2.get_install_template(self.failsafe_boot,
                                                       hybrid_boot,
                                                       self.terminal)
        try:
            self.config = 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'):
        """
            Create the grub.cfg in memory from a template suitable to boot
            a live system from an ISO image in EFI boot mode
        """
        log.info('Creating grub live ISO config file from template')
        cmdline = self.get_boot_cmdline()
        cmdline_failsafe = ' '.join(
            [cmdline, self.get_failsafe_kernel_options()])
        parameters = {
            'search_params': '--file --set=root /boot/' + mbrid.get_id(),
            'default_boot': '0',
            'kernel_file': kernel,
            'initrd_file': initrd,
            'boot_options': cmdline,
            'failsafe_boot_options': cmdline_failsafe,
            'gfxmode': self.gfxmode,
            'theme': self.theme,
            'boot_timeout': self.timeout,
            'title': self.get_menu_entry_title(plain=True),
            'bootpath': '/boot/x86_64/loader',
        }
        if self.multiboot:
            log.info('--> Using EFI multiboot template')
            parameters['hypervisor'] = hypervisor
            template = self.grub2.get_multiboot_iso_template(
                self.failsafe_boot, self.terminal)
        else:
            log.info('--> Using EFI boot template')
            hybrid_boot = True
            template = self.grub2.get_iso_template(self.failsafe_boot,
                                                   hybrid_boot, self.terminal)
        try:
            self.config = template.substitute(parameters)
        except Exception as e:
            raise KiwiTemplateError('%s: %s' % (type(e).__name__, format(e)))

    def setup_install_boot_images(self, mbrid, lookup_path=None):
        """
            Using grub2 to boot an install media means to support EFI
            boot of the install media. Therefore an EFI image needs to
            be build or used and transfered into an embedded vfat image.
            The non EFI boot of the install media is handled in the
            isolinux boot loader configuration
        """
        log.info('Creating grub bootloader images')
        self.efi_boot_path = self.create_efi_path(in_sub_dir='')

        log.info('--> Creating identifier file %s', mbrid.get_id())
        Path.create(self.__get_grub_boot_path())
        mbrid.write(self.root_dir + '/boot/' + mbrid.get_id())
        mbrid.write(self.root_dir + '/boot/mbrid')

        self.__copy_theme_data_to_boot_directory(lookup_path)

        if self.firmware.efi_mode() == 'uefi':
            log.info('--> Using signed secure boot efi image')
            self.__setup_secure_boot_efi_image(lookup_path)
        else:
            log.info('--> Creating unsigned efi image')
            self.__copy_efi_modules_to_boot_directory(lookup_path)
            self.__create_efi_image(mbrid=mbrid)

        self.__create_embedded_fat_efi_image()

    def setup_live_boot_images(self, mbrid, lookup_path=None):
        # same action as for install media
        self.setup_install_boot_images(mbrid, lookup_path)

    def setup_disk_boot_images(self, boot_uuid, lookup_path=None):
        """
            EFI and bios images needs to be build or used if provided
            by the distribution
        """
        log.info('Creating grub bootloader images')

        if self.firmware.efi_mode():
            self.efi_boot_path = self.create_efi_path()

        self.__copy_theme_data_to_boot_directory(lookup_path)

        if self.firmware.efi_mode() == 'efi':
            log.info('--> Creating unsigned efi image')
            self.__copy_efi_modules_to_boot_directory(lookup_path)
            self.__create_efi_image(uuid=boot_uuid)
        elif self.firmware.efi_mode() == 'uefi':
            log.info('--> Using signed secure boot efi image')
            self.__setup_secure_boot_efi_image(lookup_path)

        log.info('--> Creating bios core image')
        self.__copy_bios_modules_to_boot_directory(lookup_path)
        self.__create_bios_boot_image(boot_uuid)

    def __setup_secure_boot_efi_image(self, lookup_path):
        """
            use prebuilt and signed efi images provided by the distribution
        """
        secure_efi_lookup_path = self.root_dir + '/usr/lib64/efi/'
        if lookup_path:
            secure_efi_lookup_path = lookup_path
        shim_image = secure_efi_lookup_path + Defaults.get_shim_name()
        if not os.path.exists(shim_image):
            raise KiwiBootLoaderGrubSecureBootError(
                'Microsoft signed shim loader %s not found' % shim_image)
        grub_image = secure_efi_lookup_path + Defaults.get_signed_grub_name()
        if not os.path.exists(grub_image):
            raise KiwiBootLoaderGrubSecureBootError(
                'Signed grub2 efi loader %s not found' % grub_image)
        Command.run(['cp', shim_image, self.__get_efi_image_name()])
        Command.run(['cp', grub_image, self.efi_boot_path])

    def __create_embedded_fat_efi_image(self):
        Path.create(self.root_dir + '/boot/' + self.arch)
        efi_fat_image = ''.join([self.root_dir + '/boot/', self.arch, '/efi'])
        Command.run(['qemu-img', 'create', efi_fat_image, '4M'])
        Command.run(['mkdosfs', '-n', 'BOOT', efi_fat_image])
        Command.run([
            'mcopy', '-Do', '-s', '-i', efi_fat_image, self.root_dir + '/EFI',
            '::'
        ])

    def __create_efi_image(self, uuid=None, mbrid=None):
        """
            create efi image
        """
        early_boot_script = self.efi_boot_path + '/earlyboot.cfg'
        if uuid:
            self.__create_early_boot_script_for_uuid_search(
                early_boot_script, uuid)
        else:
            self.__create_early_boot_script_for_mbrid_search(
                early_boot_script, mbrid)
        Command.run([
            'grub2-mkimage', '-O',
            self.__get_efi_format(), '-o',
            self.__get_efi_image_name(), '-c', early_boot_script, '-p',
            self.get_boot_path() + '/' + self.boot_directory_name, '-d',
            self.__get_grub_boot_path() + '/' + self.__get_efi_format()
        ] + self.__get_efi_modules())

    def __create_bios_boot_image(self, uuid):
        """
            create bios image
        """
        early_boot_script = self.__get_grub_boot_path() + '/earlyboot.cfg'
        self.__create_early_boot_script_for_uuid_search(
            early_boot_script, uuid)
        Command.run([
            'grub2-mkimage', '-O',
            self.__get_bios_format(), '-o',
            self.__get_bios_image_name(), '-c', early_boot_script, '-p',
            self.get_boot_path() + '/' + self.boot_directory_name, '-d',
            self.__get_grub_boot_path() + '/' + self.__get_bios_format()
        ] + self.__get_bios_modules())

    def __create_early_boot_script_for_uuid_search(self, filename, uuid):
        with open(filename, 'w') as early_boot:
            early_boot.write('search --fs-uuid --set=root %s\n' % uuid)
            early_boot.write('set prefix=($root)%s/%s\n' %
                             (self.get_boot_path(), self.boot_directory_name))

    def __create_early_boot_script_for_mbrid_search(self, filename, mbrid):
        with open(filename, 'w') as early_boot:
            early_boot.write('search --file --set=root /boot/%s\n' %
                             mbrid.get_id())
            early_boot.write('set prefix=($root)/boot/%s\n' %
                             self.boot_directory_name)

    def __get_grub_boot_path(self):
        return self.root_dir + '/boot/' + self.boot_directory_name

    def __get_basic_modules(self):
        modules = [
            'ext2', 'iso9660', 'linux', 'echo', 'configfile', 'search_label',
            'search_fs_file', 'search', 'search_fs_uuid', 'ls', 'normal',
            'gzio', 'png', 'fat', 'gettext', 'font', 'minicmd', 'gfxterm',
            'gfxmenu', 'video', 'video_fb', 'xfs', 'btrfs', 'lvm', 'multiboot'
        ]
        return modules

    def __get_efi_modules(self):
        modules = self.__get_basic_modules() + [
            'part_gpt', 'efi_gop', 'efi_uga', 'linuxefi'
        ]
        return modules

    def __get_bios_modules(self):
        modules = self.__get_basic_modules() + [
            'part_gpt', 'part_msdos', 'biosdisk', 'vga', 'vbe', 'chain', 'boot'
        ]
        return modules

    def __get_efi_image_name(self):
        efi_image_name = None
        if self.arch == 'x86_64':
            efi_image_name = 'bootx64.efi'
        if efi_image_name:
            return ''.join([self.efi_boot_path, '/', efi_image_name])

    def __get_bios_image_name(self):
        return ''.join([
            self.__get_grub_boot_path(), '/',
            self.__get_bios_format(), '/core.img'
        ])

    def __get_efi_format(self):
        if self.arch == 'x86_64':
            return 'x86_64-efi'

    def __get_bios_format(self):
        return 'i386-pc'

    def __get_xen_format(self):
        return 'x86_64-xen'

    def __get_efi_modules_path(self, lookup_path=None):
        return self.__get_module_path(self.__get_efi_format(), lookup_path)

    def __get_bios_modules_path(self, lookup_path=None):
        return self.__get_module_path(self.__get_bios_format(), lookup_path)

    def __get_xen_modules_path(self, lookup_path=None):
        return self.__get_module_path(self.__get_xen_format(), lookup_path)

    def __get_module_path(self, format_name, lookup_path=None):
        if not lookup_path:
            lookup_path = self.root_dir
        return ''.join([
            self.__find_grub_data(lookup_path + '/usr/lib'), '/', format_name
        ])

    def __get_gfxmode(self):
        selected_gfxmode = '800x600'
        gfxmode = {
            '0x301': '640x480',
            '0x310': '640x480',
            '0x311': '640x480',
            '0x312': '640x480',
            '0x303': '800x600',
            '0x313': '800x600',
            '0x314': '800x600',
            '0x315': '800x600',
            '0x305': '1024x768',
            '0x316': '1024x768',
            '0x317': '1024x768',
            '0x318': '1024x768',
            '0x307': '1280x1024',
            '0x319': '1280x1024',
            '0x31a': '1280x1024',
            '0x31b': '1280x1024',
        }
        requested_gfxmode = self.xml_state.build_type.get_vga()
        if requested_gfxmode in gfxmode:
            selected_gfxmode = gfxmode[requested_gfxmode]
        return selected_gfxmode

    def __copy_theme_data_to_boot_directory(self, lookup_path):
        if not lookup_path:
            lookup_path = self.root_dir
        boot_unicode_font = self.root_dir + '/boot/unicode.pf2'
        if not os.path.exists(boot_unicode_font):
            unicode_font = self.__find_grub_data(lookup_path + '/usr/share') + \
                '/unicode.pf2'
            try:
                Command.run(['cp', unicode_font, boot_unicode_font])
            except Exception:
                raise KiwiBootLoaderGrubFontError('Unicode font %s not found' %
                                                  unicode_font)

        boot_theme_dir = self.root_dir + '/boot/' + \
            self.boot_directory_name + '/themes'
        if self.theme and not os.path.exists(boot_theme_dir):
            Path.create(boot_theme_dir)
            theme_dir = self.__find_grub_data(lookup_path + '/usr/share') + \
                '/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))

    def __copy_bios_modules_to_boot_directory(self, lookup_path):
        self.__copy_modules_to_boot_directory_from(
            self.__get_bios_modules_path(lookup_path))
        if self.xen_guest:
            self.__copy_modules_to_boot_directory_from(
                self.__get_xen_modules_path(lookup_path))

    def __copy_modules_to_boot_directory_from(self, module_path):
        boot_module_path = \
            self.__get_grub_boot_path() + '/' + os.path.basename(module_path)
        if not os.path.exists(boot_module_path):
            try:
                Command.run(['cp', '-a', module_path, boot_module_path])
            except Exception:
                raise KiwiBootLoaderGrubModulesError(
                    'grub2 modules %s not found' % module_path)

    def __find_grub_data(self, lookup_path):
        """
            depending on the distribution grub could be installed below
            a grub2 or grub directory. Therefore this information needs
            to be dynamically looked up
        """
        for grub_name in ['grub2', 'grub']:
            grub_path = lookup_path + '/' + grub_name
            if os.path.exists(grub_path):
                return grub_path

        raise KiwiBootLoaderGrubDataError('No grub2 installation found in %s' %
                                          lookup_path)
Пример #3
0
class BootLoaderConfigGrub2(BootLoaderConfigBase):
    """
        grub2 bootloader configuration.
    """
    def post_init(self, custom_args):
        self.custom_args = custom_args
        arch = platform.machine()
        if arch == 'x86_64':
            self.arch = arch
        else:
            raise KiwiBootLoaderGrubPlatformError(
                'host architecture %s not supported for grub2 setup' % arch
            )

        self.terminal = 'gfxterm'
        self.bootpath = self.get_boot_path()
        self.gfxmode = self.__get_gfxmode()
        self.theme = self.get_boot_theme()
        self.timeout = self.get_boot_timeout_seconds()
        self.failsafe_boot = self.failsafe_boot_entry_requested()
        self.hypervisor_domain = self.get_hypervisor_domain()
        self.firmware = FirmWare(
            self.xml_state
        )

        self.hybrid_boot = True
        self.multiboot = False
        if self.hypervisor_domain:
            if self.hypervisor_domain == 'dom0':
                self.hybrid_boot = False
                self.multiboot = True
            elif self.hypervisor_domain == 'domU':
                self.hybrid_boot = False
                self.multiboot = False

        self.xen_guest = False
        if self.hypervisor_domain == 'domU' or self.firmware.ec2_mode():
            self.xen_guest = True

        self.grub2 = BootLoaderTemplateGrub2()
        self.config = None
        self.efi_boot_path = None
        self.boot_directory_name = 'grub2'

    def write(self):
        """
            Write grub.cfg file to all required places
        """
        log.info('Writing grub.cfg file')
        config_dir = self.__get_grub_boot_path()
        config_file = config_dir + '/grub.cfg'
        if self.config:
            Path.create(config_dir)
            with open(config_file, 'w') as config:
                config.write(self.config)

            if self.efi_boot_path:
                config_file = self.efi_boot_path + '/grub.cfg'
                with open(config_file, 'w') as config:
                    config.write(self.config)

    def setup_disk_image_config(
        self, uuid, hypervisor='xen.gz', kernel='linux.vmx', initrd='initrd.vmx'
    ):
        """
            Create the grub.cfg in memory from a template suitable to boot
            from a disk image
        """
        log.info('Creating grub config file from template')
        cmdline = self.get_boot_cmdline(uuid)
        cmdline_failsafe = ' '.join(
            [cmdline, self.get_failsafe_kernel_options()]
        )
        parameters = {
            'search_params': '--fs-uuid --set=root ' + uuid,
            'default_boot': '0',
            'kernel_file': kernel,
            'initrd_file': initrd,
            'boot_options': cmdline,
            'failsafe_boot_options': cmdline_failsafe,
            'gfxmode': self.gfxmode,
            'theme': self.theme,
            'boot_timeout': self.timeout,
            'title': self.get_menu_entry_title(),
            'bootpath': self.bootpath,
        }
        if self.multiboot:
            log.info('--> Using multiboot disk template')
            parameters['hypervisor'] = hypervisor
            template = self.grub2.get_multiboot_disk_template(
                self.failsafe_boot, self.terminal
            )
        else:
            log.info('--> Using EFI/BIOS hybrid boot disk template')
            template = self.grub2.get_disk_template(
                self.failsafe_boot, self.hybrid_boot, self.terminal
            )
        try:
            self.config = template.substitute(parameters)
        except Exception as e:
            raise KiwiTemplateError(
                '%s: %s' % (type(e).__name__, format(e))
            )

    def setup_install_image_config(
        self, mbrid, hypervisor='xen.gz', kernel='linux', initrd='initrd'
    ):
        """
            Create the grub.cfg in memory from a template suitable to boot
            from an ISO image in EFI boot mode
        """
        log.info('Creating grub install config file from template')
        cmdline = self.get_boot_cmdline()
        cmdline_failsafe = ' '.join(
            [cmdline, self.get_failsafe_kernel_options()]
        )
        parameters = {
            'search_params': '--file --set=root /boot/' + mbrid.get_id(),
            'default_boot': '0',
            'kernel_file': kernel,
            'initrd_file': initrd,
            'boot_options': cmdline,
            'failsafe_boot_options': cmdline_failsafe,
            'gfxmode': self.gfxmode,
            'theme': self.theme,
            'boot_timeout': self.timeout,
            'title': self.get_menu_entry_install_title(),
            'bootpath': '/boot/x86_64/loader',
        }
        if self.multiboot:
            log.info('--> Using EFI multiboot install template')
            parameters['hypervisor'] = hypervisor
            template = self.grub2.get_multiboot_install_template(
                self.failsafe_boot, self.terminal
            )
        else:
            log.info('--> Using EFI boot install template')
            hybrid_boot = True
            template = self.grub2.get_install_template(
                self.failsafe_boot, hybrid_boot, self.terminal
            )
        try:
            self.config = 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'
    ):
        """
            Create the grub.cfg in memory from a template suitable to boot
            a live system from an ISO image in EFI boot mode
        """
        log.info('Creating grub live ISO config file from template')
        cmdline = self.get_boot_cmdline()
        cmdline_failsafe = ' '.join(
            [cmdline, self.get_failsafe_kernel_options()]
        )
        parameters = {
            'search_params': '--file --set=root /boot/' + mbrid.get_id(),
            'default_boot': '0',
            'kernel_file': kernel,
            'initrd_file': initrd,
            'boot_options': cmdline,
            'failsafe_boot_options': cmdline_failsafe,
            'gfxmode': self.gfxmode,
            'theme': self.theme,
            'boot_timeout': self.timeout,
            'title': self.get_menu_entry_title(plain=True),
            'bootpath': '/boot/x86_64/loader',
        }
        if self.multiboot:
            log.info('--> Using EFI multiboot template')
            parameters['hypervisor'] = hypervisor
            template = self.grub2.get_multiboot_iso_template(
                self.failsafe_boot, self.terminal
            )
        else:
            log.info('--> Using EFI boot template')
            hybrid_boot = True
            template = self.grub2.get_iso_template(
                self.failsafe_boot, hybrid_boot, self.terminal
            )
        try:
            self.config = template.substitute(parameters)
        except Exception as e:
            raise KiwiTemplateError(
                '%s: %s' % (type(e).__name__, format(e))
            )

    def setup_install_boot_images(self, mbrid, lookup_path=None):
        """
            Using grub2 to boot an install media means to support EFI
            boot of the install media. Therefore an EFI image needs to
            be build or used and transfered into an embedded vfat image.
            The non EFI boot of the install media is handled in the
            isolinux boot loader configuration
        """
        log.info('Creating grub bootloader images')
        self.efi_boot_path = self.create_efi_path(in_sub_dir='')

        log.info('--> Creating identifier file %s', mbrid.get_id())
        Path.create(
            self.__get_grub_boot_path()
        )
        mbrid.write(
            self.root_dir + '/boot/' + mbrid.get_id()
        )
        mbrid.write(
            self.root_dir + '/boot/mbrid'
        )

        self.__copy_theme_data_to_boot_directory(lookup_path)

        if self.firmware.efi_mode() == 'uefi':
            log.info('--> Using signed secure boot efi image')
            self.__setup_secure_boot_efi_image(lookup_path)
        else:
            log.info('--> Creating unsigned efi image')
            self.__copy_efi_modules_to_boot_directory(lookup_path)
            self.__create_efi_image(mbrid=mbrid)

        self.__create_embedded_fat_efi_image()

    def setup_live_boot_images(self, mbrid, lookup_path=None):
        # same action as for install media
        self.setup_install_boot_images(mbrid, lookup_path)

    def setup_disk_boot_images(self, boot_uuid, lookup_path=None):
        """
            EFI and bios images needs to be build or used if provided
            by the distribution
        """
        log.info('Creating grub bootloader images')

        if self.firmware.efi_mode():
            self.efi_boot_path = self.create_efi_path()

        self.__copy_theme_data_to_boot_directory(lookup_path)

        if self.firmware.efi_mode() == 'efi':
            log.info('--> Creating unsigned efi image')
            self.__copy_efi_modules_to_boot_directory(lookup_path)
            self.__create_efi_image(uuid=boot_uuid)
        elif self.firmware.efi_mode() == 'uefi':
            log.info('--> Using signed secure boot efi image')
            self.__setup_secure_boot_efi_image(lookup_path)

        log.info('--> Creating bios core image')
        self.__copy_bios_modules_to_boot_directory(lookup_path)
        self.__create_bios_boot_image(boot_uuid)

    def __setup_secure_boot_efi_image(self, lookup_path):
        """
            use prebuilt and signed efi images provided by the distribution
        """
        secure_efi_lookup_path = self.root_dir + '/usr/lib64/efi/'
        if lookup_path:
            secure_efi_lookup_path = lookup_path
        shim_image = secure_efi_lookup_path + Defaults.get_shim_name()
        if not os.path.exists(shim_image):
            raise KiwiBootLoaderGrubSecureBootError(
                'Microsoft signed shim loader %s not found' % shim_image
            )
        grub_image = secure_efi_lookup_path + Defaults.get_signed_grub_name()
        if not os.path.exists(grub_image):
            raise KiwiBootLoaderGrubSecureBootError(
                'Signed grub2 efi loader %s not found' % grub_image
            )
        Command.run(
            ['cp', shim_image, self.__get_efi_image_name()]
        )
        Command.run(
            ['cp', grub_image, self.efi_boot_path]
        )

    def __create_embedded_fat_efi_image(self):
        Path.create(self.root_dir + '/boot/' + self.arch)
        efi_fat_image = ''.join(
            [self.root_dir + '/boot/', self.arch, '/efi']
        )
        Command.run(
            ['qemu-img', 'create', efi_fat_image, '4M']
        )
        Command.run(
            ['mkdosfs', '-n', 'BOOT', efi_fat_image]
        )
        Command.run(
            [
                'mcopy', '-Do', '-s', '-i', efi_fat_image,
                self.root_dir + '/EFI', '::'
            ]
        )

    def __create_efi_image(self, uuid=None, mbrid=None):
        """
            create efi image
        """
        early_boot_script = self.efi_boot_path + '/earlyboot.cfg'
        if uuid:
            self.__create_early_boot_script_for_uuid_search(
                early_boot_script, uuid
            )
        else:
            self.__create_early_boot_script_for_mbrid_search(
                early_boot_script, mbrid
            )
        Command.run(
            [
                'grub2-mkimage',
                '-O', self.__get_efi_format(),
                '-o', self.__get_efi_image_name(),
                '-c', early_boot_script,
                '-p', self.get_boot_path() + '/' + self.boot_directory_name,
                '-d',
                self.__get_grub_boot_path() + '/' + self.__get_efi_format()
            ] + self.__get_efi_modules()
        )

    def __create_bios_boot_image(self, uuid):
        """
            create bios image
        """
        early_boot_script = self.__get_grub_boot_path() + '/earlyboot.cfg'
        self.__create_early_boot_script_for_uuid_search(
            early_boot_script, uuid
        )
        Command.run(
            [
                'grub2-mkimage', '-O', self.__get_bios_format(),
                '-o', self.__get_bios_image_name(),
                '-c', early_boot_script,
                '-p', self.get_boot_path() + '/' + self.boot_directory_name,
                '-d',
                self.__get_grub_boot_path() + '/' + self.__get_bios_format()
            ] + self.__get_bios_modules()
        )

    def __create_early_boot_script_for_uuid_search(self, filename, uuid):
        with open(filename, 'w') as early_boot:
            early_boot.write(
                'search --fs-uuid --set=root %s\n' % uuid
            )
            early_boot.write(
                'set prefix=($root)%s/%s\n' % (
                    self.get_boot_path(), self.boot_directory_name
                )
            )

    def __create_early_boot_script_for_mbrid_search(self, filename, mbrid):
        with open(filename, 'w') as early_boot:
            early_boot.write(
                'search --file --set=root /boot/%s\n' % mbrid.get_id()
            )
            early_boot.write(
                'set prefix=($root)/boot/%s\n' % self.boot_directory_name
            )

    def __get_grub_boot_path(self):
        return self.root_dir + '/boot/' + self.boot_directory_name

    def __get_basic_modules(self):
        modules = [
            'ext2',
            'iso9660',
            'linux',
            'echo',
            'configfile',
            'search_label',
            'search_fs_file',
            'search',
            'search_fs_uuid',
            'ls',
            'normal',
            'gzio',
            'png',
            'fat',
            'gettext',
            'font',
            'minicmd',
            'gfxterm',
            'gfxmenu',
            'video',
            'video_fb',
            'xfs',
            'btrfs',
            'lvm',
            'multiboot'
        ]
        return modules

    def __get_efi_modules(self):
        modules = self.__get_basic_modules() + [
            'part_gpt',
            'efi_gop',
            'efi_uga',
            'linuxefi'
        ]
        return modules

    def __get_bios_modules(self):
        modules = self.__get_basic_modules() + [
            'part_gpt',
            'part_msdos',
            'biosdisk',
            'vga',
            'vbe',
            'chain',
            'boot'
        ]
        return modules

    def __get_efi_image_name(self):
        efi_image_name = None
        if self.arch == 'x86_64':
            efi_image_name = 'bootx64.efi'
        if efi_image_name:
            return ''.join(
                [self.efi_boot_path, '/', efi_image_name]
            )

    def __get_bios_image_name(self):
        return ''.join(
            [
                self.__get_grub_boot_path(), '/',
                self.__get_bios_format(), '/core.img'
            ]
        )

    def __get_efi_format(self):
        if self.arch == 'x86_64':
            return 'x86_64-efi'

    def __get_bios_format(self):
        return 'i386-pc'

    def __get_xen_format(self):
        return 'x86_64-xen'

    def __get_efi_modules_path(self, lookup_path=None):
        return self.__get_module_path(self.__get_efi_format(), lookup_path)

    def __get_bios_modules_path(self, lookup_path=None):
        return self.__get_module_path(self.__get_bios_format(), lookup_path)

    def __get_xen_modules_path(self, lookup_path=None):
        return self.__get_module_path(self.__get_xen_format(), lookup_path)

    def __get_module_path(self, format_name, lookup_path=None):
        if not lookup_path:
            lookup_path = self.root_dir
        return ''.join(
            [
                self.__find_grub_data(lookup_path + '/usr/lib'),
                '/', format_name
            ]
        )

    def __get_gfxmode(self):
        selected_gfxmode = '800x600'
        gfxmode = {
            '0x301': '640x480',
            '0x310': '640x480',
            '0x311': '640x480',
            '0x312': '640x480',
            '0x303': '800x600',
            '0x313': '800x600',
            '0x314': '800x600',
            '0x315': '800x600',
            '0x305': '1024x768',
            '0x316': '1024x768',
            '0x317': '1024x768',
            '0x318': '1024x768',
            '0x307': '1280x1024',
            '0x319': '1280x1024',
            '0x31a': '1280x1024',
            '0x31b': '1280x1024',
        }
        requested_gfxmode = self.xml_state.build_type.get_vga()
        if requested_gfxmode in gfxmode:
            selected_gfxmode = gfxmode[requested_gfxmode]
        return selected_gfxmode

    def __copy_theme_data_to_boot_directory(self, lookup_path):
        if not lookup_path:
            lookup_path = self.root_dir
        boot_unicode_font = self.root_dir + '/boot/unicode.pf2'
        if not os.path.exists(boot_unicode_font):
            unicode_font = self.__find_grub_data(lookup_path + '/usr/share') + \
                '/unicode.pf2'
            try:
                Command.run(
                    ['cp', unicode_font, boot_unicode_font]
                )
            except Exception:
                raise KiwiBootLoaderGrubFontError(
                    'Unicode font %s not found' % unicode_font
                )

        boot_theme_dir = self.root_dir + '/boot/' + \
            self.boot_directory_name + '/themes'
        if self.theme and not os.path.exists(boot_theme_dir):
            Path.create(boot_theme_dir)
            theme_dir = self.__find_grub_data(lookup_path + '/usr/share') + \
                '/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)
        )

    def __copy_bios_modules_to_boot_directory(self, lookup_path):
        self.__copy_modules_to_boot_directory_from(
            self.__get_bios_modules_path(lookup_path)
        )
        if self.xen_guest:
            self.__copy_modules_to_boot_directory_from(
                self.__get_xen_modules_path(lookup_path)
            )

    def __copy_modules_to_boot_directory_from(self, module_path):
        boot_module_path = \
            self.__get_grub_boot_path() + '/' + os.path.basename(module_path)
        if not os.path.exists(boot_module_path):
            try:
                Command.run(
                    ['cp', '-a', module_path, boot_module_path]
                )
            except Exception:
                raise KiwiBootLoaderGrubModulesError(
                    'grub2 modules %s not found' % module_path
                )

    def __find_grub_data(self, lookup_path):
        """
            depending on the distribution grub could be installed below
            a grub2 or grub directory. Therefore this information needs
            to be dynamically looked up
        """
        for grub_name in ['grub2', 'grub']:
            grub_path = lookup_path + '/' + grub_name
            if os.path.exists(grub_path):
                return grub_path

        raise KiwiBootLoaderGrubDataError(
            'No grub2 installation found in %s' % lookup_path
        )
Пример #4
0
class LiveImageBuilder(object):
    """
        Live image builder
    """
    def __init__(self, xml_state, target_dir, root_dir):
        self.media_dir = None
        self.arch = platform.machine()
        self.root_dir = root_dir
        self.target_dir = target_dir
        self.xml_state = xml_state
        self.live_type = xml_state.build_type.get_flags()
        self.types = Defaults.get_live_iso_types()
        self.hybrid = xml_state.build_type.get_hybrid()
        self.volume_id = xml_state.build_type.get_volid()
        self.machine = xml_state.get_build_type_machine_section()
        self.mbrid = ImageIdentifier()
        self.mbrid.calculate_id()

        if not self.live_type:
            self.live_type = Defaults.get_default_live_iso_type()

        self.boot_image_task = BootImageTask(
            'kiwi', xml_state, target_dir
        )
        self.firmware = FirmWare(
            xml_state
        )
        self.system_setup = SystemSetup(
            xml_state=xml_state, description_dir=None, root_dir=self.root_dir
        )
        self.isoname = ''.join(
            [
                target_dir, '/',
                xml_state.xml_data.get_name(),
                '.' + platform.machine(),
                '-' + xml_state.get_image_version(),
                '.iso'
            ]
        )
        self.live_image_file = ''.join(
            [
                target_dir, '/',
                xml_state.xml_data.get_name(),
                '-read-only.', self.arch, '-',
                xml_state.get_image_version()
            ]
        )
        self.result = Result()

    def create(self):
        # media dir to store CD contents
        self.media_dir = mkdtemp(
            prefix='live-media.', dir=self.target_dir
        )
        rootsize = SystemSize(self.media_dir)

        # custom iso metadata
        log.info('Using following live ISO metadata:')
        log.info('--> Application id: %s', self.mbrid.get_id())
        log.info('--> Publisher: %s', Defaults.get_publisher())
        custom_iso_args = [
            '-A', self.mbrid.get_id(),
            '-p', '"' + Defaults.get_preparer() + '"',
            '-publisher', '"' + Defaults.get_publisher() + '"',
        ]
        if self.volume_id:
            log.info('--> Volume id: %s', self.volume_id)
            custom_iso_args.append('-V')
            custom_iso_args.append('"' + self.volume_id + '"')

        # prepare boot(initrd) root system
        log.info('Preparing live ISO boot system')
        self.boot_image_task.prepare()

        # export modprobe configuration to boot image
        self.system_setup.export_modprobe_setup(
            self.boot_image_task.boot_root_directory
        )

        # pack system into live boot structure
        log.info('Packing system into live ISO type: %s', self.live_type)
        if self.live_type in self.types:
            live_type_image = FileSystem(
                name=self.types[self.live_type],
                device_provider=None,
                root_dir=self.root_dir
            )
            live_type_image.create_on_file(self.live_image_file)
            Command.run(
                ['mv', self.live_image_file, self.media_dir]
            )
            self.__create_live_iso_client_config(self.live_type)
        else:
            raise KiwiLiveBootImageError(
                'live ISO type "%s" not supported' % self.live_type
            )

        # setup bootloader config to boot the ISO via isolinux
        log.info('Setting up isolinux bootloader configuration')
        bootloader_config_isolinux = BootLoaderConfig(
            'isolinux', self.xml_state, self.media_dir
        )
        bootloader_config_isolinux.setup_live_boot_images(
            mbrid=None,
            lookup_path=self.boot_image_task.boot_root_directory
        )
        bootloader_config_isolinux.setup_live_image_config(
            mbrid=None
        )
        bootloader_config_isolinux.write()

        # setup bootloader config to boot the ISO via EFI
        if self.firmware.efi_mode():
            log.info('Setting up EFI grub bootloader configuration')
            bootloader_config_grub = BootLoaderConfig(
                'grub2', self.xml_state, self.media_dir
            )
            bootloader_config_grub.setup_live_boot_images(
                mbrid=self.mbrid,
                lookup_path=self.boot_image_task.boot_root_directory
            )
            bootloader_config_grub.setup_live_image_config(
                mbrid=self.mbrid
            )
            bootloader_config_grub.write()

        # create initrd for live image
        log.info('Creating live ISO boot image')
        self.__create_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.append('-allow-limited-size')
            custom_iso_args.append('-udf')

        # 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_header_offset = iso_image.create_on_file(self.isoname)

        # make it hybrid
        if self.hybrid:
            Iso.create_hybrid(
                iso_header_offset, self.mbrid, self.isoname
            )

        self.result.add(
            'live_image', self.isoname
        )
        return self.result

    def __create_live_iso_kernel_and_initrd(self):
        boot_path = self.media_dir + '/boot/x86_64/loader'
        Path.create(boot_path)
        kernel = Kernel(self.boot_image_task.boot_root_directory)
        if kernel.get_kernel():
            kernel.copy_kernel(boot_path, '/linux')
        else:
            raise KiwiLiveBootImageError(
                'No kernel in boot image tree %s found' %
                self.boot_image_task.boot_root_directory
            )
        if self.machine and self.machine.get_domain() == 'dom0':
            if kernel.get_xen_hypervisor():
                kernel.copy_xen_hypervisor(boot_path, '/xen.gz')
            else:
                raise KiwiLiveBootImageError(
                    '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(
            [
                'mv', self.boot_image_task.initrd_filename,
                boot_path + '/initrd'
            ]
        )

    def __create_live_iso_client_config(self, iso_type):
        """
            Setup IMAGE and UNIONFS_CONFIG variables as they are used in
            the kiwi isoboot code. Variable contents:

            + IMAGE=target_device;live_iso_name_definition
            + UNIONFS_CONFIG=rw_device,ro_device,union_type

            If no real block device is used or can be predefined the
            word 'loop' is set as a placeholder or indicator to use a loop
            device. For more details please refer to the kiwi shell boot
            code
        """
        iso_client_config_file = self.media_dir + '/config.isoclient'
        iso_client_params = Defaults.get_live_iso_client_parameters()
        (system_device, union_device, union_type) = iso_client_params[iso_type]

        with open(iso_client_config_file, 'w') as config:
            config.write(
                'IMAGE="%s;%s.%s;%s"\n' % (
                    system_device,
                    self.xml_state.xml_data.get_name(), self.arch,
                    self.xml_state.get_image_version()
                )
            )
            config.write(
                'UNIONFS_CONFIG="%s,loop,%s"\n' %
                (union_device, union_type)
            )

    def __del__(self):
        if self.media_dir:
            log.info('Cleaning up %s instance', type(self).__name__)
            Path.wipe(self.media_dir)
Пример #5
0
class DiskBuilder(object):
    """
        Disk image builder
    """
    def __init__(self, xml_state, target_dir, root_dir):
        self.root_dir = root_dir
        self.target_dir = target_dir
        self.xml_state = xml_state
        self.custom_filesystem_args = None
        self.build_type_name = xml_state.get_build_type_name()
        self.image_format = xml_state.build_type.get_format()
        self.install_iso = xml_state.build_type.get_installiso()
        self.install_stick = xml_state.build_type.get_installstick()
        self.install_pxe = xml_state.build_type.get_installpxe()
        self.blocksize = xml_state.build_type.get_target_blocksize()
        self.volume_manager_name = xml_state.get_volume_management()
        self.volumes = xml_state.get_volumes()
        self.volume_group_name = xml_state.get_volume_group_name()
        self.mdraid = xml_state.build_type.get_mdraid()
        self.luks = xml_state.build_type.get_luks()
        self.luks_os = xml_state.build_type.get_luksOS()
        self.machine = xml_state.get_build_type_machine_section()
        self.requested_filesystem = xml_state.build_type.get_filesystem()
        self.requested_boot_filesystem = \
            xml_state.build_type.get_bootfilesystem()
        self.bootloader = xml_state.build_type.get_bootloader()
        self.disk_setup = DiskSetup(
            xml_state, root_dir
        )
        self.boot_image_task = BootImageTask(
            'kiwi', xml_state, target_dir
        )
        self.firmware = FirmWare(
            xml_state
        )
        self.system_setup = SystemSetup(
            xml_state=xml_state, description_dir=None, root_dir=self.root_dir
        )
        self.diskname = ''.join(
            [
                target_dir, '/',
                xml_state.xml_data.get_name(),
                '.' + platform.machine(),
                '-' + xml_state.get_image_version(),
                '.raw'
            ]
        )
        self.install_media = self.__install_image_requested()
        self.install_image = InstallImageBuilder(
            xml_state, target_dir, self.boot_image_task
        )
        # an instance of a class with the sync_data capability
        # representing the entire image system except for the boot/ area
        # which could live on another part of the disk
        self.system = None

        # an instance of a class with the sync_data capability
        # representing the boot/ area of the disk if not part of
        # self.system
        self.system_boot = None

        # an instance of a class with the sync_data capability
        # representing the boot/efi area of the disk
        self.system_efi = None

        # result store
        self.result = Result()

    def create(self):
        if self.install_media and self.build_type_name != 'oem':
            raise KiwiInstallMediaError(
                'Install media requires oem type setup, got %s' %
                self.build_type_name
            )

        # setup recovery archive, cleanup and create archive if requested
        self.system_setup.create_recovery_archive()

        # prepare boot(initrd) root system
        log.info('Preparing boot system')
        self.boot_image_task.prepare()

        # precalculate needed disk size
        disksize_mbytes = self.disk_setup.get_disksize_mbytes()

        # create the disk
        log.info('Creating raw disk image %s', self.diskname)
        loop_provider = LoopDevice(
            self.diskname, disksize_mbytes, self.blocksize
        )
        loop_provider.create()

        self.disk = Disk(
            self.firmware.get_partition_table_type(), loop_provider
        )

        # create the bootloader instance
        self.bootloader_config = BootLoaderConfig(
            self.bootloader, self.xml_state, self.root_dir,
            {'targetbase': loop_provider.get_device()}
        )

        # create disk partitions and instance device map
        device_map = self.__build_and_map_disk_partitions()

        # create raid on current root device if requested
        if self.mdraid:
            self.raid_root = RaidDevice(device_map['root'])
            self.raid_root.create_degraded_raid(raid_level=self.mdraid)
            device_map['root'] = self.raid_root.get_device()

        # create luks on current root device if requested
        if self.luks:
            self.luks_root = LuksDevice(device_map['root'])
            self.luks_root.create_crypto_luks(
                passphrase=self.luks, os=self.luks_os
            )
            device_map['root'] = self.luks_root.get_device()

        # create filesystems on boot partition(s) if any
        self.__build_boot_filesystems(device_map)

        # create volumes and filesystems for root system
        if self.volume_manager_name:
            volume_manager_custom_parameters = {
                'root_filesystem_args':
                    self.custom_filesystem_args,
                'root_label':
                    self.disk_setup.get_root_label(),
                'root_is_snapshot':
                    self.xml_state.build_type.get_btrfs_root_is_snapshot()
            }
            volume_manager = VolumeManager(
                self.volume_manager_name, device_map['root'],
                self.root_dir + '/',
                self.volumes, volume_manager_custom_parameters
            )
            volume_manager.setup(
                self.volume_group_name
            )
            volume_manager.create_volumes(
                self.requested_filesystem
            )
            volume_manager.mount_volumes()
            self.system = volume_manager
            device_map['root'] = volume_manager.get_device()['root']
        else:
            log.info(
                'Creating root(%s) filesystem on %s',
                self.requested_filesystem, device_map['root'].get_device()
            )
            filesystem = FileSystem(
                self.requested_filesystem, device_map['root'],
                self.root_dir + '/',
                self.custom_filesystem_args
            )
            filesystem.create_on_device(
                label=self.disk_setup.get_root_label()
            )
            self.system = filesystem

        # create a random image identifier
        self.mbrid = ImageIdentifier()
        self.mbrid.calculate_id()

        # create first stage metadata to boot image
        self.__write_partition_id_config_to_boot_image()

        self.__write_recovery_metadata_to_boot_image()

        self.__write_raid_config_to_boot_image()

        self.system_setup.export_modprobe_setup(
            self.boot_image_task.boot_root_directory
        )

        # create first stage metadata to system image
        self.__write_image_identifier_to_system_image()

        self.__write_crypttab_to_system_image()

        # create initrd cpio archive
        self.boot_image_task.create_initrd(self.mbrid)

        # create second stage metadata to boot
        self.__copy_first_boot_files_to_system_image()

        self.__write_bootloader_config_to_system_image(device_map)

        self.mbrid.write_to_disk(
            self.disk.storage_provider
        )

        # syncing system data to disk image
        log.info('Syncing system to image')
        if self.system_efi:
            log.info('--> Syncing EFI boot data to EFI partition')
            self.system_efi.sync_data()

        if self.system_boot:
            log.info('--> Syncing boot data at extra partition')
            self.system_boot.sync_data(
                self.__get_exclude_list_for_boot_data_sync()
            )

        log.info('--> Syncing root filesystem data')
        self.system.sync_data(
            self.__get_exclude_list_for_root_data_sync(device_map)
        )

        # install boot loader
        self.__install_bootloader(device_map)

        self.result.add(
            'disk_image', self.diskname
        )

        # create install media if requested
        if self.install_media:
            if self.image_format:
                log.warning('Install image requested, ignoring disk format')
            if self.install_iso or self.install_stick:
                log.info('Creating hybrid ISO installation image')
                self.install_image.create_install_iso()
                self.result.add(
                    'installation_image', self.install_image.isoname
                )

            if self.install_pxe:
                log.info('Creating PXE installation archive')
                self.install_image.create_install_pxe_archive()
                self.result.add(
                    'installation_pxe_archive', self.install_image.pxename
                )

        # create disk image format if requested
        elif self.image_format:
            log.info('Creating %s Disk Format', self.image_format)
            disk_format = DiskFormat(
                self.image_format, self.xml_state,
                self.root_dir, self.target_dir
            )
            disk_format.create_image_format()
            self.result.add(
                'disk_format_image',
                self.target_dir + '/' + disk_format.get_target_name_for_format(
                    self.image_format
                )
            )

        return self.result

    def __install_image_requested(self):
        if self.install_iso or self.install_stick or self.install_pxe:
            return True

    def __get_exclude_list_for_root_data_sync(self, device_map):
        exclude_list = [
            'image', '.profile', '.kconfig', 'var/cache/kiwi'
        ]
        if 'boot' in device_map and self.bootloader == 'grub2_s390x_emu':
            exclude_list.append('boot/zipl/*')
            exclude_list.append('boot/zipl/.*')
        elif 'boot' in device_map:
            exclude_list.append('boot/*')
            exclude_list.append('boot/.*')
        return exclude_list

    def __get_exclude_list_for_boot_data_sync(self):
        return ['efi/*']

    def __build_boot_filesystems(self, device_map):
        if 'efi' in device_map:
            log.info(
                'Creating EFI(fat16) filesystem on %s',
                device_map['efi'].get_device()
            )
            filesystem = FileSystem(
                'fat16', device_map['efi'], self.root_dir + '/boot/efi/'
            )
            filesystem.create_on_device(
                label=self.disk_setup.get_efi_label()
            )
            self.system_efi = filesystem

        if 'boot' in device_map:
            boot_filesystem = self.requested_boot_filesystem
            if not boot_filesystem:
                boot_filesystem = self.requested_filesystem
            boot_directory = self.root_dir + '/boot/'
            if self.bootloader == 'grub2_s390x_emu':
                boot_directory = self.root_dir + '/boot/zipl/'
                boot_filesystem = 'ext2'
            log.info(
                'Creating boot(%s) filesystem on %s',
                boot_filesystem, device_map['boot'].get_device()
            )
            filesystem = FileSystem(
                boot_filesystem, device_map['boot'], boot_directory
            )
            filesystem.create_on_device(
                label=self.disk_setup.get_boot_label()
            )
            self.system_boot = filesystem

    def __build_and_map_disk_partitions(self):
        self.disk.wipe()
        if self.firmware.legacy_bios_mode():
            log.info('--> creating EFI CSM(legacy bios) partition')
            self.disk.create_efi_csm_partition(
                self.firmware.get_legacy_bios_partition_size()
            )

        if self.firmware.efi_mode():
            log.info('--> creating EFI partition')
            self.disk.create_efi_partition(
                self.firmware.get_efi_partition_size()
            )

        if self.disk_setup.need_boot_partition():
            log.info('--> creating boot partition')
            self.disk.create_boot_partition(
                self.disk_setup.boot_partition_size()
            )

        if self.volume_manager_name and self.volume_manager_name == 'lvm':
            log.info('--> creating LVM root partition')
            self.disk.create_root_lvm_partition('all_free')

        elif self.mdraid:
            log.info('--> creating mdraid root partition')
            self.disk.create_root_raid_partition('all_free')

        else:
            log.info('--> creating root partition')
            self.disk.create_root_partition('all_free')

        if self.firmware.bios_mode():
            log.info('--> setting active flag to primary boot partition')
            self.disk.activate_boot_partition()

        self.disk.map_partitions()
        return self.disk.get_device()

    def __write_partition_id_config_to_boot_image(self):
        log.info('Creating config.partids in boot system')
        filename = self.boot_image_task.boot_root_directory + '/config.partids'
        partition_id_map = self.disk.get_partition_id_map()
        with open(filename, 'w') as partids:
            for id_name, id_value in partition_id_map.iteritems():
                partids.write('%s="%s"\n' % (id_name, id_value))

    def __write_raid_config_to_boot_image(self):
        if self.mdraid:
            log.info('Creating etc/mdadm.conf in boot system')
            self.raid_root.create_raid_config(
                self.boot_image_task.boot_root_directory + '/etc/mdadm.conf'
            )

    def __write_crypttab_to_system_image(self):
        if self.luks:
            log.info('Creating etc/crypttab')
            self.luks_root.create_crypttab(
                self.root_dir + '/etc/crypttab'
            )

    def __write_image_identifier_to_system_image(self):
        log.info('Creating image identifier: %s', self.mbrid.get_id())
        self.mbrid.write(
            self.root_dir + '/boot/mbrid'
        )

    def __write_recovery_metadata_to_boot_image(self):
        if os.path.exists(self.root_dir + '/recovery.partition.size'):
            log.info('Copying recovery metadata to boot image')
            Command.run(
                [
                    'cp', self.root_dir + '/recovery.partition.size',
                    self.boot_image_task.boot_root_directory
                ]
            )

    def __write_bootloader_config_to_system_image(self, device_map):
        log.info('Creating %s bootloader configuration', self.bootloader)
        boot_device = device_map['root']
        if 'boot' in device_map:
            boot_device = device_map['boot']

        partition_id_map = self.disk.get_partition_id_map()
        boot_partition_id = partition_id_map['kiwi_RootPart']
        if 'kiwi_BootPart' in partition_id_map:
            boot_partition_id = partition_id_map['kiwi_BootPart']

        boot_uuid = self.disk.get_uuid(
            boot_device.get_device()
        )
        self.bootloader_config.setup_disk_boot_images(boot_uuid)
        self.bootloader_config.setup_disk_image_config(boot_uuid)
        self.bootloader_config.write()

        self.system_setup.call_edit_boot_config_script(
            self.requested_filesystem, boot_partition_id
        )

    def __install_bootloader(self, device_map):
        boot_device = device_map['root']
        custom_install_arguments = {}
        if 'boot' in device_map:
            boot_device = device_map['boot']
            custom_install_arguments['boot_device'] = boot_device.get_device()

        bootloader = BootLoaderInstall(
            self.bootloader, self.root_dir, self.disk.storage_provider,
            custom_install_arguments
        )
        bootloader.install()

        self.system_setup.call_edit_boot_install_script(
            self.diskname, boot_device.get_device()
        )

    def __copy_first_boot_files_to_system_image(self):
        log.info('Copy boot files to system image')
        kernel = Kernel(self.boot_image_task.boot_root_directory)
        if kernel.get_kernel():
            log.info('--> boot image kernel as first boot linux.vmx')
            kernel.copy_kernel(
                self.root_dir, '/boot/linux.vmx'
            )
        else:
            raise KiwiDiskBootImageError(
                'No kernel in boot image tree %s found' %
                self.boot_image_task.boot_root_directory
            )
        if self.machine and self.machine.get_domain() == 'dom0':
            if kernel.get_xen_hypervisor():
                log.info('--> boot image Xen hypervisor as xen.gz')
                kernel.copy_xen_hypervisor(
                    self.root_dir, '/boot/xen.gz'
                )
            else:
                raise KiwiDiskBootImageError(
                    'No hypervisor in boot image tree %s found' %
                    self.boot_image_task.boot_root_directory
                )
        log.info('--> initrd archive as first boot initrd.vmx')
        Command.run(
            [
                'mv', self.boot_image_task.initrd_filename,
                self.root_dir + '/boot/initrd.vmx'
            ]
        )