Example #1
0
 def _setup_secure_boot_efi_image(self, lookup_path):
     """
     Provide the shim loader and the shim signed grub2 loader
     in the required boot path. Normally this task is done by
     the shim-install tool. However, shim-install does not exist
     on all distributions and the script does not operate well
     in e.g CD environments from which we generate live and/or
     install media. Thus shim-install is used if possible at
     install time of the bootloader because it requires access
     to the target block device. In any other case this setup
     code should act as the fallback solution
     """
     log.warning(
         '--> Running fallback setup for shim secure boot efi image'
     )
     if not lookup_path:
         lookup_path = self.root_dir
     shim_image = Defaults.get_shim_loader(lookup_path)
     if not shim_image:
         raise KiwiBootLoaderGrubSecureBootError(
             'Microsoft signed shim loader not found'
         )
     grub_image = Defaults.get_signed_grub_loader(lookup_path)
     if not grub_image:
         raise KiwiBootLoaderGrubSecureBootError(
             'Shim signed grub2 efi loader not found'
         )
     Command.run(
         ['cp', shim_image, self._get_efi_image_name()]
     )
     Command.run(
         ['cp', grub_image, self.efi_boot_path]
     )
Example #2
0
 def _get_target_offset(self):
     if self.target_table_type == 'dasd':
         blocks = self._read_dasd_disk_geometry('blocks per track')
         bash_command = [
             'fdasd', '-f', '-s', '-p', self.target_device,
             '|', 'head', '-n', '1', '|', 'tr', '-s', '" "'
         ]
         fdasd_call = Command.run(
             ['bash', '-c', ' '.join(bash_command)]
         )
         fdasd_output = fdasd_call.output
         try:
             start_track = int(fdasd_output.split(' ')[2].lstrip())
         except Exception:
             raise KiwiDiskGeometryError(
                 'unknown partition format: %s' % fdasd_output
             )
         return start_track * blocks
     else:
         blocks = self._read_msdos_disk_geometry('blocks per track')
         parted_call = Command.run(
             ['parted', '-m', self.target_device, 'unit', 's', 'print']
         )
         parted_output = parted_call.output.lstrip()
         first_partition_format = re.search('1:(.*?)s', parted_output)
         if not first_partition_format:
             raise KiwiDiskGeometryError(
                 'unknown partition format: %s' % parted_output
             )
         start_track = int(first_partition_format.group(1))
         return start_track * blocks
Example #3
0
    def create(self, name, mbsize, type_name, flags=None):
        """
        Create DASD partition

        :param string name: partition name
        :param int mbsize: partition size
        :param string type_name: unused
        :param list flags: unused
        """
        self.partition_id += 1
        fdasd_input = NamedTemporaryFile()
        with open(fdasd_input.name, 'w') as partition:
            log.debug(
                '%s: fdasd: n p cur_position +%sM w q',
                name, format(mbsize)
            )
            if mbsize == 'all_free':
                partition.write('n\np\n\n\nw\nq\n')
            else:
                partition.write('n\np\n\n+%dM\nw\nq\n' % mbsize)
        bash_command = ' '.join(
            ['cat', fdasd_input.name, '|', 'fdasd', '-f', self.disk_device]
        )
        try:
            Command.run(
                ['bash', '-c', bash_command]
            )
        except Exception:
            # unfortunately fdasd reports that it can't read in the partition
            # table which I consider a bug in fdasd. However the table was
            # correctly created and therefore we continue. Problem is that we
            # are not able to detect real errors with the fdasd operation at
            # that point.
            log.debug('potential fdasd errors were ignored')
Example #4
0
    def create_degraded_raid(self, raid_level):
        """
        Create a raid array in degraded mode with one device missing.
        This only works in the raid levels 0(striping) and 1(mirroring)

        :param string raid_level: raid level name
        """
        if raid_level not in self.raid_level_map:
            raise KiwiRaidSetupError(
                'Only raid levels 0(striping) and 1(mirroring) are supported'
            )
        raid_device = None
        for raid_id in range(9):
            raid_device = '/dev/md' + format(raid_id)
            if os.path.exists(raid_device):
                raid_device = None
            else:
                break
        if not raid_device:
            raise KiwiRaidSetupError(
                'Could not find free raid device in range md0-8'
            )
        log.info(
            'Creating raid array in %s mode as %s',
            raid_level, raid_device
        )
        Command.run(
            [
                'mdadm', '--create', '--run', raid_device,
                '--level', self.raid_level_map[raid_level],
                '--raid-disks', '2',
                self.storage_provider.get_device(), 'missing'
            ]
        )
        self.raid_device = raid_device
Example #5
0
    def process_delete_requests(self, force=False):
        """
        Process package delete requests (chroot)

        :param bool force: force deletion: true|false
        """
        delete_items = []
        for delete_item in self._delete_items():
            try:
                Command.run(['chroot', self.root_dir, 'rpm', '-q', delete_item])
                delete_items.append(delete_item)
            except Exception:
                # ignore packages which are not installed
                pass
        if not delete_items:
            raise KiwiRequestError(
                'None of the requested packages to delete are installed'
            )
        if force:
            force_options = ['--nodeps', '--allmatches', '--noscripts']
            return Command.call(
                [
                    'chroot', self.root_dir, 'rpm', '-e'
                ] + force_options + delete_items,
                self.chroot_command_env
            )
        else:
            return Command.call(
                [
                    'chroot', self.root_dir, 'zypper'
                ] + self.chroot_zypper_args + [
                    'remove', '-u', '--force-resolution'
                ] + delete_items,
                self.chroot_command_env
            )
Example #6
0
    def resize_raw_disk(self, size_bytes):
        """
        Resize raw disk image to specified size. If the request
        would actually shrink the disk an exception is raised.
        If the disk got changed the method returns True, if
        the new size is the same as the current size nothing
        gets resized and the method returns False

        :param int size: new size in bytes
        :rtype: bool
        """
        current_byte_size = os.path.getsize(self.diskname)
        size_bytes = int(size_bytes)
        if size_bytes < current_byte_size:
            raise KiwiResizeRawDiskError(
                'shrinking {0} disk to {1} bytes corrupts the image'.format(
                    self.diskname, size_bytes
                )
            )
        elif size_bytes == current_byte_size:
            return False
        Command.run(
            ['qemu-img', 'resize', self.diskname, format(size_bytes)]
        )
        return True
Example #7
0
    def setup_intermediate_config(self):
        """
        Create intermediate config files

        Some config files e.g etc/hosts needs to be temporarly copied
        from the buildsystem host to the image root system in order to
        allow e.g DNS resolution in the way as it is configured on the
        buildsystem host. These config files only exists during the image
        build process and are not part of the final image

        :raises KiwiSetupIntermediateConfigError: if the management of
            intermediate configuration files fails
        """
        try:
            for config in self.config_files:
                if os.path.exists(config):
                    self.cleanup_files.append(config + '.kiwi')
                    Command.run(
                        ['cp', config, self.root_dir + config + '.kiwi']
                    )
                    link_target = os.path.basename(config) + '.kiwi'
                    Command.run(
                        ['ln', '-s', '-f', link_target, self.root_dir + config]
                    )
        except Exception as e:
            self.cleanup()
            raise KiwiSetupIntermediateConfigError(
                '%s: %s' % (type(e).__name__, format(e))
            )
Example #8
0
    def create(self, name, mbsize, type_name, flags=None):
        """
        Create GPT partition

        :param string name: partition name
        :param int mbsize: partition size
        :param string type_name: partition type
        :param list flags: additional flags
        """
        self.partition_id += 1
        if mbsize == 'all_free':
            partition_end = '0'
        else:
            partition_end = '+' + format(mbsize) + 'M'
        if self.partition_id > 1 or not self.start_sector:
            # A start  sector value of 0 specifies the default value
            # defined in sgdisk
            self.start_sector = 0
        Command.run(
            [
                'sgdisk', '-n', ':'.join(
                    [
                        format(self.partition_id),
                        format(self.start_sector),
                        partition_end
                    ]
                ), '-c', ':'.join([format(self.partition_id), name]),
                self.disk_device
            ]
        )
        self.set_flag(self.partition_id, type_name)
        if flags:
            for flag_name in flags:
                self.set_flag(self.partition_id, flag_name)
Example #9
0
    def sync_data(self):
        """
        Synchronize data from the given base image to the target root
        directory.
        """
        self.extract_oci_image()
        Command.run([
            'umoci', 'unpack', '--image',
            '{0}:base_layer'.format(self.oci_layout_dir), self.oci_unpack_dir
        ])

        synchronizer = DataSync(
            os.sep.join([self.oci_unpack_dir, 'rootfs', '']),
            ''.join([self.root_dir, os.sep])
        )
        synchronizer.sync_data(options=['-a', '-H', '-X', '-A'])

        # A copy of the uncompressed image and its checksum are
        # kept inside the root_dir in order to ensure the later steps
        # i.e. system create are atomic and don't need any third
        # party archive.
        image_copy = Defaults.get_imported_root_image(self.root_dir)
        Path.create(os.path.dirname(image_copy))
        image_tar = ArchiveTar(image_copy)
        image_tar.create(self.oci_layout_dir)
        self._make_checksum(image_copy)
Example #10
0
    def create(self, source_dir, exclude=None):
        """
        Create cpio archive

        :param string source_dir: data source directory
        :param list exclude: list of excluded items
        """
        find_excludes = []
        find_command = ['cd', source_dir, '&&', 'find', '.']
        cpio_command = [
            'cpio', '--quiet', '-o', '-H', 'newc', '>', self.filename
        ]
        if exclude:
            for path in exclude:
                if find_excludes:
                    find_excludes.append('-or')
                find_excludes.append('-path')
                find_excludes.append('.' + path)
                find_excludes.append('-prune')
            find_excludes.append('-o')
            find_excludes.append('-print')
            find_command += find_excludes

        bash_command = find_command + ['|'] + cpio_command
        Command.run(
            ['bash', '-c', ' '.join(bash_command)]
        )
Example #11
0
 def test_run_raises_error(self, mock_popen, mock_which):
     mock_which.return_value = "command"
     mock_process = mock.Mock()
     mock_process.communicate = mock.Mock(return_value=[str.encode("stdout"), str.encode("stderr")])
     mock_process.returncode = 1
     mock_popen.return_value = mock_process
     Command.run(["command", "args"])
Example #12
0
 def setup_locale(self):
     """
     Setup UTF8 system wide locale
     """
     if 'locale' in self.preferences:
         if 'POSIX' in self.preferences['locale'].split(','):
             locale = 'POSIX'
         else:
             locale = '{0}.UTF-8'.format(
                 self.preferences['locale'].split(',')[0]
             )
         log.info('Setting up locale: %s', self.preferences['locale'])
         if CommandCapabilities.has_option_in_help(
             'systemd-firstboot', '--locale',
             root=self.root_dir, raise_on_error=False
         ):
             Path.wipe(self.root_dir + '/etc/locale.conf')
             Command.run([
                 'chroot', self.root_dir, 'systemd-firstboot',
                 '--locale=' + locale
             ])
         elif os.path.exists(self.root_dir + '/etc/sysconfig/language'):
             Shell.run_common_function(
                 'baseUpdateSysConfig', [
                     self.root_dir + '/etc/sysconfig/language',
                     'RC_LANG', locale
                 ]
             )
         else:
             log.warning(
                 'locale setup skipped no capable '
                 'systemd-firstboot or etc/sysconfig/language not found'
             )
Example #13
0
    def uncompress(self, temporary=False):
        """
        Uncompress with format autodetection

        By default the original source file will be changed into
        the uncompressed variant. If temporary is set to True
        a temporary file is created instead

        :param bool temporary: uncompress to a temporary file
        """
        zipper = self.get_format()
        if not zipper:
            raise KiwiCompressionFormatUnknown(
                'could not detect compression format for %s' %
                self.source_filename
            )
        if not temporary:
            Command.run([zipper, '-d', self.source_filename])
            self.uncompressed_filename = self.source_filename
        else:
            self.temp_file = NamedTemporaryFile()
            bash_command = [
                zipper, '-c', '-d', self.source_filename,
                '>', self.temp_file.name
            ]
            Command.run(['bash', '-c', ' '.join(bash_command)])
            self.uncompressed_filename = self.temp_file.name
        return self.uncompressed_filename
Example #14
0
 def wipe(self):
     """
     Zap (destroy) any GPT and MBR data structures if present
     For DASD disks create a new VTOC table
     """
     if 'dasd' in self.table_type:
         log.debug('Initialize DASD disk with new VTOC table')
         fdasd_input = NamedTemporaryFile()
         with open(fdasd_input.name, 'w') as vtoc:
             vtoc.write('y\n\nw\nq\n')
         bash_command = ' '.join(
             [
                 'cat', fdasd_input.name, '|',
                 'fdasd', '-f', self.storage_provider.get_device()
             ]
         )
         try:
             Command.run(
                 ['bash', '-c', bash_command]
             )
         except Exception:
             # unfortunately fdasd reports that it can't read in the
             # partition table which I consider a bug in fdasd. However
             # the table was correctly created and therefore we continue.
             # Problem is that we are not able to detect real errors
             # with the fdasd operation at that point.
             log.debug('potential fdasd errors were ignored')
     else:
         log.debug('Initialize %s disk', self.table_type)
         Command.run(
             [
                 'sgdisk', '--zap-all', self.storage_provider.get_device()
             ]
         )
Example #15
0
 def setup_keyboard_map(self):
     """
     Setup console keyboard
     """
     if 'keytable' in self.preferences:
         log.info(
             'Setting up keytable: %s', self.preferences['keytable']
         )
         if CommandCapabilities.has_option_in_help(
             'systemd-firstboot', '--keymap',
             root=self.root_dir, raise_on_error=False
         ):
             Path.wipe(self.root_dir + '/etc/vconsole.conf')
             Command.run([
                 'chroot', self.root_dir, 'systemd-firstboot',
                 '--keymap=' + self.preferences['keytable']
             ])
         elif os.path.exists(self.root_dir + '/etc/sysconfig/keyboard'):
             Shell.run_common_function(
                 'baseUpdateSysConfig', [
                     self.root_dir + '/etc/sysconfig/keyboard', 'KEYTABLE',
                     '"' + self.preferences['keytable'] + '"'
                 ]
             )
         else:
             log.warning(
                 'keyboard setup skipped no capable '
                 'systemd-firstboot or etc/sysconfig/keyboard found'
             )
Example #16
0
    def set_flag(self, partition_id, flag_name):
        """
        Set msdos partition flag

        :param int partition_id: partition number
        :param string flag_name: name from flag map
        """
        if flag_name not in self.flag_map:
            raise KiwiPartitionerMsDosFlagError(
                'Unknown partition flag %s' % flag_name
            )
        if self.flag_map[flag_name]:
            if flag_name == 'f.active':
                Command.run(
                    [
                        'parted', self.disk_device,
                        'set', format(partition_id), 'boot', 'on'
                    ]
                )
            else:
                Command.run(
                    [
                        'sfdisk', '-c', self.disk_device,
                        format(partition_id), self.flag_map[flag_name]
                    ]
                )
        else:
            log.warning('Flag %s ignored on msdos', flag_name)
Example #17
0
    def _copy_first_boot_files_to_system_image(self):
        boot_names = self.boot_image.get_boot_names()
        if self.initrd_system == 'kiwi':
            log.info('Copy boot files to system image')
            kernel = Kernel(self.boot_image.boot_root_directory)

            log.info('--> boot image kernel as %s', boot_names.kernel_name)
            kernel.copy_kernel(
                self.root_dir, ''.join(['/boot/', boot_names.kernel_name])
            )

            if self.xen_server:
                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.boot_root_directory
                    )

        log.info('--> initrd archive as %s', boot_names.initrd_name)
        Command.run(
            [
                'mv', self.boot_image.initrd_filename,
                self.root_dir + ''.join(['/boot/', boot_names.initrd_name])
            ]
        )
Example #18
0
 def _create_iso_install_kernel_and_initrd(self):
     boot_path = self.media_dir + '/boot/' + self.arch + '/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 KiwiInstallBootImageError(
             'No kernel in boot image tree %s found' %
             self.boot_image_task.boot_root_directory
         )
     if self.xml_state.is_xen_server():
         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
             )
     if self.initrd_system == 'dracut':
         self._create_dracut_install_config()
         self._add_system_image_boot_options_to_boot_image()
     self.boot_image_task.create_initrd(self.mbrid, 'initrd_kiwi_install')
     Command.run(
         [
             'mv', self.boot_image_task.initrd_filename,
             boot_path + '/initrd'
         ]
     )
Example #19
0
    def process_install_requests_bootstrap(self):
        """
        Process package install requests for bootstrap phase (no chroot)

        :return: process results in command type

        :rtype: namedtuple
        """
        yum = self._get_yum_binary_name()
        Command.run(
            [yum] + self.yum_args + ['makecache']
        )
        bash_command = [
            yum
        ] + self.yum_args + [
            '--installroot', self.root_dir
        ] + self.custom_args + ['install'] + self.package_requests
        if self.collection_requests:
            bash_command += [
                '&&', yum
            ] + self.yum_args + [
                '--installroot', self.root_dir
            ] + self.custom_args + ['groupinstall'] + self.collection_requests
        self.cleanup_requests()
        return Command.call(
            ['bash', '-c', ' '.join(bash_command)], self.command_env
        )
Example #20
0
    def pack_image_to_file(self, filename):
        """
        Packs the given oci image into the given filename.

        :param string filename: file name of the resulting packed image
        """
        oci_image = os.sep.join([
            self.oci_dir, ':'.join(['umoci_layout', self.container_tag])
        ])

        additional_tags = []
        for tag in self.additional_tags:
            additional_tags.extend([
                '--additional-tag', '{0}:{1}'.format(self.container_name, tag)
            ])

        # make sure the target tar file does not exist
        # skopeo doesn't support force overwrite
        Path.wipe(filename)
        Command.run(
            [
                'skopeo', 'copy', 'oci:{0}'.format(
                    oci_image
                ),
                'docker-archive:{0}:{1}:{2}'.format(
                    filename, self.container_name, self.container_tag
                )
            ] + additional_tags
        )
        container_compressor = self.runtime_config.get_container_compression()
        if container_compressor:
            compressor = Compress(filename)
            return compressor.xz(self.runtime_config.get_xz_options())
        else:
            return filename
Example #21
0
    def create(self, name, mbsize, type_name, flags=None):
        """
        Create GPT partition

        :param string name: partition name
        :param int mbsize: partition size
        :param string type_name: partition type
        :param list flags: additional flags
        """
        self.partition_id += 1
        if mbsize == 'all_free':
            partition_end = '0'
        else:
            partition_end = '+' + format(mbsize) + 'M'
        Command.run(
            [
                'sgdisk', '-n',
                ':'.join([format(self.partition_id), '0', partition_end]),
                '-c', ':'.join([format(self.partition_id), name]),
                self.disk_device
            ]
        )
        self.set_flag(self.partition_id, type_name)
        if flags:
            for flag_name in flags:
                self.set_flag(self.partition_id, flag_name)
Example #22
0
 def process_install_requests(self):
     """
     Process package install requests for image phase (chroot)
     """
     yum = self._get_yum_binary_name(root=self.root_dir)
     if self.exclude_requests:
         # For Yum, excluding a package means removing it from
         # the solver operation. This is done by adding --exclude
         # to the command line. This means that if the package is
         # hard required by another package, it will break the transaction.
         for package in self.exclude_requests:
             self.custom_args.append('--exclude=' + package)
     Command.run(
         ['chroot', self.root_dir, 'rpm', '--rebuilddb']
     )
     chroot_yum_args = self.root_bind.move_to_root(
         self.yum_args
     )
     bash_command = [
         'chroot', self.root_dir, yum
     ] + chroot_yum_args + self.custom_args + [
         'install'
     ] + self.package_requests
     if self.collection_requests:
         bash_command += [
             '&&', 'chroot', self.root_dir, yum
         ] + chroot_yum_args + self.custom_args + [
             'groupinstall'
         ] + self.collection_requests
     self.cleanup_requests()
     return Command.call(
         ['bash', '-c', ' '.join(bash_command)], self.command_env
     )
Example #23
0
    def process_delete_requests(self, force=False):
        """
        Process package delete requests (chroot)

        :param bool force: force deletion: true|false
        """
        delete_items = []
        for delete_item in self.package_requests:
            try:
                Command.run(['chroot', self.root_dir, 'rpm', '-q', delete_item])
                delete_items.append(delete_item)
            except Exception:
                # ignore packages which are not installed
                pass
        if not delete_items:
            raise KiwiRequestError(
                'None of the requested packages to delete are installed'
            )
        delete_options = ['--nodeps', '--allmatches', '--noscripts']
        self.cleanup_requests()
        return Command.call(
            [
                'chroot', self.root_dir, 'rpm', '-e'
            ] + delete_options + delete_items,
            self.command_env
        )
Example #24
0
    def process_install_requests(self):
        """
        Process package install requests for image phase (chroot)

        :return: process results in command type

        :rtype: namedtuple
        """
        if self.exclude_requests:
            # For zypper excluding a package means, removing it from
            # the solver operation. This is done by adding a package
            # lock. This means that if the package is hard required
            # by another package, it will break the transaction.
            metadata_dir = ''.join([self.root_dir, '/etc/zypp'])
            if not os.path.exists(metadata_dir):
                Path.create(metadata_dir)
            for package in self.exclude_requests:
                Command.run(
                    ['chroot', self.root_dir, 'zypper'] +
                    self.chroot_zypper_args + ['al'] + [package],
                    self.chroot_command_env
                )
        return Command.call(
            ['chroot', self.root_dir, 'zypper'] + self.chroot_zypper_args + [
                'install', '--auto-agree-with-licenses'
            ] + self.custom_args + self._install_items(),
            self.chroot_command_env
        )
Example #25
0
    def create_xz_compressed(
        self, source_dir, exclude=None, options=None, xz_options=None
    ):
        """
        Create XZ compressed tar archive

        :param string source_dir: data source directory
        :param list exclude: list of excluded items
        :param list options: custom tar creation options
        :param list xz_options: custom xz compression options
        """
        if not options:
            options = []
        if not xz_options:
            xz_options = Defaults.get_xz_compression_options()
        bash_command = [
            'tar', '-C', source_dir
        ] + options + self.xattrs_options + [
            '-c', '--to-stdout'
        ] + self._get_archive_items(source_dir, exclude) + [
            '|', 'xz', '-f'
        ] + xz_options + [
            '>', self.filename + '.xz'
        ]
        Command.run(['bash', '-c', ' '.join(bash_command)])
        return self.filename + '.xz'
Example #26
0
 def test_run_raises_error(self, mock_popen):
     mock_process = mock.Mock()
     mock_process.communicate = mock.Mock(
         return_value=[str.encode('stdout'), str.encode('stderr')]
     )
     mock_process.returncode = 1
     mock_popen.return_value = mock_process
     Command.run(['command', 'args'])
Example #27
0
    def import_trusted_keys(self, signing_keys):
        """
        Imports trusted keys into the image

        :param list signing_keys: list of the key files to import
        """
        for key in signing_keys:
            Command.run(['rpm', '--root', self.root_dir, '--import', key])
Example #28
0
    def process_install_requests_bootstrap(self):
        """
        Process package install requests for bootstrap phase (no chroot)
        The debootstrap program is used to bootstrap a new system with
        a collection of predefined packages. The kiwi bootstrap section
        information is not used in this case
        """
        if not self.distribution:
            raise KiwiDebootstrapError(
                'No main distribution repository is configured'
            )
        bootstrap_script = '/usr/share/debootstrap/scripts/' + \
            self.distribution
        if not os.path.exists(bootstrap_script):
            raise KiwiDebootstrapError(
                'debootstrap script for %s distribution not found' %
                self.distribution
            )
        bootstrap_dir = self.root_dir + '.debootstrap'
        if 'apt-get' in self.package_requests:
            # debootstrap takes care to install apt-get
            self.package_requests.remove('apt-get')
        try:
            dev_mount = MountManager(
                device='/dev', mountpoint=self.root_dir + '/dev'
            )
            dev_mount.umount()
            if self.repository.unauthenticated == 'false':
                log.warning(
                    'KIWI does not support signature checks for apt-get '
                    'package manager during the bootstrap procedure, any '
                    'provided key will only be used inside the chroot '
                    'environment'
                )
            Command.run(
                [
                    'debootstrap', '--no-check-gpg', self.distribution,
                    bootstrap_dir, self.distribution_path
                ], self.command_env
            )
            data = DataSync(
                bootstrap_dir + '/', self.root_dir
            )
            data.sync_data(
                options=['-a', '-H', '-X', '-A']
            )
            for key in self.repository.signing_keys:
                Command.run([
                    'chroot', self.root_dir, 'apt-key', 'add', key
                ], self.command_env)
        except Exception as e:
            raise KiwiDebootstrapError(
                '%s: %s' % (type(e).__name__, format(e))
            )
        finally:
            Path.wipe(bootstrap_dir)

        return self.process_install_requests()
Example #29
0
 def __del__(self):
     if self.node_name:
         log.info('Cleaning up %s instance', type(self).__name__)
         try:
             Command.run(['losetup', '-d', self.node_name])
         except Exception:
             log.warning(
                 'loop device %s still busy', self.node_name
             )
Example #30
0
 def _search_for(self, name, in_file):
     search = '^' + name + ':'
     try:
         Command.run(
             ['chroot', self.root_dir, 'grep', '-q', search, in_file]
         )
     except Exception:
         return False
     return True
Example #31
0
    def _import_custom_scripts(self):
        """
        Import custom scripts
        """
        # custom_scripts defines a dictionary with all script hooks
        # for each script name a the filepath and additional flags
        # are defined. the filepath could be either a relative or
        # absolute information. If filepath is set to None this indicates
        # the script hook is not used. The raise_if_not_exists flag
        # causes kiwi to raise an exception if a specified script
        # filepath does not exist
        script_type = namedtuple('script_type',
                                 ['filepath', 'raise_if_not_exists'])
        custom_scripts = {
            defaults.POST_BOOTSTRAP_SCRIPT:
            script_type(filepath=defaults.POST_BOOTSTRAP_SCRIPT,
                        raise_if_not_exists=False),
            defaults.POST_PREPARE_SCRIPT:
            script_type(filepath=defaults.POST_PREPARE_SCRIPT,
                        raise_if_not_exists=False),
            defaults.PRE_CREATE_SCRIPT:
            script_type(filepath=defaults.PRE_CREATE_SCRIPT,
                        raise_if_not_exists=False),
            defaults.POST_DISK_SYNC_SCRIPT:
            script_type(filepath=defaults.POST_DISK_SYNC_SCRIPT,
                        raise_if_not_exists=False),
            defaults.EDIT_BOOT_CONFIG_SCRIPT:
            script_type(
                filepath=self.xml_state.build_type.get_editbootconfig(),
                raise_if_not_exists=True),
            defaults.EDIT_BOOT_INSTALL_SCRIPT:
            script_type(
                filepath=self.xml_state.build_type.get_editbootinstall(),
                raise_if_not_exists=True)
        }
        sorted_custom_scripts = OrderedDict(sorted(custom_scripts.items()))

        script_target_dir = os.path.join(self.root_dir,
                                         defaults.IMAGE_METADATA_DIR)
        need_script_helper_functions = False

        for name, script in list(sorted_custom_scripts.items()):
            if script.filepath:
                if script.filepath.startswith('/'):
                    script_file = script.filepath
                else:
                    script_file = os.path.join(self.description_dir,
                                               script.filepath)
                if os.path.exists(script_file):
                    script_target_file = os.path.join(script_target_dir, name)
                    log.info('--> Importing {0} script to {1}'.format(
                        script.filepath, script_target_file))
                    Command.run(['cp', script_file, script_target_file])
                    need_script_helper_functions = True
                elif script.raise_if_not_exists:
                    raise KiwiImportDescriptionError(
                        'Specified script {0} does not exist'.format(
                            script_file))

        if need_script_helper_functions:
            log.info('--> Importing script helper functions')
            Command.run([
                'cp',
                Defaults.get_common_functions_file(),
                self.root_dir + '/.kconfig'
            ])
Example #32
0
    def create_install_pxe_archive(self):
        """
        Create an oem install tar archive suitable for installing a
        disk image via the network using the PXE boot protocol.
        The archive contains:

        * The raw system image xz compressed
        * The raw system image checksum metadata file
        * The append file template for the boot server
        * The system image initrd for kexec
        * The install initrd
        * The kernel

        Image types which triggers this builder are:

        * installpxe="true|false"
        """
        self.pxe_dir = mkdtemp(prefix='kiwi_pxe_install_media.',
                               dir=self.target_dir)
        # the system image is transfered as xz compressed variant
        log.info('xz compressing disk image')
        pxe_image_filename = ''.join([self.pxe_dir, '/', self.pxename, '.xz'])
        compress = Compress(source_filename=self.diskname,
                            keep_source_on_compress=True)
        compress.xz(self.xz_options)
        Command.run(['mv', compress.compressed_filename, pxe_image_filename])

        # the system image transfer is checked against a checksum
        log.info('Creating disk image checksum')
        pxe_md5_filename = ''.join([self.pxe_dir, '/', self.pxename, '.md5'])
        checksum = Checksum(self.diskname)
        checksum.md5(pxe_md5_filename)

        # the install image name is stored in a config file
        if self.initrd_system == 'kiwi':
            self._write_install_image_info_to_boot_image()

        # the kexec required system image initrd is stored for dracut kiwi-dump
        if self.initrd_system == 'dracut':
            boot_names = self.boot_image_task.get_boot_names()
            system_image_initrd = os.sep.join(
                [self.root_dir, 'boot', boot_names.initrd_name])
            target_initrd_name = '{0}/{1}.initrd'.format(
                self.pxe_dir, self.pxename)
            shutil.copy(system_image_initrd, target_initrd_name)
            os.chmod(target_initrd_name, 420)

        # create pxe config append information
        # this information helps to configure the boot server correctly
        append_filename = ''.join([self.pxe_dir, '/', self.pxename, '.append'])
        if self.initrd_system == 'kiwi':
            cmdline = 'pxe=1'
        else:
            cmdline = ' '.join([
                'rd.kiwi.install.pxe',
                'rd.kiwi.install.image=http://example.com/image.xz'
            ])
        custom_cmdline = self.xml_state.build_type.get_kernelcmdline()
        if custom_cmdline:
            cmdline += ' ' + custom_cmdline
        with open(append_filename, 'w') as append:
            append.write('%s\n' % cmdline)

        # create initrd for pxe install
        log.info('Creating pxe install boot image')
        self._create_pxe_install_kernel_and_initrd()

        # create pxe image bound boot config file, contents can be
        # changed but presence is required.
        log.info('Creating pxe install boot options file')
        configname = '{0}.config.bootoptions'.format(self.pxename)
        shutil.copy(os.sep.join([self.root_dir, 'config.bootoptions']),
                    os.sep.join([self.pxe_dir, configname]))

        # create pxe install tarball
        log.info('Creating pxe install archive')
        archive = ArchiveTar(self.pxetarball)

        archive.create(self.pxe_dir)
Example #33
0
    def install(self):  # noqa: C901
        """
        Install bootloader on disk device
        """
        log.info('Installing grub2 on disk %s', self.device)

        if self.target_removable:
            self.install_arguments.append('--removable')

        if Defaults.is_x86_arch(self.arch):
            self.target = 'i386-pc'
            self.install_device = self.device
            self.modules = ' '.join(
                Defaults.get_grub_bios_modules(multiboot=True)
            )
            self.install_arguments.append('--skip-fs-probe')
        elif self.arch.startswith('ppc64'):
            if not self.custom_args or 'prep_device' not in self.custom_args:
                raise KiwiBootLoaderGrubInstallError(
                    'prep device name required for grub2 installation on ppc'
                )
            self.target = 'powerpc-ieee1275'
            self.install_device = self.custom_args['prep_device']
            self.modules = ' '.join(Defaults.get_grub_ofw_modules())
            self.install_arguments.append('--skip-fs-probe')
            self.install_arguments.append('--no-nvram')
        elif self.arch.startswith('s390'):
            self.target = 's390x-emu'
            self.install_device = self.device
            self.modules = ' '.join(Defaults.get_grub_s390_modules())
            self.install_arguments.append('--skip-fs-probe')
            self.install_arguments.append('--no-nvram')
        else:
            raise KiwiBootLoaderGrubPlatformError(
                'host architecture %s not supported for grub2 installation' %
                self.arch
            )

        self.root_mount = MountManager(
            device=self.custom_args['root_device']
        )
        if 's390' in self.arch:
            self.boot_mount = MountManager(
                device=self.custom_args['boot_device'],
                mountpoint=self.root_mount.mountpoint + '/boot/zipl'
            )
        else:
            self.boot_mount = MountManager(
                device=self.custom_args['boot_device'],
                mountpoint=self.root_mount.mountpoint + '/boot'
            )
        if self.custom_args.get('efi_device'):
            self.efi_mount = MountManager(
                device=self.custom_args['efi_device'],
                mountpoint=self.root_mount.mountpoint + '/boot/efi'
            )

        self.root_mount.mount()

        if not self.root_mount.device == self.boot_mount.device:
            self.boot_mount.mount()

        if self.efi_mount:
            self.efi_mount.mount()

        if self.volumes:
            for volume_path in Path.sort_by_hierarchy(
                sorted(self.volumes.keys())
            ):
                volume_mount = MountManager(
                    device=self.volumes[volume_path]['volume_device'],
                    mountpoint=self.root_mount.mountpoint + '/' + volume_path
                )
                self.volumes_mount.append(volume_mount)
                volume_mount.mount(
                    options=[self.volumes[volume_path]['volume_options']]
                )

        self.device_mount = MountManager(
            device='/dev',
            mountpoint=self.root_mount.mountpoint + '/dev'
        )
        self.proc_mount = MountManager(
            device='/proc',
            mountpoint=self.root_mount.mountpoint + '/proc'
        )
        self.sysfs_mount = MountManager(
            device='/sys',
            mountpoint=self.root_mount.mountpoint + '/sys'
        )
        self.device_mount.bind_mount()
        self.proc_mount.bind_mount()
        self.sysfs_mount.bind_mount()

        # check if a grub installation could be found in the image system
        module_directory = Defaults.get_grub_path(
            self.root_mount.mountpoint, self.target, raise_on_error=False
        )
        if not module_directory:
            raise KiwiBootLoaderGrubDataError(
                'No grub2 installation found in {0} for target {1}'.format(
                    self.root_mount.mountpoint, self.target
                )
            )
        module_directory = module_directory.replace(
            self.root_mount.mountpoint, ''
        )
        boot_directory = '/boot'

        # wipe existing grubenv to allow the grub installer to create a new one
        grubenv_glob = os.sep.join(
            [self.root_mount.mountpoint, 'boot', '*', 'grubenv']
        )
        for grubenv in glob.glob(grubenv_glob):
            Path.wipe(grubenv)

        # install grub2 boot code
        if self.firmware.get_partition_table_type() == 'dasd':
            # On s390 and in CDL mode (4k DASD) the call of grub2-install
            # does not work because grub2-install is not able to identify
            # a 4k fdasd partitioned device as a grub supported device
            # and fails. As grub2-install is only used to invoke
            # grub2-zipl-setup and has no other job to do we can
            # circumvent this problem by directly calling grub2-zipl-setup
            # instead.
            Command.run(
                [
                    'chroot', self.root_mount.mountpoint,
                    'grub2-zipl-setup', '--keep'
                ]
            )
            zipl_config_file = ''.join(
                [
                    self.root_mount.mountpoint, '/boot/zipl/config'
                ]
            )
            zipl2grub_config_file_orig = ''.join(
                [
                    self.root_mount.mountpoint,
                    '/etc/default/zipl2grub.conf.in.orig'
                ]
            )
            if os.path.exists(zipl2grub_config_file_orig):
                Command.run(
                    [
                        'mv', zipl2grub_config_file_orig,
                        zipl2grub_config_file_orig.replace('.orig', '')
                    ]
                )
            if os.path.exists(zipl_config_file):
                Command.run(
                    ['mv', zipl_config_file, zipl_config_file + '.kiwi']
                )
        else:
            Command.run(
                [
                    'chroot', self.root_mount.mountpoint,
                    self._get_grub2_install_tool_name(
                        self.root_mount.mountpoint
                    )
                ] + self.install_arguments + [
                    '--directory', module_directory,
                    '--boot-directory', boot_directory,
                    '--target', self.target,
                    '--modules', self.modules,
                    self.install_device
                ]
            )

        if self.firmware and self.firmware.efi_mode() == 'uefi':
            shim_install = self._get_shim_install_tool_name(
                self.root_mount.mountpoint
            )
            # if shim-install does _not_ exist the fallback mechanism
            # has applied at the bootloader/config level and we expect
            # no further tool calls to be required
            if shim_install:
                # Before we call shim-install, the grub installer binary is
                # replaced by a noop. Actually there is no reason for
                # shim-install to call the grub installer because it should
                # only setup the system for EFI secure boot which does not
                # require any bootloader code in the master boot record.
                # In addition kiwi has called the grub installer right
                # before
                self._disable_grub2_install(self.root_mount.mountpoint)
                Command.run(
                    [
                        'chroot', self.root_mount.mountpoint,
                        'shim-install', '--removable',
                        self.install_device
                    ]
                )
                # restore the grub installer noop
                self._enable_grub2_install(self.root_mount.mountpoint)
Example #34
0
 def rebuild_database(self):
     """
     Rebuild image rpm database taking current macro setup into account
     """
     Command.run(['chroot', self.root_dir, 'rpmdb', '--rebuilddb'])
Example #35
0
 def _volume_group_in_use_on_host_system(self, volume_group_name):
     vgs_call = Command.run(['vgs', '--noheadings', '-o', 'vg_name'])
     for host_volume_group_name in vgs_call.output.split('\n'):
         if volume_group_name in host_volume_group_name:
             return True
     return False
Example #36
0
 def test_call_command_does_not_exist(self):
     Command.call(['does-not-exist'], os.environ)
Example #37
0
    def process(self):
        """
        Prepare and install a new system for chroot access
        """
        self.manual = Help()
        if self._help():
            return

        Privileges.check_for_root_permissions()

        self.load_xml_description(self.command_args['--description'],
                                  self.global_args['--kiwi-file'])

        abs_root_path = os.path.abspath(self.command_args['--root'])

        prepare_checks = self.checks_before_command_args
        prepare_checks.update(
            {'check_target_directory_not_in_shared_cache': [abs_root_path]})
        self.run_checks(prepare_checks)

        if self.command_args['--ignore-repos']:
            self.xml_state.delete_repository_sections()
        elif self.command_args['--ignore-repos-used-for-build']:
            self.xml_state.delete_repository_sections_used_for_build()

        if self.command_args['--set-repo']:
            self.xml_state.set_repository(
                *self.sextuple_token(self.command_args['--set-repo']))

        if self.command_args['--add-repo']:
            for add_repo in self.command_args['--add-repo']:
                self.xml_state.add_repository(*self.sextuple_token(add_repo))

        if self.command_args['--set-container-tag']:
            self.xml_state.set_container_config_tag(
                self.command_args['--set-container-tag'])

        if self.command_args['--add-container-label']:
            for add_label in self.command_args['--add-container-label']:
                try:
                    (name, value) = add_label.split('=', 1)
                    self.xml_state.add_container_config_label(name, value)
                except Exception:
                    log.warning('Container label {0} ignored. Invalid format: '
                                'expected labelname=value'.format(add_label))

        if self.command_args['--set-container-derived-from']:
            self.xml_state.set_derived_from_image_uri(
                self.command_args['--set-container-derived-from'])

        self.run_checks(self.checks_after_command_args)

        log.info('Preparing system')
        system = SystemPrepare(self.xml_state, abs_root_path,
                               self.command_args['--allow-existing-root'])
        manager = system.setup_repositories(
            self.command_args['--clear-cache'],
            self.command_args['--signing-key'] +
            self.xml_state.get_repositories_signing_keys(),
            self.global_args['--target-arch'])
        run_bootstrap = True
        if self.xml_state.get_package_manager() == 'apt' and \
           self.command_args['--allow-existing-root']:
            # try to call apt-get inside of the existing root.
            # If the call succeeds we skip calling debootstrap again
            # and assume the root to be ok to proceed with apt-get
            # if it fails, treat the root as dirty and give the
            # bootstrap a try
            try:
                Command.run(['chroot', abs_root_path, 'apt-get', '--version'])
                run_bootstrap = False
                log.warning('debootstrap will only be called once, skipped')
            except Exception:
                run_bootstrap = True

        if run_bootstrap:
            system.install_bootstrap(
                manager, self.command_args['--add-bootstrap-package'])

        setup = SystemSetup(self.xml_state, abs_root_path)
        setup.import_description()

        # call post_bootstrap.sh script if present
        setup.call_post_bootstrap_script()

        system.install_system(manager)

        if self.command_args['--add-package']:
            system.install_packages(manager,
                                    self.command_args['--add-package'])
        if self.command_args['--delete-package']:
            system.delete_packages(manager,
                                   self.command_args['--delete-package'])

        profile = Profile(self.xml_state)

        defaults = Defaults()
        defaults.to_profile(profile)

        profile.create(Defaults.get_profile_file(abs_root_path))

        setup.import_overlay_files()
        setup.import_image_identifier()
        setup.setup_groups()
        setup.setup_users()
        setup.setup_keyboard_map()
        setup.setup_locale()
        setup.setup_plymouth_splash()
        setup.setup_timezone()
        setup.setup_permissions()

        # make sure manager instance is cleaned up now
        del manager

        # setup permanent image repositories after cleanup
        setup.import_repositories_marked_as_imageinclude()

        # call config.sh script if present
        setup.call_config_script()

        # handle uninstall package requests, gracefully uninstall
        # with dependency cleanup
        system.pinch_system(force=False)

        # handle delete package requests, forced uninstall without
        # any dependency resolution
        system.pinch_system(force=True)

        # delete any custom rpm macros created
        system.clean_package_manager_leftovers()

        # make sure system instance is cleaned up now
        del system
Example #38
0
 def test_run_does_not_raise_error_if_command_not_found(self, mock_which):
     mock_which.return_value = None
     result = Command.run(['command', 'args'], os.environ, False)
     assert result.error is None
     assert result.output is None
     assert result.returncode == -1
Example #39
0
 def test_run_command_does_not_exist(self):
     Command.run(['does-not-exist'])
Example #40
0
 def test_run_invalid_environment(self):
     Command.run(['command', 'args'], {'HOME': '/root'})
Example #41
0
 def test_run_failure(self, mock_popen, mock_which):
     mock_which.return_value = 'command'
     mock_popen.side_effect = KiwiCommandError('Run failure')
     Command.run(['command', 'args'])
Example #42
0
 def test_call_failure(self, mock_popen, mock_which):
     mock_which.return_value = 'command'
     mock_popen.side_effect = KiwiCommandError('Call failure')
     Command.call(['command', 'args'])
Example #43
0
    def _copy_theme_data_to_boot_directory(self, lookup_path, target):
        if not lookup_path:
            lookup_path = self.boot_dir
        font_name = 'unicode.pf2'
        efi_font_dir = Defaults.get_grub_efi_font_directory(
            lookup_path
        )
        boot_fonts_dir = os.path.normpath(
            os.sep.join(
                [
                    self.boot_dir,
                    self.get_boot_path(target),
                    self.boot_directory_name,
                    'fonts'
                ]
            )
        )
        try:
            unicode_font = Defaults.get_grub_path(
                lookup_path, font_name
            )
            if not os.path.exists(os.sep.join([boot_fonts_dir, font_name])):
                Path.create(boot_fonts_dir)
                Command.run(
                    ['cp', unicode_font, boot_fonts_dir]
                )
            if efi_font_dir:
                Command.run(
                    ['cp', unicode_font, efi_font_dir]
                )
        except Exception as issue:
            raise KiwiBootLoaderGrubFontError(
                'Setting up unicode font failed with {0}'.format(issue)
            )

        boot_theme_dir = os.sep.join(
            [self.boot_dir, 'boot', self.boot_directory_name, 'themes']
        )
        Path.create(boot_theme_dir)

        if self.theme:
            theme_dir = Defaults.get_grub_path(
                lookup_path, 'themes/' + self.theme, raise_on_error=False
            )
            boot_theme_background_file = self._find_theme_background_file(
                lookup_path
            )
            if theme_dir and os.path.exists(theme_dir):
                if boot_theme_background_file:
                    # A background file was found. Preserve a copy of the
                    # file which was created at install time of the theme
                    # package by the activate-theme script
                    boot_theme_background_backup_file = os.sep.join(
                        [self.boot_dir, 'background.png']
                    )
                    Command.run(
                        [
                            'cp', boot_theme_background_file,
                            boot_theme_background_backup_file
                        ]
                    )
                # sync theme data from install path to boot path
                data = DataSync(
                    theme_dir, boot_theme_dir
                )
                data.sync_data(
                    options=['-a']
                )
                if boot_theme_background_file:
                    # Install preserved background file to the theme
                    Command.run(
                        [
                            'mv', boot_theme_background_backup_file,
                            os.sep.join([boot_theme_dir, self.theme])
                        ]
                    )
            elif boot_theme_background_file:
                # assume all theme data is in the directory of the
                # background file and just sync that directory to the
                # boot path
                data = DataSync(
                    os.path.dirname(boot_theme_background_file), boot_theme_dir
                )
                data.sync_data(
                    options=['-a']
                )

        self._check_boot_theme_exists()
Example #44
0
 def _get_modules(self) -> List[str]:
     cmd = Command.run([
         'chroot', self.boot_root_directory, 'dracut', '--list-modules',
         '--no-kernel'
     ])
     return cmd.output.splitlines()
Example #45
0
File: zypper.py Project: D4N/kiwi
    def add_repo(self,
                 name,
                 uri,
                 repo_type='rpm-md',
                 prio=None,
                 dist=None,
                 components=None,
                 user=None,
                 secret=None,
                 credentials_file=None,
                 repo_gpgcheck=None,
                 pkg_gpgcheck=None):
        """
        Add zypper repository

        :param str name: repository name
        :param str uri: repository URI
        :param repo_type: repostory type name
        :param int prio: zypper repostory priority
        :param dist: unused
        :param components: unused
        :param user: credentials username
        :param secret: credentials password
        :param credentials_file: zypper credentials file
        :param bool repo_gpgcheck: enable repository signature validation
        :param bool pkg_gpgcheck: enable package signature validation
        """
        if credentials_file:
            repo_secret = os.sep.join(
                [self.shared_zypper_dir['credentials-dir'], credentials_file])
            if os.path.exists(repo_secret):
                Path.wipe(repo_secret)

            if user and secret:
                uri = ''.join([uri, '?credentials=', credentials_file])
                with open(repo_secret, 'w') as credentials:
                    credentials.write('username={0}{1}'.format(
                        user, os.linesep))
                    credentials.write('password={0}{1}'.format(
                        secret, os.linesep))

        repo_file = ''.join(
            [self.shared_zypper_dir['reposd-dir'], '/', name, '.repo'])
        self.repo_names.append(''.join([name, '.repo']))

        if os.path.exists(repo_file):
            Path.wipe(repo_file)

        self._backup_package_cache()
        zypper_addrepo_command = ['zypper'] + self.zypper_args + [
            '--root', self.root_dir, 'addrepo', '--refresh', '--keep-packages'
            if Uri(uri).is_remote() else '--no-keep-packages', '--no-check',
            uri, name
        ]
        try:
            Command.run(zypper_addrepo_command, self.command_env)
        except Exception:
            # for whatever reason zypper sometimes failes with
            # a 'failed to cache rpm database' error. I could not
            # find any reason why and a simple recall of the exact
            # same command in the exact same environment works.
            # Thus the stupid but simple workaround to this problem
            # is try one recall before really failing
            Command.run(zypper_addrepo_command, self.command_env)

        if prio or repo_gpgcheck is not None or pkg_gpgcheck is not None:
            repo_config = ConfigParser()
            repo_config.read(repo_file)
            if repo_gpgcheck is not None:
                repo_config.set(name, 'repo_gpgcheck',
                                '1' if repo_gpgcheck else '0')
            if pkg_gpgcheck is not None:
                repo_config.set(name, 'pkg_gpgcheck',
                                '1' if pkg_gpgcheck else '0')
            if prio:
                repo_config.set(name, 'priority', format(prio))
            with open(repo_file, 'w') as repo:
                repo_config.write(repo)
        self._restore_package_cache()
Example #46
0
    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(),
                'ofw_mode': self.firmware.ofw_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={
                'compression':
                self.xml_state.build_type.get_squashfscompression()
            })
        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)
Example #47
0
 def init_database(self):
     Command.run(['rpm', '--root', self.root_dir, '--initdb'])
Example #48
0
File: apt.py Project: isbm/kiwi
    def process_install_requests_bootstrap(self):
        """
        Process package install requests for bootstrap phase (no chroot)
        The debootstrap program is used to bootstrap a new system with
        a collection of predefined packages. The kiwi bootstrap section
        information is not used in this case

        :raises KiwiDebootstrapError: if no main distribution repository
            is configured, if the debootstrap script is not found or if the
            debootstrap script execution fails
        :return: process results in command type
        :rtype: namedtuple
        """
        if not self.distribution:
            raise KiwiDebootstrapError(
                'No main distribution repository is configured'
            )
        bootstrap_script = '/usr/share/debootstrap/scripts/' + \
            self.distribution
        if not os.path.exists(bootstrap_script):
            raise KiwiDebootstrapError(
                'debootstrap script for %s distribution not found' %
                self.distribution
            )
        bootstrap_dir = self.root_dir + '.debootstrap'
        if 'apt-get' in self.package_requests:
            # debootstrap takes care to install apt-get
            self.package_requests.remove('apt-get')
        try:
            cmd = ['debootstrap']
            if self.repository.unauthenticated == 'false' and \
               os.path.exists(self.repository.keyring):
                cmd.append('--keyring={}'.format(self.repository.keyring))
            else:
                cmd.append('--no-check-gpg')
            if self.deboostrap_minbase:
                cmd.append('--variant=minbase')
            if self.repository.components:
                cmd.append(
                    '--components={0}'.format(
                        ','.join(self.repository.components)
                    )
                )
            cmd.extend([
                self.distribution, bootstrap_dir, self.distribution_path
            ])
            Command.run(cmd, self.command_env)
            data = DataSync(
                bootstrap_dir + '/', self.root_dir
            )
            data.sync_data(
                options=['-a', '-H', '-X', '-A'],
                exclude=['proc', 'sys', 'dev']
            )
        except Exception as e:
            raise KiwiDebootstrapError(
                '%s: %s' % (type(e).__name__, format(e))
            )
        finally:
            Path.wipe(bootstrap_dir)

        return self.process_install_requests()
Example #49
0
    def add_repo(self,
                 name,
                 uri,
                 repo_type='rpm-md',
                 prio=None,
                 dist=None,
                 components=None,
                 user=None,
                 secret=None,
                 credentials_file=None,
                 repo_gpgcheck=None,
                 pkg_gpgcheck=None):
        """
        Add zypper repository

        :param str name: repository name
        :param str uri: repository URI
        :param repo_type: repostory type name
        :param int prio: zypper repostory priority
        :param dist: unused
        :param components: unused
        :param user: credentials username
        :param secret: credentials password
        :param credentials_file: zypper credentials file
        :param bool repo_gpgcheck: enable repository signature validation
        :param bool pkg_gpgcheck: enable package signature validation
        """
        if credentials_file:
            repo_secret = os.sep.join(
                [self.shared_zypper_dir['credentials-dir'], credentials_file])
            if os.path.exists(repo_secret):
                Path.wipe(repo_secret)

            if user and secret:
                uri = ''.join([uri, '?credentials=', credentials_file])
                with open(repo_secret, 'w') as credentials:
                    credentials.write('username={0}{1}'.format(
                        user, os.linesep))
                    credentials.write('password={0}{1}'.format(
                        secret, os.linesep))

        repo_file = ''.join(
            [self.shared_zypper_dir['reposd-dir'], '/', name, '.repo'])
        self.repo_names.append(''.join([name, '.repo']))

        if os.path.exists(repo_file):
            Path.wipe(repo_file)

        self._backup_package_cache()
        Command.run(['zypper'] + self.zypper_args + [
            '--root', self.root_dir, 'addrepo', '--refresh', '--type',
            self._translate_repo_type(repo_type), '--keep-packages'
            if Uri(uri).is_remote() else '--no-keep-packages', '-C', uri, name
        ], self.command_env)
        if prio or repo_gpgcheck is not None or pkg_gpgcheck is not None:
            repo_config = ConfigParser()
            repo_config.read(repo_file)
            if repo_gpgcheck is not None:
                repo_config.set(name, 'repo_gpgcheck',
                                '1' if repo_gpgcheck else '0')
            if pkg_gpgcheck is not None:
                repo_config.set(name, 'pkg_gpgcheck',
                                '1' if pkg_gpgcheck else '0')
            if prio:
                repo_config.set(name, 'priority', format(prio))
            with open(repo_file, 'w') as repo:
                repo_config.write(repo)
        self._restore_package_cache()
Example #50
0
    def _setup_default_grub(self):  # noqa: C901
        """
        Create or update etc/default/grub by parameters required
        according to the root filesystem setup

        * GRUB_TIMEOUT
        * SUSE_BTRFS_SNAPSHOT_BOOTING
        * GRUB_BACKGROUND
        * GRUB_THEME
        * GRUB_USE_LINUXEFI
        * GRUB_USE_INITRDEFI
        * GRUB_SERIAL_COMMAND
        * GRUB_CMDLINE_LINUX_DEFAULT
        * GRUB_GFXMODE
        * GRUB_TERMINAL
        * GRUB_DISTRIBUTOR
        """
        grub_default_entries = {
            'GRUB_TIMEOUT': self.timeout,
            'GRUB_GFXMODE': self.gfxmode,
            'GRUB_TERMINAL': '"{0}"'.format(self.terminal),
            'GRUB_DISTRIBUTOR': '"{0}"'.format(self.get_menu_entry_title())
        }
        if self.cmdline:
            grub_default_entries[
                'GRUB_CMDLINE_LINUX_DEFAULT'] = '"{0}"'.format(
                    re.sub(r'root=.* |root=.*$', '', self.cmdline).strip())
        if self.terminal and 'serial' in self.terminal:
            serial_format = '"serial {0} {1} {2} {3} {4}"'
            grub_default_entries['GRUB_SERIAL_COMMAND'] = serial_format.format(
                '--speed=38400', '--unit=0', '--word=8', '--parity=no',
                '--stop=1')
        if self.theme:
            theme_setup = '{0}/{1}/theme.txt'
            grub_default_entries['GRUB_THEME'] = theme_setup.format(
                ''.join(['/boot/', self.boot_directory_name, '/themes']),
                self.theme)
            theme_background = '{0}/{1}/background.png'.format(
                ''.join(['/boot/', self.boot_directory_name, '/themes']),
                self.theme)
            if os.path.exists(os.sep.join([self.root_dir, theme_background])):
                grub_default_entries['GRUB_BACKGROUND'] = theme_background
        if self.firmware.efi_mode():
            # linuxefi/initrdefi only exist on x86, others always use efi
            if self.arch == 'ix86' or self.arch == 'x86_64':
                use_linuxefi_implemented = Command.run([
                    'grep', '-q', 'GRUB_USE_LINUXEFI',
                    Defaults.get_grub_config_tool()
                ],
                                                       raise_on_error=False)
                if use_linuxefi_implemented.returncode == 0:
                    grub_default_entries['GRUB_USE_LINUXEFI'] = 'true'
                    grub_default_entries['GRUB_USE_INITRDEFI'] = 'true'
        if self.xml_state.build_type.get_btrfs_root_is_snapshot():
            grub_default_entries['SUSE_BTRFS_SNAPSHOT_BOOTING'] = 'true'
        if self.custom_args.get('boot_is_crypto'):
            grub_default_entries['GRUB_ENABLE_CRYPTODISK'] = 'y'

        enable_blscfg_implemented = Command.run([
            'grep', '-q', 'GRUB_ENABLE_BLSCFG',
            Defaults.get_grub_config_tool()
        ],
                                                raise_on_error=False)
        if enable_blscfg_implemented.returncode == 0:
            grub_default_entries['GRUB_ENABLE_BLSCFG'] = 'true'

        if grub_default_entries:
            log.info('Writing grub2 defaults file')
            grub_default_location = ''.join([self.root_dir, '/etc/default/'])
            if os.path.exists(grub_default_location):
                grub_default_file = ''.join([grub_default_location, 'grub'])
                grub_default = SysConfig(grub_default_file)
                grub_default_entries_sorted = OrderedDict(
                    sorted(grub_default_entries.items()))
                for key, value in list(grub_default_entries_sorted.items()):
                    log.info('--> {0}:{1}'.format(key, value))
                    grub_default[key] = value
                grub_default.write()
Example #51
0
    def create(self, filename, base_image):
        """
        Create compressed oci system container tar archive

        :param string filename: archive file name
        :param string base_image: archive used as a base image
        """
        exclude_list = Defaults.get_exclude_list_for_root_data_sync()
        exclude_list.append('boot')
        exclude_list.append('dev')
        exclude_list.append('sys')
        exclude_list.append('proc')

        self.oci_dir = mkdtemp(prefix='kiwi_oci_dir.')
        self.oci_root_dir = mkdtemp(prefix='kiwi_oci_root_dir.')

        container_dir = os.sep.join([self.oci_dir, 'umoci_layout'])
        container_name = ':'.join([container_dir, self.container_tag])

        if base_image:
            Path.create(container_dir)
            image_tar = ArchiveTar(base_image)
            image_tar.extract(container_dir)
            Command.run([
                'umoci', 'config', '--image',
                '{0}:base_layer'.format(container_dir), '--tag',
                self.container_tag
            ])
        else:
            Command.run(['umoci', 'init', '--layout', container_dir])
            Command.run(['umoci', 'new', '--image', container_name])

        Command.run(
            ['umoci', 'unpack', '--image', container_name, self.oci_root_dir])
        oci_root = DataSync(''.join([self.root_dir, os.sep]),
                            os.sep.join([self.oci_root_dir, 'rootfs']))
        oci_root.sync_data(options=['-a', '-H', '-X', '-A', '--delete'],
                           exclude=exclude_list)
        Command.run(
            ['umoci', 'repack', '--image', container_name, self.oci_root_dir])
        for tag in self.additional_tags:
            Command.run(
                ['umoci', 'config', '--image', container_name, '--tag', tag])
        Command.run(['umoci', 'config'] + self.maintainer + self.user +
                    self.workingdir + self.entry_command +
                    self.entry_subcommand + self.expose_ports + self.volumes +
                    self.environment + self.labels + [
                        '--image', container_name, '--created',
                        datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S+00:00')
                    ])
        Command.run(['umoci', 'gc', '--layout', container_dir])

        return self.pack_image_to_file(filename)
Example #52
0
 def test_call_command_does_not_exist(self):
     with raises(KiwiCommandNotFound):
         Command.call(['does-not-exist'], os.environ)
Example #53
0
 def cleanup(self):
     """
     Delete all traces of a kiwi description which are not
     required in the later image
     """
     Command.run(['rm', '-r', '-f', '/.kconfig', '/image'])
Example #54
0
 def test_run_command_does_not_exist(self):
     with raises(KiwiCommandNotFound):
         Command.run(['does-not-exist'])
Example #55
0
    def setup_disk_image_config(self,
                                boot_uuid=None,
                                root_uuid=None,
                                hypervisor=None,
                                kernel=None,
                                initrd=None,
                                boot_options={}):
        """
        Create grub2 config file to boot from disk using grub2-mkconfig

        :param string boot_uuid: unused
        :param string root_uuid: unused
        :param string hypervisor: unused
        :param string kernel: unused
        :param string initrd: unused
        :param dict boot_options:
            options dictionary that has to contain the root and boot
            device and optional volume configuration. KIWI has to
            mount the system prior to run grub2-mkconfig.

            .. code:: python

                {
                    'root_device': string,
                    'boot_device': string,
                    'efi_device': string,
                    'system_volumes': volume_manager_instance.get_volumes()
                }
        """
        self._mount_system(boot_options.get('root_device'),
                           boot_options.get('boot_device'),
                           boot_options.get('efi_device'),
                           boot_options.get('system_volumes'))
        config_file = os.sep.join([
            self.root_mount.mountpoint, 'boot', self.boot_directory_name,
            'grub.cfg'
        ])
        Command.run([
            'chroot', self.root_mount.mountpoint,
            self._get_grub2_mkconfig_tool(), '-o',
            config_file.replace(self.root_mount.mountpoint, '')
        ])
        if self.root_reference:
            if self.root_filesystem_is_overlay or \
               Defaults.is_buildservice_worker():
                # grub2-mkconfig has no idea how the correct root= setup is
                # for disk images created with overlayroot enabled or in a
                # buildservice worker environment. Because of that the mkconfig
                # tool just finds the raw partition loop device and includes it
                # which is wrong. In this particular case we have to patch the
                # written config file and replace the wrong root= reference with
                # the correct value.
                with open(config_file) as grub_config_file:
                    grub_config = grub_config_file.read()
                    grub_config = grub_config.replace(
                        'root={0}'.format(boot_options.get('root_device')),
                        self.root_reference)
                with open(config_file, 'w') as grub_config_file:
                    grub_config_file.write(grub_config)

        if self.firmware.efi_mode():
            self._copy_grub_config_to_efi_path(self.efi_mount.mountpoint,
                                               config_file)
Example #56
0
 def _create_passwd_hash(self, password):
     openssl = Command.run(
         ['openssl', 'passwd', '-1', '-salt', 'xyz', password])
     return openssl.output[:-1]
Example #57
0
 def post_process(self):
     """
     Cleanup unused data from operations
     """
     Command.run(['umoci', 'gc', '--layout', self.container_dir])
Example #58
0
    def process_install_requests_bootstrap(self, root_bind=None):
        """
        Process package install requests for bootstrap phase (no chroot)
        The debootstrap program is used to bootstrap a new system with
        a collection of predefined packages. The kiwi bootstrap section
        information is not used in this case

        :param object root_bind: instance of RootBind to manage kernel
            file systems before debootstrap call

        :raises KiwiDebootstrapError: if no main distribution repository
            is configured, if the debootstrap script is not found or if the
            debootstrap script execution fails
        :return: process results in command type
        :rtype: namedtuple
        """
        if not self.distribution:
            raise KiwiDebootstrapError(
                'No main distribution repository is configured')
        bootstrap_script = '/usr/share/debootstrap/scripts/' + \
            self.distribution
        if not os.path.exists(bootstrap_script):
            raise KiwiDebootstrapError(
                'debootstrap script for %s distribution not found' %
                self.distribution)

        # APT package manager does not support bootstrapping. To circumvent
        # this limitation there is the debootstrap tool for APT based distros.
        # Because of that there is a little overlap between KIWI and
        # debootstrap. Debootstrap manages itself the kernel file systems for
        # chroot environment, thus we need to umount the kernel file systems
        # before calling debootstrap and remount them afterwards.
        root_bind.umount_kernel_file_systems()
        # debootsrap will create its own dev/fd device
        os.unlink(os.path.normpath(os.sep.join([self.root_dir, 'dev/fd'])))

        if 'apt-get' in self.package_requests:
            # debootstrap takes care to install apt-get
            self.package_requests.remove('apt-get')
        try:
            cmd = ['debootstrap']
            if self.repository.unauthenticated == 'false' and \
               os.path.exists(self.repository.keyring):
                cmd.append('--keyring={}'.format(self.repository.keyring))
            else:
                cmd.append('--no-check-gpg')
            if self.deboostrap_minbase:
                cmd.append('--variant=minbase')
            if self.package_requests:
                cmd.append('--include={}'.format(','.join(
                    self.package_requests)))
            if self.repository.components:
                cmd.append('--components={0}'.format(','.join(
                    self.repository.components)))
            self.cleanup_requests()
            cmd.extend(
                [self.distribution, self.root_dir, self.distribution_path])

            return Command.call(cmd, self.command_env)
        except Exception as e:
            raise KiwiDebootstrapError('%s: %s' %
                                       (type(e).__name__, format(e)))
Example #59
0
    def process(self):
        """
        Create result bundle from the image build results in the
        specified target directory. Each result image will contain
        the specified bundle identifier as part of its filename.
        Uncompressed image files will also become xz compressed
        and a sha sum will be created from every result image
        """
        self.manual = Help()
        if self._help():
            return

        # load serialized result object from target directory
        result_directory = os.path.abspath(self.command_args['--target-dir'])
        bundle_directory = os.path.abspath(self.command_args['--bundle-dir'])
        if result_directory == bundle_directory:
            raise KiwiBundleError(
                'Bundle directory must be different from target directory'
            )

        log.info(
            'Bundle build results from %s', result_directory
        )
        result = Result.load(
            result_directory + '/kiwi.result'
        )
        image_version = result.xml_state.get_image_version()
        image_name = result.xml_state.xml_data.get_name()
        ordered_results = OrderedDict(sorted(result.get_results().items()))

        # hard link bundle files, compress and build checksum
        if not os.path.exists(bundle_directory):
            Path.create(bundle_directory)
        for result_file in list(ordered_results.values()):
            if result_file.use_for_bundle:
                bundle_file_basename = os.path.basename(result_file.filename)
                # The bundle id is only taken into account for image results
                # which contains the image version appended in its file name
                part_name = list(bundle_file_basename.partition(image_name))
                bundle_file_basename = ''.join([
                    part_name[0], part_name[1],
                    part_name[2].replace(
                        image_version,
                        image_version + '-' + self.command_args['--id']
                    )
                ])
                log.info('Creating %s', bundle_file_basename)
                bundle_file = ''.join(
                    [bundle_directory, '/', bundle_file_basename]
                )
                Command.run(
                    [
                        'cp', result_file.filename, bundle_file
                    ]
                )
                if result_file.compress:
                    log.info('--> XZ compressing')
                    compress = Compress(bundle_file)
                    compress.xz(self.runtime_config.get_xz_options())
                    bundle_file = compress.compressed_filename

                if self.command_args['--zsync-source'] and result_file.shasum:
                    # Files with a checksum are considered to be image files
                    # and are therefore eligible to be provided via the
                    # requested Partial/differential file download based on
                    # zsync
                    zsyncmake = Path.which('zsyncmake', access_mode=os.X_OK)
                    if zsyncmake:
                        log.info('--> Creating zsync control file')
                        Command.run(
                            [
                                zsyncmake, '-e', '-u', os.sep.join(
                                    [
                                        self.command_args['--zsync-source'],
                                        os.path.basename(bundle_file)
                                    ]
                                ), '-o', bundle_file + '.zsync', bundle_file
                            ]
                        )
                    else:
                        log.warning(
                            '--> zsyncmake missing, zsync setup skipped'
                        )

                if result_file.shasum:
                    log.info('--> Creating SHA 256 sum')
                    checksum = Checksum(bundle_file)
                    with open(bundle_file + '.sha256', 'w') as shasum:
                        shasum.write(
                            '{0}  {1}'.format(
                                checksum.sha256(), bundle_file_basename
                            )
                        )
Example #60
0
 def create_recovery_archive(self) -> None:
     """
     Create a compressed recovery archive from the root tree
     for use with kiwi's recvoery system. The method creates
     additional data into the image root filesystem which is
     deleted prior to the creation of a new recovery data set
     """
     # cleanup
     bash_comand = ['rm', '-f', self.root_dir + '/recovery.*']
     Command.run(['bash', '-c', ' '.join(bash_comand)])
     if not self.oemconfig['recovery']:
         return
     # recovery.tar
     log.info('Creating recovery tar archive')
     metadata = {
         'archive_name': self.root_dir + '/recovery.tar',
         'archive_filecount': self.root_dir + '/recovery.tar.files',
         'archive_size': self.root_dir + '/recovery.tar.size',
         'partition_size': self.root_dir + '/recovery.partition.size',
         'partition_filesystem': self.root_dir + '/recovery.tar.filesystem'
     }
     pathlib.Path(metadata['archive_name']).touch()
     archive = ArchiveTar(filename=metadata['archive_name'],
                          create_from_file_list=False)
     archive.create(source_dir=self.root_dir,
                    exclude=['dev', 'proc', 'sys'],
                    options=[
                        '--numeric-owner', '--hard-dereference',
                        '--preserve-permissions'
                    ])
     # recovery.tar.filesystem
     recovery_filesystem = self.xml_state.build_type.get_filesystem()
     with open(metadata['partition_filesystem'], 'w') as partfs:
         partfs.write('{0}'.format(recovery_filesystem))
     log.info('--> Recovery partition filesystem: {0}'.format(
         recovery_filesystem))
     # recovery.tar.files
     bash_comand = ['tar', '-tf', metadata['archive_name'], '|', 'wc', '-l']
     tar_files_call = Command.run(['bash', '-c', ' '.join(bash_comand)])
     tar_files_count = int(tar_files_call.output.rstrip('\n'))
     with open(metadata['archive_filecount'], 'w') as files:
         files.write('{0}{1}'.format(tar_files_count, os.linesep))
     log.info('--> Recovery file count: {0} files'.format(tar_files_count))
     # recovery.tar.size
     recovery_archive_size_bytes = os.path.getsize(metadata['archive_name'])
     with open(metadata['archive_size'], 'w') as size:
         size.write('{0}'.format(recovery_archive_size_bytes))
     log.info('--> Recovery uncompressed size: {0} mbytes'.format(
         int(recovery_archive_size_bytes / 1048576)))
     # recovery.tar.gz
     log.info('--> Compressing recovery archive')
     compress = Compress(self.root_dir + '/recovery.tar')
     compress.gzip()
     # recovery.partition.size
     recovery_archive_gz_size_mbytes = int(
         os.path.getsize(metadata['archive_name'] + '.gz') / 1048576)
     recovery_partition_mbytes = recovery_archive_gz_size_mbytes \
         + Defaults.get_recovery_spare_mbytes()
     with open(metadata['partition_size'], 'w') as gzsize:
         gzsize.write('{0}'.format(recovery_partition_mbytes))
     log.info('--> Recovery partition size: {0} mbytes'.format(
         recovery_partition_mbytes))
     # delete recovery archive if inplace recovery is requested
     # In this mode the recovery archive is created at install time
     # and not at image creation time. However the recovery metadata
     # is preserved in order to be able to check if enough space
     # is available on the disk to create the recovery archive.
     if self.oemconfig['recovery_inplace']:
         log.info('--> Inplace recovery requested, deleting archive')
         Path.wipe(metadata['archive_name'] + '.gz')