2

I have a group with a large list of systems and need to grab the first 3 systems from the group. Is there a way to take a group such as this:

[webservers]
web01
web02
web03
web04
web05

And produce a quoted list similar to the following?:

- name: Pick the initial masters
  lineinfile:
    dest: "/bits/etc/web.conf"
    state: present
    regexp: 'node.masters'
    line: 'node.masters: [ "web01", "web02", "web03" ]'

I may need to change the number of masters in the future so I'm hoping to use a slice if at all possible. Thanks for any insight.

Mickster
  • 643
  • 2
  • 9
  • 13

2 Answers2

2

You can reference the built-in groups variable.

- name: Pick the initial masters
  lineinfile:
    dest: "/bits/etc/web.conf"
    state: present
    regexp: 'node.masters'
    line: "node.masters: [ \"{{ groups['webservers'][0] }}\", \"{{ groups['webservers'][1] }}\", \"{{ groups['webservers'][2] }}\" ]"

Updated answer from comments:

You could also use jinja in your variable declarations to loop over an arbitrary number of hosts in webservers.

vars: 
  master_nodes: 3
  master_nodes_line: "{% for item in groups['webservers'][:master_nodes] %}\"{{ item }}\"{% if not loop.last %},{% endif %}{% endfor %}"
tasks:
- name: Print list
  lineinfile:
    dest: foo
    regexp: "node.masters"
    line: "node.masters: [ {{ master_nodes_line }} ]"
kfreezy
  • 1,499
  • 12
  • 16
  • Is it possible to build the list dynamically with a for loop? I would like to be able to define a variable (say master_nodes: 3 ) in group_vars and have loop iterate over the first X items in groups[] to create the line entry. Is that possible? – Mickster Aug 21 '17 at 16:57
2

You can use the python array slice syntax and pipe it to the json filter. This will avoid looping in Jinja2 and produce nice quoted output.

- name: Pick the initial masters
  lineinfile:
    dest: /bits/etc/web.conf
    state: present
    regexp: 'node.masters'
    line: 'node.masters: {{groups['webservers'][:3] | to_json}}'

Be careful with slices of groups, as the order is not necessarily consistent if the inventory is dynamically generated, as stated in the Ansible FAQ. To avoid this, I would advice on creating a second group, "masters" in the inventory, specifying which nodes to use rather than relying on order. This has other benefits, such as being able to target the masters or non-masters instead of having to know and change the number of masters in every playbook.

[webservers]
web[01:05]

[masters]
web[01:03]
LHSnow
  • 1,146
  • 9
  • 12
  • I'd like to point out that the inventory example only appears to be a string generator, and can't slice another list. you can however use slicing in `--limit web[:3]`. In some cases, it may not work, such as reverse slicing doesn't seem `--limit web[:-3]`, but negative index is fine `--limit web[-3]` – Xarses Aug 22 '18 at 13:45