Add install_python_debian parameter to deb822_repository (#85487)

* Add python3-debian dependency installation in module

* Add tests to exercise automatic dependency installation

* Fix broken tests to include new module parameter

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
pull/85516/head
Patrick Kingston 4 months ago committed by GitHub
parent d2be8684b3
commit 737c68ace3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,2 @@
minor_changes:
- deb822_repository - Add automatic installation of the ``python3-debian`` package if it is missing by adding the parameter ``install_python_debian``

@ -67,6 +67,17 @@ options:
- Determines the path to the C(InRelease) file, relative to the normal
position of an C(InRelease) file.
type: str
install_python_debian:
description:
- Whether to automatically try to install the Python C(debian) library or not, if it is not already installed.
Without this library, the module does not work.
- Runs C(apt install python3-debian).
- Only works with the system Python. If you are using a Python on the remote that is not
the system Python, set O(install_python_debian=false) and ensure that the Python C(debian) library
for your Python version is installed some other way.
type: bool
default: false
version_added: '2.20'
languages:
description:
- Defines which languages information such as translated
@ -228,6 +239,7 @@ key_filename:
import os
import re
import sys
import tempfile
import textwrap
@ -235,6 +247,7 @@ from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.common.collections import is_sequence
from ansible.module_utils.common.file import S_IRWXU_RXG_RXO, S_IRWU_RG_RO
from ansible.module_utils.common.respawn import has_respawned, probe_interpreters_for_module, respawn_module
from ansible.module_utils.common.text.converters import to_bytes
from ansible.module_utils.common.text.converters import to_native
from ansible.module_utils.six import raise_from # type: ignore[attr-defined]
@ -357,6 +370,21 @@ def write_signed_by_key(module, v, slug):
return changed, filename, None
def install_python_debian(module, deb_pkg_name):
if not module.check_mode:
apt_path = module.get_bin_path('apt', required=True)
if apt_path:
rc, so, se = module.run_command([apt_path, 'update'])
if rc != 0:
module.fail_json(msg=f"Failed update while auto installing {deb_pkg_name} due to '{se.strip()}'")
rc, so, se = module.run_command([apt_path, 'install', deb_pkg_name, '-y', '-q'])
if rc != 0:
module.fail_json(msg=f"Failed to auto-install {deb_pkg_name} due to : '{se.strip()}'")
else:
module.fail_json(msg=f"{deb_pkg_name} must be installed to use check mode")
def main():
module = AnsibleModule(
argument_spec={
@ -395,6 +423,10 @@ def main():
'inrelease_path': {
'type': 'str',
},
'install_python_debian': {
'type': 'bool',
'default': False,
},
'languages': {
'elements': 'str',
'type': 'list',
@ -453,7 +485,52 @@ def main():
)
if not HAS_DEBIAN:
module.fail_json(msg=missing_required_lib("python3-debian"),
deb_pkg_name = 'python3-debian'
# This interpreter can't see the debian Python library- we'll do the following to try and fix that as per
# the apt_repository module:
# 1) look in common locations for system-owned interpreters that can see it; if we find one, respawn under it
# 2) finding none, try to install a matching python-debian package for the current interpreter version;
# we limit to the current interpreter version to try and avoid installing a whole other Python just
# for deb support
# 3) if we installed a support package, try to respawn under what we think is the right interpreter (could be
# the current interpreter again, but we'll let it respawn anyway for simplicity)
# 4) if still not working, return an error and give up (some corner cases not covered, but this shouldn't be
# made any more complex than it already is to try and cover more, eg, custom interpreters taking over
# system locations)
if has_respawned():
# this shouldn't be possible; short-circuit early if it happens...
module.fail_json(msg=f"{deb_pkg_name} must be installed and visible from {sys.executable}.")
interpreters = ['/usr/bin/python3', '/usr/bin/python']
interpreter = probe_interpreters_for_module(interpreters, 'debian')
if interpreter:
# found the Python bindings; respawn this module under the interpreter where we found them
respawn_module(interpreter)
# this is the end of the line for this process, it will exit here once the respawned module has completed
# don't make changes if we're in check_mode
if module.check_mode:
module.fail_json(msg=f"{deb_pkg_name} must be installed to use check mode. If run with install_python_debian, this module can auto-install it.")
if module.params['install_python_debian']:
install_python_debian(module, deb_pkg_name)
else:
module.fail_json(msg=f'{deb_pkg_name} is not installed, and install_python_debian is False')
# try again to find the bindings in common places
interpreter = probe_interpreters_for_module(interpreters, 'debian')
if interpreter:
# found the Python bindings; respawn this module under the interpreter where we found them
# NB: respawn is somewhat wasteful if it's this interpreter, but simplifies the code
respawn_module(interpreter)
# this is the end of the line for this process, it will exit here once the respawned module has completed
else:
# we've done all we can do; just tell the user it's busted and get out
module.fail_json(msg=missing_required_lib(deb_pkg_name),
exception=DEBIAN_IMP_ERR)
check_mode = module.check_mode

@ -1,13 +1,62 @@
- meta: end_play
when: ansible_os_family != 'Debian'
- set_fact:
python_debian: python3-debian
- block:
# UNINSTALL 'python3-debian'
# The `deb822_repository` module has the smarts to auto-install `python3-debian`. To
# test, we will first uninstall `python3-debian`.
- name: check {{ python_debian }} with dpkg
shell: dpkg -s {{ python_debian }}
register: dpkg_result
ignore_errors: true
- name: uninstall {{ python_debian }} with apt
apt: pkg={{ python_debian }} state=absent purge=yes
register: apt_result
when: dpkg_result is successful
- name: check failure when python3-debian is absent
deb822_repository:
name: myrepo
types: deb
uris: "http://example.com/debian/"
suites: stable
components: main
register: no_python3_debian
ignore_errors: true
- name: Assert failure with absent python3-debian
assert:
that: no_python3_debian.msg is contains 'python3-debian is not installed'
- name: run deb822 to check for python3-debian installation
deb822_repository:
name: myrepo
types: deb
uris: "http://example.com/debian/"
suites: stable
components: main
install_python_debian: true
- name: Clean up the previously added basic Debian repository
deb822_repository:
name: myrepo
state: absent
- name: install python3-debian
apt:
name: python3-debian
state: present
register: py3_deb_install
- name: assert python3-debian already installed
assert:
that:
- not py3_deb_install.changed
- import_tasks: test.yml
- import_tasks: install.yml

@ -119,6 +119,7 @@
focal_archive_expected: |-
Components: main restricted
Date-Max-Future: 10
Install-Python-Debian: no
X-Repolib-Name: ansible-test focal archive
Suites: focal focal-updates
Types: deb
@ -192,6 +193,7 @@
vars:
signed_by_inline_expected: |-
Components: main contrib non-free
Install-Python-Debian: no
X-Repolib-Name: ansible-test
Signed-By:
-----BEGIN PGP PUBLIC KEY BLOCK-----

Loading…
Cancel
Save