From e162eda1e6512790f93da860c857b2c243d8d75d Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Thu, 3 Jul 2025 09:25:11 -0700 Subject: [PATCH] apt: Mark dependencies as auto (#85170) * Mark dependent packages as auto which are installed as part of deb file installation Fixes: #78123 Co-authored-by: Matt Clay Signed-off-by: Abhijeet Kasurde --- changelogs/fragments/apt_deb_install.yml | 3 ++ lib/ansible/modules/apt.py | 28 +++++++++------- .../targets/apt/tasks/apt_deb_depend.yml | 33 +++++++++++++++++++ test/integration/targets/apt/tasks/main.yml | 2 ++ .../package_specs/stable/packagetwo-1.0.0 | 10 ++++++ 5 files changed, 65 insertions(+), 11 deletions(-) create mode 100644 changelogs/fragments/apt_deb_install.yml create mode 100644 test/integration/targets/apt/tasks/apt_deb_depend.yml create mode 100644 test/integration/targets/setup_deb_repo/files/package_specs/stable/packagetwo-1.0.0 diff --git a/changelogs/fragments/apt_deb_install.yml b/changelogs/fragments/apt_deb_install.yml new file mode 100644 index 00000000000..4f96af6c7d3 --- /dev/null +++ b/changelogs/fragments/apt_deb_install.yml @@ -0,0 +1,3 @@ +--- +bugfixes: + - apt - mark dependencies installed as part of deb file installation as auto (https://github.com/ansible/ansible/issues/78123). diff --git a/lib/ansible/modules/apt.py b/lib/ansible/modules/apt.py index 5efc3653fcf..53c403133a2 100644 --- a/lib/ansible/modules/apt.py +++ b/lib/ansible/modules/apt.py @@ -372,6 +372,7 @@ import locale as locale_module import os import re import secrets +import shlex import shutil import sys import tempfile @@ -390,8 +391,6 @@ APT_GET_ZERO = "\n0 upgraded, 0 newly installed, 0 to remove" APTITUDE_ZERO = "\n0 packages upgraded, 0 newly installed, 0 to remove" APT_LISTS_PATH = "/var/lib/apt/lists" APT_UPDATE_SUCCESS_STAMP_PATH = "/var/lib/apt/periodic/update-success-stamp" -APT_MARK_INVALID_OP = 'Invalid operation' -APT_MARK_INVALID_OP_DEB6 = 'Usage: apt-mark [options] {markauto|unmarkauto} packages' CLEAN_OP_CHANGED_STR = dict( autoremove='The following packages will be REMOVED', @@ -690,26 +689,30 @@ def parse_diff(output): return {'prepared': '\n'.join(diff[diff_start:diff_end])} -def mark_installed_manually(m, packages): +def mark_installed(m: AnsibleModule, packages: list[str], manual: bool) -> None: + """Mark packages as manually or automatically installed.""" if not packages: return + if manual: + mark_msg = "manually" + mark_op = "manual" + else: + mark_msg = "auto" + mark_op = "auto" + apt_mark_cmd_path = m.get_bin_path("apt-mark") # https://github.com/ansible/ansible/issues/40531 if apt_mark_cmd_path is None: - m.warn("Could not find apt-mark binary, not marking package(s) as manually installed.") + m.warn(f"Could not find apt-mark binary, not marking package(s) as {mark_msg} installed.") return - cmd = "%s manual %s" % (apt_mark_cmd_path, ' '.join(packages)) + cmd = [apt_mark_cmd_path, mark_op] + packages rc, out, err = m.run_command(cmd) - if APT_MARK_INVALID_OP in err or APT_MARK_INVALID_OP_DEB6 in err: - cmd = "%s unmarkauto %s" % (apt_mark_cmd_path, ' '.join(packages)) - rc, out, err = m.run_command(cmd) - if rc != 0: - m.fail_json(msg="'%s' failed: %s" % (cmd, err), stdout=out, stderr=err, rc=rc) + m.fail_json(msg=f"Command {shlex.join(cmd)!r} failed.", stdout=out, stderr=err, rc=rc) def install(m, pkgspec, cache, upgrade=False, default_release=None, @@ -835,7 +838,7 @@ def install(m, pkgspec, cache, upgrade=False, default_release=None, data = dict(changed=False) if not build_dep and not m.check_mode: - mark_installed_manually(m, package_names) + mark_installed(m, package_names, manual=True) return (status, data) @@ -914,6 +917,9 @@ def install_deb( dpkg_options=install_dpkg_options) if not success: m.fail_json(**retvals) + # Mark the dependencies as auto installed + # https://github.com/ansible/ansible/issues/78123 + mark_installed(m, deps_to_install, manual=False) changed = retvals.get('changed', False) if pkgs_to_install: diff --git a/test/integration/targets/apt/tasks/apt_deb_depend.yml b/test/integration/targets/apt/tasks/apt_deb_depend.yml new file mode 100644 index 00000000000..0cb26b6e6d0 --- /dev/null +++ b/test/integration/targets/apt/tasks/apt_deb_depend.yml @@ -0,0 +1,33 @@ +- block: + - name: Clean up before running tests + apt: + name: + - packageone + - packagetwo + state: absent + + - name: Install packageone from deb URL + apt: + deb: https://ci-files.testing.ansible.com/test/integration/targets/apt/packageone_1.0_all.deb + register: packageone_installed + + - name: Check if packagetwo is installed as part of packageone installation + shell: dpkg -s packagetwo + + - name: Check if packageone and packagetwo are marked as auto + shell: apt-mark showauto packageone packagetwo + register: auto_installed + + - name: Make sure packageone is installed manually and packagetwo is marked as auto + assert: + that: + - packageone_installed.changed + - auto_installed.stdout_lines == ["packagetwo"] + + always: + - name: Clean up after tests + apt: + name: + - packageone + - packagetwo + state: absent diff --git a/test/integration/targets/apt/tasks/main.yml b/test/integration/targets/apt/tasks/main.yml index f9c185eba0f..4ae93219d69 100644 --- a/test/integration/targets/apt/tasks/main.yml +++ b/test/integration/targets/apt/tasks/main.yml @@ -22,6 +22,8 @@ - block: - import_tasks: 'apt.yml' + - import_tasks: 'apt_deb_depend.yml' + - import_tasks: 'url-with-deps.yml' - import_tasks: 'apt-multiarch.yml' diff --git a/test/integration/targets/setup_deb_repo/files/package_specs/stable/packagetwo-1.0.0 b/test/integration/targets/setup_deb_repo/files/package_specs/stable/packagetwo-1.0.0 new file mode 100644 index 00000000000..c02d6845524 --- /dev/null +++ b/test/integration/targets/setup_deb_repo/files/package_specs/stable/packagetwo-1.0.0 @@ -0,0 +1,10 @@ +Section: misc +Priority: optional +Standards-Version: 2.3.3 + +Package: packagetwo +Version: 1.0 +Section: system +Maintainer: John Doe +Architecture: all +Description: Dummy package upon which packageone depends