Получить список пользователей с UID > 14000 — преобразование строки в целое число

В моей книге игр я хочу получить список всех локальных пользователей с пользовательским интерфейсом выше 14000.

Я использовал ansible.builtin.slurp в /etc/passwd или ansible.builtin.getent, но реальная проблема заключается в том, что значение 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, но результат всегда пустой. (У меня есть UID выше 14000 в dict)

Здесь пользовательское определение, предоставляемое 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

У меня закончилась идея попробовать, кроме запуска какого-нибудь командного процессора оболочки, которого я бы избегал.

Введение в Ansible Roles
Введение в Ansible Roles
Ansible - это отличный инструмент управления конфигурацией, который можно использовать для автоматизации настройки или развертывания на большом...
0
0
52
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Я вижу несколько проблем с вашей цепочкой фильтров:

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

Во-первых, нет теста с именем int, хотя есть фильтр с именем целое число. К сожалению, это проверка, а не фильтр преобразования, поэтому, поскольку во всех случаях значение 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"
    ]
}

Благодаря ответу @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')
      }}

Используйте 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
    ...

Атрибуты uid и gid являются целыми числами. Вы можете проверить это

    - 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

  • Example of a complete playbook for testing
- 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
  • Proposed scenario

Put the declarations into the 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) }}"

In the playbook, fetch the file and declare the interval. For example,

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

  tasks:

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

    - debug:
        var: filtered_users
      vars:
        uid_min: 14000

Другие вопросы по теме