Fragan
Fragan

Reputation: 892

Ansible filter dict based on key presence and list values

I have this variable :

components:
  comp_one:
    name: first_component
    remote_server_path: "/tmp/path/one"
    binaries:
      - test
      - test_two


  comp_two:
    name: second_component
    remote_server_path: "/tmp/path/two"
    binaries:
      - ed_test
      - ed_test_2

  comp_three:
    name: third_component
    remote_server_path: "/tmp/path/three"

What I'm trying to achieve, is to only keep sub-dictionaries of components that has key binaries, and the filter those binaries using my group_names. Also, D'd like to only keep dict keys binaries and remote_server_path.

For example, if i have this hosts.yaml :

---
all:
  children:
    kubernetes_dev:
      children:
        ed_test:
          hosts:
            host_one:
              ansible_host: XXX.XXX.XXX.XXX
              ansible_ssh_user: ansible
        test_two:
          hosts:
            host_one:
              ansible_host: XXX.XXX.XXX.XXX
              ansible_ssh_user: ansible
        test:
          hosts:
            host_one:
              ansible_host: XXX.XXX.XXX.XXX
              ansible_ssh_user: ansible

The expected output would be :

comp_one:
  remote_server_path: "/tmp/path/one"
  binaries:
    - test
    - test_two

comp_two:
  remote_server_path: "/tmp/path/two"
  binaries:
    - ed_test

I've successfully filtered the comp_three dict using this :

- name: Debug
  ansible.builtin.debug:
    msg: "{{ item }}"
  with_items: "{{ components | dict2items | selectattr('value.binaries', 'defined') }}"

But, I can't figure out a way to only select binaries and remote_server_path keys while filtering with my `group_names.

Does anyone can't help me find a clean way to do this ?

Regards,

Upvotes: 1

Views: 769

Answers (1)

Vladimir Botka
Vladimir Botka

Reputation: 68294

Use group_names. This is: "List of groups the current host is part of.". For the host host_one in the inventory hosts.yaml this is

  group_names: [ed_test, test, test_two]

Convert the dictionary components to list and test intersect of binaries and group_names. Default to empty list if the attribute binaries is missing

    - set_fact:
        selected_list: "{{ selected_list|d([]) + [_item] }}"
      loop: "{{ components|dict2items }}"
      when: my_groups|length > 0
      vars:
        _item: "{{ item|combine(my_value) }}"
        my_value: "{{ {'value': {'binaries': my_groups,
                                'remote_server_path': item.value.remote_server_path}} }}"
        my_groups: "{{ item.value.binaries|d([])|intersect(group_names) }}"

gives

  selected_list:
  - key: comp_one
    value:
      binaries:
      - test
      - test_two
      remote_server_path: /tmp/path/one
  - key: comp_two
    value:
      binaries:
      - ed_test
      remote_server_path: /tmp/path/two

Conver the list into a dictionary

    - set_fact:
        selected_dict: "{{ selected_list|items2dict }}"

gives the expected result

  selected_dict:
    comp_one:
      binaries:
      - test
      - test_two
      remote_server_path: /tmp/path/one
    comp_two:
      binaries:
      - ed_test
      remote_server_path: /tmp/path/two

Example of a complete playbook

- hosts: all
  vars:
    components:
      comp_one:
        name: first_component
        remote_server_path: /tmp/path/one
        binaries:
          - test
          - test_two
      comp_two:
        name: second_component
        remote_server_path: /tmp/path/two
        binaries:
          - ed_test
          - ed_test_2
      comp_three:
        name: third_component
        remote_server_path: /tmp/path/three
  tasks:
    - set_fact:
        selected_list: "{{ selected_list|d([]) + [_item] }}"
      loop: "{{ components|dict2items }}"
      when: my_groups|length > 0
      vars:
        _item: "{{ item|combine(my_value) }}"
        my_value: "{{ {'value': {'binaries': my_groups,
                                'remote_server_path': item.value.remote_server_path}} }}"
        my_groups: "{{ item.value.binaries|d([])|intersect(group_names) }}"
    - set_fact:
        selected_dict: "{{ selected_list|items2dict }}"
    - debug:
        var: selected_dict

Upvotes: 1

Related Questions