Example #1
0
    def _check_mount_fstab_partitions(self,
                                      os_root_dir,
                                      skip_mounts=["/", "/boot"],
                                      skip_filesystems=["swap"],
                                      mountable_lvm_devs=None):
        """ Reads the contents of /etc/fstab from the VM's root directory and
        tries to mount all clearly identified (by UUID or path) filesystems.
        Returns the list of the new directories which were mounted.
        param: skip_mounts: list(str()): list of directories (inside the
        chroot) to not try to mount.
        param: skip_filesystems: list(str()): list of filesystem types to skip
        mounting entirely
        param: mountable_lvm_devs: list(str()): list of LVM device paths which
        exist and are mountable should they appear in /etc/fstab
        """
        new_mountpoints = []
        etc_fstab_path = os.path.join(os_root_dir, "etc/fstab")
        if not utils.test_ssh_path(self._ssh, etc_fstab_path):
            LOG.warn(
                "etc/fstab file not found in '%s'. Cannot mount non-root dirs",
                os_root_dir)
            return []

        etc_fstab_raw = utils.read_ssh_file(self._ssh, etc_fstab_path)
        etc_fstab = etc_fstab_raw.decode('utf-8')

        LOG.debug("Mounting non-root partitions from fstab file: %s" %
                  (base64.b64encode(etc_fstab_raw)))

        # dictionary of the form {"mountpoint":
        #   {"device": "<dev>", "filesystem": "<fs>", "options": "<opts>"}}
        mounts = {}
        # fstab entry format:
        # <device> <mountpoint> <filesystem> <options> <dump> <fsck>
        fstab_entry_regex = (
            "^(\s*([^#\s]+)\s+(\S+)\s+(\S+)\s+(\S+)(\s+(\d)(\s+(\d))?)?\s*)$")
        for line in etc_fstab.splitlines():
            match = re.match(fstab_entry_regex, line)

            if not match:
                LOG.warn("Skipping unparseable /etc/fstab line: '%s'", line)
                continue

            device = match.group(2)
            mountpoint = match.group(3)
            if mountpoint in mounts:
                raise exception.CoriolisException(
                    "Mountpoint '%s' appears to be mounted twice in "
                    "'/etc/fstab'" % mountpoint)

            mounts[mountpoint] = {
                "device": device,
                "filesystem": match.group(4),
                "options": match.group(5)
            }
        # NOTE: we sort the mountpoints based on length to ensure
        # they get mounted in the correct order:
        mounts = collections.OrderedDict(
            (mountpoint, mounts[mountpoint])
            for mountpoint in sorted(mounts, key=len))

        # regexes for supported fstab device references:
        uuid_char_regex = "[0-9a-fA-F]"
        fs_uuid_regex = ("%(char)s{8}-%(char)s{4}-%(char)s{4}-"
                         "%(char)s{4}-%(char)s{12}") % {
                             "char": uuid_char_regex
                         }
        fs_uuid_entry_regex = "^(UUID=%s)$" % fs_uuid_regex
        by_uuid_entry_regex = "^(/dev/disk/by-uuid/%s)$" % fs_uuid_regex
        if not mountable_lvm_devs:
            mountable_lvm_devs = []
        device_paths = self._get_device_file_paths(mountable_lvm_devs)
        for (mountpoint, details) in mounts.items():
            device = details['device']
            if (re.match(fs_uuid_entry_regex, device) is None
                    and re.match(by_uuid_entry_regex, device) is None):
                device_file_path = self._get_symlink_target(device)
                if device not in mountable_lvm_devs and (device_file_path
                                                         not in device_paths):
                    LOG.warn(
                        "Found fstab entry for dir %s which references device "
                        "%s. Only LVM volumes or devices referenced by UUID=* "
                        "or /dev/disk/by-uuid/* notation are supported. "
                        "Devicemapper paths for LVM volumes are also "
                        "supported. Skipping mounting directory." %
                        (mountpoint, device))
                    continue
            if mountpoint in skip_mounts:
                LOG.debug("Skipping undesired mount: %s: %s", mountpoint,
                          details)
                continue
            if details["filesystem"] in skip_filesystems:
                LOG.debug("Skipping mounting undesired FS for device %s: %s",
                          device, details)
                continue

            LOG.debug("Attempting to mount fstab device: %s: %s", device,
                      details)
            # NOTE: `mountpoint` should always be an absolute path:
            chroot_mountpoint = "%s%s" % (os_root_dir, mountpoint)
            mountcmd = "sudo mount -t %s -o %s %s '%s'" % (
                details["filesystem"], details["options"], device,
                chroot_mountpoint)
            try:
                self._exec_cmd(mountcmd)
                new_mountpoints.append(chroot_mountpoint)
            except Exception:
                LOG.warn(
                    "Failed to run fstab filesystem mount command: '%s'. "
                    "Skipping mount. Error details: %s", mountcmd,
                    utils.get_exception_details())

        if new_mountpoints:
            LOG.info(
                "The following new /etc/fstab entries were successfully "
                "mounted: %s", new_mountpoints)

        return new_mountpoints
Example #2
0
 def _read_file(self, chroot_path):
     path = os.path.join(self._os_root_dir, chroot_path)
     return utils.read_ssh_file(self._ssh, path)
Example #3
0
 def _read_file(self, chroot_path):
     path = os.path.join(self._os_root_dir, chroot_path)
     return utils.read_ssh_file(self._ssh, path)