summaryrefslogtreecommitdiff
path: root/lib/ansible/plugins/action/dnf.py
blob: bf8ac3f46ac5e61951afaa41a1ebb657a128c539 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# Copyright: (c) 2023, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from ansible.errors import AnsibleActionFail
from ansible.plugins.action import ActionBase
from ansible.utils.display import Display

display = Display()

VALID_BACKENDS = frozenset(("dnf", "dnf4", "dnf5"))


# FIXME mostly duplicate of the yum action plugin
class ActionModule(ActionBase):

    TRANSFERS_FILES = False

    def run(self, tmp=None, task_vars=None):
        self._supports_check_mode = True
        self._supports_async = True

        result = super(ActionModule, self).run(tmp, task_vars)
        del tmp  # tmp no longer has any effect

        # Carry-over concept from the package action plugin
        if 'use' in self._task.args and 'use_backend' in self._task.args:
            raise AnsibleActionFail("parameters are mutually exclusive: ('use', 'use_backend')")

        module = self._task.args.get('use', self._task.args.get('use_backend', 'auto'))

        if module == 'auto':
            try:
                if self._task.delegate_to:  # if we delegate, we should use delegated host's facts
                    module = self._templar.template("{{hostvars['%s']['ansible_facts']['pkg_mgr']}}" % self._task.delegate_to)
                else:
                    module = self._templar.template("{{ansible_facts.pkg_mgr}}")
            except Exception:
                pass  # could not get it from template!

        if module not in VALID_BACKENDS:
            facts = self._execute_module(
                module_name="ansible.legacy.setup", module_args=dict(filter="ansible_pkg_mgr", gather_subset="!all"),
                task_vars=task_vars)
            display.debug("Facts %s" % facts)
            module = facts.get("ansible_facts", {}).get("ansible_pkg_mgr", "auto")
            if (not self._task.delegate_to or self._task.delegate_facts) and module != 'auto':
                result['ansible_facts'] = {'pkg_mgr': module}

        if module not in VALID_BACKENDS:
            result.update(
                {
                    'failed': True,
                    'msg': ("Could not detect which major revision of dnf is in use, which is required to determine module backend.",
                            "You should manually specify use_backend to tell the module whether to use the dnf4 or dnf5 backend})"),
                }
            )

        else:
            if module == "dnf4":
                module = "dnf"

            # eliminate collisions with collections search while still allowing local override
            module = 'ansible.legacy.' + module

            if not self._shared_loader_obj.module_loader.has_plugin(module):
                result.update({'failed': True, 'msg': "Could not find a dnf module backend for %s." % module})
            else:
                new_module_args = self._task.args.copy()
                if 'use_backend' in new_module_args:
                    del new_module_args['use_backend']
                if 'use' in new_module_args:
                    del new_module_args['use']

                display.vvvv("Running %s as the backend for the dnf action plugin" % module)
                result.update(self._execute_module(
                    module_name=module, module_args=new_module_args, task_vars=task_vars, wrap_async=self._task.async_val))

        # Cleanup
        if not self._task.async_val:
            # remove a temporary path we created
            self._remove_tmp_path(self._connection._shell.tmpdir)

        return result