获取 UID > 14000 的用户列表 - 字符串到整数转换

问题描述 投票:0回答:3

在我的剧本中,我想获取 UI 高于 14000 的所有本地用户的列表

我在 /etc/passwd 或 ansible.builtin.getent 上使用了 ansible.builtin.slurp 但真正的问题是我得到的 UID 值是字符串,而不是 int,所以我无法正确过滤并且我得到的所有结果都是空的,或抱怨因为不是整数。

- 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
      }}

我以为

selectattr('value.1', 'int')
会转换为int,但结果总是空的。 (我的字典里确实有一些超过14000的UID)

这里是getent提供的用户字典,所有UID都被引用,所以它们是字符串

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

我没有办法尝试,除了运行一些我会避免的 shell cmd。

ansible jinja2
3个回答
2
投票

我发现您的过滤器链存在几个问题:

filtered_users: >-
  {{
    users_info.ansible_facts.getent_passwd |
    dict2items |
    selectattr('value.1', 'int') |
    selectattr('value.1', >, 14000) |
    map(attribute='key') |
    list
  }}

首先,虽然有一个名为

int
 的过滤器,但没有名为 
integer
的测试。不幸的是,这是一个 test,而不是转换过滤器,因此由于在所有情况下
value.1
的值都是字符串,因此此
selectattr()
过滤器将拒绝您的所有条目,从而导致空列表。此点之后的所有内容都无关紧要,因为没有任何内容可以过滤。

例如:

- hosts: localhost
  gather_facts: false
  vars:
    example:
      - val: '1'
      - val: '2'
      - val: '3'
  tasks:
    - debug:
        msg: "{{ example | selectattr('val', 'integer') }}"

结果:

ok: [localhost] => {
    "msg": []
}

我认为您会找到使用

json_query
过滤器 更简单的解决方案。对于您想要的,我们可以这样做:

- 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')
        }}

这里,我们使用

to_number
函数 将字符串值转换为整数进行比较。

在我的系统上,这会产生:

ok: [localhost] => {
    "filtered_users": [
        "nobody"
    ]
}

1
投票

使用 community.general.jc 解析文件 /etc/passwd。宣布目的地

  dest_dir: /tmp/ansible/fetch

并获取文件

    - fetch:
        src: /etc/passwd
        dest: "{{ dest_dir }}"

声明路径并解析文件

  passwd_path: "{{ dest_dir }}/{{ inventory_hostname }}/etc/passwd"
  my_users: "{{ lookup('file', passwd_path) | community.general.jc('passwd') }}"

给出(删节)

  my_users:
  - comment: Charlie &
    gid: 0
    home: /root
    password: '*'
    shell: /bin/sh
    uid: 0
    username: root
  - comment: Bourne-again Superuser
    ...

属性 uidgid 是整数。你可以测试一下

    - debug:
        msg: |
          {{ my_users.0.username }}
          {{ my_users.0.uid }}
          {{ my_users.0.uid | type_debug }}

给予

  msg: |-
    root
    0
    int

现在,选择按预期进行了

  filtered_users: "{{ my_users |
                      selectattr('uid', '>', 14000) |
                      map(attribute='username') }}"

给予

  filtered_users:
  - nobody

  • 用于测试的完整剧本示例
- hosts: host_a

  vars:

    dest_dir: /tmp/ansible/fetch
    passwd_path: "{{ dest_dir }}/{{ inventory_hostname }}/etc/passwd"
    my_users: "{{ lookup('file', passwd_path) | community.general.jc('passwd') }}"
    filtered_users: "{{ my_users | selectattr('uid', '>', 14000) | map(attribute='username') }}"

  tasks:

    - fetch:
        src: /etc/passwd
        dest: "{{ dest_dir }}"

    - debug:
        var: my_users

    - debug:
        msg: |
          {{ my_users.0.username }}
          {{ my_users.0.uid }}
          {{ my_users.0.uid | type_debug }}

    - debug:
        var: filtered_users
  • 提议的场景

将声明放入group_vars

shell> cat group_vars/all.yml
dest_dir: /tmp/ansible/fetch
passwd_path: "{{ dest_dir }}/{{ inventory_hostname }}/etc/passwd"
my_users: "{{ lookup('file', passwd_path) | community.general.jc('passwd') }}"
uid_min: 0
uid_max: 65535
filtered_users_min: "{{ my_users | selectattr('uid', '>=', uid_min|int) | map(attribute='username') }}"
filtered_users_max: "{{ my_users | selectattr('uid', '<=', uid_max|int) | map(attribute='username') }}"
filtered_users: "{{ filtered_users_min | intersect(filtered_users_max) }}"

在剧本中,获取文件并声明间隔。例如,

shell> cat playbook.yml
---
- hosts: host_a

  tasks:

    - fetch:
        src: /etc/passwd
        dest: "{{ dest_dir }}"

    - debug:
        var: filtered_users
      vars:
        uid_min: 14000

0
投票

感谢 @larsks 的回答,我能够修改查询以过滤 14000-15000 UID,如下所示,这给出了预期的结果:

- name: Filter users 14k-15k range
  set_fact:
    filtered_users: >-
      {{
        users_info.ansible_facts.getent_passwd |
        dict2items |
        json_query('[?to_number(value[1]) > `14000` && to_number(value[1]) <= `15000`].key')
      }}
© www.soinside.com 2019 - 2024. All rights reserved.