Dynamically passing a json as a parameter in a "command" task
I have this task in my playbook:
- name: Update instance tags
command: oci compute instance update -c {{ compartment }} --freeform-tags {{ tag_var_json }}
According to the oracle documentation for this command, the parameter --freeform-tags
accepts a json that represents the key-value pair for the tag. I need to have this json be created dynamically in the playbook itself, so prior to running that task, I have this one for testing purposes:
- name: Create a json object to use as tag
set_fact:
tag_var: '{ "test": "thisisatest" }'
set_fact:
tag_var_json: "{{ tag_var | to_json }}"
But I must be doing something wrong because I keep getting this error:fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'tag_var' is undefined
Is there an easier way of creating a json directly in the playbook and passing it as an argument to that parameter?
Thank you.
Solution 1:
There are two things going on here. The first is that you have created YAML that is accepted by the parser, but behaves in a slightly unexpected way (and will produce a warning in the current version of Ansible.)
- name: Create a json object to use as tag
set_fact:
tag_var: '{ "test": "thisisatest" }'
set_fact:
tag_var_json: "{{ tag_var | to_json }}"
Keys in YAML are unique; when the parser encounters a second instance of the same key it throws away the first one. Since you've repeated set_fact
, this is equivalent to:
- name: Create a json object to use as tag
set_fact:
tag_var_json: "{{ tag_var | to_json }}"
Correcting the syntax error will still result in a failure, however.
- name: Create a json object to use as tag
set_fact:
tag_var: '{ "test": "thisisatest" }'
tag_var_json: "{{ tag_var | to_json }}"
The arguments to set_fact
have to be templated before the task runs, at which point tag_var is still undefined (because this task is defining it.)
One correct way to write this task is as two separate tasks:
- name: Create a tag object
set_fact:
tag_var:
test: thisisatest
- name: Create a JSON string for tagging
set_fact:
tag_var_json: "{{ tag_var | to_json }}"
However, set_fact
isn't required at all. You can just set the var directly on the task where you use it, which is both more efficient and makes it more tightly scoped.
- name: Update instance tags
command: oci compute instance update -c {{ compartment }} --freeform-tags "{{ tag_var | to_json }}"
vars:
tag_var:
test: thisisatest