In my playbook I want to get a list of all local users with UI above 14000
I used ansible.builtin.slurp on /etc/passwd or ansible.builtin.getent but the real issue is the UID value that I get is string, not int so I can't filter properly and all results I get are empty, or complain because is not an integer.
- name: Get all users from /etc/passwd
ansible.builtin.getent:
database: passwd
register: users_info
- name: Filter users with UID greater than 14000
set_fact:
filtered_users: >-
{{
users_info.ansible_facts.getent_passwd |
dict2items |
selectattr('value.1', 'int') |
selectattr('value.1', >, 14000) |
map(attribute='key') |
list
}}
I thought selectattr('value.1', 'int')
would convert to int, but the result is always empty. (I do have some UID above 14000 in the dict)
Here the user dict that getent provides, all UID are quoted so they are string
root:
- x
- '0'
- '0'
- root
- /root
- /bin/bash
shutdown:
- x
- '6'
- '0'
- shutdown
- /sbin
- /sbin/shutdown
sshd:
- x
- '74'
- '74'
- Privilege-separated SSH
- /usr/share/empty.sshd
- /sbin/nologin
I run out of idea to try, except run some shell cmd which I would avoid.
I can see several problems with your filter chain:
filtered_users: >-
{{
users_info.ansible_facts.getent_passwd |
dict2items |
selectattr('value.1', 'int') |
selectattr('value.1', >, 14000) |
map(attribute='key') |
list
}}
First, there is no test named int
, although there is a filter named integer
. Unfortunately, this is a test, not a conversion filter, so since in all cases the value of value.1
is a string, this selectattr()
filter will reject all of your entries, leading to an empty list. Everything after this point is irrelevant because there is nothing left to filter.
For example:
- hosts: localhost
gather_facts: false
vars:
example:
- val: '1'
- val: '2'
- val: '3'
tasks:
- debug:
msg: "{{ example | selectattr('val', 'integer') }}"
Results in:
ok: [localhost] => {
"msg": []
}
I think you'll find a solution using the json_query
filter is simpler. For what you want, we could do this:
- name: Filter users with UID > 1000
set_fact:
filtered_users: >-
{{
users_info.ansible_facts.getent_passwd |
dict2items |
json_query('[?to_number(value[1]) > `1000`].key')
}}
Here, we're using the to_number
function to convert the string values into integers for comparison.
On my system, this produces:
ok: [localhost] => {
"filtered_users": [
"nobody"
]
}