4

How can I create a list like this in an Ansible playbook:

['user1', 'user2', 'user3', '...', 'user20']

and save it to a var in that same playbook?

I tried Using set_facts and with_items together in Ansible and modified the answer of @serge a little bit.

My code looks like the following:

- name: preparation for list
  set_fact:
     userItem: userItem= "{{ item }}"
  with_sequence: start=1 end=20 format=user%d
  register: userResult

- name: make a list
  set_fact: users= "{{ userResult.results | map(attribute= 'ansible_facts.userItem) | list }}"

- name resulted list
  debug: var=users

But I get the following error:

TASK [make a list] ***************************************************************** 
fatal: [10.0.2.11]: FAILED! => {"msg": "template error while templating string: unexpected end of  template, expected ',' .. String: \"{{ userResult.results | map(attribute"} 

I want to use that list in a task where I change a line in a configuration file like this:

- name: allow users to ssh into jail
  lineinfile:
     path: /etc/ssh/shd_config
     regexp: '^AllowUsers '
     line: 'AllowUsers ansible {{ users }}'
   notify: "restart ssh"

where {{ users }} should be replaced with the desired list.

Is there a way I can achieve getting the desired list saved in some kind of variable (not a file) so I can use it in other tasks?

β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
L.Gashi
  • 183
  • 1
  • 11

2 Answers2

6

You can create a list in a set_fact right away, there is no need for any intermediary task:

- set_fact:
    users: "{{ users | default([]) + ['user%s' | format(item)] }}"
  loop: "{{ range(1, 21) | list }}"

Which gives

{
    "users": [
        "user1",
        "user2",
        "user3",
        "user4",
        "user5",
        "user6",
        "user7",
        "user8",
        "user9",
        "user10",
        "user11",
        "user12",
        "user13",
        "user14",
        "user15",
        "user16",
        "user17",
        "user18",
        "user19",
        "user20"
    ]
}

This is actually really close to the example found in the documentation: https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#with-sequence


This said you won't be able to fit a list into your lineinfile module, because you do need a string.

So you can either create a string right away:

- set_fact:
    users: "{{ users | default('') + ' user%s' | format(item) }}"
  loop: "{{ range(1, 21) | list }}"

-  lineinfile:
     path: /etc/ssh/shd_config
     regexp: '^AllowUsers '
     line: 'AllowUsers ansible {{ users }}'
   notify: "restart ssh"

So, instead of creating a list we are creating a string:

{
    "users": " user1 user2 user3 user4 user5 user6 user7 user8 user9 user10 user11 user12 user13 user14 user15 user16 user17 user18 user19 user20"
}

Or use the join filter when using the users list:

- set_fact:
    users: "{{ users | default([]) + ['user%s' | format(item)] }}"
  loop: "{{ range(1, 21) | list }}"

-  lineinfile:
     path: /etc/ssh/shd_config
     regexp: '^AllowUsers '
     line: 'AllowUsers ansible {{ users | join(' ') }}'
   notify: "restart ssh"
β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
3

For example

    - set_fact:
        users: "{{ ['user']|product(range(start,end))|map('join')|list }}"
      vars:
        start: 1
        end: 5

gives

  users:
  - user1
  - user2
  - user3
  - user4

The next option gives the same result

    - set_fact:
        users: "{{ query('sequence', user_range) }}"
      vars:
        start: 1
        end: 4
        user_range: "start={{ start }} end={{ end }} format=user%d"
Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63
  • @β.εηοιτ.βε, I have fixed your edit of the code. You changed the parameter of `sequence` to `end: 5`. This is wrong. My answer says this `option gives the same result`. `sequence` returns a list `[start, .... , end]` but `range` returns `[start, ..., end-1]`. Read the documentation properly and test the code before you make any changes, please. – Vladimir Botka Feb 14 '21 at 04:55