dictionaryansiblemultiple-choice

ansible - select appropriate dictionary value when configuring user accounts


I have multiple users from 4x different LDAP domains and am trying to automate a way of adding them across multiple servers. Attributes for each user/group are static except for the identity_source_id which can be one of 4 possible values.

I would like to select the correct identity_source_id value based on the name value.

First step is to get the LDAP IDs and Domains from each server Using

I'm able to get the LDAP ID and Domain Name for each LDAP Config on the server. Then

- name: set fact to store ID and domain_name
  set_fact:
    id_domain: "{{ id_domain|d([]) + [{'id': item.id, 'domain_name': item.domain_name }] }}" 
  with_items: "{{id_source_results.json.results }}"

- name: Create dict for domain_name to id
  set_fact:
    id_domain_dict: "{{ id_domain | items2dict(key_name='domain_name', value_name='id' ) }}"

- name: Print dict
  debug:
    var: id_domain_dict

Gives

    "id_domain_dict": {
        "north.acme.com": "1111111-aaaaa",
        "south.acme.com": "2222222-bbbbb",
        "east.acme.com": "3333333-ccccc",
        "west.acme.com": "4444444-ddddd"
    }

The playbook i'm using to push the config is

- name: List LDAP Identity Sources
  ansible.builtin.uri:
    url: https://{{inventory_hostname}}/api/v1/aaa/role-bindings
    validate_certs: no
    timeout: 15
    force_basic_auth: yes
    url_username: "administrator"
    url_password: "{{ admin_password }}"
    method: POST
    body_format: json
    body: 
    [{
      "name": "frank@NORTH.ACME.COM",
      "type": "remote_user",
      "identity_source_type": "LDAP",
      "identity_source_id": "{{id_domain_dict.value}}",
      "roles": [
        {
          "role": "admin",
          "role_display_name": "Admin"
        }
      ],
      "resource_type": "RoleBinding",
      "display_name": "frank@NORTH.ACME.COM"
    },
    {
      "name": "ruth@SOUTH.ACME.COM",
      "type": "remote_user",
      "identity_source_type": "LDAP",
      "identity_source_id": "{{id_domain_dict.value}}",
      "roles": [
        {
          "role": "network_engineer",
          "role_display_name": "Network Engineer"
        }
      ],
      "resource_type": "RoleBinding",
      "display_name": "ruth@SOUTH.ACME.COM"
    },
    {
      "name": "finance_team@east.acme.com",
      "type": "remote_group",
      "identity_source_type": "LDAP",
      "identity_source_id": "{{id_domain_dict.value}}",
      "roles": [
        {
          "role": "finance_admin",
          "role_display_name": "Finance Admin"
        }
      ],
      "resource_type": "RoleBinding",
      "display_name": "finance_team@east.acme.com"
    },
    {
      "name": "auditors@west.acme.com",
      "type": "remote_group",
      "identity_source_type": "LDAP",
      "identity_source_id": "{{id_domain_dict.value}}",
      "roles": [
        {
          "role": "read-only",
          "role_display_name": "Read-Only"
        }
      ],
      "resource_type": "RoleBinding",
      "display_name": "auditors@west.acme.com"
    }]
    return_content: yes
    status_code: 200
  delegate_to: localhost

Because the API Post body is static, i can't figure out how to select the correct value from id_domain_dict. eg for auditors@west.acme.com the id_domain_dict.value should be 4444444-ddddd

I've tried splitting the user value using "@" but can't get this to work

{% for k,v in id_domain_dict.items %}
{% domain = {{name}}.split('@') %}
{% if domain[1] in k %}
{{ v }}
{% endfor %}

I've also tried

"identity_source_id": "{{ v if domain[1] in k '' }}"

But have been unsuccessful in all attempts


Solution

  •   id_domain_dict: "{{ dict(id_source_results.json.results|
                               json_query('[].[domain_name, id]')) }}"
    

    gives

      id_domain_dict:
        east.acme.com: 3333333-ccccc
        north.acme.com: 1111111-aaaaa
        south.acme.com: 2222222-bbbbb
        west.acme.com: 4444444-ddddd
    
    shell> cat body.yml 
    - display_name: frank@NORTH.ACME.COM
      identity_source_id: '{{ id_domain_dict.value }}'
      identity_source_type: LDAP
      name: frank@NORTH.ACME.COM
      resource_type: RoleBinding
      roles:
      - {role: admin, role_display_name: Admin}
      type: remote_user
    - display_name: ruth@SOUTH.ACME.COM
      identity_source_id: '{{ id_domain_dict.value }}'
      identity_source_type: LDAP
      name: ruth@SOUTH.ACME.COM
      resource_type: RoleBinding
      roles:
      - {role: network_engineer, role_display_name: Network Engineer}
      type: remote_user
    - display_name: finance_team@east.acme.com
      identity_source_id: '{{ id_domain_dict.value }}'
      identity_source_type: LDAP
      name: finance_team@east.acme.com
      resource_type: RoleBinding
      roles:
      - {role: finance_admin, role_display_name: Finance Admin}
      type: remote_group
    - display_name: auditors@west.acme.com
      identity_source_id: '{{ id_domain_dict.value }}'
      identity_source_type: LDAP
      name: auditors@west.acme.com
      resource_type: RoleBinding
      roles:
      - {role: read-only, role_display_name: Read-Only}
      type: remote_group
    
      body: "{{ lookup('file', 'body.yml')|from_yaml }}"
    

    gives

      body:
      - display_name: frank@NORTH.ACME.COM
        identity_source_id: '{{ id_domain_dict.value }}'
        identity_source_type: LDAP
        name: frank@NORTH.ACME.COM
        resource_type: RoleBinding
        roles:
        - role: admin
          role_display_name: Admin
        type: remote_user
      - display_name: ruth@SOUTH.ACME.COM
        identity_source_id: '{{ id_domain_dict.value }}'
        identity_source_type: LDAP
        name: ruth@SOUTH.ACME.COM
        resource_type: RoleBinding
        roles:
        - role: network_engineer
          role_display_name: Network Engineer
        type: remote_user
      - display_name: finance_team@east.acme.com
        identity_source_id: '{{ id_domain_dict.value }}'
        identity_source_type: LDAP
        name: finance_team@east.acme.com
        resource_type: RoleBinding
        roles:
        - role: finance_admin
          role_display_name: Finance Admin
        type: remote_group
      - display_name: auditors@west.acme.com
        identity_source_id: '{{ id_domain_dict.value }}'
        identity_source_type: LDAP
        name: auditors@west.acme.com
        resource_type: RoleBinding
        roles:
        - role: read-only
          role_display_name: Read-Only
        type: remote_group
    
      domains: "{{ body|map(attribute='name')|
                        map('split', '@')|map('last')|map('lower')|
                        map('extract', id_domain_dict)|
                        map('community.general.dict_kv', 'identity_source_id') }}"
    

    gives

      domains:
      - identity_source_id: 1111111-aaaaa
      - identity_source_id: 2222222-bbbbb
      - identity_source_id: 3333333-ccccc
      - identity_source_id: 4444444-ddddd
    
      body_update: "{{ body|zip(domains)|map('combine') }}"
    

    gives the structure you're looking for

      body_update:
      - display_name: frank@NORTH.ACME.COM
        identity_source_id: 1111111-aaaaa
        identity_source_type: LDAP
        name: frank@NORTH.ACME.COM
        resource_type: RoleBinding
        roles:
        - role: admin
          role_display_name: Admin
        type: remote_user
      - display_name: ruth@SOUTH.ACME.COM
        identity_source_id: 2222222-bbbbb
        identity_source_type: LDAP
        name: ruth@SOUTH.ACME.COM
        resource_type: RoleBinding
        roles:
        - role: network_engineer
          role_display_name: Network Engineer
        type: remote_user
      - display_name: finance_team@east.acme.com
        identity_source_id: 3333333-ccccc
        identity_source_type: LDAP
        name: finance_team@east.acme.com
        resource_type: RoleBinding
        roles:
        - role: finance_admin
          role_display_name: Finance Admin
        type: remote_group
      - display_name: auditors@west.acme.com
        identity_source_id: 4444444-ddddd
        identity_source_type: LDAP
        name: auditors@west.acme.com
        resource_type: RoleBinding
        roles:
        - role: read-only
          role_display_name: Read-Only
        type: remote_group
    
      {{ body_update|to_nice_json }}
    

    gives

        [
            {
                "display_name": "frank@NORTH.ACME.COM",
                "identity_source_id": "1111111-aaaaa",
                "identity_source_type": "LDAP",
                "name": "frank@NORTH.ACME.COM",
                "resource_type": "RoleBinding",
                "roles": [
                    {
                        "role": "admin",
                        "role_display_name": "Admin"
                    }
                ],
                "type": "remote_user"
            },
            {
                "display_name": "ruth@SOUTH.ACME.COM",
                "identity_source_id": "2222222-bbbbb",
                "identity_source_type": "LDAP",
                "name": "ruth@SOUTH.ACME.COM",
                "resource_type": "RoleBinding",
                "roles": [
                    {
                        "role": "network_engineer",
                        "role_display_name": "Network Engineer"
                    }
                ],
                "type": "remote_user"
            },
            {
                "display_name": "finance_team@east.acme.com",
                "identity_source_id": "3333333-ccccc",
                "identity_source_type": "LDAP",
                "name": "finance_team@east.acme.com",
                "resource_type": "RoleBinding",
                "roles": [
                    {
                        "role": "finance_admin",
                        "role_display_name": "Finance Admin"
                    }
                ],
                "type": "remote_group"
            },
            {
                "display_name": "auditors@west.acme.com",
                "identity_source_id": "4444444-ddddd",
                "identity_source_type": "LDAP",
                "name": "auditors@west.acme.com",
                "resource_type": "RoleBinding",
                "roles": [
                    {
                        "role": "read-only",
                        "role_display_name": "Read-Only"
                    }
                ],
                "type": "remote_group"
            }
        ]
    

    Example of a complete playbook for testing

    - hosts: localhost
    
      vars:
    
        id_source_results:
          json:
            results:
              - {id: 1111111-aaaaa, domain_name: north.acme.com}
              - {id: 2222222-bbbbb, domain_name: south.acme.com}
              - {id: 3333333-ccccc, domain_name: east.acme.com}
              - {id: 4444444-ddddd, domain_name: west.acme.com}
    
        id_domain_dict: "{{ dict(id_source_results.json.results|
                                 json_query('[].[domain_name, id]')) }}"
    
        body: "{{ lookup('file', 'body.yml')|from_yaml }}"
        domains: "{{ body|map(attribute='name')|
                          map('split', '@')|map('last')|map('lower')|
                          map('extract', id_domain_dict)|
                          map('community.general.dict_kv', 'identity_source_id') }}"
        body_update: "{{ body|zip(domains)|map('combine') }}"
    
      tasks:
    
        - debug:
            var: id_domain_dict
        - debug:
            var: body
        - debug:
            var: domains
        - debug:
            var: body_update
    
        - debug:
            msg: |
              {{ body_update|to_nice_json }}