Search code examples
ansibleansible-inventory

Ansible - Use a variable as a slice value [0:var_name]


Is there a way to dynamically assign a variable as the slice amount when working with lists?

My goal is to grab a random 10% of hosts from an inventory file. Something along the lines of this:

tasks: 
- name: Get 10% of the servers 
  set_fact:
    win_amt: "{{ ((groups.windows_servers | length) * 0.1) | round(0, 'floor') | int }}"
    lin_amt: "{{ ((groups.linux_servers | length) * 0.1) | round(0, 'floor') | int }}"

- name: Get random hosts from windows and linux 
  set_fact:
    random_win: "{{ (groups.windows_servers | shuffle) [0:win_amt] }}"
    random_lin: "{{ (groups.linux_servers | shuffle) [0:lin_amt] }}"

This code produces the following error:

fatal: [localhost]: FAILED! => {"msg": "Unexpected templating type error occurred on ({{ (groups.windows_servers | shuffle) [0:win_amt] }}): slice indices must be integers or None or have an __index__ method"}

Has anyone done something similar to this or can point me to a better solution? This needs to be dynamic due to company policy requiring 10% of servers to be scanned periodically, and the amount of servers is subject to change as new resources are added/deleted.


Solution

  • Explicitly convert the slice limit to an integer. For example, given the inventory of 30 Windows and 70 Linux servers

    shell> cat hosts
    [win]
    node[1:30]
    
    [lin]
    node[31:100]
    

    Declare the 10% of the servers

      win_amt: "{{ (groups.win|length * 0.1)|round(0, 'floor') }}"
      lin_amt: "{{ (groups.lin|length * 0.1)|round(0, 'floor') }}"
    

    gives

      win_amt: '3.0'
      lin_amt: '7.0'
    

    Get the random nodes

      win_rnd: "{{ (groups.win|shuffle)[0:win_amt|int] }}"
      lin_rnd: "{{ (groups.lin|shuffle)[0:lin_amt|int] }}"
    

    gives

      win_rnd: [node8, node4, node17]
      lin_rnd: [node71, node69, node61, node42, node40, node73, node99]
    

    Example of a complete playbook for testing

    - hosts: all
    
      vars:
    
        win_amt: "{{ (groups.win|length * 0.1)|round(0, 'floor') }}"
        lin_amt: "{{ (groups.lin|length * 0.1)|round(0, 'floor') }}"
        win_rnd: "{{ (groups.win|shuffle)[0:win_amt|int] }}"
        lin_rnd: "{{ (groups.lin|shuffle)[0:lin_amt|int] }}"
    
      tasks:
    
        - block:
    
            - debug:
                var: win_amt
            - debug:
                var: lin_amt
    
            - debug:
                var: win_rnd|to_yaml
            - debug:
                var: lin_rnd|to_yaml
    
          run_once: true