linuxansiblepackage

Read every line from a text file through ansible


I have to read every line from a text file and add that in yaml. Here is my play book

- hosts: localhost
  tasks:
    - name: Register a file content as a variable
      ansible.builtin.shell: cat /home/packages.txt
      register: result

    - name: Print the transformed variable
      ansible.builtin.debug:
        msg: '{{ item }}'
      loop: '{{ result.stdout | list }}'

    - name: install
      shell: yum install '{{ item }}'
      loop: '{{ result.stdout | list }}'

packages.txt contains

nginx
vim
grafana

When I run this, the packages are not getting installed. This is the console output,

TASK [Register a file content as a variable] **********************************************************************************
changed: [localhost]

TASK [Print the transformed variable] *****************************************************************************************

TASK [install] ****************************************************************************************************************

PLAY RECAP ********************************************************************************************************************
localhost : ok=2    changed=1    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0

Requirement is to install those packages from the text file through this ansible playbook


Solution

  • Given the file

    shell> cat packages.txt
    nginx
    vim
    grafana
    

    On localhost, iterate the list. For example, the playbook below

    shell> cat test.yml
    - hosts: localhost
    
      tasks:
    
        - name: install
          package:
            name: "{{ item }}"
          loop: "{{ lookup('file', 'packages.txt').split() }}"
    

    gives (abridged, if the packages have already been installed)

    
    TASK [install] *******************************************************
    ok: [localhost] => (item=nginx)
    ok: [localhost] => (item=vim)
    ok: [localhost] => (item=grafana)
    
    

    The module package says:

    To operate on several packages this can accept a comma-separated string of packages or a list of packages, depending on the underlying package manager.

    You can check with the package managers. For example, the below package managers allow the list of packages:

    Then, you don't have to iterate the installation

        - name: install
          when: ansible_os_family in ['Debian', 'FreeBSD', 'RedHat']
          package:
            name: "{{ lookup('file', 'packages.txt').split() }}"
    

    You can check with other package managers and fit the list of the systems to your needs.

    The variable ansible_pkg_mgr keeps the system's package manager. For example, in FreeBSD

    shell> ansible <remote_host> -m setup | grep ansible_pkg_mgr
            "ansible_pkg_mgr": "pkgng",
    

    On a remote host (lookup works on the localhost only), iterate stdout_lines. For example,

        - name: Register a file content as a variable
          command: cat packages.txt
          register: result
    
        - name: install
          package:
            name: "{{ item }}"
          loop: "{{ result.stdout_lines }}"
    

    Optionally, if you want to avoid the command or shell module use fetch. For example, in the playbook below

    shell> cat test.yml
    - hosts: test_11
    
      tasks:
    
        - name: Get file
          fetch:
            src: packages.txt
            dest: files
    
        - name: install
          package:
            name: "{{ item }}"
          loop: "{{ lookup('file', path).split() }}"
          vars:
            path: 'files/{{ inventory_hostname }}/packages.txt'
    

    fetch the file from the remote host(s) first. This will create the file

    shell> cat files/test_11/packages.txt 
    nginx
    vim
    grafana
    

    Then iterate the lines from the file

    TASK [install] ***************************************************
    changed: [test_11] => (item=nginx)
    changed: [test_11] => (item=vim)
    changed: [test_11] => (item=grafana)