Example #1
0
    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)
Example #3
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()
Example #4
0
    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
Example #5
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"