From e829a7384fbb200537af357f59183e4a0c309c51 Mon Sep 17 00:00:00 2001 From: Dmitrii Kuptsov Date: Wed, 25 Oct 2023 09:46:08 +0300 Subject: [PATCH] apt_rpm module: fix local RPM installation (#7396) * Fix local RPM install in apt_rpm * Add changelog entry * apt_rpm: update docs, handle import error * apt_rpm: remove extra debugging output * apt_rpm: use to_native, doc formatting --- ...396-fix-apt_rpm-local-rpm-installation.yml | 5 ++ plugins/modules/apt_rpm.py | 49 ++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/7396-fix-apt_rpm-local-rpm-installation.yml diff --git a/changelogs/fragments/7396-fix-apt_rpm-local-rpm-installation.yml b/changelogs/fragments/7396-fix-apt_rpm-local-rpm-installation.yml new file mode 100644 index 0000000000..39e098ce0a --- /dev/null +++ b/changelogs/fragments/7396-fix-apt_rpm-local-rpm-installation.yml @@ -0,0 +1,5 @@ +minor_changes: + - | + apt_rpm - extract package name from local ``.rpm`` path when verifying + installation success. Allows installing packages from local ``.rpm`` files + (https://github.com/ansible-collections/community.general/pull/7396). diff --git a/plugins/modules/apt_rpm.py b/plugins/modules/apt_rpm.py index 4c632a6fd2..d93db03e02 100644 --- a/plugins/modules/apt_rpm.py +++ b/plugins/modules/apt_rpm.py @@ -28,6 +28,9 @@ options: package: description: - List of packages to install, upgrade, or remove. + - Since community.general 8.0.0, may include paths to local C(.rpm) files + if O(state=installed) or O(state=present), requires C(rpm) python + module. aliases: [ name, pkg ] type: list elements: str @@ -63,6 +66,9 @@ options: type: bool default: false version_added: 6.5.0 +requirements: + - C(rpm) python package (rpm bindings), optional. Required if O(package) + option includes local files. author: - Evgenii Terechkov (@evgkrsk) ''' @@ -109,8 +115,22 @@ EXAMPLES = ''' ''' import os +import traceback -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import ( + AnsibleModule, + missing_required_lib, +) +from ansible.module_utils.common.text.converters import to_native + +try: + import rpm +except ImportError: + HAS_RPM_PYTHON = False + RPM_PYTHON_IMPORT_ERROR = traceback.format_exc() +else: + HAS_RPM_PYTHON = True + RPM_PYTHON_IMPORT_ERROR = None APT_PATH = "/usr/bin/apt-get" RPM_PATH = "/usr/bin/rpm" @@ -118,6 +138,23 @@ APT_GET_ZERO = "\n0 upgraded, 0 newly installed" UPDATE_KERNEL_ZERO = "\nTry to install new kernel " +def local_rpm_package_name(path): + """return package name of a local rpm passed in. + Inspired by ansible.builtin.yum""" + + ts = rpm.TransactionSet() + ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES) + fd = os.open(path, os.O_RDONLY) + try: + header = ts.hdrFromFdno(fd) + except rpm.error as e: + return None + finally: + os.close(fd) + + return to_native(header[rpm.RPMTAG_NAME]) + + def query_package(module, name): # rpm -q returns 0 if the package is installed, # 1 if it is not installed @@ -131,6 +168,16 @@ def query_package(module, name): def query_package_provides(module, name): # rpm -q returns 0 if the package is installed, # 1 if it is not installed + if name.endswith('.rpm'): + # Likely a local RPM file + if not HAS_RPM_PYTHON: + module.fail_json( + msg=missing_required_lib('rpm'), + exception=RPM_PYTHON_IMPORT_ERROR, + ) + + name = local_rpm_package_name(name) + rc, out, err = module.run_command("%s -q --provides %s" % (RPM_PATH, name)) return rc == 0