Ejemplo n.º 1
0
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])
Ejemplo n.º 2
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)
Ejemplo n.º 3
0
    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()
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
    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()
Ejemplo n.º 6
0
    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()
Ejemplo n.º 7
0
 def mount_state(self):
     """ Mount main state partition on self.state_fs. """
     self.state_fs = util.TempMount(
         self.state_device,
         'state-',
     )
Ejemplo n.º 8
0
 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
Ejemplo n.º 9
0
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"
Ejemplo n.º 10
0
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"
Ejemplo n.º 11
0
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)