Repository: ansible/ansible
Pull request: apt: honor cache_update=false on auto-install deps
##### SUMMARY
 Fixed the issue the cache being updated while auto-installing its
  dependencies even ``update_cache`` is set to false. Fixes #51489

##### ISSUE TYPE
<!--- Pick one below and delete the rest -->
- Bugfix Pull Request

##### COMPONENT NAME
<!--- Write the short name of the module, plugin, task or feature below -->
apt

##### ADDITIONAL INFORMATION
<!--- Include additional information to help people understand the change here -->
<!--- A step-by-step reproduction of the problem is helpful if there is no related issue -->

<!--- Paste verbatim command output below, e.g. before and after your change -->
```paste below

```


Problem statement:
apt does not honor update_cache
##### ISSUE TYPE
- Bug Report

##### COMPONENT NAME
ansible/lib/python2.7/site-packages/ansible/modules/packaging/os/apt.py


##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes -->
```
ansible 2.7.6
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/usr/share/ansible']
  ansible python module location = /home/ansible/ansible/lib/python2.7/site-packages/ansible
  executable location = /home/ansible/ansible/bin/ansible
  python version = 2.7.5 (default, Jul 13 2018, 13:06:57) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]

```

##### CONFIGURATION
- Default

##### OS / ENVIRONMENT
- Debian GNU/Linux 9

##### SUMMARY
I need to install a custom .deb and for some internal reason some repositories are not working, so I do not want 'apt-get update' to be ran. So, here is my task : 
```
- name: Install package
  apt:
    update_cache: false
    deb: '/root/local_package_amd64.deb'
    state: present
```
when I run the playbook, it seams that ansible is always trying to update the apt cache.
fatal: [hostanem]: FAILED! => {"changed": false, "cmd": "apt-get update", "msg": "W:....."]}

The issue seams to come from the module : apt (modules/packaging/os/apt.py)
```
    if not HAS_PYTHON_APT:
        if module.check_mode:
            module.fail_json(msg="%s must be installed to use check mode. "
                                 "If run normally this module can auto-install it." % PYTHON_APT)
        try:
            module.run_command(['apt-get', 'update'], check_rc=True)
            module.run_command(['apt-get', 'install', '--no-install-recommends', PYTHON_APT, '-y', '-q'], check_rc=True)
```
We can see that if python-apt is not installed, it will run apt-get update no matter what.
ansible should honor update_cache/cache_valid_time variables

Hints from issue discussion:
Files identified in the description:
* [lib/ansible/modules/packaging/os/apt.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/packaging/os/apt.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @mgwilliams
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
resolved_by_pr #56549

Commit message: add porting guide

Patch to review:
diff --git a/changelogs/fragments/51489-apt-not-honor-update-cache.yml b/changelogs/fragments/51489-apt-not-honor-update-cache.yml
new file mode 100644
index 00000000000000..4f9ebca4faa983
--- /dev/null
+++ b/changelogs/fragments/51489-apt-not-honor-update-cache.yml
@@ -0,0 +1,4 @@
+---
+bugfixes:
+- apt - Fixed the issue the cache being updated while auto-installing its
+  dependencies even ``update_cache`` is set to false.
diff --git a/docs/docsite/rst/porting_guides/porting_guide_2.9.rst b/docs/docsite/rst/porting_guides/porting_guide_2.9.rst
index da602ec92a3755..442ae01446aecf 100644
--- a/docs/docsite/rst/porting_guides/porting_guide_2.9.rst
+++ b/docs/docsite/rst/porting_guides/porting_guide_2.9.rst
@@ -61,7 +61,7 @@ Modules
 =======
 
 * The ``win_get_url`` and ``win_uri`` module now sends requests with a default ``User-Agent`` of ``ansible-httpget``. This can be changed by using the ``http_agent`` key.
-
+* The ``apt`` module now honors ``update_cache=false`` while installing its own dependency and skips the cache update. Explicitly set ``update_cache=true` or omitting the param ``update_cache`` will result in a cache update while installing its own dependency.
 
 Writing modules
 ---------------
diff --git a/lib/ansible/modules/packaging/os/apt.py b/lib/ansible/modules/packaging/os/apt.py
index 5eb806c70f8262..d8795489dc81f2 100644
--- a/lib/ansible/modules/packaging/os/apt.py
+++ b/lib/ansible/modules/packaging/os/apt.py
@@ -1031,8 +1031,14 @@ def main():
             module.fail_json(msg="%s must be installed to use check mode. "
                                  "If run normally this module can auto-install it." % PYTHON_APT)
         try:
-            module.warn("Updating cache and auto-installing missing dependency: %s" % PYTHON_APT)
-            module.run_command(['apt-get', 'update'], check_rc=True)
+            # We skip cache update in auto install the dependency if the
+            # user explicitly declared it with update_cache=no.
+            if module.params.get('update_cache') is False:
+                module.warn("Auto-installing missing dependency without updating cache: %s" % PYTHON_APT)
+            else:
+                module.warn("Updating cache and auto-installing missing dependency: %s" % PYTHON_APT)
+                module.run_command(['apt-get', 'update'], check_rc=True)
+
             module.run_command(['apt-get', 'install', '--no-install-recommends', PYTHON_APT, '-y', '-q'], check_rc=True)
             global apt, apt_pkg
             import apt
diff --git a/test/integration/targets/apt/tasks/apt.yml b/test/integration/targets/apt/tasks/apt.yml
index b0131682dd220b..9a51a7609eba10 100644
--- a/test/integration/targets/apt/tasks/apt.yml
+++ b/test/integration/targets/apt/tasks/apt.yml
@@ -31,6 +31,57 @@
   register: apt_result
   when: dpkg_result is successful
 
+# In check mode, auto-install of `python-apt` must fail
+- name: test fail uninstall hello without required apt deps in check mode
+  apt:
+    pkg: hello
+    state: absent
+    purge: yes
+  register: apt_result
+  check_mode: yes
+  ignore_errors: yes
+
+- name: verify fail uninstall hello without required apt deps in check mode
+  assert:
+    that:
+    - apt_result is failed
+    - '"If run normally this module can auto-install it." in apt_result.msg'
+
+- name: check {{ python_apt }} with dpkg
+  shell: dpkg -s {{ python_apt }}
+  register: dpkg_result
+  ignore_errors: true
+
+# UNINSTALL 'hello'
+#   With 'python-apt' uninstalled, the first call to 'apt' should install
+#   python-apt without updating the cache.
+- name: uninstall hello with apt and prevent updating the cache
+  apt:
+    pkg: hello
+    state: absent
+    purge: yes
+    update_cache: no
+  register: apt_result
+
+- name: check hello with dpkg
+  shell: dpkg-query -l hello
+  failed_when: False
+  register: dpkg_result
+
+- name: verify uninstall hello with apt and prevent updating the cache
+  assert:
+    that:
+    - "'changed' in apt_result"
+    - apt_result is not changed
+    - "dpkg_result.rc == 1"
+    - "'Auto-installing missing dependency without updating cache: {{ python_apt }}' in apt_result.warnings"
+
+- name: uninstall {{ python_apt }} with apt again
+  apt:
+    pkg: "{{ python_apt }}"
+    state: absent
+    purge: yes
+
 # UNINSTALL 'hello'
 #   With 'python-apt' uninstalled, the first call to 'apt' should install
 #   python-apt.
@@ -46,8 +97,10 @@
 - name: verify uninstallation of hello
   assert:
     that:
-        - "'changed' in apt_result"
-        - "dpkg_result.rc == 1"
+    - "'changed' in apt_result"
+    - apt_result is not changed
+    - "dpkg_result.rc == 1"
+    - "'Updating cache and auto-installing missing dependency: {{ python_apt }}' in apt_result.warnings"
 
 # UNINSTALL AGAIN
 - name: uninstall hello with apt
@@ -259,7 +312,7 @@
     that:
       - apt_result is not changed
 
-# check policy_rc_d parameter 
+# check policy_rc_d parameter
 
 - name: Install unscd but forbid service start
   apt:


Code review comments:
diff_hunk: @@ -0,0 +1,4 @@
+---
+bugfixes:
+- apt - Fixed the issue the cache being updated while auto-installing its
+  dependencies even ``update_cache`` is set to false.
path: changelogs/fragments/51489-apt-not-honor-update-cache.yml
text: @user1:
```suggestion
  dependencies even when ``update_cache`` is set to false.
```

diff_hunk: @@ -61,7 +61,7 @@ Modules
 =======
 
 * The ``win_get_url`` and ``win_uri`` module now sends requests with a default ``User-Agent`` of ``ansible-httpget``. This can be changed by using the ``http_agent`` key.
-
+* The ``apt`` module now honors ``update_cache=false`` while installing its own dependency and skips the cache update. Explicitly set ``update_cache=true` or omitting the param ``update_cache`` will result in a cache update while installing its own dependency.
path: docs/docsite/rst/porting_guides/porting_guide_2.9.rst
text: @user1:
```suggestion
* The ``apt`` module now honors ``update_cache=false`` while installing its own dependency and skips the cache update. Explicitly setting ``update_cache=true`` or omitting the param ``update_cache`` will result in a cache update while installing its own dependency.
```