Как перебрать список JSON в Ansible, отфильтрованный по значениям из отдельного списка?

У меня есть список пользовательских словарей, каждый из которых содержит имя пользователя, gecos и т. Д., А также список словарей групп, каждый из которых содержит список членов группы. Мне нужна задача Ansible для перебора только тех записей списка пользователей, которые соответствуют списку участников определенной группы из списка групп.

Я подозреваю, что моя проблема связана с правильным использованием цитат и разделителей Jinja, чтобы все оценивалось на должном уровне в иерархии Ansible -> Jinja -> JMESPath, но я не смог точно определить, что я делаю неправильно. Я пробовал десятки вариантов ниже, включая разбиение подзапросов на их собственные переменные, но без значимой обратной связи у меня не так много информации для внесения улучшений.

users.json:

{
  "aws_users": [
    {
      "name": "userA",
      "gecos": "User A"
    },
    {
      "name": "userB",
      "gecos": "User B"
    },
    {
      "name": "userC",
      "gecos": "User C"
    }
  ]
}

groups.json:

{
  "aws_groups": [
    {
      "name": "groupA",
      "members": [
        "userA",
        "userC"
      ]
    }
  ]
}

ansible.yml:

---
- hosts: 127.0.0.1
  become: true
  connection: local
  gather_facts: no
  vars_files:
    - ../../config/groups.json
    - ../../config/users.json

  vars:
     groupARoster: "{{ aws_groups | json_query('[?name==`groupA`].members | [0]') }}"
     query: "aws_users[?contains(`{{ groupARoster }}`, name)]"
     groupAUsers: "{{ aws_users | json_query(query) }}"

  tasks:
    - debug:
        var: groupARoster

    - debug:
        var: query

    - debug:
        var: groupAUsers

#    - name: Some looping thing
#      command: ...
#      loop: "{{ groupAusers }}"

Выход:

PLAY [127.0.0.1] ***********************************************************************************************************************************************************************************************

TASK [debug] ***************************************************************************************************************************************************************************************************
ok: [127.0.0.1] => {
    "groupARoster": [
        "userA", 
        "userC"
    ]
}

TASK [debug] ***************************************************************************************************************************************************************************************************
ok: [127.0.0.1] => {
    "query": "aws_users[?contains(`[u'userA', u'userC']`, name)]"
}

TASK [debug] ***************************************************************************************************************************************************************************************************
ok: [127.0.0.1] => {
    "groupAUsers": ""
}

PLAY RECAP *****************************************************************************************************************************************************************************************************
127.0.0.1                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

Желаемый результат (для перехода в параметр цикла Ansible):

"groupAUsers": [
    {
      "name": "userA",
      "gecos": "User A"
    },
    {
      "name": "userC",
      "gecos": "User C"
    }
  ]

person Brian Bauman    schedule 07.04.2020    source источник
comment
Вам нужно, чтобы каждый пользователь в aws_users перебирал все группы в aws_groups?   -  person Uttam    schedule 08.04.2020
comment
Или вы хотите зациклить каждого пользователя в каждой группе?   -  person Uttam    schedule 08.04.2020
comment
Ни то, ни другое - я обновил вопрос, чтобы включить желаемый результат.   -  person Brian Bauman    schedule 08.04.2020


Ответы (1)


Если вы действительно не хотите использовать для этого jmespath, есть более простой способ IMO с использованием selectattr:

groupARoster: "{{ (aws_groups | selectattr('name', 'equalto', 'groupA') | list)[0].members }}"
groupAUsers: "{{ aws_users | selectattr('name', 'in', groupARoster) | list }}"

Между тем это все еще возможно с json_query. Вы были действительно близки. Проблема в вашем промежуточном запросе. Вы передаете переменную aws_user в json_query. Следовательно, в передаваемом значении нет ключа первого уровня "aws_user". Вы должны удалить его из запроса:

groupARoster: "{{ aws_groups | json_query('[?name==`groupA`].members | [0]') }}"
query: "[?contains(`{{ groupARoster }}`, name)]"
groupAUsers: "{{ aws_users | json_query(query) }}"
person Zeitounator    schedule 07.04.2020
comment
Ого, это прекрасно. Я пропустил в документации по фильтрам Ansible тот бит, что я мог использовать произвольные фильтры Jinja (а документация по selectattr в Jinja настолько бедна, что я, вероятно, не понял бы, для чего она предназначена). С тех пор я также добавил rejectattr, чтобы сузить круг поиска. - person Brian Bauman; 08.04.2020