Dibya prakash
Dibya prakash

Reputation: 13

Check if multiple packages in redhat machine are already installed if not available then install via ansible playbook

I want to check if certain packages are installed in my nodes or not. If not then install those packages via ansible playbook.

Here are the variables that I am providing to the playbook as input (node IPs & packages to be installed):

exec_server: '10.50.10.40,34.228.208.5'
pkgs:
  - zip
  - unzip
  - git

Here is the playbook I wrote to find out if any of the packages has been installed and, if not, then install them.

- name: Check Package installation
  hosts: "{{ exec_server }}"
  become: yes
  gather_facts: no
  
  tasks:
    - name: Gather the packager facts
      package_facts:
        manager: "auto"
  
    - name: Package status
      debug:
        msg: "{{ item }} {{ 'installed' if item in ansible_facts.packages else 'not installed' }}"
      loop: "{{ pkgs | default([]) }}"
      register: find_output

    - name: install the latest version of not installed Packages
      yum:
        name: "{% if pkgs is undefined in ansible_facts.packages %}-{{ pkgs }}{% endif %}"
        state: latest 

The error that I am facing:

Identity added: /tmp/awx_2137_f_94gy2c/artifacts/2137/ssh_key_data (/tmp/awx_2137_f_94gy2c/artifacts/2137/ssh_key_data)

PLAY [Check Package installation] **********************************************

TASK [Gather the packager facts] ***********************************************
ok: [34.228.208.5]
ok: [10.50.10.40]

TASK [Package status] **********************************************************
ok: [10.50.10.40] => (item=zip) => {
    "msg": "zip installed"
}
ok: [10.50.10.40] => (item=unzip) => {
    "msg": "unzip installed"
}
ok: [10.50.10.40] => (item=git) => {
    "msg": "git not installed"
}
ok: [10.50.10.40] => (item=python-pip) => {
    "msg": "python-pip not installed"
}
ok: [10.50.10.40] => (item=gcc) => {
    "msg": "gcc not installed"
}
ok: [34.228.208.5] => (item=zip) => {
    "msg": "zip installed"
}
ok: [34.228.208.5] => (item=unzip) => {
    "msg": "unzip installed"
}
ok: [34.228.208.5] => (item=git) => {
    "msg": "git not installed"
}
ok: [34.228.208.5] => (item=python-pip) => {
    "msg": "python-pip not installed"
}
ok: [34.228.208.5] => (item=gcc) => {
    "msg": "gcc not installed"
}

TASK [install the latest version of Uninstalled Packages] **********************
fatal: [10.50.10.40]: FAILED! => {"msg": "template error while templating string: expected token 'end of statement block', got 'ansible_facts'. String: {% if pkgs is undefined in ansible_facts.packages %}-{{ pkgs }}{% endif %}"}
fatal: [34.228.208.5]: FAILED! => {"msg": "template error while templating string: expected token 'end of statement block', got 'ansible_facts'. String: {% if pkgs is undefined in ansible_facts.packages %}-{{ pkgs }}{% endif %}"}

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

How can I only get the packages that are not installed based on my pkgs variables and the facts gathered by Ansible?

Upvotes: 1

Views: 798

Answers (1)

β.εηοιτ.βε
β.εηοιτ.βε

Reputation: 39264

You don't need to check if the package is installed or not before doing anything, this is what the state: present is for:

present and installed will simply ensure that a desired package is installed.

Source: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/yum_module.html#parameter-state

So your playbook should be as simple as

- name: Check Package installation
  hosts: "{{ exec_server }}"
  become: yes
  gather_facts: no
  
  tasks:
    - name: install the latest version of not installed Packages
      yum:
        name: "{{ pkgs }}"
        state: present 

Now if you want to know what is incorrect in your construct, it is the if:

{% if pkgs is undefined in ansible_facts.packages %}-{{ pkgs }}{% endif %}

You cannot run two test on the same variable in the same instruction (without an or or and, that is).
While here you are trying to run an in and is undefined tests at the same time.

What you could do, if you want to keep in that route, which is sub-optimal, as stated above, is to use the difference filter:

- name: install the latest version of not installed Packages
  yum:
    name: "{{ pkgs | difference(ansible_facts.packages) }}"
    state: latest 

Upvotes: 1

Related Questions