Q: How to create a random number 1-3 and dynamically assign to hosts on a per-host basis?

I feel like this is a dumb question that’s been answered a million times, but my Google-fu has failed me.

I have clusters of 30 hosts, and would like for them NOT to reboot all at once for patches. So, our VM admins have given me an option: update “patching.cfg” with a number between 1 and 3, and they’ll do the reboots in batches based on the number.

Great! However, I can’t for the life of me figure out how to do that in Ansible without just manually assigning the numbers to each host. Anybody know how to do this dynamically, so that it’ll just expand if I doubled the hosts in the cluster or something?

So there’s not enough information here in terms of what kind of hosts you’re referring to. RHEL, Ubuntu, Windows? However for the sake of just providing an example I’ll use RHEL. The 2nd play of the playbook will reboot the hosts in 30% increments (based on the total). HTH

- name: Example
  hosts: all
  gather_facts: true
  tasks:
    
     - name:  include patching tasks
       ansible.builtin.include_tasks: 
         file: patching.yml

    - name: Run needs-restarting
      ansible.builtin.command: needs-restarting -r
      register: results
      failed_when: false

   - name: Create in memory inventory
     ansible.builtin.add_host:
        hostname: "{{ ansible_hostname }}"
        groups: reboot_group
    when: results['rc'] | int == 1


- name: Reboot  a percentage of hosts
  hosts: reboot_group
  serial: 30%
  tasks:
   
     - name: reboot hosts
       ansible.buiiltin.reboot:



I don’t believe the OS should matter here. I’m not personally trying to reboot the hosts; I’m trying to put a number into a file (which I actually know how to do), and crucially, I need this number to be between 1-3 but different for each host.

So for example, my initial thought had been some kind of modulus operator, like:
foo_host_1: 1%3
foo_host_2: 2%3
foo_host_3: 3%3
foo_host_4: 4%3
foo_host_5: 5%3
foo_host_6: 6%3
etc.

But I’d much prefer to do that in the playbook as opposed to the inventory file, because that seems like the most scalable way to approach it (and I do need this to be scalable; we have a large-ish and increasing number of servers). And that is where I get stymied.

I’m looking now at the docs page and examples for playbook strategies and it doesn’t look obvious to me how I could use that to achieve what I’m looking for: different numbers on each host between 1-3 (e.g. using modulus somehow). Maybe I’m missing something, though! Wouldn’t be the first time! :slight_smile:

Is that a little bit clearer in what I’m looking for?

How about taking a pseudorandom number seeded by the inventory hostname? If the inventory hostname stays constant for the lifetime of a machine, this gives you the same “random” number for that machine. It’s even mentioned in the docs: Using filters to manipulate data — Ansible Community Documentation

Adjusting to your needs (since you want the numbers 1, 2, 3):

{{ 1 + (3 | random(seed=inventory_hostname)) }}
1 Like

Thank you both! Your suggestions got us discussing more internally, and this is the solution we’re using now. Leaving it here so if anyone comes behind us wondering how to do something similar, hopefully they don’t spend as much time on it as we did! This in the value in our replace line using the replace module:

patching_group={{ ((play_hosts.index(ansible_hostname) + 1) % 3) + 1 }}

@huntes5 there’s one downside of your solution you need to be aware of: if the list play_hosts changes (for example if you add hosts, or restrict the playbook to a group), the generated numbers also change. This is fine if you only need the number to be constant for this play, but can be problematic if you need it to be constant over a longer time and when the host list changes.