Replacing value of list elements with info from another variable

Working on a role for Authentik; as with any IdP, I’m dealing with users and groups. Authentik gives an idempotent API path to use for updating groups, and it uses JSON for the body of its API calls, which is convenient, except in one way. To define which users are in a group, I have to list the users by their “pk” number, which is a random number assigned when the user was created in the system.

user_info_from_api_call:
# A previous task makes an API request for this info that I register to a variable.
    - name: Luke
      pk: 2843
    - name: ObiWan
      pk: 4973
    - name: Vader
      pk: 8693
    - name: Palpatine
      pk: 6666
desired_groups:
    - name: Jedi
      is_superuser: true
      users:
          - Luke
          - ObiWan
    - name: Sith
      is_superuser: false
      users:
          - Vader
          - Palpatine

Given the above variables, I need to transform desired_groups by replacing the user names with their pk numbers to plug into my API request to idempotently update the group:

# example desired outcome
desired_groups:
    - name: Jedi
      is_superuser: true
      users:
          - 2843
          - 4973
    - name: Sith
      is_superuser: false
      users:
          - 8693
          - 6666

I tried using items2dict on user_info_from_api_call to make it easier to reference the pk number by the user’s name, then using map() on desired_groups, but couldn’t make it gel. I appreciate any solutions people might have.

I’m sure there’s a clever pipeline that will do this, but if you want me to be able to read it later, you’d better go old school and throw in some loops.

---
# JethCalark_01.yml
- name: Name games
  hosts: localhost
  gather_facts: false
  vars:
    user_info_from_api_call:
      - name: Luke
        pk: 2843
      - name: ObiWan
        pk: 4973
      - name: Vader
        pk: 8693
      - name: Palpatine
        pk: 6666
    desired_groups:
      - name: Jedi
        is_superuser: true
        users:
          - Luke
          - ObiWan
      - name: Sith
        is_superuser: false
        users:
          - Vader
          - Palpatine
  tasks:
    - name: Substitute pk for user names
      ansible.builtin.set_fact:
        new_groups: |
          {% set new_groups = [] -%}
          {% for group in desired_groups -%}
          {%   set new_users = [] -%}
          {%   for user in group.users -%}
          {%     for uifac in user_info_from_api_call -%}
          {%       if uifac.name == user -%}
          {%         set _ = new_users.append(uifac.pk) -%}
          {%       endif -%}
          {%     endfor -%} 
          {%   endfor -%}
          {%   set _ = new_groups.append({"name": group.name,
                                          "is_superuser": group.is_superuser,
                                          "users": new_users}) -%}
          {% endfor %}{{ new_groups }}

produces this:

TASK [Substitute pk for user names] *************************
ok: [localhost] => changed=false 
  ansible_facts:
    new_groups:
    - is_superuser: true
      name: Jedi
      users:
      - 2843
      - 4973
    - is_superuser: false
      name: Sith
      users:
      - 8693
      - 6666
5 Likes

That Jinja is definitely giving me flashbacks to certain templates… :laughing:

I do tend to like the clever pipelines, and I also forget that Jinja can be used in Ansible tasks. Definitely going to need a moment to process that, to make sure I understand how it’s working.

1 Like