def setUpClass(cls): cls.backing_store = "/tmp/disk.img" cls.device = "/dev/loop0" cls.mount = "/tmp/dattobd" cls.kmod = kmod.Module("../src/dattobd.ko") cls.kmod.load(debug=1) util.dd("/dev/zero", cls.backing_store, 256, bs="1M") util.loop_create(cls.device, cls.backing_store) util.mkfs(cls.device) os.makedirs(cls.mount, exist_ok=True) util.mount(cls.device, cls.mount)
def setUpClass(cls): cls.minor = randint(0, 23) r = randint(0, 999) cls.mount = "/tmp/elastio-snap_{0:03d}".format(r) cls.kmod = kmod.Module("../src/elastio-snap.ko") cls.kmod.load(debug=1) if os.getenv('TEST_DEVICE'): cls.device = os.getenv('TEST_DEVICE') dev_size = int( subprocess.check_output("blockdev --getsize64 %s" % cls.device, shell=True, text=True)) // 1024**2 util.dd("/dev/zero", cls.device, dev_size, bs="1M") else: cls.backing_store = "/tmp/disk_{0:03d}.img".format(r) util.dd("/dev/zero", cls.backing_store, 256, bs="1M") cls.device = util.loop_create(cls.backing_store) util.mkfs(cls.device) os.makedirs(cls.mount, exist_ok=True) util.mount(cls.device, cls.mount)
def doBackup(self, progress_callback, target_disk, backup_partnum, boot_partnum, storage_partnum, logs_partnum, partition_table_type): tool = PartitionTool(target_disk) boot_part = tool.getPartition(boot_partnum) boot_device = partitionDevice(target_disk, boot_partnum) if boot_part else None logs_partition = tool.getPartition(logs_partnum) # Check if possible to create new partition layout, increasing the size, using plugin result if self.safe2upgrade and logs_partition is None and partition_table_type == constants.PARTITION_GPT: if storage_partnum > 0: # Get current Volume Group rc, out = util.runCmd2( ['pvs', '-o', 'pv_name,vg_name', '--noheadings'], with_stdout=True) vgs_list = out.strip().splitlines() target_dev = getMajMin(target_disk) self.vgs_output = [ i for i in vgs_list if diskutil.parentdev_from_devpath( i.strip().split()[0]) == target_dev ] if self.vgs_output: self.vgs_output = self.vgs_output[0] self.vgs_output = self.vgs_output.split()[1] self.vgs_output = self.vgs_output.strip() # Remove current Volume Group util.runCmd2(['vgremove', '-f', self.vgs_output]) # Remove LVM Phisical Volume storage_part = partitionDevice(target_disk, storage_partnum) util.runCmd2(['pvremove', storage_part]) # Delete LVM partition tool.deletePartition(storage_partnum) # Resize backup partition tool.resizePartition(number=backup_partnum, sizeBytes=constants.backup_size * 2**20) # Write partition table tool.commit(log=True) # format the backup partition: backup_partition = partitionDevice(target_disk, backup_partnum) try: util.mkfs('ext3', backup_partition) except Exception as e: raise RuntimeError( "Backup: Failed to format filesystem on %s: %s" % (backup_partition, e)) progress_callback(10) # copy the files across: primary_fs = util.TempMount(self.source.root_device, 'primary-', options=['ro'], boot_device=boot_device) try: backup_fs = util.TempMount(backup_partition, 'backup-') try: just_dirs = ['dev', 'proc', 'lost+found', 'sys'] top_dirs = os.listdir(primary_fs.mount_point) val = 10 for x in top_dirs: if x in just_dirs: path = os.path.join(backup_fs.mount_point, x) if not os.path.exists(path): os.mkdir(path, 0755) else: cmd = ['cp', '-a'] + \ [ os.path.join(primary_fs.mount_point, x) ] + \ ['%s/' % backup_fs.mount_point] if util.runCmd2(cmd) != 0: raise RuntimeError, "Backup of %s directory failed" % x val += 90 / len(top_dirs) progress_callback(val) if partition_table_type == constants.PARTITION_GPT: # save the GPT table rc, err = util.runCmd2([ "sgdisk", "-b", os.path.join(backup_fs.mount_point, '.xen-gpt.bin'), target_disk ], with_stderr=True) if rc != 0: raise RuntimeError, "Failed to save partition layout: %s" % err finally: # replace rolling pool upgrade bootloader config def replace_config(config_file, destination): src = os.path.join(backup_fs.mount_point, constants.ROLLING_POOL_DIR, config_file) if os.path.exists(src): util.runCmd2([ 'cp', '-f', src, os.path.join(backup_fs.mount_point, destination) ]) map(replace_config, ('efi-grub.cfg', 'grub.cfg', 'menu.lst', 'extlinux.conf'), ('boot/efi/EFI/xenserver/grub.cfg', 'boot/grub', 'boot/grub', 'boot')) fh = open( os.path.join(backup_fs.mount_point, '.xen-backup-partition'), 'w') fh.close() backup_fs.unmount() finally: primary_fs.unmount()
def prepareTarget(self, progress_callback, primary_disk, target_boot_mode, boot_partnum, primary_partnum, logs_partnum, swap_partnum, storage_partnum, partition_table_type, new_partition_layout): """ Modify partition layout prior to installation. """ if partition_table_type == constants.PARTITION_GPT: tool = PartitionTool(primary_disk, partition_table_type) logs_partition = tool.getPartition(logs_partnum) # Create the new partition layout (5,2,1,4,6,3) after the backup # 1 - dom0 partition # 2 - backup partition # 3 - LVM partition # 4 - Boot partition # 5 - logs partition # 6 - swap partition if self.safe2upgrade and logs_partition is None: new_partition_layout = True # Rename old dom0 and Boot (if any) partitions (10 and 11 are temporary number which let us create # dom0 and Boot partitions using the same numbers) tool.renamePartition(srcNumber=primary_partnum, destNumber=10, overwrite=False) boot_part = tool.getPartition(boot_partnum) if boot_part: tool.renamePartition(srcNumber=boot_partnum, destNumber=11, overwrite=False) # Create new bigger dom0 partition tool.createPartition(tool.ID_LINUX, sizeBytes=constants.root_size * 2**20, number=primary_partnum) # Create Boot partition if target_boot_mode == constants.TARGET_BOOT_MODE_UEFI: tool.createPartition(tool.ID_EFI_BOOT, sizeBytes=constants.boot_size * 2**20, number=boot_partnum) else: tool.createPartition(tool.ID_BIOS_BOOT, sizeBytes=constants.boot_size * 2**20, number=boot_partnum) # Create swap partition tool.createPartition(tool.ID_LINUX_SWAP, sizeBytes=constants.swap_size * 2**20, number=swap_partnum) # Create storage LVM partition if storage_partnum > 0 and self.vgs_output: tool.createPartition(tool.ID_LINUX_LVM, number=storage_partnum) # Create logs partition using the old dom0 + Boot (if any) partitions tool.deletePartition(10) if boot_part: tool.deletePartition(11) tool.createPartition(tool.ID_LINUX, sizeBytes=constants.logs_size * 2**20, startBytes=1024 * 1024, number=logs_partnum) tool.commit(log=True) if storage_partnum > 0 and self.vgs_output: storage_part = partitionDevice(primary_disk, storage_partnum) rc, out = util.runCmd2( ['pvs', '-o', 'pv_name,vg_name', '--noheadings'], with_stdout=True) vgs_list = out.strip().splitlines() primary_dev = getMajMin(primary_disk) vgs_output_wrong = [ i for i in vgs_list if diskutil.parentdev_from_devpath( i.strip().split()[0]) == primary_dev ] if vgs_output_wrong: vgs_output_wrong = vgs_output_wrong[0].strip() if ' ' in vgs_output_wrong: _, vgs_label = vgs_output_wrong.split(None, 1) util.runCmd2(['vgremove', '-f', vgs_label]) util.runCmd2(['vgcreate', self.vgs_output, storage_part]) if self.storage_type == 'ext': _, sr_uuid = self.vgs_output.split('-', 1) util.runCmd2([ 'lvcreate', '-n', sr_uuid, '-l', '100%VG', self.vgs_output ]) try: util.mkfs( 'ext3', '/dev/' + self.vgs_output + '/' + sr_uuid, ['-F']) except Exception as e: raise RuntimeError( "Backup: Failed to format filesystem on %s: %s" % (storage_part, e)) return new_partition_layout else: # If the boot partition already, exists, no partition updates are # necessary. part = tool.getPartition(boot_partnum) if part: if logs_partition is None: return new_partition_layout #FALSE else: new_partition_layout = True return new_partition_layout
def restoreFromBackup(backup, progress=lambda x: ()): """ Restore files from backup_partition to the root partition on disk. Call progress with a value between 0 and 100. Re-install bootloader. Fails if backup is not same version as the CD in use.""" label = None bootlabel = None disk = backup.root_disk tool = PartitionTool(disk) _, boot_partnum, primary_partnum, backup_partnum, logs_partnum, swap_partnum, _ = backend.inspectTargetDisk( disk, None, [], constants.PRESERVE_IF_UTILITY, True, True) backup_fs = util.TempMount(backup.partition, 'backup-', options=['ro']) inventory = util.readKeyValueFile(os.path.join(backup_fs.mount_point, constants.INVENTORY_FILE), strip_quotes=True) backup_partition_layout = inventory['PARTITION_LAYOUT'].split(',') backup_fs.unmount() xelogging.log("BACKUP DISK PARTITION LAYOUT: %s" % backup_partition_layout) backup_partition = backup.partition assert backup_partition.startswith('/dev/') assert disk.startswith('/dev/') restore_partition = partitionDevice(disk, primary_partnum) xelogging.log("Restoring to partition %s." % restore_partition) boot_part = tool.getPartition(boot_partnum) boot_device = partitionDevice(disk, boot_partnum) if boot_part else None efi_boot = boot_part and boot_part['id'] == GPTPartitionTool.ID_EFI_BOOT # determine current location of bootloader current_location = 'unknown' try: root_fs = util.TempMount(restore_partition, 'root-', options=['ro'], boot_device=boot_device) try: boot_config = bootloader.Bootloader.loadExisting( root_fs.mount_point) current_location = boot_config.location xelogging.log("Bootloader currently in %s" % current_location) finally: root_fs.unmount() except: pass # mount the backup fs backup_fs = util.TempMount(backup_partition, 'restore-backup-', options=['ro']) try: # extract the bootloader config boot_config = bootloader.Bootloader.loadExisting(backup_fs.mount_point) if boot_config.src_fmt == 'grub': raise RuntimeError, "Backup uses grub bootloader which is no longer supported - " + \ "to restore please use a version of the installer that matches the backup partition" # format the restore partition(s): try: util.mkfs(constants.rootfs_type, restore_partition) except Exception as e: raise RuntimeError("Failed to create root filesystem: %s" % e) if efi_boot: try: util.mkfs('vfat', boot_device) except Exception as e: raise RuntimeError("Failed to create boot filesystem: %s" % e) # mount restore partition: dest_fs = util.TempMount(restore_partition, 'restore-dest-') try: # copy files from the backup partition to the restore partition: objs = filter( lambda x: x not in ['lost+found', '.xen-backup-partition', '.xen-gpt.bin'], os.listdir(backup_fs.mount_point)) for i in range(len(objs)): obj = objs[i] xelogging.log("Restoring subtree %s..." % obj) progress((i * 100) / len(objs)) # Use 'cp' here because Python's copying tools are useless and # get stuck in an infinite loop when copying e.g. /dev/null. if util.runCmd2([ 'cp', '-a', os.path.join(backup_fs.mount_point, obj), dest_fs.mount_point ]) != 0: raise RuntimeError, "Failed to restore %s directory" % obj xelogging.log( "Data restoration complete. About to re-install bootloader.") location = boot_config.location m = re.search(r'root=LABEL=(\S+)', boot_config.menu[boot_config.default].kernel_args) if m: label = m.group(1) if location == constants.BOOT_LOCATION_PARTITION and current_location == constants.BOOT_LOCATION_MBR: # if bootloader in the MBR it's probably not safe to restore with it # on the partition xelogging.log( "Bootloader is currently installed to MBR, restoring to MBR instead of partition" ) location = constants.BOOT_LOCATION_MBR with open(os.path.join(backup_fs.mount_point, 'etc', 'fstab'), 'r') as fstab: for line in fstab: m = re.match(r'LABEL=(\S+)\s+/boot/efi\s', line) if m: bootlabel = m.group(1) mounts = { 'root': dest_fs.mount_point, 'boot': os.path.join(dest_fs.mount_point, 'boot') } # prepare extra mounts for installing bootloader: util.bindMount("/dev", "%s/dev" % dest_fs.mount_point) util.bindMount("/sys", "%s/sys" % dest_fs.mount_point) util.bindMount("/proc", "%s/proc" % dest_fs.mount_point) if boot_config.src_fmt == 'grub2': if efi_boot: branding = util.readKeyValueFile( os.path.join(backup_fs.mount_point, constants.INVENTORY_FILE)) branding['product-brand'] = branding['PRODUCT_BRAND'] backend.setEfiBootEntry(mounts, disk, boot_partnum, branding) else: if location == constants.BOOT_LOCATION_MBR: backend.installGrub2(mounts, disk, False) else: backend.installGrub2(mounts, restore_partition, True) else: backend.installExtLinux(mounts, disk, probePartitioningScheme(disk), location) # restore bootloader configuration dst_file = boot_config.src_file.replace(backup_fs.mount_point, dest_fs.mount_point, 1) util.assertDir(os.path.dirname(dst_file)) boot_config.commit(dst_file) finally: util.umount("%s/proc" % dest_fs.mount_point) util.umount("%s/sys" % dest_fs.mount_point) util.umount("%s/dev" % dest_fs.mount_point) dest_fs.unmount() finally: backup_fs.unmount() if not label: raise RuntimeError, "Failed to find label required for root filesystem." if efi_boot and not bootlabel: raise RuntimeError( "Failed to find label required for boot filesystem.") if util.runCmd2(['e2label', restore_partition, label]) != 0: raise RuntimeError, "Failed to label root partition" if bootlabel: if util.runCmd2(['fatlabel', boot_device, bootlabel]) != 0: raise RuntimeError, "Failed to label boot partition" if 'LOG' in backup_partition_layout: # From 7.x (new layout) to 7.x (new layout) tool.commitActivePartitiontoDisk(boot_partnum) rdm_label = label.split("-")[1] logs_part = partitionDevice(disk, logs_partnum) swap_part = partitionDevice(disk, swap_partnum) if util.runCmd2( ['e2label', logs_part, constants.logsfs_label % rdm_label]) != 0: raise RuntimeError, "Failed to label logs partition" if util.runCmd2([ 'swaplabel', '-L', constants.swap_label % rdm_label, swap_part ]) != 0: raise RuntimeError, "Failed to label swap partition"