简体   繁体   中英

Ansible: count hosts based on specific fact

I'm using Ansible 2.9.13 to manage about 250 ubuntu clients. If I list all the facts of one client, one of the lines is:

"distribution_release": "bionic",

What I would like to do now is count the number of machines, which are bionic, focal, and any other version it may find. So, something like this:

bionic:  180
focal:   42
precise: 2

Is that possible and if yes, how?

You can use group_by to create new dynamic groups on the fly.

---
 - name: Count hosts based on ansible_distribution_release
   hosts: "{{ target|default('all') }}"
   gather_facts: true

   tasks:
    - name: Create dynamic groups
      group_by:
        key: dist_release_{{ ansible_distribution_release }}

 - name: Make the statistics
   hosts: localhost
   gather_facts: false

   tasks:
     - name: Sample output
       debug:
         msg: "Group {{ item }} has {{ groups[item] | length }} hosts."
       when: item.startswith('dist_release_')
       loop: "{{ groups|flatten(levels=1) }}"

The first play creates dynamic groups based on {{ ansible_distribution_release }} and all groups start with the prefix dist_ .

In the second play the dynamic groups will just be used to create a rather ugly but working statistics of the groups and the number of hosts within the groups.

If you like you could just use Jinja2 template to create a nice output to a file.

Create the dictionary from the hostvars in a single task

- hosts: all
  tasks:
    - set_fact:
        distros: "{{ distros|default({})|
                     combine({ item.0: item.1|length }) }}"
      loop: "{{ hostvars|dict2items|
                groupby('value.ansible_distribution_release') }}"
      run_once: true

The same dictionary can be created without iteration when json_query is used

- hosts: all
  tasks:
    - set_fact:
        distros: "{{ dict(keys|zip(vals)) }}"
      vars:
        dist: "{{ hostvars|dict2items|
                  json_query('[].{distro: value.ansible_distribution_release}')|
                  groupby('distro') }}"
        keys: "{{ dist|map('first')|list }}"
        vals: "{{ dist|map('last')|map('length')|list }}"
      run_once: true

Next option is to create the dictionary with the help of a custom filter

shell> cat filter_plugins/count.py
def count(l):
    d = {}
    for i in set(l):
        d[i] = l.count(i)
    return d

class FilterModule(object):

        def filters(self):
            return {
                'count': count,
                }
- hosts: all
  tasks:
    - set_fact:
        distros: "{{ hostvars|
                     json_query('*.ansible_distribution_release')|
                     count}}"
      run_once: true

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM