Geert Smelt
Geert Smelt

Reputation: 1093

Select hosts from Ansible inventory based on value of host variable

I am trying to set up a client and server using Ansible that need to connect to each other (Wireguard client and server in this case). Since the server needs to know the peers that will connect to it, I'm looking to gather a list of hosts that the server will be able to create a peer entry for in its configuration. The list should be dynamically generated (there could be multiple clients connecting to the same server) and generated based on the target_server variable assigned to each client, the value of which should be equal to the inventory_hostname of the server it needs to connect to. The jinja2 expression I am using in the MWE below unfortunately keeps coming up empty, but I'm unsure how to improve it.

Playbook

- name: Set up Wireguard Server
  hosts: servers
  gather_facts: true
  tasks:
    - name: Figure out peers for this server
      become: false
      ansible.builtin.debug:
        var: item
      loop: "{{ groups['servers'] | select('match', 'target_server={{ inventory_hostname }}') | map('extract', hostvars, 'inventory_hostname') | list }}"

Inventory

servers:
  hosts:
    Wireguard-Server:
      ansible_host: 2.3.4.5

clients:
  hosts:
    Wireguard-Client-1:
      ansible_host: 1.2.3.4
      target_server: Wireguard-Server
    Wireguard-Client-2:
      ansible_host: 4.3.2.1
      target_server: Different-Server

Log

TASK [Figure out peers for this server] ********************************************
skipping: [Wireguard-Server] =>
  skipped_reason: No items in the list

Upvotes: 2

Views: 991

Answers (1)

Vladimir Botka
Vladimir Botka

Reputation: 68294

Create the dictionary of the clients and target_server

  clients: "{{ dict(groups.clients|
                    zip(groups.clients|
                        map('extract', hostvars, 'target_server'))) }}"

gives

  clients:
    Wireguard-Client-1: Wireguard-Server
    Wireguard-Client-2: Different-Server

Use it to select the matching clients

  my_clients: "{{ clients|dict2items|
                  selectattr('value', 'eq', inventory_hostname)|
                  map(attribute='key') }}"

gives

  my_clients:
  - Wireguard-Client-1

Example of a complete playbook for testing

- hosts: servers

  vars:

    clients: "{{ dict(groups.clients|
                      zip(groups.clients|
                          map('extract', hostvars, 'target_server'))) }}"
    my_clients: "{{ clients|dict2items|
                    selectattr('value', 'eq', inventory_hostname)|
                    map(attribute='key') }}"

  tasks:

    - debug:
        var: clients

    - debug:
        var: my_clients

You can select all hosts from the inventory that match target_server

  my_clients: "{{ hostvars|dict2items|
                  selectattr('value.target_server', 'defined')|
                  selectattr('value.target_server', 'eq', inventory_hostname)|
                  map(attribute='key') }}"

Upvotes: 3

Related Questions