Ansible: set_fact on a json object

16,172

Solution 1

this was my solution - probably not the most eloquent:

- set_fact:
    my_temp_enabled_var: '{ "Enabled": "false" }'

- set_fact:
    my_temp_enabled_var: "{{ my_temp_enabled_var | from_json }}"

- set_fact:
    my_var: "{{ my_var | combine(my_temp_enabled_var) }}"

Solution 2

You can create a new dictionary with a Jinja2 template:

---
- hosts: localhost
  gather_facts: no
  connection: local
  vars:
    my_var:
      Enabled: true
      SomeOtherVariable: value
  tasks:
    - debug:
        var: my_var
    - set_fact:
        my_var: '{ "Enabled": false, "SomeOtherVariable": "{{ my_var.SomeOtherVariable }}" }'
    - debug:
        var: my_var

And the result:

TASK [debug] *******************************************************************
ok: [localhost] => {
    "my_var": {
        "Enabled": true,
        "SomeOtherVariable": "value"
    }
}

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

TASK [debug] *******************************************************************
ok: [localhost] => {
    "my_var": {
        "Enabled": false,
        "SomeOtherVariable": "value"
    }
}
Share:
16,172
Willem van Ketwich
Author by

Willem van Ketwich

I code and administrate using a variety of languages and platforms using a variety of services including node.js, .net, php, powershell, javascript, c#, vb, ruby, python, java, angular, on linux, windows, android, using aws, and azure among others.

Updated on June 27, 2022

Comments

  • Willem van Ketwich
    Willem van Ketwich almost 2 years

    I have a json object in an Ansible variable (my_var), which contains values similar to the following:

    {
        "Enabled": "true"
        "SomeOtherVariable": "value"
    }
    

    I want to modify the value of Enabled in my_var and have tried the following:

    set_fact:
      my_var.Enabled: false
    

    and

    set_fact:
      my_var['Enabled']: false
    

    Which both give errors similar to:

    "The variable name 'my_var.Enabled' is not valid. Variables must start with a letter or underscore character, and contain only letters, numbers and underscores."

    Can this be done with set_fact or is there some other way of achieving this?

  • Willem van Ketwich
    Willem van Ketwich over 7 years
    Thanks for that. I ended up going with the solution I posted. If the json wasn't passed in and could be created in the playbook as per your example, your solution would be ideal.
  • Willem van Ketwich
    Willem van Ketwich over 7 years
    I beg to differ. If the object is passed in as a large serialized json object, then your approach is simply not feasible. It would require reconstructing the entire object in the task to set one attribute. The example I gave of the json is a simplification of the actual object.
  • techraf
    techraf over 7 years
    This can be shortened to a single task my_var: '{{ my_var | combine({ "Enabled": false }) }}'. You don't need to use from_json.
  • techraf
    techraf over 7 years
    Except that it's the way to do it especially with what you call "a large serialized JSON object". Because, if it contained nested dictionaries your combine method would replace the whole branch, not only the leaf.
  • Willem van Ketwich
    Willem van Ketwich over 7 years
    That is a good point. It was lucky that in this case that the leaf was on the top branch. It is a bit concerning that your approach is the only way to do it if it is a nested object several levels down.. Couldn't clones of each branch at each sub-level be made and combined iteratively to produce the same result?