In my playbook, a JSON file is included using the include_vars module. The content of the JSON file is as given below:
{
"Component1": {
"parameter1" : "value1",
"parameter2" : "value2"
},
"Component2": {
"parameter1" : "{{ NET_SEG_VLAN }}",
"parameter2": "value2"
}
}
After the JSON file is included in the playbook, I am using uri module to sent an http request as given below:
- name: Configure Component2 variables using REST API
uri:
url: "http://0.0.0.0:5000/vse/api/v1.0/config/working/Component2/configvars/"
method: POST
return_content: yes
HEADER_x-auth-token: "{{ login_resp.json.token }}"
HEADER_Content-Type: "application/json"
body: "{{ Component2 }}"
body_format: json
As it can be seen, the body of the http request is send with the JSON data Component2. However, Jinja2 tries to substitute the {{ NET_SEG_VLAN }} in the JSON file and throws and undefined error. The intention is not to substitute anything inside the JSON file using Jinja2 and send the body as it is in http request.
How to prevent the Jinja2 substitution for the variables included from the JSON file?
You should able to escape the variable even with {{'{{NET_SEG_VLAN}}'}} to tell jinja not to template anything inside that block.
You should be able to escape the variable with {% raw %} and {% endraw %} to tell Jinja not to template anything inside that block.
!unsafe
From documentation at https://docs.ansible.com/ansible/2.10/user_guide/playbooks_advanced_syntax.html#unsafe-or-raw-strings:
When handling values returned by lookup plugins, Ansible uses a data type called unsafe to block templating. Marking data as unsafe prevents malicious users from abusing Jinja2 templates to execute arbitrary code on target machines. The Ansible implementation ensures that unsafe values are never templated. It is more comprehensive than escaping Jinja2 with {% raw %} ... {% endraw %} tags.
You can use the same unsafe data type in variables you define, to prevent templating errors and information disclosure. You can mark values supplied by vars_prompts as unsafe. You can also use unsafe in playbooks. The most common use cases include passwords that allow special characters like { or %, and JSON arguments that look like templates but should not be templated.
I am using it all the time, like this:
# Load JSON content, as a raw string with !unsafe
- tags: ["always"]
set_fact:
dashboard_content: !unsafe "{{ lookup('file', './dash.json') | to_json }}"
# Build dictionnary via template
- tags: ["always"]
set_fact:
cc: "{{ lookup('template', './templates/cm_dashboard.yaml.j2') | from_yaml }}"
## cm_dashboard.yaml.j2 content:
hello: {{ cc_dashboard_content }}
# Now, "cc" is a dict variable, with "hello" field protected!
Related
I created a role and with a variables file named defaults/main.yml with following content:
level1:
level2_1:
level3_1: "value_3_1"
level2_2:
level3_2: "value_3_2"
level3_3: "{{ level1.level2_1.level3_1 }} {{ level1.level2_2.level3_2 }}"
When I try running inside a task file it throws An unhandled exception occurred while templating.
I have tried changing the level3_3 line without adding parrents but also throws an error.
The only way I found to work is if I remove indentation from level3_3 which will not make it part of the structure.
How can I compose a variable similar to level3_3 inside the structure without throwing an error?
It's not possible by design. See Can't reference a dict key inside the same dict #50280. Either create compounds outside the dictionary or put the repeating values into a variables. For example
val_A: value_3_1
val_B: value_3_2
level1:
level2_1:
level3_1: "{{ val_A }}"
level2_2:
level3_2: "{{ val_B }}"
level3_3: "{{ val_A }} {{ val_B }}"
I'd prefer this structure. It's simpler and less error-prone.
I would like to use the 2 values of a group variable in two different places. My current group vars looks like this.
[test1:vars]
fooname=foo1
barname=bar1
I am using jinja template in the playbook as {{ fooname }} and {{ barname }} based on my requirements in the playbook in multiple places. Now instead of two different variables, i would like to use it as one variable as names and i would like to use the values of it in different places.
Expected group variables :
[test1:vars]
names=foo1,bar1
Is there a way that now i can call {{ names }} variable with some function or condition like {{ names is search(foo) }} or {{ names is search(bar) }} inside the playbook like we use in condition so that i can avoid declaring 2 variables instead of one. I will use these variables in different places in my playbook.
I tried using the above one which prints "True" instead i need the value of my variable which has only foo or bar when i search accordingly.
Note : I have close to 400 groups which same pattern with makes the extra variable makes my inventory lengthy. So, i would like to minimize it.
Ansible 2 supports Arrays in the inventory File.
[test1:vars]
names=["foo","bar"]
But there are some limitations.
[example:vars]
# working
var1=["foo","bar"]
var2=[1,2]
var3=[True, False]
# not working
var4=[yes, no] # Boolean need to be True and False
var5=[foo, bar] # Interpreted as one string
var6='["foo","bar"]' # Interpreted as one string as well
Usage example:
- debug:
- msg: "Item: {{ example[0] }}"
- debug:
- msg: "Item: {{ example | first }}"
I'm wondering if it's possible to use a Jinja2 {% if %} expression inside a vars file?
So say I have:
az:
az1: foo
az2: bar
az3: foobar
{% if az == az['az1'] %}
floating_ip_pool = bar
{% endif %}
Basically, I'm trying to avoid having to set these variables each time since they'll always be based on the az.
Thanks.
That's not valid syntax. A vars file must first be parsed as a YAML document, and introducing that Jinja syntax results in something that is no longer valid YAML.
You can do something like this instead:
az:
az1: foo
az2: bar
az3: foobar
floating_ip_pool: "{% if target_az == az['az1'] %}bar{% endif %}"
I have Cloudformation template in yaml format.
The template is rendered by Ansible Jinja2.
I need to find a way to add validation of some elements inside the template. Something like this ("if" statement is a pseudo code of what I want to get):
Parameters:
EnvironmentType:
Default: {{profile}}
Mappings:
Environments:
dev:
DbSnapshotArn: ""
test:
DbSnapshotArn: "AAA"
Type: AWS::RDS::DBInstance
Properties:
{% if Mappings.Environments.{{profile}}.DbInstanceClass %}
DBSnapshotIdentifier: !FindInMap [Environments, !Ref 'EnvironmentType', DbSnapshotArn]
{% endif %}
Is it possible?
Not if Mappings.Environments.{{profile}}.DbInstanceClass references something inside the template.
But if you define a variable like this:
Mappings:
Environments:
Dev:
DbInstanceClass: "..."
And another variable that contains the value of profile, then inside your template you can create an if statement like this:
{% if Mappings.Environments[profile].DbInstanceClass is defined %}
...
{% endif %}
See also:
Jinja2 Tests
New to Jinja2 templating
I can iterate over a list using a for conditional which is simple enough but i am trying to do the below...
I have a variable that contains a un-ordered lists of values which are group names. I would like to access the group_names lists/variable and check if a specific item in this list exists and then perform an action if that value is found.
group_names: [ "groupname1", "groupname2", "groupname3", "groupname4"]
Sounds like you want:
{% if "somevalue" in group_names %}
whatever stuff
{% endif %}
http://jinja.pocoo.org/docs/2.9/templates/