Search code examples
automationansibleapt

Installing hundreds of packages listed in a text file using apt in ansible


I used to just sudo apt install -y "$(cat pkg_apt)" and I want to do something similar in Ansible

I don't understand what are roles and why I need to use them.

I don't want to indent and fit into yaml file every package since there are hundreds of them that I have stored in a file from apt-mark showmanual I am running this on my local machine.

Where should I put the packages? In inventory file? in Var directory? in roles?

If I just have to use commands and load them into variable and do loop over them, then what is the point of ansible?


Solution

  • I don't want to indent and fit into yaml file every package since there are hundreds of them that I have stored in a file from apt-mark showmanual. I am running this on my local machine.

    I'll let you read on roles but we really don't need one at this point for the below example.

    Demo project structure

    $ tree
    .
    ├── pkg_apt
    └── playbook.yml
    
    0 directories, 2 files
    

    This can be stored in your favorite versionning system and updated whenever you make changes to your system.

    Stripped content of pkg_apt as gotten on my local machine using the same command as yours (i.e. apt-mark showmanual > pkg_apt)

    locate
    login
    lsb-release
    make
    memtest86+
    mokutil
    mousetweaks
    

    From there, what we have to do is extremely simple:

    1. load the above file into a usable list
    2. feed that list to the apt module at once into the name option so that all packages are installed during the same apt transaction. We don't want to loop:. See the notes on apt module documentations

      When used with a loop: each package will be processed individually, it is much more efficient to pass the list directly to the name option.

    The resulting playbook.yml looks like this:

    ---
    - name: Restore packages on system from a saved package list
      hosts: localhost
      become: true
      gather_facts: false
    
      vars:
        package_file: pkg_apt
        package_list: "{{ lookup('file', package_file) | split('\n') }}"
    
      tasks:
        - name: Install all packages in {{ package_file }} through apt
          ansible.builtin.apt:
            name: "{{ package_list }}"
            state: present
    

    which gives on my local machine (note: apt is reporting "ok" as expected since the packages are already installed on my system)

    $ ansible-playbook playbook.yml 
    
    PLAY [Restore packages on system from a saved package list] **********
    
    TASK [Install all packages in pkg_apt through apt] ***********
    ok: [localhost]
    
    PLAY RECAP ***********************************************************
    localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
    

    Since you mentioned using a single command line before as a bit of a frustration, note that all the above can be summarized into a single ansible ad-hoc one-liner running from the directory where you stored the file:

    ansible localhost -b -m apt \
    -e "package_list={{ lookup('file', 'pkg_apt') | split('\n') }}" \
    -a "name={{ package_list }} state=present"