Shaghayegh Tavakoli
Shaghayegh Tavakoli

Reputation: 530

Ansible - Filter Dictionary Values

I have gathered the list of all users using getent_module:

- name: Get user info
  getent:
    database: passed

This returns this variable as getent_passwd, a dictionary like this:

{
    "uuidd": [
        "x",
        "107",
        "112",
        "",
        "/run/uuidd",
        "/usr/sbin/nologin"
    ],
    "www-data": [
        "x",
        "33",
        "33",
        "www-data",
        "/var/www",
        "/usr/sbin/nologin"
    ]
}

I'm trying to return an array of users, including some specific users, finding the key of item.value in which "/home" is a part of one of the value array items and "nologin" is not. This is the code I have written so far, but it is not correct.

- name: style the user list
  set_fact:
    my_users: "{{ item.key | default([]) }}"
  when:
    - "'nologin' not in (item.value)"
    - "'/home' search in (item.value)"
  loop: "{{ lookup('dict', getent_passwd) }}"

How should I change my conditions to get the expected result?

Upvotes: 3

Views: 2748

Answers (2)

D-rk
D-rk

Reputation: 5919

Extension of the other answer with additional check to exclude system users:

- name: save users with actual login
  set_fact:
    actual_users: "{{ actual_users | default([]) + [ item.key ] }}"
  when:
    - "item.value[1] | int >= 1000"
    - "'/home' in item.value[4]"
    - "'nologin' not in item.value[5]"
  loop: "{{ lookup('dict', getent_passwd) }}"

Upvotes: 1

seshadri_c
seshadri_c

Reputation: 7340

As you understood correctly, since pattern/regex matching works on strings and not on items of list, when condition won't work. While matching items from a list, we need to match the complete item, i.e.

when:
  - "'/home/someuser' in item.value"
  - "'/usr/sbin/nologin' not in item.value"

Typically, the $HOME path in Linux is /home/$USER. The resulting getent_passwd contains the username in item.key. Which means that we can use /home/{{ item.key }} to match in item.value.

A task such as below should do the job:

    - name: save users with actual login
      set_fact:
        my_users: "{{ my_users | default([]) + [ item.key ] }}"
      when:
        - "'/home/' ~ item.key in item.value"
        - "'/usr/sbin/nologin' not in item.value"
      loop: "{{ lookup('dict', getent_passwd) }}"

The other approach could be to actually join the item.value to get a string similar to the one in /etc/passwd so that we can do text search such as: '/home' search in (item.value).

Example:

   # item.value | join(':') is the same as each line of '/etc/passwd'
    - name: save users with actual login
      set_fact:
        my_users: "{{ my_users | default([]) + [ item.key ] }}"
      when:
        - "'/home' in item.value | join(':')"
        - "'nologin' not in item.value | join(':')"
      loop: "{{ lookup('dict', getent_passwd) }}"

Upvotes: 2

Related Questions