From b38cb37728df76e0529243bdce694b18ca0e1163 Mon Sep 17 00:00:00 2001 From: Andrew Gaffney Date: Thu, 8 Aug 2019 16:31:42 -0500 Subject: [PATCH] Transform octal escape sequences in mtab fields (#60122) --- changelogs/fragments/mount-facts-octal-escapes.yaml | 2 ++ lib/ansible/module_utils/facts/hardware/linux.py | 13 +++++++++++++ test/units/module_utils/facts/test_facts.py | 11 ++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/mount-facts-octal-escapes.yaml diff --git a/changelogs/fragments/mount-facts-octal-escapes.yaml b/changelogs/fragments/mount-facts-octal-escapes.yaml new file mode 100644 index 00000000000..0b2bec5cd06 --- /dev/null +++ b/changelogs/fragments/mount-facts-octal-escapes.yaml @@ -0,0 +1,2 @@ +minor_changes: +- setup - octal escape sequences are now evaluated for mount facts pulled from /etc/mtab diff --git a/lib/ansible/module_utils/facts/hardware/linux.py b/lib/ansible/module_utils/facts/hardware/linux.py index 19ca6e47999..befc2fb5e70 100644 --- a/lib/ansible/module_utils/facts/hardware/linux.py +++ b/lib/ansible/module_utils/facts/hardware/linux.py @@ -79,6 +79,9 @@ class LinuxHardware(Hardware): # regex used against mtab content to find entries that are bind mounts MTAB_BIND_MOUNT_RE = re.compile(r'.*bind.*"') + # regex used for replacing octal escape sequences + OCTAL_ESCAPE_RE = re.compile(r'\\[0-9]{3}') + def populate(self, collected_facts=None): hardware_facts = {} self.module.run_command_environ_update = {'LANG': 'C', 'LC_ALL': 'C', 'LC_NUMERIC': 'C'} @@ -460,6 +463,14 @@ class LinuxHardware(Hardware): mtab_entries.append(fields) return mtab_entries + @staticmethod + def _replace_octal_escapes_helper(match): + # Convert to integer using base8 and then convert to character + return chr(int(match.group()[1:], 8)) + + def _replace_octal_escapes(self, value): + return self.OCTAL_ESCAPE_RE.sub(self._replace_octal_escapes_helper, value) + def get_mount_info(self, mount, device, uuids): mount_size = get_mount_size(mount) @@ -485,6 +496,8 @@ class LinuxHardware(Hardware): pool = ThreadPool(processes=min(len(mtab_entries), cpu_count())) maxtime = globals().get('GATHER_TIMEOUT') or timeout.DEFAULT_GATHER_TIMEOUT for fields in mtab_entries: + # Transform octal escape sequences + fields = [self._replace_octal_escapes(field) for field in fields] device, mount, fstype, options = fields[0], fields[1], fields[2], fields[3] diff --git a/test/units/module_utils/facts/test_facts.py b/test/units/module_utils/facts/test_facts.py index a037ee0ce3c..ae1678341ce 100644 --- a/test/units/module_utils/facts/test_facts.py +++ b/test/units/module_utils/facts/test_facts.py @@ -514,7 +514,11 @@ MTAB_ENTRIES = [ '0', '0' ], - ['fusectl', '/sys/fs/fuse/connections', 'fusectl', 'rw,relatime', '0', '0']] + ['fusectl', '/sys/fs/fuse/connections', 'fusectl', 'rw,relatime', '0', '0'], + # Mount path with space in the name + # The space is encoded as \040 since the fields in /etc/mtab are space-delimeted + ['/dev/sdz9', r'/mnt/foo\040bar', 'ext4', 'rw,relatime', '0', '0'], +] BIND_MOUNTS = ['/not/a/real/bind_mount'] @@ -555,6 +559,11 @@ class TestFactsLinuxHardwareGetMountFacts(unittest.TestCase): self.assertIsInstance(mount_facts['mounts'], list) self.assertIsInstance(mount_facts['mounts'][0], dict) + # Find mounts with space in the mountpoint path + mounts_with_space = [x for x in mount_facts['mounts'] if ' ' in x['mount']] + self.assertEqual(len(mounts_with_space), 1) + self.assertEqual(mounts_with_space[0]['mount'], '/mnt/foo bar') + @patch('ansible.module_utils.facts.hardware.linux.get_file_content', return_value=MTAB) def test_get_mtab_entries(self, mock_get_file_content):