Search code examples
ansibleansible-facts

Compare ansible registered variables for multiple hosts


I have this ansible playbook:

---
- name: Portal Quality Checks - IC
  become: yes
  hosts: all
  tasks:

   - name: Verify software version on Interconnect(s)
     shell: |
       dpkg -l | grep network-controller | awk '{print $3}'
     register: cv_raw
     when: inventory_hostname in groups.IC
     tags: ['ic', 'software']

   - debug:
       msg: "{{ (cv_raw.stdout_lines | last) }}"
     failed_when: ( hostvars[groups['IC'][0]].cv_raw.stdout_lines != hostvars[groups['IC'][1]].cv_raw.stdout_lines )
     ignore_errors: true
     tags: ['ic', 'software']

The output is something like:

TASK [debug] ****************************************************************************************************************************************************************************************************************************************************************************************************************
ok: [10.241.55.6] => {
    "msg": "5.0.0.0600-1"
}
ok: [10.241.55.8] => {
    "msg": "4.2.0.819477-1"
}

The ideea is that I'm trying to compare the version from the ouput (that's in the 2nd task in the playlist). Right now there are only 2 hosts in the inventory and it works just fine.

My question is how do I do this if I have let's say 10 hosts in the inventory and all should be running the same version? There should be an easier way to compare the resulted version for each of the hostname than how I'm doing it now hostvars[groups['IC'][0]].cv_raw.stdout_lines for host1 and hostvars[groups['IC'][0]].cv_raw.stdout_lines for host2 because it will really a lot of manual work to do this for each of the 10 hosts or even more complicated if let's say there are 50 hosts in the inventory.

Also I would be interested in displaying a message on the screen like:

Network Controller version:

host1 - version
host2 - version
host3 - version
...

Also if there is a version mismatch, then to display a message like:

Network Controller version missmatch:

host1 version different than host2 version etc...

Based on your suggestion, here's the output for 3 hosts, 2 of them running the same controller version and one of them running a different version:

TASK [debug]

ok: [10.241.55.6] => {
    "sw_versions": [
        {
            "host": "ro151",
            "version": "5.0.0.0600-1"
        },
        {
            "host": "PrimaryIC-Stack5",
            "version": "4.2.2.600111061-1"
        },
        {
            "host": "SecondaryIC-Stack5",
            "version": "4.2.2.600111061-1"
        }
    ]
}

So how do I compare those versions and display an error message if there's a version mismatch?

UPDATE:

So in addition to your playbook I've added this:

 - set_fact:
     compare_versions: "{{ groups.IC | map('extract', hostvars) | list | json_query('[].sw_version') }}"
 - debug:
     var: compare_versions
   run_once: true

Which results into a debug message of:

TASK [debug]
ok: [10.241.55.6] => {
    "compare_versions": [
        "5.0.0.0600-1",
        "4.2.2.600111061-1",
        "4.2.2.600111061-1"
    ]
}

So how do I compare those versions?!


Solution

  • Q: "Display a message on the screen like host1 - version ..."

    A: The tasks below do the job. For each host put the version into the variable sw_version. In the next task extract hostvars of the hosts from the group IC and create the list of the host-version dictionaries

    - set_fact:
        sw_version: "{{ cv_raw.stdout_lines|last }}"
    - set_fact:
        sw_versions: "{{ groups.IC|
                         map('extract', hostvars)|
                         list|
                         json_query('[].{host: ansible_hostname,
                                         version: sw_version}') }}"
      run_once: true
    

    For example, given the inventory below and the list of the versions from the question

    shell> cat hosts
    [IC]
    10.241.55.6 ansible_hostname=ro151
    10.241.55.8 ansible_hostname=PrimaryIC-Stack5
    10.241.55.9 ansible_hostname=SecondaryIC-Stack5
    

    the result would be

      sw_versions:
        - {host: ro151, version: 5.0.0.0600-1}
        - {host: PrimaryIC-Stack5, version: 4.2.2.600111061-1}
        - {host: SecondaryIC-Stack5, version: 4.2.2.600111061-1}
    

    Q: "How do I compare those versions and display an error message if there's a version mismatch?"

    A: Use Version Comparison tests to analyze the data. For example

        - debug:
            msg: "{{ item.host }} version is {{ item.version }}.
                  Upgrade to {{ install_version }}."
          loop: "{{ sw_versions }}"
          when: item.version is version( install_version, '<')
          vars:
            install_version: 5.0.0.0600-1
          run_once: true
    

    gives

      msg: PrimaryIC-Stack5 version is 4.2.2.600111061-1. Upgrade to 5.0.0.0600-1
      msg: SecondaryIC-Stack5 version is 4.2.2.600111061-1. Upgrade to 5.0.0.0600-1
    

    Q: "Let's say host1: 4.2.2.6, host2: 4.2.2.6, host3: 5.5.0. I want to display a message: Version mismatch between hosts: host1,host2, and host3. If all hosts are running the same version then say: All your hosts are running the same version."

    A: For example

        - block:
            - debug:
                msg: "All your hosts are running the same version."
              when: sw_versions|json_query('[].version')|unique|length == 1
            - debug:
                msg: |-
                  Version mismatch among hosts:
                  {{ my_hosts|to_nice_yaml }}
              when: sw_versions|json_query('[].version')|unique|length > 1
              vars:
                my_hosts: "{{ sw_versions|json_query('[].host') }}"
          run_once: true
    

    gives

      msg:
        Version mismatch among hosts:
        - ro151
        - PrimaryIC-Stack5
        - SecondaryIC-Stack5
    

    If all versions are the same the result will be

      msg: All your hosts are running the same version.
    

    Notes

        - set_fact:
            versions_hosts: "{{ dict(_keys|zip(_vals)) }}"
          vars:
            _groupby: "{{ sw_versions|groupby('version') }}"
            _keys: "{{ _groupby|map('first')|list }}"
            _vals: "{{ _groupby|map('last')|map('map', attribute='host')|list }}"
          run_once: true
    

    gives

      versions_hosts:
        4.2.2.600111061-1: [PrimaryIC-Stack5, SecondaryIC-Stack5]
        5.0.0.0600-1: [ro151]