class Disk(DeviceProvider): """ implement storage disk and partition table setup """ 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.partition_id_map = {} self.partition_id = {} self.is_mapped = False self.partitioner = Partitioner( table_type, storage_provider ) self.table_type = table_type def get_device(self): """ return names of partition devices, note that the mapping requires an explicit map() call """ device_map = {} for partition_name, device_node in self.partition_map.iteritems(): device_map[partition_name] = MappedDevice( device=device_node, device_provider=self ) return device_map def is_loop(self): """ returns if this disk is based on a loop device. 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): self.partitioner.create('p.lxroot', mbsize, 't.linux') self.__add_to_map('root') self.__add_to_id_map('kiwi_RootPart') if 'kiwi_BootPart' not in self.partition_id_map: self.__add_to_id_map('kiwi_BootPart') def create_root_lvm_partition(self, mbsize): self.partitioner.create('p.lxlvm', mbsize, 't.lvm') self.__add_to_map('root') self.__add_to_id_map('kiwi_RootPart') self.__add_to_id_map('kiwi_RootPartVol', 'LVRoot') def create_root_raid_partition(self, mbsize): self.partitioner.create('p.lxraid', mbsize, 't.raid') self.__add_to_map('root') self.__add_to_id_map('kiwi_RootPart') self.__add_to_id_map('kiwi_RaidPart') self.__add_to_id_map('kiwi_RaidDev', '/dev/md0') def create_boot_partition(self, mbsize): self.partitioner.create('p.lxboot', mbsize, 't.linux') self.__add_to_map('boot') self.__add_to_id_map('kiwi_BootPart') def create_efi_csm_partition(self, mbsize): self.partitioner.create('p.legacy', mbsize, 't.csm') self.__add_to_map('efi_csm') self.__add_to_id_map('kiwi_BiosGrub') def create_efi_partition(self, mbsize): self.partitioner.create('p.UEFI', mbsize, 't.efi') self.__add_to_map('efi') self.__add_to_id_map('kiwi_JumpPart') def activate_boot_partition(self): partition_id = None if 'boot' in self.partition_id: partition_id = self.partition_id['boot'] elif 'root' in self.partition_id: partition_id = self.partition_id['root'] if partition_id: self.partitioner.set_flag(partition_id, 'f.active') 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() ] ) Command.run( ['bash', '-c', bash_command] ) else: log.debug('Initialize %s disk', self.table_type) Command.run( [ 'sgdisk', '--zap-all', self.storage_provider.get_device() ] ) def map_partitions(self): 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_partition_id_map(self): return OrderedDict( sorted(self.partition_id_map.items()) ) def __add_to_id_map(self, name, value=None): if not value: value = self.partitioner.get_id() self.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[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: Command.run( ['kpartx', '-s', '-d', self.storage_provider.get_device()] ) except Exception: log.warning( 'cleanup of partition device maps failed, %s still busy', self.storage_provider.get_device() )