From 8ec2c261bda9672795950864ddc35088e114dd4c Mon Sep 17 00:00:00 2001 From: Maxwell G Date: Sun, 14 May 2023 05:19:38 +0000 Subject: [PATCH 1/5] add helper to respawn modules with system python 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 --- plugins/module_utils/_respawn.py | 45 ++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 plugins/module_utils/_respawn.py diff --git a/plugins/module_utils/_respawn.py b/plugins/module_utils/_respawn.py new file mode 100644 index 0000000000..55abaf544b --- /dev/null +++ b/plugins/module_utils/_respawn.py @@ -0,0 +1,45 @@ +# Copyright (c) 2023 Maxwell G +# 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) From 63fba50912a2aec9f342ffc03447e7df7ec63b60 Mon Sep 17 00:00:00 2001 From: Maxwell G Date: Sat, 13 May 2023 18:47:07 +0000 Subject: [PATCH 2/5] respawn seboolean module when selinux is missing --- changelogs/fragments/460-respawn.yaml | 4 ++++ plugins/modules/seboolean.py | 7 +++++++ 2 files changed, 11 insertions(+) create mode 100644 changelogs/fragments/460-respawn.yaml diff --git a/changelogs/fragments/460-respawn.yaml b/changelogs/fragments/460-respawn.yaml new file mode 100644 index 0000000000..cd0b29a6bc --- /dev/null +++ b/changelogs/fragments/460-respawn.yaml @@ -0,0 +1,4 @@ +--- +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)." diff --git a/plugins/modules/seboolean.py b/plugins/modules/seboolean.py index 657b7fa41a..0d2307332c 100644 --- a/plugins/modules/seboolean.py +++ b/plugins/modules/seboolean.py @@ -75,6 +75,7 @@ from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.six import binary_type 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): @@ -281,6 +282,12 @@ def main(): 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: module.fail_json(msg=missing_required_lib('libselinux-python'), exception=SELINUX_IMP_ERR) From 34a9cf3e4d8cf1181a506618d1c5e2a5807b37d9 Mon Sep 17 00:00:00 2001 From: Maxwell G Date: Sat, 13 May 2023 18:56:38 +0000 Subject: [PATCH 3/5] respawn selinux module when selinux is missing --- changelogs/fragments/460-respawn.yaml | 2 ++ plugins/modules/selinux.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/changelogs/fragments/460-respawn.yaml b/changelogs/fragments/460-respawn.yaml index cd0b29a6bc..7223b5ddca 100644 --- a/changelogs/fragments/460-respawn.yaml +++ b/changelogs/fragments/460-respawn.yaml @@ -2,3 +2,5 @@ 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)." diff --git a/plugins/modules/selinux.py b/plugins/modules/selinux.py index 14110fe448..0609462f92 100644 --- a/plugins/modules/selinux.py +++ b/plugins/modules/selinux.py @@ -107,6 +107,8 @@ from ansible.module_utils.common.process import get_bin_path 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 def get_config_state(configfile): @@ -236,6 +238,8 @@ def main(): ) if not HAS_SELINUX: + if HAS_RESPAWN_UTIL: + respawn_module("selinux") module.fail_json(msg=missing_required_lib('libselinux-python'), exception=SELINUX_IMP_ERR) # global vars From ad414c87b4ed35ac00c6b9087e03bc6e8f8b771d Mon Sep 17 00:00:00 2001 From: Maxwell G Date: Sat, 13 May 2023 19:02:18 +0000 Subject: [PATCH 4/5] respawn firewalld module when selinux is missing --- changelogs/fragments/460-respawn.yaml | 2 ++ plugins/module_utils/firewalld.py | 3 +++ tests/integration/targets/firewalld/tasks/main.yml | 7 ------- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/changelogs/fragments/460-respawn.yaml b/changelogs/fragments/460-respawn.yaml index 7223b5ddca..00f80281a3 100644 --- a/changelogs/fragments/460-respawn.yaml +++ b/changelogs/fragments/460-respawn.yaml @@ -4,3 +4,5 @@ minor_changes: (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)." diff --git a/plugins/module_utils/firewalld.py b/plugins/module_utils/firewalld.py index 6a76c32ae7..011b140043 100644 --- a/plugins/module_utils/firewalld.py +++ b/plugins/module_utils/firewalld.py @@ -5,6 +5,7 @@ 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._respawn import respawn_module, HAS_RESPAWN_UTIL from ansible.module_utils.basic import missing_required_lib __metaclass__ = type @@ -314,6 +315,8 @@ def sanity_check(module): installed version (%s) likely too old. Requires firewalld >= 0.2.11" % FW_VERSION) if import_failure: + if HAS_RESPAWN_UTIL: + respawn_module("firewall") module.fail_json( msg=missing_required_lib('firewall') + '. Version 0.2.11 or newer required (0.3.9 or newer for offline operations)' ) diff --git a/tests/integration/targets/firewalld/tasks/main.yml b/tests/integration/targets/firewalld/tasks/main.yml index 17f14c2b56..5f81c62476 100644 --- a/tests/integration/targets/firewalld/tasks/main.yml +++ b/tests/integration/targets/firewalld/tasks/main.yml @@ -10,11 +10,6 @@ state: present # 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 service: name: dbus-broker @@ -30,7 +25,6 @@ state: started - import_tasks: run_all_tests.yml - when: check_output.rc == 0 - name: Test Offline Operations block: @@ -40,7 +34,6 @@ state: stopped - import_tasks: run_all_tests.yml - when: check_output.rc == 0 when: - ansible_facts.os_family == "RedHat" and ansible_facts.distribution_major_version is version('7', '>=') From 85c958ccb8caba8610604a976b268a760d4a50eb Mon Sep 17 00:00:00 2001 From: Maxwell G Date: Sat, 13 May 2023 19:51:57 +0000 Subject: [PATCH 5/5] respawn firewalld_info module when selinux is missing --- changelogs/fragments/460-respawn.yaml | 2 ++ plugins/modules/firewalld_info.py | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/changelogs/fragments/460-respawn.yaml b/changelogs/fragments/460-respawn.yaml index 00f80281a3..b88763b349 100644 --- a/changelogs/fragments/460-respawn.yaml +++ b/changelogs/fragments/460-respawn.yaml @@ -6,3 +6,5 @@ minor_changes: (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)." diff --git a/plugins/modules/firewalld_info.py b/plugins/modules/firewalld_info.py index 334518df0e..8b5c80c500 100644 --- a/plugins/modules/firewalld_info.py +++ b/plugins/modules/firewalld_info.py @@ -211,6 +211,7 @@ from ansible.module_utils.basic import AnsibleModule, missing_required_lib 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 @@ -322,6 +323,12 @@ def main(): ) # 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: module.fail_json(msg=missing_required_lib('python-dbus')) if not HAS_FIREWALLD: