5

I am gathering ansible facts . A serial number is coming in upper and lower case. see below.

5A2c32a-f1G85g-2035-0483-1fe9c129216d 

I need to compare that fact with another serial number which is in complete lower case.see below.

5a2c32a-f1g85g-2035-0483-1fe9c129216d 

If i use jinja2 filter to convert into lower case. Then i cannot manipulate the json ouput. For example. i tried this

- set_fact:
     facts: "{{ facts | lower | to_json }}"

- debug:
    var: facts.instance

it throws error

TASK [play : set_fact] ******************************************************************************
ok: [localhost]

TASK [play : debug] ******************************************************************************
ok: [localhost] => {
    "facts.instance": "VARIABLE IS NOT DEFINED!"
}

But if i debug facts only. it gives me the output. below works,

- set_fact:
     facts: "{{ facts | lower | to_json }}"

- debug:
    var: facts

but i need to get further value on facts.instance.disk etc

Zeitounator
  • 38,476
  • 7
  • 53
  • 66
sherri
  • 421
  • 2
  • 9
  • 19
  • 1
    I don't think `to_json` is required. Works for me without it (Ansible 2.8.5) – Matt P Sep 26 '19 at 03:33
  • @MattP If i remove `to_json`, then i get the same error ```TASK [play : set_fact] ****************************************************************************** ok: [localhost] TASK [play : debug] ****************************************************************************** ok: [localhost] => { "facts.instance": "VARIABLE IS NOT DEFINED!" }``` – sherri Sep 26 '19 at 03:42
  • @MattP i am using `vmware_guest_facts` module – sherri Sep 26 '19 at 03:43
  • 1
    Are you able to show a dump of the `facts` variable? Be sure to change/remove any sensitive information first – Matt P Sep 26 '19 at 03:54
  • @MattP. okay. The output is very huge. so i am pasting a portion of it. might have some alignment issues. – sherri Sep 26 '19 at 05:12
  • ```"facts": { "instance": { "config": { "hardware": { "device": [ { "backing": { "uuid": "5A2c32a-f1G85g-2035-0483-1fe9c129216d", }, "unitNumber": 0 } ] } } } } ``` – sherri Sep 26 '19 at 05:17
  • 1
    @sherri Could you please post the value of facts variable set in yml file and not from the output? I tried removing to_json and it worked in both Ansible version 2.85 and 1.9.6 – Sriram Sep 26 '19 at 09:46

1 Answers1

0

I would probably solve this with a few lines of python for convenience and easier maintenance. Example below is with a custom filter plugin adjacent to playbook but you can distribute this as part of a collection

In the below example, I'll pass a list of keys which can appear anywhere in you original dict and need to be down-cased. This gives you control over the exact data to lower case and you can pass several keys if needed.

This is the example file structure:

.
├── filter_plugins
│   └── my_facts_filters.py
└── playbook.yml

This is the filter_plugins/my_facts_filters.py custom filter (adapted from an other answer):

from ansible.errors import AnsibleError


def inspect_and_replace(data, elements_list):
    if isinstance(data, (dict, list)):
        for k, v in (data.items() if isinstance(data, dict) else enumerate(data)):
            if k in elements_list and isinstance(v, str):
                data[k] = v.lower()
            inspect_and_replace(v, elements_list)


def elements_to_lower(input_dict, elements_list):
    # Raise an ansible error in input is not a dict
    try:
        assert isinstance(input_dict, dict)
    except AssertionError:
        raise AnsibleError(f'Input is not a dict. Got {type(input_dict)}')

    try:
        assert isinstance(elements_list, list)
    except AssertionError:
        raise AnsibleError(f'filter argument (i.e. elements to downcase) is not a list. Got {type(elements_list)}')

    inspect_and_replace(input_dict, elements_list)
    return input_dict


class FilterModule(object):
    """my facts filters."""

    def filters(self):
        """Return the filter list."""
        return {
            'elements_to_lower': elements_to_lower
        }

A minimal test playbook:

---
- hosts: localhost
  gather_facts: false

  tasks:
    - name: Dummy task to set the same var (I believe...) as in your example
      ansible.builtin.set_fact:
        facts:
          instance:
            config:
              hardware:
                device:
                  - backing:
                      uuid: 5A2c32a-f1G85g-2035-0483-1fe9c129216d
                    unitNumber: 0

    - name: Use custom filter to transform needed elements
      ansible.builtin.debug:
        msg: "{{ facts | elements_to_lower(['uuid']) }}"

results in:

$ ansible-playbook playbook.yml 

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

TASK [Dummy task to set the same var (I believe...) as in your example] *******************************************************************************************************************************************************
ok: [localhost]

TASK [Use custom filter to transform needed elements] *************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": {
        "instance": {
            "config": {
                "hardware": {
                    "device": [
                        {
                            "backing": {
                                "uuid": "5a2c32a-f1g85g-2035-0483-1fe9c129216d"
                            },
                            "unitNumber": 0
                        }
                    ]
                }
            }
        }
    }
}

PLAY RECAP ********************************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
Zeitounator
  • 38,476
  • 7
  • 53
  • 66