diff --git a/changelogs/fragments/22766-fact-cmdline-return_multiple_lvm_values.yaml b/changelogs/fragments/22766-fact-cmdline-return_multiple_lvm_values.yaml new file mode 100644 index 0000000000..c3ea253bd8 --- /dev/null +++ b/changelogs/fragments/22766-fact-cmdline-return_multiple_lvm_values.yaml @@ -0,0 +1,2 @@ +minor_changes: +- cmdline fact parsing can return multiple values of a single key. Deprecate cmdline fact in favor of proc_cmdline. diff --git a/docs/docsite/rst/porting_guides/porting_guide_2.8.rst b/docs/docsite/rst/porting_guides/porting_guide_2.8.rst index 4afe4d31b8..1af22062eb 100644 --- a/docs/docsite/rst/porting_guides/porting_guide_2.8.rst +++ b/docs/docsite/rst/porting_guides/porting_guide_2.8.rst @@ -55,6 +55,12 @@ In Ansible 2.7 and older:: {{ foo.bar.baz if (foo is defined and foo.bar is defined and foo.bar.baz is defined) else 'DEFAULT' }} +Command line facts +------------------ + +``cmdline`` facts returned in system will be deprecated in favor of ``proc_cmdline``. This change handles special case where Kernel command line parameter +contains multiple values with the same key. + Command Line ============ diff --git a/lib/ansible/module_utils/facts/system/cmdline.py b/lib/ansible/module_utils/facts/system/cmdline.py index dbce3843b8..1b1b71e7f7 100644 --- a/lib/ansible/module_utils/facts/system/cmdline.py +++ b/lib/ansible/module_utils/facts/system/cmdline.py @@ -44,6 +44,27 @@ class CmdLineFactCollector(BaseFactCollector): return cmdline_dict + def _parse_proc_cmdline_facts(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: + if item[0] in cmdline_dict: + if isinstance(cmdline_dict[item[0]], list): + cmdline_dict[item[0]].append(item[1]) + else: + new_list = [cmdline_dict[item[0]], item[1]] + cmdline_dict[item[0]] = new_list + else: + cmdline_dict[item[0]] = item[1] + except ValueError: + pass + + return cmdline_dict + def collect(self, module=None, collected_facts=None): cmdline_facts = {} @@ -53,4 +74,6 @@ class CmdLineFactCollector(BaseFactCollector): return cmdline_facts cmdline_facts['cmdline'] = self._parse_proc_cmdline(data) + cmdline_facts['proc_cmdline'] = self._parse_proc_cmdline_facts(data) + return cmdline_facts diff --git a/test/units/module_utils/facts/system/test_cmdline.py b/test/units/module_utils/facts/system/test_cmdline.py new file mode 100644 index 0000000000..59cfd118cc --- /dev/null +++ b/test/units/module_utils/facts/system/test_cmdline.py @@ -0,0 +1,67 @@ +# unit tests for ansible system cmdline fact collectors +# -*- coding: utf-8 -*- +# Copyright: (c) 2018, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import pytest +from ansible.module_utils.facts.system.cmdline import CmdLineFactCollector + +test_data = [ + ( + "crashkernel=auto rd.lvm.lv=fedora_test-elementary-os/root rd.lvm.lv=fedora_test-elementary-os/swap rhgb quiet", + { + 'crashkernel': 'auto', + 'quiet': True, + 'rd.lvm.lv': [ + 'fedora_test-elementary-os/root', + 'fedora_test-elementary-os/swap', + ], + 'rhgb': True + } + ), + ( + "root=/dev/mapper/vg_ssd-root ro rd.lvm.lv=fedora_xenon/root rd.lvm.lv=fedora_xenon/swap rhgb quiet " + "resume=/dev/mapper/fedora_xenon-swap crashkernel=128M zswap.enabled=1", + { + 'crashkernel': '128M', + 'quiet': True, + 'rd.lvm.lv': [ + 'fedora_xenon/root', + 'fedora_xenon/swap' + ], + 'resume': '/dev/mapper/fedora_xenon-swap', + 'rhgb': True, + 'ro': True, + 'root': '/dev/mapper/vg_ssd-root', + 'zswap.enabled': '1' + } + ), + ( + "rhgb", + { + "rhgb": True + } + ), + ( + "root=/dev/mapper/vg_ssd-root", + { + 'root': '/dev/mapper/vg_ssd-root', + } + ), + ( + "", + {}, + ) +] + +test_ids = ['lvm_1', 'lvm_2', 'single_without_equal_sign', 'single_with_equal_sign', 'blank_cmdline'] + + +@pytest.mark.parametrize("cmdline, cmdline_dict", test_data, ids=test_ids) +def test_cmd_line_factor(cmdline, cmdline_dict): + cmdline_facter = CmdLineFactCollector() + parsed_cmdline = cmdline_facter._parse_proc_cmdline_facts(data=cmdline) + assert parsed_cmdline == cmdline_dict