Пример #1
0
    def process(self):
        """
        reformats raw disk image and its format to a new disk
        geometry using the qemu tool chain
        """
        self.manual = Help()
        if self.command_args.get('help') is True:
            return self.manual.show('kiwi::image::resize')

        abs_target_dir_path = os.path.abspath(
            self.command_args['--target-dir'])

        if self.command_args['--root']:
            image_root = os.path.abspath(
                os.path.normpath(self.command_args['--root']))
        else:
            image_root = os.sep.join(
                [abs_target_dir_path, 'build', 'image-root'])

        self.load_xml_description(image_root)

        disk_format = self.xml_state.build_type.get_format()

        image_format = DiskFormat(disk_format or 'raw', self.xml_state,
                                  image_root, abs_target_dir_path)
        if not image_format.has_raw_disk():
            raise KiwiImageResizeError(
                'no raw disk image {0} found in build results'.format(
                    image_format.diskname))

        new_disk_size = StringToSize.to_bytes(self.command_args['--size'])

        # resize raw disk
        log.info('Resizing raw disk to {0} bytes'.format(new_disk_size))
        resize_result = image_format.resize_raw_disk(new_disk_size)

        # resize raw disk partition table
        firmware = FirmWare(self.xml_state)
        loop_provider = LoopDevice(image_format.diskname)
        loop_provider.create(overwrite=False)
        partitioner = Partitioner(firmware.get_partition_table_type(),
                                  loop_provider)
        partitioner.resize_table()
        del loop_provider

        # resize disk format from resized raw disk
        if disk_format and resize_result is True:
            log.info('Creating {0} disk format from resized raw disk'.format(
                disk_format))
            image_format.create_image_format()
        elif resize_result is False:
            log.info('Raw disk is already at {0} bytes'.format(new_disk_size))
Пример #2
0
    def __init__(self, table_type, storage_provider):
        # bind the underlaying block device providing class instance
        # to this object (e.g loop) if present. This is done to guarantee
        # the correct destructor order when the device should be released.
        self.storage_provider = storage_provider

        self.partition_map = {}
        self.public_partition_id_map = {}
        self.partition_id_map = {}
        self.is_mapped = False

        self.partitioner = Partitioner(table_type, storage_provider)

        self.table_type = table_type
Пример #3
0
    def __init__(self,
                 table_type: str,
                 storage_provider: DeviceProvider,
                 start_sector: int = None):
        # bind the underlaying block device providing class instance
        # to this object (e.g loop) if present. This is done to guarantee
        # the correct destructor order when the device should be released.
        self.storage_provider = storage_provider

        # list of protected map ids. If used in a custom partitions
        # setup this will lead to a raise conditition in order to
        # avoid conflicts with the existing partition layout and its
        # customizaton capabilities
        self.protected_map_ids = [
            'root', 'readonly', 'boot', 'prep', 'spare', 'swap', 'efi_csm',
            'efi'
        ]

        self.partition_map: Dict[str, str] = {}
        self.public_partition_id_map: Dict[str, str] = {}
        self.partition_id_map: Dict[str, str] = {}
        self.is_mapped = False

        self.partitioner = Partitioner.new(table_type, storage_provider,
                                           start_sector)

        self.table_type = table_type
Пример #4
0
 def append_unpartitioned_space(self):
     """
     Extends the raw disk if an unpartitioned area is specified
     """
     if self.unpartitioned_bytes:
         log.info('Expanding disk with %d bytes of unpartitioned space',
                  self.unpartitioned_bytes)
         disk_format = DiskFormat('raw', self.xml_state, self.root_dir,
                                  self.target_dir)
         disk_format.resize_raw_disk(self.unpartitioned_bytes, append=True)
         firmware = FirmWare(self.xml_state)
         loop_provider = LoopDevice(disk_format.diskname)
         loop_provider.create(overwrite=False)
         partitioner = Partitioner(firmware.get_partition_table_type(),
                                   loop_provider)
         partitioner.resize_table()
Пример #5
0
 def test_partitioner_s390_dasd_with_custom_start_sector(
         self, mock_machine, mock_dasd):
     mock_machine.return_value = 's390'
     storage_provider = Mock()
     with self._caplog.at_level(logging.WARNING):
         Partitioner('dasd', storage_provider, 4096)
         mock_dasd.assert_called_once_with(storage_provider)
Пример #6
0
 def test_partitioner_s390_dasd_with_custom_start_sector(
         self, mock_machine, mock_dasd, mock_warning):
     mock_machine.return_value = 's390'
     storage_provider = Mock()
     Partitioner('dasd', storage_provider, 4096)
     mock_dasd.assert_called_once_with(storage_provider)
     assert mock_warning.called
Пример #7
0
 def append_unpartitioned_space(self):
     """
     Extends the raw disk if an unpartitioned area is specified
     """
     if self.unpartitioned_bytes:
         log.info(
             'Expanding disk with %d bytes of unpartitioned space',
             self.unpartitioned_bytes
         )
         disk_format = DiskFormat(
             'raw', self.xml_state, self.root_dir, self.target_dir
         )
         disk_format.resize_raw_disk(self.unpartitioned_bytes, append=True)
         firmware = FirmWare(self.xml_state)
         loop_provider = LoopDevice(disk_format.diskname)
         loop_provider.create(overwrite=False)
         partitioner = Partitioner(
             firmware.get_partition_table_type(), loop_provider
         )
         partitioner.resize_table()
Пример #8
0
    def __init__(
        self, table_type: str, storage_provider: DeviceProvider,
        start_sector: int = None, extended_layout: bool = False
    ):
        """
        Construct a new Disk layout object

        :param string table_type: Partition table type name
        :param object storage_provider:
            Instance of class based on DeviceProvider
        :param int start_sector: sector number
        :param bool extended_layout:
            If set to true and on msdos table type when creating
            more than 4 partitions, this will cause the fourth
            partition to be an extended partition and all following
            partitions will be placed as logical partitions inside
            of that extended partition
        """
        # bind the underlaying block device providing class instance
        # to this object (e.g loop) if present. This is done to guarantee
        # the correct destructor order when the device should be released.
        self.storage_provider = storage_provider

        # list of protected map ids. If used in a custom partitions
        # setup this will lead to a raise conditition in order to
        # avoid conflicts with the existing partition layout and its
        # customizaton capabilities
        self.protected_map_ids = [
            'root',
            'readonly',
            'boot',
            'prep',
            'spare',
            'swap',
            'efi_csm',
            'efi'
        ]

        self.partition_map: Dict[str, str] = {}
        self.public_partition_id_map: Dict[str, str] = {}
        self.partition_id_map: Dict[str, str] = {}
        self.is_mapped = False

        self.partitioner = Partitioner.new(
            table_type, storage_provider, start_sector, extended_layout
        )

        self.table_type = table_type
Пример #9
0
    def __init__(self, table_type, storage_provider):
        # bind the underlaying block device providing class instance
        # to this object (e.g loop) if present. This is done to guarantee
        # the correct destructor order when the device should be released.
        self.storage_provider = storage_provider

        self.partition_map = {}
        self.public_partition_id_map = {}
        self.partition_id_map = {}
        self.is_mapped = False

        self.partitioner = Partitioner(
            table_type, storage_provider
        )

        self.table_type = table_type
Пример #10
0
 def test_partitioner_not_implemented(self, mock_machine):
     mock_machine.return_value = 'x86_64'
     Partitioner('foo', mock.Mock())
Пример #11
0
 def test_partitioner_ppc_gpt(self, mock_machine, mock_gpt):
     mock_machine.return_value = 'ppc64'
     storage_provider = Mock()
     Partitioner('gpt', storage_provider)
     mock_gpt.assert_called_once_with(storage_provider, None)
Пример #12
0
 def test_partitioner_s390_msdos(self, mock_machine, mock_dos):
     mock_machine.return_value = 's390'
     storage_provider = Mock()
     Partitioner('msdos', storage_provider)
     mock_dos.assert_called_once_with(storage_provider, None)
Пример #13
0
    def process(self):
        """
        reformats raw disk image and its format to a new disk
        geometry using the qemu tool chain
        """
        self.manual = Help()
        if self.command_args.get('help') is True:
            return self.manual.show('kiwi::image::resize')

        abs_target_dir_path = os.path.abspath(
            self.command_args['--target-dir']
        )

        if self.command_args['--root']:
            image_root = os.path.abspath(
                os.path.normpath(self.command_args['--root'])
            )
        else:
            image_root = os.sep.join(
                [abs_target_dir_path, 'build', 'image-root']
            )

        self.load_xml_description(
            image_root
        )

        disk_format = self.xml_state.build_type.get_format()

        image_format = DiskFormat(
            disk_format or 'raw', self.xml_state, image_root,
            abs_target_dir_path
        )
        if not image_format.has_raw_disk():
            raise KiwiImageResizeError(
                'no raw disk image {0} found in build results'.format(
                    image_format.diskname
                )
            )

        new_disk_size = StringToSize.to_bytes(self.command_args['--size'])

        # resize raw disk
        log.info(
            'Resizing raw disk to {0} bytes'.format(new_disk_size)
        )
        resize_result = image_format.resize_raw_disk(new_disk_size)

        # resize raw disk partition table
        firmware = FirmWare(self.xml_state)
        loop_provider = LoopDevice(image_format.diskname)
        loop_provider.create(overwrite=False)
        partitioner = Partitioner(
            firmware.get_partition_table_type(), loop_provider
        )
        partitioner.resize_table()
        del loop_provider

        # resize disk format from resized raw disk
        if disk_format and resize_result is True:
            log.info(
                'Creating {0} disk format from resized raw disk'.format(
                    disk_format
                )
            )
            image_format.create_image_format()
        elif resize_result is False:
            log.info(
                'Raw disk is already at {0} bytes'.format(new_disk_size)
            )
Пример #14
0
 def test_partitioner_msdos(self, mock_dos):
     storage_provider = Mock()
     Partitioner.new('msdos', storage_provider)
     mock_dos.assert_called_once_with(storage_provider, None, False)
Пример #15
0
 def test_partitioner_arm_gpt(self, mock_machine, mock_gpt):
     mock_machine.return_value = 'aarch64'
     storage_provider = mock.Mock()
     Partitioner('gpt', storage_provider)
     mock_gpt.assert_called_once_with(storage_provider)
Пример #16
0
class Disk(DeviceProvider):
    """
    Implements storage disk and partition table setup

    Attributes

    * :attr:`storage_provider`
        Instance of class based on DeviceProvider

    * :attr:`partition_map`
        Dict of internal partition names to device node name

    * :attr:`public_partition_id_map`
        Dict of public partition names to partition number

    * :attr:`partition_id_map`
        Dict of internal partition names to partition number

    * :attr:`is_mapped`
        Indicate if partitions are kpartx mapped

    * :attr:`partitioner`
        Instance of Partitioner

    * :attr:`table_type`
        Partition table type
    """
    def __init__(self, table_type, storage_provider):
        # bind the underlaying block device providing class instance
        # to this object (e.g loop) if present. This is done to guarantee
        # the correct destructor order when the device should be released.
        self.storage_provider = storage_provider

        self.partition_map = {}
        self.public_partition_id_map = {}
        self.partition_id_map = {}
        self.is_mapped = False

        self.partitioner = Partitioner(
            table_type, storage_provider
        )

        self.table_type = table_type

    def get_device(self):
        """
        Names of partition devices

        Note that the mapping requires an explicit map() call

        :return: instances of MappedDevice
        :rtype: dict
        """
        device_map = {}
        for partition_name, device_node in list(self.partition_map.items()):
            device_map[partition_name] = MappedDevice(
                device=device_node, device_provider=self
            )
        return device_map

    def is_loop(self):
        """
        Check if storage provider is loop based

        The information is taken from the storage provider. If
        the storage provider is loop based the disk is it too
        """
        return self.storage_provider.is_loop()

    def create_root_partition(self, mbsize):
        """
        Create root partition

        Populates kiwi_RootPart(id) and kiwi_BootPart(id) if no extra
        boot partition is requested

        :param int mbsize: partition size
        """
        self.partitioner.create('p.lxroot', mbsize, 't.linux')
        self._add_to_map('root')
        self._add_to_public_id_map('kiwi_RootPart')
        if 'kiwi_ROPart' in self.public_partition_id_map:
            self._add_to_public_id_map('kiwi_RWPart')
        if 'kiwi_BootPart' not in self.public_partition_id_map:
            self._add_to_public_id_map('kiwi_BootPart')

    def create_root_lvm_partition(self, mbsize):
        """
        Create root partition for use with LVM

        Populates kiwi_RootPart(id) and kiwi_RootPartVol(LVRoot)

        :param int mbsize: partition size
        """
        self.partitioner.create('p.lxlvm', mbsize, 't.lvm')
        self._add_to_map('root')
        self._add_to_public_id_map('kiwi_RootPart')
        self._add_to_public_id_map('kiwi_RootPartVol', 'LVRoot')

    def create_root_raid_partition(self, mbsize):
        """
        Create root partition for use with MD Raid

        Populates kiwi_RootPart(id) and kiwi_RaidPart(id) as well
        as the default raid device node at boot time which is
        configured to be kiwi_RaidDev(/dev/mdX)

        :param int mbsize: partition size
        """
        self.partitioner.create('p.lxraid', mbsize, 't.raid')
        self._add_to_map('root')
        self._add_to_public_id_map('kiwi_RootPart')
        self._add_to_public_id_map('kiwi_RaidPart')

    def create_root_readonly_partition(self, mbsize):
        """
        Create root readonly partition for use with overlayfs

        Populates kiwi_ReadOnlyPart(id), the partition is meant to
        contain a squashfs readonly filesystem. The partition size
        should be the size of the squashfs filesystem in order to
        avoid wasting disk space

        :param int mbsize: partition size
        """
        self.partitioner.create('p.lxreadonly', mbsize, 't.linux')
        self._add_to_map('readonly')
        self._add_to_public_id_map('kiwi_ROPart')

    def create_boot_partition(self, mbsize):
        """
        Create boot partition

        Populates kiwi_BootPart(id)

        :param int mbsize: partition size
        """
        self.partitioner.create('p.lxboot', mbsize, 't.linux')
        self._add_to_map('boot')
        self._add_to_public_id_map('kiwi_BootPart')

    def create_prep_partition(self, mbsize):
        """
        Create prep partition

        Populates kiwi_PrepPart(id)

        :param int mbsize: partition size
        """
        self.partitioner.create('p.prep', mbsize, 't.prep')
        self._add_to_map('prep')
        self._add_to_public_id_map('kiwi_PrepPart')

    def create_spare_partition(self, mbsize):
        """
        Create spare partition for custom use

        Populates kiwi_SparePart(id)

        :param int mbsize: partition size
        """
        self.partitioner.create('p.spare', mbsize, 't.linux')
        self._add_to_map('spare')
        self._add_to_public_id_map('kiwi_SparePart')

    def create_efi_csm_partition(self, mbsize):
        """
        Create EFI bios grub partition

        Populates kiwi_BiosGrub(id)

        :param int mbsize: partition size
        """
        self.partitioner.create('p.legacy', mbsize, 't.csm')
        self._add_to_map('efi_csm')
        self._add_to_public_id_map('kiwi_BiosGrub')

    def create_efi_partition(self, mbsize):
        """
        Create EFI partition

        Populates kiwi_EfiPart(id)

        :param int mbsize: partition size
        """
        self.partitioner.create('p.UEFI', mbsize, 't.efi')
        self._add_to_map('efi')
        self._add_to_public_id_map('kiwi_EfiPart')

    def activate_boot_partition(self):
        """
        Activate boot partition

        Note: not all Partitioner instances supports this
        """
        partition_id = None
        if 'prep' in self.partition_id_map:
            partition_id = self.partition_id_map['prep']
        elif 'boot' in self.partition_id_map:
            partition_id = self.partition_id_map['boot']
        elif 'root' in self.partition_id_map:
            partition_id = self.partition_id_map['root']

        if partition_id:
            self.partitioner.set_flag(partition_id, 'f.active')

    def create_hybrid_mbr(self):
        """
        Turn partition table into a hybrid GPT/MBR table

        Note: only GPT tables supports this
        """
        self.partitioner.set_hybrid_mbr()

    def create_mbr(self):
        """
        Turn partition table into MBR (msdos table)

        Note: only GPT tables supports this
        """
        self.partitioner.set_mbr()

    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()
                ]
            )

    def map_partitions(self):
        """
        Map/Activate partitions

        In order to access the partitions through a device node it is
        required to map them if the storage provider is loop based
        """
        if self.storage_provider.is_loop():
            Command.run(
                ['kpartx', '-s', '-a', self.storage_provider.get_device()]
            )
            self.is_mapped = True
        else:
            Command.run(
                ['partprobe', self.storage_provider.get_device()]
            )

    def get_public_partition_id_map(self):
        """
        Populated partition name to number map
        """
        return OrderedDict(
            sorted(self.public_partition_id_map.items())
        )

    def _add_to_public_id_map(self, name, value=None):
        if not value:
            value = self.partitioner.get_id()
        self.public_partition_id_map[name] = value

    def _add_to_map(self, name):
        device_node = None
        partition_number = format(self.partitioner.get_id())
        if self.storage_provider.is_loop():
            device_base = os.path.basename(self.storage_provider.get_device())
            device_node = ''.join(
                ['/dev/mapper/', device_base, 'p', partition_number]
            )
        else:
            device = self.storage_provider.get_device()
            if device[-1].isdigit():
                device_node = ''.join(
                    [device, 'p', partition_number]
                )
            else:
                device_node = ''.join(
                    [device, partition_number]
                )
        if device_node:
            self.partition_map[name] = device_node
            self.partition_id_map[name] = partition_number

    def __del__(self):
        if self.storage_provider.is_loop() and self.is_mapped:
            log.info('Cleaning up %s instance', type(self).__name__)
            try:
                for device_node in self.partition_map.values():
                    Command.run(['dmsetup', 'remove', device_node])
            except Exception:
                log.warning(
                    'cleanup of partition device maps failed, %s still busy',
                    self.storage_provider.get_device()
                )
Пример #17
0
 def test_partitioner_dasd(self, mock_dasd):
     storage_provider = Mock()
     Partitioner.new('dasd', storage_provider)
     mock_dasd.assert_called_once_with(storage_provider, None, False)
Пример #18
0
 def test_partitioner_for_arch_not_implemented(self, mock_machine):
     mock_machine.return_value = 'some-arch'
     Partitioner('foo', mock.Mock())
Пример #19
0
 def test_partitioner_gpt(self, mock_gpt):
     storage_provider = Mock()
     Partitioner.new('gpt', storage_provider)
     mock_gpt.assert_called_once_with(storage_provider, None, False)
Пример #20
0
 def test_partitioner_s390_dasd(self, mock_machine, mock_dasd):
     mock_machine.return_value = 's390'
     storage_provider = mock.Mock()
     Partitioner('dasd', storage_provider)
     mock_dasd.assert_called_once_with(storage_provider)
Пример #21
0
class Disk(DeviceProvider):
    """
    **Implements storage disk and partition table setup**

    :param string table_type: Partition table type name
    :param object storage_provider: Instance of class based on DeviceProvider
    :param int start_sector: sector number
    """
    def __init__(self, table_type, storage_provider, start_sector=None):
        # bind the underlaying block device providing class instance
        # to this object (e.g loop) if present. This is done to guarantee
        # the correct destructor order when the device should be released.
        self.storage_provider = storage_provider

        self.partition_map = {}
        self.public_partition_id_map = {}
        self.partition_id_map = {}
        self.is_mapped = False

        self.partitioner = Partitioner(table_type, storage_provider,
                                       start_sector)

        self.table_type = table_type

    def get_device(self):
        """
        Names of partition devices

        Note that the mapping requires an explicit map() call

        :return: instances of MappedDevice

        :rtype: dict
        """
        device_map = {}
        for partition_name, device_node in list(self.partition_map.items()):
            device_map[partition_name] = MappedDevice(device=device_node,
                                                      device_provider=self)
        return device_map

    def is_loop(self):
        """
        Check if storage provider is loop based

        The information is taken from the storage provider. If
        the storage provider is loop based the disk is it too

        :return: True or False

        :rtype: bool
        """
        return self.storage_provider.is_loop()

    def create_root_partition(self, mbsize):
        """
        Create root partition

        Populates kiwi_RootPart(id) and kiwi_BootPart(id) if no extra
        boot partition is requested

        :param int mbsize: partition size
        """
        self.partitioner.create('p.lxroot', mbsize, 't.linux')
        self._add_to_map('root')
        self._add_to_public_id_map('kiwi_RootPart')
        if 'kiwi_ROPart' in self.public_partition_id_map:
            self._add_to_public_id_map('kiwi_RWPart')
        if 'kiwi_BootPart' not in self.public_partition_id_map:
            self._add_to_public_id_map('kiwi_BootPart')

    def create_root_lvm_partition(self, mbsize):
        """
        Create root partition for use with LVM

        Populates kiwi_RootPart(id) and kiwi_RootPartVol(LVRoot)

        :param int mbsize: partition size
        """
        self.partitioner.create('p.lxlvm', mbsize, 't.lvm')
        self._add_to_map('root')
        self._add_to_public_id_map('kiwi_RootPart')
        self._add_to_public_id_map('kiwi_RootPartVol', 'LVRoot')

    def create_root_raid_partition(self, mbsize):
        """
        Create root partition for use with MD Raid

        Populates kiwi_RootPart(id) and kiwi_RaidPart(id) as well
        as the default raid device node at boot time which is
        configured to be kiwi_RaidDev(/dev/mdX)

        :param int mbsize: partition size
        """
        self.partitioner.create('p.lxraid', mbsize, 't.raid')
        self._add_to_map('root')
        self._add_to_public_id_map('kiwi_RootPart')
        self._add_to_public_id_map('kiwi_RaidPart')

    def create_root_readonly_partition(self, mbsize):
        """
        Create root readonly partition for use with overlayfs

        Populates kiwi_ReadOnlyPart(id), the partition is meant to
        contain a squashfs readonly filesystem. The partition size
        should be the size of the squashfs filesystem in order to
        avoid wasting disk space

        :param int mbsize: partition size
        """
        self.partitioner.create('p.lxreadonly', mbsize, 't.linux')
        self._add_to_map('readonly')
        self._add_to_public_id_map('kiwi_ROPart')

    def create_boot_partition(self, mbsize):
        """
        Create boot partition

        Populates kiwi_BootPart(id)

        :param int mbsize: partition size
        """
        self.partitioner.create('p.lxboot', mbsize, 't.linux')
        self._add_to_map('boot')
        self._add_to_public_id_map('kiwi_BootPart')

    def create_prep_partition(self, mbsize):
        """
        Create prep partition

        Populates kiwi_PrepPart(id)

        :param int mbsize: partition size
        """
        self.partitioner.create('p.prep', mbsize, 't.prep')
        self._add_to_map('prep')
        self._add_to_public_id_map('kiwi_PrepPart')

    def create_spare_partition(self, mbsize):
        """
        Create spare partition for custom use

        Populates kiwi_SparePart(id)

        :param int mbsize: partition size
        """
        self.partitioner.create('p.spare', mbsize, 't.linux')
        self._add_to_map('spare')
        self._add_to_public_id_map('kiwi_SparePart')

    def create_swap_partition(self, mbsize):
        """
        Create swap partition

        Populates kiwi_SwapPart(id)

        :param int mbsize: partition size
        """
        self.partitioner.create('p.swap', mbsize, 't.swap')
        self._add_to_map('swap')
        self._add_to_public_id_map('kiwi_SwapPart')

    def create_efi_csm_partition(self, mbsize):
        """
        Create EFI bios grub partition

        Populates kiwi_BiosGrub(id)

        :param int mbsize: partition size
        """
        self.partitioner.create('p.legacy', mbsize, 't.csm')
        self._add_to_map('efi_csm')
        self._add_to_public_id_map('kiwi_BiosGrub')

    def create_efi_partition(self, mbsize):
        """
        Create EFI partition

        Populates kiwi_EfiPart(id)

        :param int mbsize: partition size
        """
        self.partitioner.create('p.UEFI', mbsize, 't.efi')
        self._add_to_map('efi')
        self._add_to_public_id_map('kiwi_EfiPart')

    def activate_boot_partition(self):
        """
        Activate boot partition

        Note: not all Partitioner instances supports this
        """
        partition_id = None
        if 'prep' in self.partition_id_map:
            partition_id = self.partition_id_map['prep']
        elif 'boot' in self.partition_id_map:
            partition_id = self.partition_id_map['boot']
        elif 'root' in self.partition_id_map:
            partition_id = self.partition_id_map['root']

        if partition_id:
            self.partitioner.set_flag(partition_id, 'f.active')

    def create_hybrid_mbr(self):
        """
        Turn partition table into a hybrid GPT/MBR table

        Note: only GPT tables supports this
        """
        self.partitioner.set_hybrid_mbr()

    def create_mbr(self):
        """
        Turn partition table into MBR (msdos table)

        Note: only GPT tables supports this
        """
        self.partitioner.set_mbr()

    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()])

    def map_partitions(self):
        """
        Map/Activate partitions

        In order to access the partitions through a device node it is
        required to map them if the storage provider is loop based
        """
        if self.storage_provider.is_loop():
            Command.run(
                ['kpartx', '-s', '-a',
                 self.storage_provider.get_device()])
            self.is_mapped = True
        else:
            Command.run(['partprobe', self.storage_provider.get_device()])

    def get_public_partition_id_map(self):
        """
        Populated partition name to number map
        """
        return OrderedDict(sorted(self.public_partition_id_map.items()))

    def _add_to_public_id_map(self, name, value=None):
        if not value:
            value = self.partitioner.get_id()
        self.public_partition_id_map[name] = value

    def _add_to_map(self, name):
        device_node = None
        partition_number = format(self.partitioner.get_id())
        if self.storage_provider.is_loop():
            device_base = os.path.basename(self.storage_provider.get_device())
            device_node = ''.join(
                ['/dev/mapper/', device_base, 'p', partition_number])
        else:
            device = self.storage_provider.get_device()
            if device[-1].isdigit():
                device_node = ''.join([device, 'p', partition_number])
            else:
                device_node = ''.join([device, partition_number])
        if device_node:
            self.partition_map[name] = device_node
            self.partition_id_map[name] = partition_number

    def __del__(self):
        if self.storage_provider.is_loop() and self.is_mapped:
            log.info('Cleaning up %s instance', type(self).__name__)
            try:
                for device_node in self.partition_map.values():
                    Command.run(['dmsetup', 'remove', device_node])
            except Exception:
                log.warning(
                    'cleanup of partition device maps failed, %s still busy',
                    self.storage_provider.get_device())
Пример #22
0
 def test_partitioner_arm_msdos(self, mock_machine, mock_dos):
     mock_machine.return_value = 'armv7l'
     storage_provider = mock.Mock()
     Partitioner('msdos', storage_provider)
     mock_dos.assert_called_once_with(storage_provider)
Пример #23
0
 def test_partitioner_for_arch_not_implemented(self, mock_machine):
     mock_machine.return_value = 'some-arch'
     with raises(KiwiPartitionerSetupError):
         Partitioner('foo', Mock())
Пример #24
0
 def test_partitioner_for_arch_not_implemented(self):
     with raises(KiwiPartitionerSetupError):
         Partitioner.new('foo', Mock())
Пример #25
0
 def test_partitioner_dasd_with_custom_start_sector(self, mock_dasd):
     storage_provider = Mock()
     with self._caplog.at_level(logging.WARNING):
         Partitioner.new('dasd', storage_provider, 4096)
         mock_dasd.assert_called_once_with(storage_provider, None, False)