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.""" 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_version = backup.version limit_version = product.THIS_PLATFORM_VERSION logs_partition = tool.getPartition(logs_partnum) boot_partition = tool.getPartition(boot_partnum) root_partition = partitionDevice(disk, primary_partnum) 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 = [] if 'PARTITION_LAYOUT' in inventory: # Present from XS 7.0 backup_partition_layout = inventory['PARTITION_LAYOUT'].split(',') backup_fs.unmount() (boot, _, _, _, logs) = diskutil.probeDisk(disk) xelogging.log("BACKUP DISK PARTITION LAYOUT: %s" % backup_partition_layout) if not logs[0] and boot[ 0] and not backup_partition_layout: # From 7.x (no new layout - yes Boot partition) to 6.x restoreWithoutRepartButUEFI(backup, progress) else: doRestore(backup, progress, backup_partition_layout, logs[0])
def mount_root(self, ro=True, boot_device=None): opts = None if ro: opts = ['ro'] self.root_fs = util.TempMount(self.root_device, 'root', opts, 'ext3', boot_device=boot_device)
def __init__(self, source): Upgrader.__init__(self, source) primary_fs = util.TempMount(self.source.root_device, 'primary-', options=['ro']) safe2upgrade_path = os.path.join(primary_fs.mount_point, constants.SAFE_2_UPGRADE) default_storage_conf_path = os.path.join(primary_fs.mount_point, "etc/firstboot.d/data/default-storage.conf") self.safe2upgrade = os.path.isfile(safe2upgrade_path) self.vgs_output = None self.storage_type = None if os.path.exists(default_storage_conf_path): input_data = util.readKeyValueFile(default_storage_conf_path) self.storage_type = input_data['TYPE'] primary_fs.unmount()
def findXenSourceBackups(): """Scans the host and find partitions containing backups of XenSource products. Returns a list of device node paths to partitions containing said backups. """ partitions = diskutil.getQualifiedPartitionList() backups = [] for p in partitions: b = None try: b = util.TempMount(p, 'backup-', ['ro'], 'ext3') if os.path.exists( os.path.join(b.mount_point, '.xen-backup-partition')): backups.append(XenServerBackup(p, b.mount_point)) except: pass if b: b.unmount() return backups
def completeUpgrade(self, mounts, target_disk, backup_partnum): """ Write any data back into the new filesystem as needed to follow through the upgrade. """ src_uid_map = {} dst_uid_map = {} src_gid_map = {} dst_gid_map = {} def init_id_maps(src_root, dst_root): """ Create mappings between (username and uid), and (group and gid) for the source and destination roots. """ with open(os.path.join(src_root, 'etc/passwd'), 'r') as f: for line in f: pwnam, _, uid, _ = line.split(':', 3) src_uid_map[int(uid)] = pwnam with open(os.path.join(src_root, 'etc/group'), 'r') as f: for line in f: pwnam, _, gid, _ = line.split(':', 3) src_gid_map[int(gid)] = pwnam with open(os.path.join(dst_root, 'etc/passwd'), 'r') as f: for line in f: pwnam, _, uid, _ = line.split(':', 3) dst_uid_map[pwnam] = int(uid) with open(os.path.join(dst_root, 'etc/group'), 'r') as f: for line in f: pwnam, _, gid, _ = line.split(':', 3) dst_gid_map[pwnam] = int(gid) # Copy ownership from a path in a source root to another path in a # destination root. The ownership is copied such that it is not # affected by changes in the underlying uid/gid. def copy_ownership(src_root, src_path, dst_root, dst_path): st = os.lstat('%s/%s' % (src_root, src_path)) new_uid = dst_uid_map[src_uid_map[st.st_uid]] new_gid = dst_gid_map[src_gid_map[st.st_gid]] if st.st_uid != new_uid or st.st_gid != new_gid: os.lchown('%s/%s' % (dst_root, dst_path), new_uid, new_gid) def restore_file(src_base, f, d=None): if not d: d = f src = os.path.join(src_base, f) dst = os.path.join(mounts['root'], d) if os.path.exists(src): xelogging.log("Restoring /%s" % f) util.assertDir(os.path.dirname(dst)) if os.path.isdir(src): util.runCmd2(['cp', '-a', src, os.path.dirname(dst)]) else: util.runCmd2(['cp', '-a', src, dst]) abs_f = os.path.join('/', f) abs_d = os.path.join('/', d) copy_ownership(src_base, abs_f, mounts['root'], abs_d) for dirpath, dirnames, filenames in os.walk(src): for i in dirnames + filenames: src_path = os.path.join(dirpath, i)[len(src_base):] dst_path = os.path.join(abs_d, src_path[len(abs_f) + 1:]) copy_ownership(src_base, src_path, mounts['root'], dst_path) else: xelogging.log( "WARNING: /%s did not exist in the backup image." % f) backup_volume = partitionDevice(target_disk, backup_partnum) tds = util.TempMount(backup_volume, 'upgrade-src-', options=['ro']) try: self.buildRestoreList() init_id_maps(tds.mount_point, mounts['root']) xelogging.log("Restoring preserved files") for f in self.restore_list: if isinstance(f, str): restore_file(tds.mount_point, f) elif isinstance(f, dict): if 'src' in f: assert 'dst' in f restore_file(tds.mount_point, f['src'], f['dst']) elif 'dir' in f: pat = 're' in f and f['re'] or None src_dir = os.path.join(tds.mount_point, f['dir']) if os.path.exists(src_dir): for ff in os.listdir(src_dir): fn = os.path.join(f['dir'], ff) if not pat or pat.match(fn): restore_file(tds.mount_point, fn) finally: tds.unmount()
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 mount_state(self): """ Mount main state partition on self.state_fs. """ self.state_fs = util.TempMount( self.state_device, 'state-', )
def mount_boot(self, ro=True): opts = None if ro: opts = ['ro'] self._boot_fs = util.TempMount(self.boot_device, 'boot', opts, 'ext3') self.boot_fs_mount = self._boot_fs.mount_point
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"
def doRestore(backup, progress, backup_partition_layout, has_logs_partition): backup_partition = backup.partition backup_version = backup.version 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) limit_version = product.THIS_PLATFORM_VERSION logs_partition = tool.getPartition(logs_partnum) boot_partition = tool.getPartition(boot_partnum) assert backup_partition.startswith('/dev/') assert disk.startswith('/dev/') label = None bootlabel = None if has_logs_partition and not backup_partition_layout: # From 7.x (new layout) to 6.x restore_partition = partitionDevice(disk, logs_partnum) else: restore_partition = partitionDevice(disk, primary_partnum) xelogging.log("Restoring to partition %s." % restore_partition) tool = PartitionTool(disk) 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): if util.runCmd2(['mkfs.%s' % constants.rootfs_type, restore_partition ]) != 0: raise RuntimeError, "Failed to create root filesystem" if efi_boot: if util.runCmd2(['mkfs.vfat', boot_device]) != 0: raise RuntimeError, "Failed to create boot filesystem" # 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 has_logs_partition: if not backup_partition_layout: # From 7.x (new layout) to 6.x # Delete backup, dom0, Boot and swap partitions tool.deletePartition(backup_partnum) tool.deletePartition(primary_partnum) tool.deletePartition(boot_partnum) tool.deletePartition(swap_partnum) # Rename logs partition to be n.1 tool.renamePartition(srcNumber=logs_partnum, destNumber=primary_partnum, overwrite=False) # Create 4GB backup partition tool.createPartition( tool.ID_LINUX, sizeBytes=constants.backup_size_old * 2**20, startBytes=tool.partitionEnd(primary_partnum) + tool.sectorSize, number=backup_partnum) # Commit partition table and mark dom0 disk as bootable tool.commit(log=True) tool.commitActivePartitiontoDisk(primary_partnum) xelogging.log("Bootloader restoration complete.") xelogging.log("Restore successful.") backend.writeLog(disk, primary_partnum, logs_partnum) elif '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"
def restoreWithoutRepartButUEFI(backup, progress): backup_partition = backup.partition disk = backup.root_disk assert backup_partition.startswith('/dev/') assert disk.startswith('/dev/') # Restore the partition layout backup_fs = util.TempMount(backup_partition, 'restore-backup-', options=['ro']) gpt_bin = None try: src_bin = os.path.join(backup_fs.mount_point, '.xen-gpt.bin') if os.path.exists(src_bin): gpt_bin = tempfile.mktemp() shutil.copyfile(src_bin, gpt_bin) finally: backup_fs.unmount() if gpt_bin: xelogging.log("Restoring partition layout") rc, err = util.runCmd2(["sgdisk", "-l", gpt_bin, disk], with_stderr=True) if rc != 0: raise RuntimeError, "Failed to restore partition layout: %s" % err label = None bootlabel = None _, boot_partnum, primary_partnum, backup_partnum, logs_partnum, swap_partnum, _ = backend.inspectTargetDisk( disk, None, [], constants.PRESERVE_IF_UTILITY, True, True) restore_partition = partitionDevice(disk, primary_partnum) xelogging.log("Restoring to partition %s." % restore_partition) tool = PartitionTool(disk) 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): if util.runCmd2(['mkfs.%s' % constants.rootfs_type, restore_partition ]) != 0: raise RuntimeError, "Failed to create root filesystem" if efi_boot: if util.runCmd2(['mkfs.vfat', boot_device]) != 0: raise RuntimeError, "Failed to create boot filesystem" # mount restore partition: dest_fs = util.TempMount(restore_partition, 'restore-dest-', boot_device=boot_device, boot_mount_point='/boot/efi') 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" xelogging.log("Bootloader restoration complete.") xelogging.log("Restore successful.") backend.writeLog(disk, primary_partnum, logs_partnum)