diff options
author | Blair Zajac <blair@orcaware.com> | 2013-03-12 09:00:48 -0400 |
---|---|---|
committer | Scott Moser <smoser@ubuntu.com> | 2013-03-12 09:00:48 -0400 |
commit | fd938d20c62320c9068a9f517ccc465f561e7499 (patch) | |
tree | 3b3e1480b561f2e328c723fc586140ff6b712b48 | |
parent | cad31255aff2b3b7d0d640bf58649aeca43b7263 (diff) | |
parent | 64c8f384ffb81f34357f2b917b08b7851c470552 (diff) | |
download | vyos-cloud-init-fd938d20c62320c9068a9f517ccc465f561e7499.tar.gz vyos-cloud-init-fd938d20c62320c9068a9f517ccc465f561e7499.zip |
refactor get_mount_info and add tests
1) Refactor util.get_mount_info() to facilitate unit testing.
2) Add unit tests for /proc/$$/mountinfo parsing.
-rw-r--r-- | cloudinit/util.py | 88 | ||||
-rw-r--r-- | tests/unittests/test_util.py | 95 |
2 files changed, 149 insertions, 34 deletions
diff --git a/cloudinit/util.py b/cloudinit/util.py index 709d5cca..a1f6e004 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -1576,44 +1576,29 @@ def expand_package_list(version_fmt, pkgs): return pkglist -def get_mount_info(path, log=LOG): - # Use /proc/$$/mountinfo to find the device where path is mounted. - # This is done because with a btrfs filesystem using os.stat(path) - # does not return the ID of the device. - # - # Here, / has a device of 18 (decimal). - # - # $ stat / - # File: '/' - # Size: 234 Blocks: 0 IO Block: 4096 directory - # Device: 12h/18d Inode: 256 Links: 1 - # Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) - # Access: 2013-01-13 07:31:04.358011255 +0000 - # Modify: 2013-01-13 18:48:25.930011255 +0000 - # Change: 2013-01-13 18:48:25.930011255 +0000 - # Birth: - - # - # Find where / is mounted: - # - # $ mount | grep ' / ' - # /dev/vda1 on / type btrfs (rw,subvol=@,compress=lzo) - # - # And the device ID for /dev/vda1 is not 18: - # - # $ ls -l /dev/vda1 - # brw-rw---- 1 root disk 253, 1 Jan 13 08:29 /dev/vda1 - # - # So use /proc/$$/mountinfo to find the device underlying the - # input path. +def parse_mount_info(path, mountinfo_lines, log=LOG): + """Return the mount information for PATH given the lines from + /proc/$$/mountinfo.""" + path_elements = [e for e in path.split('/') if e] devpth = None fs_type = None match_mount_point = None match_mount_point_elements = None - mountinfo_path = '/proc/%s/mountinfo' % os.getpid() - for line in load_file(mountinfo_path).splitlines(): + for i, line in enumerate(mountinfo_lines): parts = line.split() + # Completely fail if there is anything in any line that is + # unexpected, as continuing to parse past a bad line could + # cause an incorrect result to be returned, so it's better + # return nothing than an incorrect result. + + # The minimum number of elements in a valid line is 10. + if len(parts) < 10: + log.debug("Line %d has two few columns (%d): %s", + i + 1, len(parts), line) + return None + mount_point = parts[4] mount_point_elements = [e for e in mount_point.split('/') if e] @@ -1638,8 +1623,8 @@ def get_mount_info(path, log=LOG): try: i = parts.index('-') except ValueError: - log.debug("Did not find column named '-' in %s", - mountinfo_path) + log.debug("Did not find column named '-' in line %d: %s", + i + 1, line) return None # Get the path to the device. @@ -1647,7 +1632,8 @@ def get_mount_info(path, log=LOG): fs_type = parts[i + 1] devpth = parts[i + 2] except IndexError: - log.debug("Too few columns in %s after '-' column", mountinfo_path) + log.debug("Too few columns after '-' column in line %d: %s", + i + 1, line) return None match_mount_point = mount_point @@ -1657,3 +1643,37 @@ def get_mount_info(path, log=LOG): return (devpth, fs_type, match_mount_point) else: return None + + +def get_mount_info(path, log=LOG): + # Use /proc/$$/mountinfo to find the device where path is mounted. + # This is done because with a btrfs filesystem using os.stat(path) + # does not return the ID of the device. + # + # Here, / has a device of 18 (decimal). + # + # $ stat / + # File: '/' + # Size: 234 Blocks: 0 IO Block: 4096 directory + # Device: 12h/18d Inode: 256 Links: 1 + # Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) + # Access: 2013-01-13 07:31:04.358011255 +0000 + # Modify: 2013-01-13 18:48:25.930011255 +0000 + # Change: 2013-01-13 18:48:25.930011255 +0000 + # Birth: - + # + # Find where / is mounted: + # + # $ mount | grep ' / ' + # /dev/vda1 on / type btrfs (rw,subvol=@,compress=lzo) + # + # And the device ID for /dev/vda1 is not 18: + # + # $ ls -l /dev/vda1 + # brw-rw---- 1 root disk 253, 1 Jan 13 08:29 /dev/vda1 + # + # So use /proc/$$/mountinfo to find the device underlying the + # input path. + mountinfo_path = '/proc/%s/mountinfo' % os.getpid() + lines = load_file(mountinfo_path).splitlines() + return parse_mount_info(path, lines, log) diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py index 02611581..7ff9a57f 100644 --- a/tests/unittests/test_util.py +++ b/tests/unittests/test_util.py @@ -248,4 +248,99 @@ class TestLoadYaml(TestCase): myobj) +class TestMountinfoParsing(TestCase): + precise_ext4_mountinfo = \ +"""15 20 0:14 / /sys rw,nosuid,nodev,noexec,relatime - sysfs sysfs rw +16 20 0:3 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +17 20 0:5 / /dev rw,relatime - devtmpfs udev rw,size=16422216k,nr_inodes=4105554,mode=755 +18 17 0:11 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=000 +19 20 0:15 / /run rw,nosuid,relatime - tmpfs tmpfs rw,size=6572812k,mode=755 +20 1 252:1 / / rw,relatime - ext4 /dev/mapper/vg0-root rw,errors=remount-ro,data=ordered +21 15 0:16 / /sys/fs/cgroup rw,relatime - tmpfs cgroup rw,mode=755 +22 15 0:17 / /sys/fs/fuse/connections rw,relatime - fusectl none rw +23 15 0:6 / /sys/kernel/debug rw,relatime - debugfs none rw +25 15 0:10 / /sys/kernel/security rw,relatime - securityfs none rw +26 19 0:19 / /run/lock rw,nosuid,nodev,noexec,relatime - tmpfs none rw,size=5120k +27 19 0:20 / /run/shm rw,nosuid,nodev,relatime - tmpfs none rw +28 19 0:21 / /run/user rw,nosuid,nodev,noexec,relatime - tmpfs none rw,size=102400k,mode=755 +24 21 0:18 / /sys/fs/cgroup/cpuset rw,relatime - cgroup cgroup rw,cpuset +29 21 0:22 / /sys/fs/cgroup/cpu rw,relatime - cgroup cgroup rw,cpu +30 21 0:23 / /sys/fs/cgroup/cpuacct rw,relatime - cgroup cgroup rw,cpuacct +31 21 0:24 / /sys/fs/cgroup/memory rw,relatime - cgroup cgroup rw,memory +32 21 0:25 / /sys/fs/cgroup/devices rw,relatime - cgroup cgroup rw,devices +33 21 0:26 / /sys/fs/cgroup/freezer rw,relatime - cgroup cgroup rw,freezer +34 21 0:27 / /sys/fs/cgroup/blkio rw,relatime - cgroup cgroup rw,blkio +35 21 0:28 / /sys/fs/cgroup/perf_event rw,relatime - cgroup cgroup rw,perf_event +36 20 9:0 / /boot rw,relatime - ext4 /dev/md0 rw,data=ordered +37 16 0:29 / /proc/sys/fs/binfmt_misc rw,nosuid,nodev,noexec,relatime - binfmt_misc binfmt_misc rw +39 28 0:30 / /run/user/foobar/gvfs rw,nosuid,nodev,relatime - fuse.gvfsd-fuse gvfsd-fuse rw,user_id=1000,group_id=1000""" + + raring_btrfs_mountinfo = \ +"""15 20 0:14 / /sys rw,nosuid,nodev,noexec,relatime - sysfs sysfs rw +16 20 0:3 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +17 20 0:5 / /dev rw,relatime - devtmpfs udev rw,size=865556k,nr_inodes=216389,mode=755 +18 17 0:11 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=000 +19 20 0:15 / /run rw,nosuid,relatime - tmpfs tmpfs rw,size=348196k,mode=755 +20 1 0:16 /@ / rw,relatime - btrfs /dev/vda1 rw,compress=lzo,space_cache +21 15 0:19 / /sys/fs/fuse/connections rw,relatime - fusectl none rw +22 15 0:6 / /sys/kernel/debug rw,relatime - debugfs none rw +23 15 0:10 / /sys/kernel/security rw,relatime - securityfs none rw +24 19 0:20 / /run/lock rw,nosuid,nodev,noexec,relatime - tmpfs none rw,size=5120k +25 19 0:21 / /run/shm rw,nosuid,nodev,relatime - tmpfs none rw +26 19 0:22 / /run/user rw,nosuid,nodev,noexec,relatime - tmpfs none rw,size=102400k,mode=755 +27 20 0:16 /@home /home rw,relatime - btrfs /dev/vda1 rw,compress=lzo,space_cache""" + + def test_invalid_mountinfo(self): + line = "20 1 252:1 / / rw,relatime - ext4 /dev/mapper/vg0-root rw,errors=remount-ro,data=ordered" + elements = line.split() + for i in range(len(elements) + 1): + lines = [' '.join(elements[0:i])] + if i < 10: + expected = None + else: + expected = ('/dev/mapper/vg0-root', 'ext4', '/') + self.assertEqual(expected, util.parse_mount_info('/', lines)) + + def test_precise_ext4_root(self): + lines = TestMountinfoParsing.precise_ext4_mountinfo.splitlines() + + expected = ('/dev/mapper/vg0-root', 'ext4', '/') + self.assertEqual(expected, util.parse_mount_info('/', lines)) + self.assertEqual(expected, util.parse_mount_info('/usr', lines)) + self.assertEqual(expected, util.parse_mount_info('/usr/bin', lines)) + + expected = ('/dev/md0', 'ext4', '/boot') + self.assertEqual(expected, util.parse_mount_info('/boot', lines)) + self.assertEqual(expected, util.parse_mount_info('/boot/grub', lines)) + + expected = ('/dev/mapper/vg0-root', 'ext4', '/') + self.assertEqual(expected, util.parse_mount_info('/home', lines)) + self.assertEqual(expected, util.parse_mount_info('/home/me', lines)) + + expected = ('tmpfs', 'tmpfs', '/run') + self.assertEqual(expected, util.parse_mount_info('/run', lines)) + + expected = ('none', 'tmpfs', '/run/lock') + self.assertEqual(expected, util.parse_mount_info('/run/lock', lines)) + + def test_raring_btrfs_root(self): + lines = TestMountinfoParsing.raring_btrfs_mountinfo.splitlines() + + expected = ('/dev/vda1', 'btrfs', '/') + self.assertEqual(expected, util.parse_mount_info('/', lines)) + self.assertEqual(expected, util.parse_mount_info('/usr', lines)) + self.assertEqual(expected, util.parse_mount_info('/usr/bin', lines)) + self.assertEqual(expected, util.parse_mount_info('/boot', lines)) + self.assertEqual(expected, util.parse_mount_info('/boot/grub', lines)) + + expected = ('/dev/vda1', 'btrfs', '/home') + self.assertEqual(expected, util.parse_mount_info('/home', lines)) + self.assertEqual(expected, util.parse_mount_info('/home/me', lines)) + + expected = ('tmpfs', 'tmpfs', '/run') + self.assertEqual(expected, util.parse_mount_info('/run', lines)) + + expected = ('none', 'tmpfs', '/run/lock') + self.assertEqual(expected, util.parse_mount_info('/run/lock', lines)) + # vi: ts=4 expandtab |