From f4128746d37ecad2ef83cb06b53f7fe2f7df0aa8 Mon Sep 17 00:00:00 2001 From: Adrian Likins Date: Thu, 8 Jun 2017 16:03:29 -0400 Subject: [PATCH] Cmdline fact uefi 23647 (#25446) * Fix ansible_cmdline initrd fact for UEFI UEFI cmdline paths use \ path sep which would get munged by cmdline fact collection. * Make CmdLineFactCollector easier to test extract the parsing of the /proc/cmdline content to _parse_proc_cmdline() add a wrapper method for get_file_content _get_proc_cmdline() Add unit tests of _parse_proc_cmdline based on examples from issue #23647 Fixes #23647 --- .../module_utils/facts/system/cmdline.py | 32 ++++++++------ .../module_utils/facts/test_collectors.py | 43 +++++++++++++++++++ 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/lib/ansible/module_utils/facts/system/cmdline.py b/lib/ansible/module_utils/facts/system/cmdline.py index 612132a078..dbce3843b8 100644 --- a/lib/ansible/module_utils/facts/system/cmdline.py +++ b/lib/ansible/module_utils/facts/system/cmdline.py @@ -27,24 +27,30 @@ class CmdLineFactCollector(BaseFactCollector): name = 'cmdline' _fact_ids = set() + def _get_proc_cmdline(self): + return get_file_content('/proc/cmdline') + + def _parse_proc_cmdline(self, data): + cmdline_dict = {} + try: + for piece in shlex.split(data, posix=False): + item = piece.split('=', 1) + if len(item) == 1: + cmdline_dict[item[0]] = True + else: + cmdline_dict[item[0]] = item[1] + except ValueError: + pass + + return cmdline_dict + def collect(self, module=None, collected_facts=None): cmdline_facts = {} - data = get_file_content('/proc/cmdline') + data = self._get_proc_cmdline() if not data: return cmdline_facts - cmdline_facts['cmdline'] = {} - - try: - for piece in shlex.split(data): - item = piece.split('=', 1) - if len(item) == 1: - cmdline_facts['cmdline'][item[0]] = True - else: - cmdline_facts['cmdline'][item[0]] = item[1] - except ValueError: - pass - + cmdline_facts['cmdline'] = self._parse_proc_cmdline(data) return cmdline_facts diff --git a/test/units/module_utils/facts/test_collectors.py b/test/units/module_utils/facts/test_collectors.py index 9920052364..a356422ea9 100644 --- a/test/units/module_utils/facts/test_collectors.py +++ b/test/units/module_utils/facts/test_collectors.py @@ -119,6 +119,49 @@ class TestCmdLineFacts(BaseFactsTest): fact_namespace = 'ansible_cmdline' collector_class = CmdLineFactCollector + def test_parse_proc_cmdline_uefi(self): + uefi_cmdline = r'initrd=\70ef65e1a04a47aea04f7b5145ea3537\4.10.0-19-generic\initrd root=UUID=50973b75-4a66-4bf0-9764-2b7614489e64 ro quiet' + expected = {'initrd': r'\70ef65e1a04a47aea04f7b5145ea3537\4.10.0-19-generic\initrd', + 'root': 'UUID=50973b75-4a66-4bf0-9764-2b7614489e64', + 'quiet': True, + 'ro': True} + fact_collector = self.collector_class() + facts_dict = fact_collector._parse_proc_cmdline(uefi_cmdline) + + self.assertDictEqual(facts_dict, expected) + + def test_parse_proc_cmdline_fedora(self): + cmdline_fedora = r'BOOT_IMAGE=/vmlinuz-4.10.16-200.fc25.x86_64 root=/dev/mapper/fedora-root ro rd.lvm.lv=fedora/root rd.luks.uuid=luks-c80b7537-358b-4a07-b88c-c59ef187479b rd.lvm.lv=fedora/swap rhgb quiet LANG=en_US.UTF-8' # noqa + + expected = {'BOOT_IMAGE': '/vmlinuz-4.10.16-200.fc25.x86_64', + 'LANG': 'en_US.UTF-8', + 'quiet': True, + 'rd.luks.uuid': 'luks-c80b7537-358b-4a07-b88c-c59ef187479b', + 'rd.lvm.lv': 'fedora/swap', + 'rhgb': True, + 'ro': True, + 'root': '/dev/mapper/fedora-root'} + + fact_collector = self.collector_class() + facts_dict = fact_collector._parse_proc_cmdline(cmdline_fedora) + + self.assertDictEqual(facts_dict, expected) + + def test_parse_proc_cmdline_dup_console(self): + example = r'BOOT_IMAGE=/boot/vmlinuz-4.4.0-72-generic root=UUID=e12e46d9-06c9-4a64-a7b3-60e24b062d90 ro console=tty1 console=ttyS0' + + # FIXME: Two 'console' keywords? Using a dict for the fact value here loses info. Currently the 'last' one wins + expected = {'BOOT_IMAGE': '/boot/vmlinuz-4.4.0-72-generic', + 'root': 'UUID=e12e46d9-06c9-4a64-a7b3-60e24b062d90', + 'ro': True, + 'console': 'ttyS0'} + + fact_collector = self.collector_class() + facts_dict = fact_collector._parse_proc_cmdline(example) + + # TODO: fails because we lose a 'console' + self.assertDictEqual(facts_dict, expected) + class TestDistributionFacts(BaseFactsTest): __test__ = True