25

I maintain a flock of EC2 servers with ansible. The servers are regularly updates and upgraded using the apt module.

When I manually tried to upgrade a server, I received the following message:

$ sudo apt-get upgrade
Reading package lists... Done
Building dependency tree
Reading state information... Done
Calculating upgrade... Done
The following packages were automatically installed and are no longer required:
  linux-headers-3.13.0-29 linux-headers-3.13.0-29-generic
  linux-headers-3.13.0-32 linux-headers-3.13.0-32-generic
  linux-image-3.13.0-29-generic linux-image-3.13.0-32-generic
Use 'apt-get autoremove' to remove them.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

Is there a way to run sudo apt-get autoremove with ansible?

Adam Matan
  • 13,194
  • 19
  • 55
  • 75

6 Answers6

31

Support for the apt-get option --auto-remove is now built into Ansible's apt (option autoremove) as of version 2.1 Official documentation is at http://docs.ansible.com/ansible/apt_module.html

- name: Remove dependencies that are no longer required
  apt:
    autoremove: yes

The merge happened here.

Note that autoclean is also available as of 2.4

oalders
  • 426
  • 4
  • 6
  • Could you please add a reference link? – Adam Matan Apr 14 '16 at 13:51
  • @AdamMatan Updated answer with a link to the docs. – oalders Apr 14 '16 at 17:40
  • 1
    if you check [here](https://github.com/ansible/ansible-modules-core/issues/4029) you will see that "autoremove" with a "state" option is considered a bug. Ansible dev team will need to define if "autoremove" will be only an option or an full operation for Ansible 2.2 (I hope...) – Yonsy Solis Oct 19 '16 at 12:59
  • @YonsySolis someone hijacked this answer via an edit. I've reverted it to its original state. – oalders Oct 19 '16 at 13:20
  • Is it possible to run the autoremove as just `apt-get autoremove` rather than having to specify a package to act against with the --auto-remove flag? – flickerfly Nov 09 '16 at 02:56
  • 1
    @flickerfly according to the docs you should be able to run this without having to provide a package name. I've updated my answer to reflect this. – oalders Jul 06 '17 at 11:03
14

This simplified method requires one task only

  - name: Autoremove unused packages
    command: apt-get -y autoremove
    register: autoremove_output
    changed_when: "'The following packages will be REMOVED' in autoremove_output.stdout"
cortopy
  • 363
  • 5
  • 10
10

You can do it with command (untested):

  - name: Check if anything needs autoremoving
    shell: apt-get -y --dry-run autoremove | grep -q "0 to remove"
    register: check_autoremove
    ignore_errors: True
    changed_when: False
    always_run: True

  - name: Autoremove unused packages
    command: apt-get -y autoremove
    when: "check_autoremove.rc != 0"

However, I think it could be risky to run autoremove automatically. Because of system administration errors that you've made in the past (these could be in your ansible code), it's possible that a package that is needed can at some point be falsely detected as autoremovable, and this could stop the server from working. On the other hand, it's no big deal to leave unused packages on the system, and it's not very common unless you make a major change in the server's setup.

Therefore, I would stay away from autoremoving packages without confirmation from a human.

Antonis Christofides
  • 2,598
  • 2
  • 23
  • 35
  • Ansible does not necessarily mark packages as 'manual', even if you have installed them using the apt module. So 'autoremove' might remove the wrong packages. Quick fix: use ```apt-mark manual ``` – Willem Mar 04 '15 at 16:47
  • 1
    On Ubuntu, if you don't do regular autoremove, then your /boot might fill up until it is full! Mostly autoremove has only removed older unused kernel. Because, this needs regular check, it ought to be automated. :-) On Fedora/RHEL, you can instruct yum/dnf to keep only a certain number of package (like 3 kernel versions), so you never have this problem. – Huygens Sep 09 '15 at 12:26
6

This is a variation on the solution Antonis Christofides provided. It is tested and works for me. I avoided using ignore_errors in the check command. Otherwise it generally takes the same approach.

- name: Check if packages need to be autoremoved
  command: apt-get --dry-run autoremove
  register: check_autoremove
  changed_when: False
- name: Autoremove unused packages
  command: apt-get -y autoremove
  when: "'packages will be REMOVED' in check_autoremove.stdout"
Marwan Alsabbagh
  • 401
  • 8
  • 13
  • What's the reason for a `--dry-run` first? `apt-get -y autoremove` doesn't return a non-zero status. So it seems you could unconditionally run without the `--dry-run` and check `changed_when` against the actual autoremove call I think. – thom_nic Apr 14 '15 at 17:11
  • @thom_nic I think you're right. I was able to structure like this: - name: autoremove unused packages become: yes command: apt-get -y autoremove register: check_autoremove changed_when: "'packages will be REMOVED' in check_autoremove.stdout" – Luke Hoersten Aug 07 '15 at 15:08
2

A variation that highlights the change in packages (first task will be appropriately colored green or yellow):

  - name: check if packages need to be autoremoved
    shell: apt-get --dry-run autoremove | grep "to remove" | sed "s/^[0-9]\+ upgraded, [0-9]\+ newly installed, \([0-9]\+\) to remove and [0-9]\+ not upgraded\.$/\1/"
    register: check_autoremove
    changed_when: check_autoremove.stdout != "0"

  - name: autoremove unused packages
    command: apt-get -y autoremove
    when: check_autoremove.changed
Martin Tapp
  • 131
  • 3
  • Problem with your "sed" string is that it is not "portable". The execution of `apt-get --dry-run autoremove | grep "to remove"` returns on Ubuntu 14.04, `0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.` but on Ubuntu 15.04 it returns `0 to upgrade, 0 to newly install, 0 to remove and 0 not to upgrade.` which your sed doesn't match. – Huygens Sep 09 '15 at 11:21
  • Always hard to match changing text. Probably replace `install` with `install(ed)?` or something like that. – Martin Tapp Sep 09 '15 at 13:45
1

I like this simplified method, and I add some check and print message for me.

#!/usr/bin/env ansible-playbook
---

- name: Autoremove 'apt' package for Debian, Ubuntu
  hosts: all

  pre_tasks:
    - name: check storage space - before
      shell: df -h
      register: check_storage_space_before

    - name: print storage space
      debug:
        msg: "{{ check_storage_space_before.stdout_lines }}"

    - name: apt autoremove check 
      command: apt-get -y --dry-run autoremove
      register: apt_autoremove_output

    - name: print apt autoremove packages
      debug:
        msg: "{{ apt_autoremove_output.stdout_lines }}"

  tasks:    
    - name: autoremove unused packages
      become: yes
      command: apt-get -y autoremove
      changed_when: "'The following packages will be REMOVED' in apt_autoremove_output.stdout"

  post_tasks:
    - name: check storage space - after
      shell: df -h
      register: check_storage_space_after

    - name: print storage space
      debug:
        msg: "{{ check_storage_space_after.stdout_lines }}"

# vim: ft=ansible :

Thank you for cortopy and Dave James Miller.