Browse Source

Merge pull request #63 from gabriel-samfira/fix-mount-os

Fix mount os
Nashwan Azhari 6 years ago
parent
commit
8da4ad0d4b
1 changed files with 101 additions and 46 deletions
  1. 101 46
      coriolis/osmorphing/osmount/base.py

+ 101 - 46
coriolis/osmorphing/osmount/base.py

@@ -1,5 +1,6 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
+# pylint: disable=anomalous-backslash-in-string
 
 import abc
 import base64
@@ -244,7 +245,7 @@ class BaseLinuxOSMountTools(BaseSSHOSMountTools):
             try:
                 self._exec_cmd(mountcmd)
                 new_mountpoints.append(chroot_mountpoint)
-            except Exception as ex:
+            except Exception:
                 LOG.warn(
                     "Failed to run fstab filesystem mount command: '%s'. "
                     "Skipping mount. Error details: %s",
@@ -298,6 +299,100 @@ class BaseLinuxOSMountTools(BaseSSHOSMountTools):
         LOG.info("Volume block devices: %s", volume_devs)
         return volume_devs
 
+    def _find_dev_with_contents(self, devices, all_files=None,
+                                one_of_files=None):
+        if all_files and one_of_files:
+            raise exception.CoriolisException(
+                "all_files and one_of_files are mutually exclusive")
+        dev_name = None
+        for dev_path in devices:
+            dirs = None
+            tmp_dir = self._exec_cmd('mktemp -d').decode().split('\n')[0]
+            try:
+                self._exec_cmd('sudo mount %s %s' % (dev_path, tmp_dir))
+                # NOTE: it's possible that the device was mounted successfully
+                # but an I/O error occurs later along the line:
+                dirs = self._exec_cmd('ls %s' % tmp_dir).decode().split('\n')
+            except Exception:
+                self._event_manager.progress_update(
+                    "Failed to mount and scan device '%s'" % dev_path)
+                LOG.warn(
+                    "Failed to mount and scan device '%s':\n%s",
+                    dev_path, utils.get_exception_details())
+                utils.ignore_exceptions(self._exec_cmd)(
+                    "sudo umount %s" % tmp_dir
+                )
+                utils.ignore_exceptions(self._exec_cmd)(
+                    "sudo rmdir %s" % tmp_dir
+                )
+                continue
+
+            LOG.debug("Contents of device %s:\n%s", dev_path, dirs)
+
+            if all_files and dirs:
+                common = [i if i in dirs else None for i in all_files]
+                if not all(common):
+                    self._exec_cmd('sudo umount %s' % tmp_dir)
+                    continue
+
+                dev_name = dev_path
+                self._exec_cmd('sudo umount %s' % tmp_dir)
+            elif one_of_files and dirs:
+                common = [i for i in one_of_files if i in dirs]
+                if len(common) > 0:
+                    dev_name = dev_path
+                    self._exec_cmd('sudo umount %s' % tmp_dir)
+                    break
+            else:
+                self._exec_cmd('sudo umount %s' % tmp_dir)
+                continue
+
+        return dev_name
+
+    def _find_and_mount_root(self, devices):
+        files = ["etc", "bin", "sbin", "boot"]
+        os_root_dir = None
+        os_root_device = self._find_dev_with_contents(
+            devices, all_files=files)
+
+        if os_root_device is None:
+            raise exception.OperatingSystemNotFound(
+                "root partition not found")
+
+        try:
+            tmp_dir = self._exec_cmd('mktemp -d').decode().split('\n')[0]
+            self._exec_cmd('sudo mount %s %s' % (os_root_device, tmp_dir))
+            os_root_dir = tmp_dir
+        except Exception:
+            self._event_manager.progress_update(
+                "Failed to mount root device '%s'" % os_root_device)
+            LOG.warn(
+                "Failed to mount root device '%s':\n%s",
+                os_root_device, utils.get_exception_details())
+            utils.ignore_exceptions(self._exec_cmd)(
+                "sudo umount %s" % tmp_dir
+            )
+            utils.ignore_exceptions(self._exec_cmd)(
+                "sudo rmdir %s" % tmp_dir
+            )
+            raise
+
+        for directory in ['proc', 'sys', 'dev', 'run']:
+            mount_dir = os.path.join(os_root_dir, directory)
+            if not utils.test_ssh_path(self._ssh, mount_dir):
+                LOG.info(
+                    "No '%s' directory in mounted OS. Skipping mount.",
+                    directory)
+                continue
+            self._exec_cmd(
+                'sudo mount -o bind /%(dir)s/ %(mount_dir)s' %
+                {'dir': directory, 'mount_dir': mount_dir})
+
+        if os_root_device in devices:
+            devices.remove(os_root_device)
+
+        return os_root_dir, os_root_device
+
     def mount_os(self):
         dev_paths = []
         mounted_devs = self._get_mounted_devices()
@@ -340,43 +435,12 @@ class BaseLinuxOSMountTools(BaseSSHOSMountTools):
                     utils.check_fs(self._ssh, fs_type, dev_path)
                 dev_paths_to_mount.append(dev_path)
 
-        os_boot_device = None
-        os_root_device = None
-        os_root_dir = None
-        for dev_path in dev_paths_to_mount:
-            dirs = None
-            tmp_dir = self._exec_cmd('mktemp -d').decode().split('\n')[0]
-            try:
-                self._exec_cmd('sudo mount %s %s' % (dev_path, tmp_dir))
-                # NOTE: it's possible that the device was mounted successfully
-                # but an I/O error occurs later along the line:
-                dirs = self._exec_cmd('ls %s' % tmp_dir).decode().split('\n')
-            except Exception:
-                self._event_manager.progress_update(
-                    "Failed to mount and scan device '%s'" % dev_path)
-                LOG.warn(
-                    "Failed to mount and scan device '%s':\n%s",
-                    dev_path, utils.get_exception_details())
-                continue
-
-            LOG.debug("Contents of device %s:\n%s", dev_path, dirs)
+        os_root_dir, os_root_device = self._find_and_mount_root(
+            dev_paths_to_mount)
 
-            # TODO(alexpilotti): better ways to check for a linux root?
-            if (not os_root_dir and 'etc' in dirs and 'bin' in dirs and
-                    'sbin' in dirs):
-                os_root_dir = tmp_dir
-                os_root_device = dev_path
-                LOG.info("OS root device: %s", dev_path)
-                continue
-            elif (not os_boot_device and ('grub' in dirs or 'grub2' in dirs)):
-                os_boot_device = dev_path
-                LOG.info("OS boot device: %s", dev_path)
-                self._exec_cmd('sudo umount %s' % tmp_dir)
-            else:
-                self._exec_cmd('sudo umount %s' % tmp_dir)
-
-        if not os_root_dir:
-            raise exception.OperatingSystemNotFound("root partition not found")
+        grub_dirs = ["grub", "grub2"]
+        os_boot_device = self._find_dev_with_contents(
+            dev_paths_to_mount, one_of_files=grub_dirs)
 
         if os_boot_device:
             LOG.debug("Mounting boot device '%s'", os_boot_device)
@@ -388,15 +452,6 @@ class BaseLinuxOSMountTools(BaseSSHOSMountTools):
         self._check_mount_fstab_partitions(
             os_root_dir, mountable_lvm_devs=lvm_devs)
 
-        for dir in set(dirs).intersection(['proc', 'sys', 'dev', 'run']):
-            mount_dir = os.path.join(os_root_dir, dir)
-            if not utils.test_ssh_path(self._ssh, mount_dir):
-                LOG.info(
-                    "No '%s' directory in mounted OS. Skipping mount.", dir)
-                continue
-            self._exec_cmd(
-                'sudo mount -o bind /%(dir)s/ %(mount_dir)s' %
-                {'dir': dir, 'mount_dir': mount_dir})
         return os_root_dir, os_root_device
 
     def dismount_os(self, root_dir):