Cat Hariss
Cat Hariss

Reputation: 143

How to loop through a list of variables set-up in an Ansible inventory file?

Having an ansible inventory file like this:

hostname1 users=user1,user2,user3
hostname2 users=user1,user2

I need an Ansible playbook that will loop through each of the user variable list and run the grep username /etc/passwd command for each hostname/user variable

What I have so far is:

---
- name: Grep shadow entries for users
  hosts: all
  tasks:
    - name: Get shadow entry for each user
      shell: "grep {{ item }} /etc/shadow"
      register: shadow_entry
      with_items: "{{ hostvars[inventory_hostname].users }}"

    - name: Print shadow entry
      debug:
        msg: "{{ shadow_entry.results }}"

But this does not loop through each user list but rather goes and runs grep [user1,user2,user3] /etc/passwd.

Also tried different variations on setting the inventory file like:

hostname1 users=["user1","user2","user3"]
hostname1 users='["user1","user2","user3"]'
hostname1 users="user1","user2","user3"

Nothing seems to work.

Upvotes: 0

Views: 2791

Answers (2)

Vladimir Botka
Vladimir Botka

Reputation: 68034

  • Both options below are strings
hostname1 users=user1,user2,user3
hostname2 users=[user1,user2,user3]

You can test it

    - debug:
        var: users|type_debug

gives in both cases

  users|type_debug: str

See Defining variables in INI format

  • In the first case
hostname1 users=user1,user2,user3

split the items if you want to iterate the list

    - debug:
        msg: "{{ item }}"
      loop: "{{ users.split(',') }}"

gives

ok: [hostname1] => (item=user1) => 
  msg: user1
ok: [hostname1] => (item=user2) => 
  msg: user2
ok: [hostname1] => (item=user3) => 
  msg: user3
  • In the second case
hostname2 users=[user1,user2,user3]

the string is a valid YAML list. Use the filter from_yaml to convert the string to the list

    - debug:
        msg: "{{ item }}"
      loop: "{{ users|from_yaml }}"

gives the same result

ok: [hostname2] => (item=user1) => 
  msg: user1
ok: [hostname2] => (item=user2) => 
  msg: user2
ok: [hostname2] => (item=user3) => 
  msg: user3
  • You have to quote the string, either single or double if you put spaces into it
hostname2 users='[user1, user2, user3]'

  • Use module getent to read /etc/shadow. On the remote system, see man getent whether the database is available or not
    - getent:
        database: shadow

This module will create a dictionary in the variable ansible_facts.getent_shadow. You can use it, instead of grep, to iterate users. For example, given the users

hostname2 users=operator,nobody

The task below

    - debug:
        msg: "{{ item }}: {{ ansible_facts.getent_shadow[item]|to_yaml }}"
      loop: "{{ users.split(',') }}"

gives

ok: [hostname2] => (item=operator) => 
  msg: |-
    operator: ['*', '18397', '0', '99999', '7', '', '', '']
ok: [hostname2] => (item=nobody) => 
  msg: |-
    nobody: ['*', '18397', '0', '99999', '7', '', '', '']

Upvotes: 1

U880D
U880D

Reputation: 12063

How to loop through a list of variables set-up in an Ansible inventory file?

For a file cat hosts

[test]
test.example.com USERS="['user1','user2','user3']"

an example playbook

---
- hosts: test
  become: false
  gather_facts: false

  tasks:

  - name: Show users
    debug:
      msg: "{{ item }}"
    loop: "{{ hostvars[inventory_hostname].USERS }}"

  - name: Show users
    debug:
      msg: "{{ item }}"
    loop: "{{ USERS }}"

will both result into an output of

TASK [Show users] ***********************
ok: [test.example.com] => (item=user1) =>
  msg: user1
ok: [test.example.com] => (item=user2) =>
  msg: user2
ok: [test.example.com] => (item=user3) =>
  msg: user3

Similar Q&A


Please take note that it is recommended to proceed further with reading the account database fully via getent module – A wrapper to the unix getent utility.

Runs getent against one of it’s various databases and returns information into the host’s facts, in a getent_ prefixed variable

See Q&A

Upvotes: 2

Related Questions