Ansible: set_fact on a json object
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"
}
}
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, 2022Comments
-
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
inmy_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 over 7 yearsThanks 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 over 7 yearsI 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 over 7 yearsThis can be shortened to a single task
my_var: '{{ my_var | combine({ "Enabled": false }) }}'
. You don't need to usefrom_json
. -
techraf over 7 yearsExcept 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 over 7 yearsThat 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?