<!--- Verify first that your issue is not already reported on GitHub -->
<!--- Also test if the latest release and devel branch are affected too -->
<!--- Complete *all* sections as described, this form is processed automatically -->

##### SUMMARY
Ansible in dnf.py uses a private attributes (in this case it is an internal cache for security filters - base._update_security_filters). Using private attributes could result in random fails, because they could be even removed without announcement because it is not API.


        filters = []
        if self.bugfix:
            key = {'advisory_type__eq': 'bugfix'}
            filters.append(base.sack.query().upgrades().filter(**key))
        if self.security:
            key = {'advisory_type__eq': 'security'}
            filters.append(base.sack.query().upgrades().filter(**key))
        if filters:
            base._update_security_filters = filters

Also I an not sure if it works like expected (there is a difference in dnf upgrade, and dnf upgrade-minimal) and I don't know what was expected from ansible.

I also propose a new API in dnf that could resolve the issue (https://github.com/rpm-software-management/dnf/pull/1715). Any comment or suggestion is welcome
 
##### ISSUE TYPE
- Bug Report

##### COMPONENT NAME
<!--- Write the short name of the module, plugin, task or feature below, use your best guess if unsure -->
dnf

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes -->
```paste below
devel
```

##### CONFIGURATION
<!--- Paste verbatim output from "ansible-config dump --only-changed" between quotes -->
```paste below

```

##### OS / ENVIRONMENT
<!--- Provide all relevant information below, e.g. target OS versions, network device firmware, etc. -->


##### STEPS TO REPRODUCE
<!--- Describe exactly how to reproduce the problem, using a minimal test-case -->

<!--- Paste example playbooks or commands between quotes below -->
```yaml

```

<!--- HINT: You can paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- Describe what you expected to happen when running the steps above -->


##### ACTUAL RESULTS
<!--- Describe what actually happened. If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes -->
```paste below

```

self.base.read_all_repos()
        available = self.base.sack.query().available()
        
        files_filter = available.filter(file=filepath)
        
        pkg_spec = files_filter.union(available.filter(provides=filepath)).run()
        if pkg_spec:
            return pkg_spec[0].name
    def _parse_spec_group_file(self):
        pkg_specs, grp_specs, module_specs, filenames = [], [], [], []
        already_loaded_comps = False  
        for name in self.names:
            if '://' in name:
                name = fetch_file(self.module, name)
                filenames.append(name)
            elif name.endswith(".rpm"):
                filenames.append(name)
            elif name.startswith('/'):
                
                pkg_spec = self._whatprovides(name)
                if pkg_spec:
                    pkg_specs.append(pkg_spec)
                    continue
            elif name.startswith("@") or ('/' in name):
                if not already_loaded_comps:
                    self.base.read_comps()
                    already_loaded_comps = True
                grp_env_mdl_candidate = name[1:].strip()