From daca3ade99625bd86a120ca548e7698b7dce0345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Loyet?= <822436+fatpat@users.noreply.github.com> Date: Wed, 9 Sep 2020 20:40:48 +0200 Subject: [PATCH] Allow list of filters for the setup module (#68551) The setup module can now filter out multiple pattern by providing a list to the filter parameter instead of just a string. Single string sill works. Previous behaviour remains. (cherry picked from commit b5c36dac483fdd74d6c570d77cc8f3e396720366) --- ...w_list_of_filters_for_the_setup_module.yml | 2 ++ .../porting_guide_base_2.11.rst | 1 + .../module_utils/facts/ansible_collector.py | 10 +++++++--- lib/ansible/modules/setup.py | 20 ++++++++++++++++--- .../gathering_facts/test_gathering_facts.yml | 18 +++++++++++++++++ test/sanity/ignore.txt | 1 - 6 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 changelogs/fragments/68551_allow_list_of_filters_for_the_setup_module.yml diff --git a/changelogs/fragments/68551_allow_list_of_filters_for_the_setup_module.yml b/changelogs/fragments/68551_allow_list_of_filters_for_the_setup_module.yml new file mode 100644 index 00000000000..115690ef35b --- /dev/null +++ b/changelogs/fragments/68551_allow_list_of_filters_for_the_setup_module.yml @@ -0,0 +1,2 @@ +minor_changes: + - setup - allow list of filters (https://github.com/ansible/ansible/pull/68551). diff --git a/docs/docsite/rst/porting_guides/porting_guide_base_2.11.rst b/docs/docsite/rst/porting_guides/porting_guide_base_2.11.rst index e554aa2ab5f..bbb97278d49 100644 --- a/docs/docsite/rst/porting_guides/porting_guide_base_2.11.rst +++ b/docs/docsite/rst/porting_guides/porting_guide_base_2.11.rst @@ -61,6 +61,7 @@ Noteworthy module changes * facts - On NetBSD, ``ansible_virtualization_type`` now tries to report a more accurate result than ``xen`` when virtualized and not running on Xen. * facts - Virtualization facts now include ``virtualization_tech_guest`` and ``virtualization_tech_host`` keys. These are lists of virtualization technologies that a guest is a part of, or that a host provides, respectively. As an example, a host may be set up to provide both KVM and VirtualBox, and these will be included in ``virtualization_tech_host``, and a podman container running on a VM powered by KVM will have a ``virtualization_tech_guest`` of ``["kvm", "podman", "container"]``. +* The parameter ``filter`` type is changed from ``string`` to ``list`` in the :ref:`setup ` module in order to use more than one filter. Previous behaviour (using a ``string``) still remains and works as a single filter. Plugins diff --git a/lib/ansible/module_utils/facts/ansible_collector.py b/lib/ansible/module_utils/facts/ansible_collector.py index 8ca0089efae..7f6f576f9c2 100644 --- a/lib/ansible/module_utils/facts/ansible_collector.py +++ b/lib/ansible/module_utils/facts/ansible_collector.py @@ -34,6 +34,7 @@ import sys from ansible.module_utils.facts import timeout from ansible.module_utils.facts import collector +from ansible.module_utils.common.collections import is_string class AnsibleFactCollector(collector.BaseFactCollector): @@ -53,11 +54,14 @@ class AnsibleFactCollector(collector.BaseFactCollector): self.filter_spec = filter_spec def _filter(self, facts_dict, filter_spec): - # assume a filter_spec='' is equilv to filter_spec='*' + # assume filter_spec='' or filter_spec=[] is equivalent to filter_spec='*' if not filter_spec or filter_spec == '*': return facts_dict - return [(x, y) for x, y in facts_dict.items() if fnmatch.fnmatch(x, filter_spec)] + if is_string(filter_spec): + filter_spec = [filter_spec] + + return [(x, y) for x, y in facts_dict.items() for f in filter_spec if not f or fnmatch.fnmatch(x, f)] def collect(self, module=None, collected_facts=None): collected_facts = collected_facts or {} @@ -111,7 +115,7 @@ def get_ansible_collector(all_collector_classes, gather_timeout=None, minimal_gather_subset=None): - filter_spec = filter_spec or '*' + filter_spec = filter_spec or [] gather_subset = gather_subset or ['all'] gather_timeout = gather_timeout or timeout.DEFAULT_GATHER_TIMEOUT minimal_gather_subset = minimal_gather_subset or frozenset() diff --git a/lib/ansible/modules/setup.py b/lib/ansible/modules/setup.py index c7f16c30fa5..efe6780c286 100644 --- a/lib/ansible/modules/setup.py +++ b/lib/ansible/modules/setup.py @@ -39,9 +39,16 @@ options: filter: version_added: "1.1" description: - - If supplied, only return facts that match this shell-style (fnmatch) wildcard. + - If supplied, only return facts that match one of the shell-style + (fnmatch) pattern. An empty list basically means 'no filter'. + As of Ansible 2.11, the type has changed from string to list + and the default has became an empty list. A simple string is + still accepted and works as a single pattern. The behaviour + prior to Ansible 2.11 remains. required: false - default: "*" + type: list + elements: str + default: [] fact_path: version_added: "1.3" description: @@ -105,6 +112,13 @@ EXAMPLES = """ - '!any' - facter +- name: Collect only selected facts + setup: + filter: + - 'ansible_distribution' + - 'ansible_machine_id' + - 'ansible_*_mb' + # Display only facts about certain interfaces. # ansible all -m setup -a 'filter=ansible_eth[0-2]' @@ -141,7 +155,7 @@ def main(): argument_spec=dict( gather_subset=dict(default=["all"], required=False, type='list'), gather_timeout=dict(default=10, required=False, type='int'), - filter=dict(default="*", required=False), + filter=dict(default=[], required=False, type='list', elements='str'), fact_path=dict(default='/etc/ansible/facts.d', required=False, type='path'), ), supports_check_mode=True, diff --git a/test/integration/targets/gathering_facts/test_gathering_facts.yml b/test/integration/targets/gathering_facts/test_gathering_facts.yml index d4364d29513..0939cba702a 100644 --- a/test/integration/targets/gathering_facts/test_gathering_facts.yml +++ b/test/integration/targets/gathering_facts/test_gathering_facts.yml @@ -122,6 +122,24 @@ - 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"' - 'ansible_env|default("UNDEF_ENV") != "UNDEF_ENV"' +- hosts: facthost24 + tags: [ 'fact_min' ] + connection: local + gather_facts: no + tasks: + - setup: + filter: + - "*env*" + - "*virt*" + + - name: Test that retrieving all facts filtered to env and virt works + assert: + that: + - 'ansible_interfaces|default("UNDEF_NET") == "UNDEF_NET"' + - 'ansible_mounts|default("UNDEF_MOUNT") == "UNDEF_MOUNT"' + - 'ansible_virtualization_role|default("UNDEF_VIRT") != "UNDEF_VIRT"' + - 'ansible_env|default("UNDEF_ENV") != "UNDEF_ENV"' + - hosts: facthost13 tags: [ 'fact_min' ] connection: local diff --git a/test/sanity/ignore.txt b/test/sanity/ignore.txt index 7ee930142b8..101c769eb9d 100644 --- a/test/sanity/ignore.txt +++ b/test/sanity/ignore.txt @@ -147,7 +147,6 @@ lib/ansible/modules/iptables.py pylint:blacklisted-name lib/ansible/modules/iptables.py validate-modules:parameter-list-no-elements lib/ansible/modules/service.py validate-modules:nonexistent-parameter-documented lib/ansible/modules/service.py validate-modules:use-run-command-not-popen -lib/ansible/modules/setup.py validate-modules:doc-missing-type lib/ansible/modules/setup.py validate-modules:parameter-list-no-elements lib/ansible/modules/setup.py validate-modules:parameter-type-not-in-doc lib/ansible/modules/systemd.py validate-modules:parameter-invalid