stiller_leser
stiller_leser

Reputation: 1572

Ansible set_fact from dictionary based on item type

I am reading a dictionary from a Kubernetes config map (cm_config below) and am using it to replace variables set in defaults/main.yml like this:

- name: 'Overwrite defaults'
  set_fact: "{{ item.key }}={{ item.value }}"
  with_dict: "{{ cm_config }}"

This works fine as long as the items are simple variables. But as soon as an item is another dictionary, I'd like to combine the values.

How can I integrate this into the above task? I thought about running the loop twice, with some kind of type check. Not sure how this would work. Additionally, I believe there might be a better way?

Upvotes: 1

Views: 1885

Answers (1)

Zeitounator
Zeitounator

Reputation: 44808

One solution below to achieve your requirement in a single task whit just a bit of jinja2 templating and a vars lookup to get existing dict content. The key is to calculate the value based on the variable type.

Note that this does not take into account the situations when the var is a list which will be replaced as all other type of values. This will not either deal with type mismatch between existing vars and config map. e.g. if your existing var is string and the corresponding one in config map a dict it will break.

The following playbook:

---
- hosts: localhost
  gather_facts: false

  vars:
    cm_config:
      label1: toto
      label2:
        a_value: 1
        other_value: 2
      label3:
        a_value: 3
        other_value: 4
      label4: tata

    label1: I am set in play
    label3:
      some_value: I'm a poor lonesome cowboy

  tasks:
    - name: show initial state
      debug:
        var: "{{ item.key }}"
      with_dict: "{{ cm_config }}"

    - name: Process values from config map
      vars:
        my_value: >-
          {% if item.value is mapping %}
          {{ lookup('vars', item.key, default={}) | combine(item.value) }}
          {% else %}
          {{ item.value }}
          {% endif %}
      set_fact:
        "{{ item.key }}": "{{ my_value }}"
      with_dict: "{{ cm_config }}"

    - name: Show the result after processing config map
      debug:
        var: "{{ item.key }}"
      with_dict: "{{ cm_config }}"

gives the following result:

PLAY [localhost] ****************************************************************************************************************************************************************************************************************************

TASK [show initial state] *******************************************************************************************************************************************************************************************************************
ok: [localhost] => (item=label1) => {
    "ansible_loop_var": "item",
    "item": {
        "key": "label1",
        "value": "toto"
    },
    "label1": "I am set in play"
}
ok: [localhost] => (item=label2) => {
    "ansible_loop_var": "item",
    "item": {
        "key": "label2",
        "value": {
            "a_value": 1,
            "other_value": 2
        }
    },
    "label2": "VARIABLE IS NOT DEFINED!"
}
ok: [localhost] => (item=label3) => {
    "ansible_loop_var": "item",
    "item": {
        "key": "label3",
        "value": {
            "a_value": 3,
            "other_value": 4
        }
    },
    "label3": {
        "some_value": "I'm a poor lonesome cowboy"
    }
}
ok: [localhost] => (item=label4) => {
    "ansible_loop_var": "item",
    "item": {
        "key": "label4",
        "value": "tata"
    },
    "label4": "VARIABLE IS NOT DEFINED!"
}

TASK [Process values from config map] *******************************************************************************************************************************************************************************************************
ok: [localhost] => (item={'key': 'label1', 'value': 'toto'})
ok: [localhost] => (item={'key': 'label2', 'value': {'a_value': 1, 'other_value': 2}})
ok: [localhost] => (item={'key': 'label3', 'value': {'a_value': 3, 'other_value': 4}})
ok: [localhost] => (item={'key': 'label4', 'value': 'tata'})

TASK [Show the result after processing config map] ******************************************************************************************************************************************************************************************
ok: [localhost] => (item=label1) => {
    "ansible_loop_var": "item",
    "item": {
        "key": "label1",
        "value": "toto"
    },
    "label1": " toto "
}
ok: [localhost] => (item=label2) => {
    "ansible_loop_var": "item",
    "item": {
        "key": "label2",
        "value": {
            "a_value": 1,
            "other_value": 2
        }
    },
    "label2": " {'a_value': 1, 'other_value': 2} "
}
ok: [localhost] => (item=label3) => {
    "ansible_loop_var": "item",
    "item": {
        "key": "label3",
        "value": {
            "a_value": 3,
            "other_value": 4
        }
    },
    "label3": " {'some_value': \"I'm a poor lonesome cowboy\", 'a_value': 3, 'other_value': 4} "
}
ok: [localhost] => (item=label4) => {
    "ansible_loop_var": "item",
    "item": {
        "key": "label4",
        "value": "tata"
    },
    "label4": " tata "
}

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

Upvotes: 2

Related Questions