mirror of
https://github.com/ansible-collections/ansible.posix.git
synced 2026-01-11 15:15:26 +01:00
Merge pull request #460 from gotmax23/respawn
Respawn modules to use the system python interpreter SUMMARY The seboolean, selinux, firewalld, and firewalld_info modules depend on system bindings that are only available for the default system python interpreter. ansible-core is not packaged for the default system python interpreter on RHEL 8 and 9. When automatic interpreter discovery does not occur (e.g. when using implicit localhost [1]), ansible-core will not use the system interpreter to run ansible modules and the aforementioned modules will not work even if the bindings are installed. The RHEL ansible-core maintainers as well as the EPEL ansible and ansible-collection-* package maintainers (inc. me) have gotten multiple bug reports about this. We have been telling people to fix their setup to use the correct Python interpreter. Fortunately, ansible-core 2.11 and above have a module utility that'll respawn modules to use the correct system interpreter. [1] https://docs.ansible.com/ansible/latest/inventory/implicit_localhost.html ISSUE TYPE Feature Pull Request COMPONENT NAME seboolean selinux firewalld firewalld_info Reviewed-by: Adam Miller <admiller@redhat.com>
This commit is contained in:
commit
6f95c8b356
7 changed files with 76 additions and 7 deletions
10
changelogs/fragments/460-respawn.yaml
Normal file
10
changelogs/fragments/460-respawn.yaml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
minor_changes:
|
||||||
|
- "seboolean - respawn module to use the system python interpreter when the ``selinux`` python module is not available for ``ansible_python_interpreter``
|
||||||
|
(https://github.com/ansible-collections/ansible.posix/pull/460)."
|
||||||
|
- "selinux - respawn module to use the system python interpreter when the ``selinux`` python module is not available for ``ansible_python_interpreter``
|
||||||
|
(https://github.com/ansible-collections/ansible.posix/pull/460)."
|
||||||
|
- "firewalld - respawn module to use the system python interpreter when the ``firewall`` python module is not available for ``ansible_python_interpreter``
|
||||||
|
(https://github.com/ansible-collections/ansible.posix/pull/460)."
|
||||||
|
- "firewalld_info - respawn module to use the system python interpreter when the ``firewall`` python module is not available for ``ansible_python_interpreter``
|
||||||
|
(https://github.com/ansible-collections/ansible.posix/pull/460)."
|
||||||
45
plugins/module_utils/_respawn.py
Normal file
45
plugins/module_utils/_respawn.py
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Copyright (c) 2023 Maxwell G <maxwell@gtmx.me>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
"""
|
||||||
|
Helpers to respawn a module to run using the system interpreter
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
try:
|
||||||
|
from ansible.module_utils.common import respawn
|
||||||
|
except ImportError:
|
||||||
|
HAS_RESPAWN_UTIL = False
|
||||||
|
else:
|
||||||
|
HAS_RESPAWN_UTIL = True
|
||||||
|
|
||||||
|
|
||||||
|
SYSTEM_PYTHON_INTERPRETERS = (
|
||||||
|
"/usr/bin/libexec/platform-python",
|
||||||
|
"/usr/bin/python3",
|
||||||
|
"/usr/bin/python2",
|
||||||
|
"/usr/bin/python",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def respawn_module(module):
|
||||||
|
"""
|
||||||
|
Respawn an ansible module to using the first interpreter in
|
||||||
|
SYSTEM_PYTHON_INTERPRETERS that contains `module`.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
module (str): Name of python module to search for
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Returns None if the module cannot be respawned.
|
||||||
|
"""
|
||||||
|
if respawn.has_respawned():
|
||||||
|
return
|
||||||
|
interpreter = respawn.probe_interpreters_for_module(
|
||||||
|
SYSTEM_PYTHON_INTERPRETERS, module
|
||||||
|
)
|
||||||
|
if interpreter:
|
||||||
|
respawn.respawn_module(interpreter)
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function
|
from __future__ import absolute_import, division, print_function
|
||||||
from ansible_collections.ansible.posix.plugins.module_utils.version import LooseVersion
|
from ansible_collections.ansible.posix.plugins.module_utils.version import LooseVersion
|
||||||
|
from ansible_collections.ansible.posix.plugins.module_utils._respawn import respawn_module, HAS_RESPAWN_UTIL
|
||||||
from ansible.module_utils.basic import missing_required_lib
|
from ansible.module_utils.basic import missing_required_lib
|
||||||
|
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
@ -314,6 +315,8 @@ class FirewallTransaction(object):
|
||||||
installed version (%s) likely too old. Requires firewalld >= 0.2.11" % FW_VERSION)
|
installed version (%s) likely too old. Requires firewalld >= 0.2.11" % FW_VERSION)
|
||||||
|
|
||||||
if import_failure:
|
if import_failure:
|
||||||
|
if HAS_RESPAWN_UTIL:
|
||||||
|
respawn_module("firewall")
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib('firewall') + '. Version 0.2.11 or newer required (0.3.9 or newer for offline operations)'
|
msg=missing_required_lib('firewall') + '. Version 0.2.11 or newer required (0.3.9 or newer for offline operations)'
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -211,6 +211,7 @@ firewalld_info:
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||||
from ansible.module_utils._text import to_native
|
from ansible.module_utils._text import to_native
|
||||||
|
from ansible_collections.ansible.posix.plugins.module_utils._respawn import respawn_module, HAS_RESPAWN_UTIL
|
||||||
from ansible_collections.ansible.posix.plugins.module_utils.version import StrictVersion
|
from ansible_collections.ansible.posix.plugins.module_utils.version import StrictVersion
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -322,6 +323,12 @@ def main():
|
||||||
)
|
)
|
||||||
|
|
||||||
# Exit with failure message if requirements modules are not installed.
|
# Exit with failure message if requirements modules are not installed.
|
||||||
|
if not HAS_DBUS and not HAS_FIREWALLD and HAS_RESPAWN_UTIL:
|
||||||
|
# Only respawn the module if both libraries are missing.
|
||||||
|
# If only one is available, then usage of the "wrong" (i.e. not the system one)
|
||||||
|
# python interpreter is likely not the problem.
|
||||||
|
respawn_module("firewall")
|
||||||
|
|
||||||
if not HAS_DBUS:
|
if not HAS_DBUS:
|
||||||
module.fail_json(msg=missing_required_lib('python-dbus'))
|
module.fail_json(msg=missing_required_lib('python-dbus'))
|
||||||
if not HAS_FIREWALLD:
|
if not HAS_FIREWALLD:
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ except ImportError:
|
||||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||||
from ansible.module_utils.six import binary_type
|
from ansible.module_utils.six import binary_type
|
||||||
from ansible.module_utils._text import to_bytes, to_text
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
from ansible_collections.ansible.posix.plugins.module_utils._respawn import respawn_module, HAS_RESPAWN_UTIL
|
||||||
|
|
||||||
|
|
||||||
def get_runtime_status(ignore_selinux_state=False):
|
def get_runtime_status(ignore_selinux_state=False):
|
||||||
|
|
@ -281,6 +282,12 @@ def main():
|
||||||
supports_check_mode=True,
|
supports_check_mode=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not HAVE_SELINUX and not HAVE_SEMANAGE and HAS_RESPAWN_UTIL:
|
||||||
|
# Only respawn the module if both libraries are missing.
|
||||||
|
# If only one is available, then usage of the "wrong" (i.e. not the system one)
|
||||||
|
# python interpreter is likely not the problem.
|
||||||
|
respawn_module("selinux")
|
||||||
|
|
||||||
if not HAVE_SELINUX:
|
if not HAVE_SELINUX:
|
||||||
module.fail_json(msg=missing_required_lib('libselinux-python'), exception=SELINUX_IMP_ERR)
|
module.fail_json(msg=missing_required_lib('libselinux-python'), exception=SELINUX_IMP_ERR)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,8 @@ from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||||
from ansible.module_utils.common.process import get_bin_path
|
from ansible.module_utils.common.process import get_bin_path
|
||||||
from ansible.module_utils.facts.utils import get_file_lines
|
from ansible.module_utils.facts.utils import get_file_lines
|
||||||
|
|
||||||
|
from ansible_collections.ansible.posix.plugins.module_utils._respawn import respawn_module, HAS_RESPAWN_UTIL
|
||||||
|
|
||||||
|
|
||||||
# getter subroutines
|
# getter subroutines
|
||||||
def get_config_state(configfile):
|
def get_config_state(configfile):
|
||||||
|
|
@ -236,6 +238,8 @@ def main():
|
||||||
)
|
)
|
||||||
|
|
||||||
if not HAS_SELINUX:
|
if not HAS_SELINUX:
|
||||||
|
if HAS_RESPAWN_UTIL:
|
||||||
|
respawn_module("selinux")
|
||||||
module.fail_json(msg=missing_required_lib('libselinux-python'), exception=SELINUX_IMP_ERR)
|
module.fail_json(msg=missing_required_lib('libselinux-python'), exception=SELINUX_IMP_ERR)
|
||||||
|
|
||||||
# global vars
|
# global vars
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,6 @@
|
||||||
state: present
|
state: present
|
||||||
# This doesn't work for CentOS 6 because firewalld doesn't exist in CentOS6
|
# This doesn't work for CentOS 6 because firewalld doesn't exist in CentOS6
|
||||||
|
|
||||||
- name: Check to make sure the firewalld python module is available.
|
|
||||||
shell: "{{ansible_python.executable}} -c 'import firewall'"
|
|
||||||
register: check_output
|
|
||||||
ignore_errors: true
|
|
||||||
|
|
||||||
- name: Enable dbus-broker daemon
|
- name: Enable dbus-broker daemon
|
||||||
service:
|
service:
|
||||||
name: dbus-broker
|
name: dbus-broker
|
||||||
|
|
@ -30,7 +25,6 @@
|
||||||
state: started
|
state: started
|
||||||
|
|
||||||
- import_tasks: run_all_tests.yml
|
- import_tasks: run_all_tests.yml
|
||||||
when: check_output.rc == 0
|
|
||||||
|
|
||||||
- name: Test Offline Operations
|
- name: Test Offline Operations
|
||||||
block:
|
block:
|
||||||
|
|
@ -40,7 +34,6 @@
|
||||||
state: stopped
|
state: stopped
|
||||||
|
|
||||||
- import_tasks: run_all_tests.yml
|
- import_tasks: run_all_tests.yml
|
||||||
when: check_output.rc == 0
|
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- ansible_facts.os_family == "RedHat" and ansible_facts.distribution_major_version is version('7', '>=')
|
- ansible_facts.os_family == "RedHat" and ansible_facts.distribution_major_version is version('7', '>=')
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue