summaryrefslogtreecommitdiff
path: root/lib/ansible/plugins/action/yum.py
blob: 9121e8129da7ebeeff798326b0e7d5b10cd055ea (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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# (c) 2018, Ansible Project
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

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

display = Display()

VALID_BACKENDS = frozenset(('yum', 'yum4', 'dnf', 'dnf4', 'dnf5'))


class ActionModule(ActionBase):

    TRANSFERS_FILES = False

    def run(self, tmp=None, task_vars=None):
        '''
        Action plugin handler for yum3 vs yum4(dnf) operations.

        Enables the yum module to use yum3 and/or yum4. Yum4 is a yum
        command-line compatibility layer on top of dnf. Since the Ansible
        modules for yum(aka yum3) and dnf(aka yum4) call each of yum3 and yum4's
        python APIs natively on the backend, we need to handle this here and
        pass off to the correct Ansible module to execute on the remote system.
        '''

        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 == 'dnf':
            module = '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 yum is in use, which is required to determine module backend.",
                            "You should manually specify use_backend to tell the module whether to use the yum (yum3) or dnf (yum4) backend})"),
                }
            )

        else:
            if module in {"yum4", "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 yum 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 yum 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