Repository: ansible/ansible
Pull request: setup module, filter compensate for prefixes
  allow user to abstract internal implementation from requested info
fixes #74921
##### ISSUE TYPE
<!--- Pick one below and delete the rest -->
- Bugfix Pull Request

##### COMPONENT NAME
<!--- Write the short name of the module, plugin, task or feature below -->
modules/setup

Problem statement:
Inconsictency in fact naming, display, and filtering in setup module
### Summary

`setup` module displays facts inside `ansible_facts` dict, but with `ansible_` prefix, also `filter` acts on injected variable names instead of facts, expecting `ansible_` prefix.

### Issue Type

Bug Report

### Component Name

setup

### Ansible Version

```console
$ ansible --version
ansible 2.10.8
  config file = /home/username/.ansible.cfg
  configured module search path = ['/home/username/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.9.2 (default, Feb 28 2021, 17:03:44) [GCC 10.2.1 20210110]
```


### Configuration

```console
$ ansible-config dump --only-changed
```


### OS / Environment

Debian testing, FreeBSD 12

### Steps to Reproduce

<!--- Paste example playbooks or commands between quotes below -->

```
$ ansible localhost -m setup -a 'filter=date_time'
```

### Expected Results

I expect facts to be named as is when inside `ansible_facts` dict, and with `ansible_` prefix when injected into variable space. Since `setup` module shows results as being inside `ansible_facts` dict, it should not add `ansible_` prefix to them. `filter` parameter should also act on fact names, not on injected variables. (or at least have a clear option for such behavior).

```
$ ansible localhost -m setup -a 'filter=date_time'
localhost | SUCCESS => {
    "ansible_facts": {
        "date_time": {
            "date": "2021-06-07",
            ...
        }
    },
    "changed": false
}
```

### Actual Results

```console
$ ansible localhost -m setup -a 'filter=date_time'
localhost | SUCCESS => {
    "ansible_facts": {},
    "changed": false
}
```
```
$ ansible localhost -m setup -a 'filter=*date_time'
localhost | SUCCESS => {
    "ansible_facts": {
        "ansible_date_time": {
            "date": "2021-06-07",
            ...
        }
    },
    "changed": false
}
```
```


### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct

Hints from issue discussion:
Files identified in the description:
* [`lib/ansible/modules/setup.py`](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/setup.py)

If these files are incorrect, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->

Commit message: setup module, filter compensate for prefixes

  allow user to abstract internal implementation from requested info

Patch to review:
diff --git a/changelogs/fragments/setup_filter_smarter.yml b/changelogs/fragments/setup_filter_smarter.yml
new file mode 100644
index 00000000000000..d8e568720f6d66
--- /dev/null
+++ b/changelogs/fragments/setup_filter_smarter.yml
@@ -0,0 +1,2 @@
+bugfixes:
+  - setup module, fix filter to adjust for missing ansible_ prefix on query.
diff --git a/lib/ansible/module_utils/facts/ansible_collector.py b/lib/ansible/module_utils/facts/ansible_collector.py
index 7f6f576f9c2d52..c38d72d0d72fb7 100644
--- a/lib/ansible/module_utils/facts/ansible_collector.py
+++ b/lib/ansible/module_utils/facts/ansible_collector.py
@@ -61,7 +61,17 @@ def _filter(self, facts_dict, 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)]
+        found = []
+        for f in filter_spec:
+            for x, y in facts_dict.items():
+                if fnmatch.fnmatch(x, f):
+                    found.append((x, y))
+                elif not f.startswith(('ansible_', 'facter', 'ohai')):
+                    # try to match with ansible_ prefix added
+                    g = 'ansible_%s' % f
+                    if fnmatch.fnmatch(x, g):
+                        found.append((x, y))
+        return found
 
     def collect(self, module=None, collected_facts=None):
         collected_facts = collected_facts or {}


Code review comments:
diff_hunk: @@ -0,0 +1,2 @@
+bugfixes:
+  - setup module, fix filter to adjust for missing ansible_ prefix on query.
path: changelogs/fragments/setup_filter_smarter.yml
text: @user1:
This is tripping up the sanity test because it thinks the trailing underscore is an RST link.
```suggestion
  - setup module, fix filter to adjust for missing ``ansible_`` prefix on query.
```