I am trying to write a playbook to create two files .When nested variables are defined. I have got the output but this is not what I expect . I need to create two files with only the variables defines
playbook.yml
- hosts: all
vars:
variable:
- name: "item1"
vars:
- { id: 1, type: "get" , resource: "Customerid" }
- { id: 17, type: "post", resource: "Cus" }
- name: "item2"
vars:
- { id: 2, type: "get", resource: "Customerid" }
tasks:
- template:
src: template.j2
dest: "{{ item.name }}"
with_items: "{{ variable }}"
template.j2 file content
{% for item in variable %}
Item Name: {{ item.name }}
{% for item_var in item.vars %}
{% if item_var['type'] == 'get' %}
Item ID: {{ item_var['id'] }}
Item Resource: {{ item_var['resource'] }}
Get function
{% else %}
Item ID: {{ item_var['id'] }}
Item Resource: {{ item_var['resource'] }}
Post function
{% endif %}
{% endfor %}
{% endfor %}
Current result of two files created item1 and item2:
item1
Item Name: item1
Item ID: 1
Item Resource: Customerid
Get function
Item ID: 17
Item Resource: Cus
Post function
Item Name: item2
Item ID: 2
Item Resource: Customerid
Get function
item2
Item Name: item1
Item ID: 1
Item Resource: Customerid
Get function
Item ID: 17
Item Resource: Cus
Post function
Item Name: item2
Item ID: 2
Item Resource: Customerid
Get function
I would like to get the below output when two files are created . Not sure how to get this. Desired output:
item1
Item Name: item1
Item ID: 1
Item Resource: Customerid
Get function
Item ID: 17
Item Resource: Cus
Post function
item2
Item Name: item2
Item ID: 2
Item Resource: Customerid
Get function
Just remove the duplicate loop from the template.
Item Name: {{ item.name }}
{% for item_var in item.vars %}
{% if item_var['type'] == 'get' %}
Item ID: {{ item_var['id'] }}
Item Resource: {{ item_var['resource'] }}
Get function
{% else %}
Item ID: {{ item_var['id'] }}
Item Resource: {{ item_var['resource'] }}
Post function
{% endif %}
{% endfor %}
The template might be simplified
Item Name: {{ item.name }}
{% for item_var in item.vars %}
Item ID: {{ item_var.id }}
Item Resource: {{ item_var.resource }}
{{ item_var.type|capitalize }} function
{% endfor %}
Related
I have the below structure of data source in yml format.
systemEmailAccount:
mode: DEFAULT
username: test#gmail.com
password: Test#123
displayName: "Test"
senderAddress: test#gmail.com
oauthClientId: "xxxxxxx"
oauthSecret: "xxxxxxxxx"
tokenExpires: 1458168133864
secondarySystemEmailAccount:
mode: DEFAULT
username: test2#gmail.com
password: Test#123
displayName: "Test2"
senderAddress: test2#gmail.com
oauthClientId: "xxxxxxx"
oauthSecret: "xxxxxxxxx"
tokenExpires: 14581681338777
I'm trying to regenerate it to a new file using this jinja2 template snippet.
systemEmailAccount:
{% for key,value in config.systemEmailAccount.items() %}
{% if key == "mode" or key == "username" or key == "password" or key == "senderAddress" or key == "tokenExpires" %}
{{ key }}: {{ value }}
{% else %}
{{ key }}: {{ '"' }}{{ value }}{{ '"' }}
{% endif %}
{% endfor %}
secondarySystemEmailAccount:
{% for key,value in config.secondarySystemEmailAccount.items() %}
{% if key == "mode" or key == "username" or key == "password" or key == "senderAddress" or key == "tokenExpires" %}
{{ key }}: {{ value }}
{% else %}
{{ key }}: {{ '"' }}{{ value }}{{ '"' }}
{% endif %}
{% endfor %}
But the indentation does not seem right in the output.
emailAccount1:
username: test#gmail.com
mode: DEFAULT
password: Test#123
displayName: "Test"
senderAddress: test#gmail.com
oauthClientId: "xxxxxxx"
oauthSecret: "xxxxxxxxx"
tokenExpires: 1458168133864
emailAccount2:
username: test2#gmail.com
mode: DEFAULT
password: Test#123
displayName: "Test2"
senderAddress: test2#gmail.com
oauthClientId: "xxxxxxx"
oauthSecret: "xxxxxxxxx"
tokenExpires: 1458168133864
Any suggestion to fix this?
have a look at those 2 topics from official jinja2 docs
white space control: https://jinja.palletsprojects.com/en/2.11.x/templates/#whitespace-control
filter indent: https://jinja.palletsprojects.com/en/2.11.x/templates/?highlight=indent#indent
try this snippet below:
systemEmailAccount:
{%- for key,value in config.systemEmailAccount.items() %}
{%- if key == "mode" or key == "username" or key == "password" or key == "senderAddress" or key == "tokenExpires" %}
{%- filter indent(width=2) %}
{{ key }}: {{ value }}
{%- endfilter %}
{%- else %}
{%- filter indent(width=2) %}
{{ key }}: {{ '"' }}{{ value }}{{ '"' }}
{%- endfilter %}
{%- endif %}
{%- endfor %}
[..]
Here is the output.
"result.containers":[
{
"Image":"ca.docker/webproxy:1.0.0",
"Names":[
"/customer1"
]
},
{
"Image":"docker.local/egacustomer:1.0.1",
"Names":[
"/registrator"
]
}
]
I'm trying to get the following output using jinja2
"containerlist"=>{
"webproxy": {
"name": "customer1"
},
"egacustomer": {
"name": "registrator"
}
}
Here is my jinja2 code.
- set_fact:
containerlist: |
{
{% for item in result.containers %}
{{ item.Image.split('/')[-1].split(':')[0] | replace('\n', '') }}
name : {{ item.Names[0][1:] | replace('\n', '') }}
{% endfor %}
}
I get the below output.
"containerlist": "{\nwebproxy\n name : customer1\negacustome\n name : registrator\n}"
Could someone please help me get the desired output. Any help would be greatly appreciated
The data in YAML
result:
containers:
- Image: ca.docker/webproxy:1.0.0
Names:
- /customer1
- Image: docker.local/egacustomer:1.0.1
Names:
- /registrator
The tasks below
- set_fact:
containerlist: "{{ containerlist|default({})|
combine({key: {'name': name}}) }}"
loop: "{{ result.containers }}"
vars:
key: "{{ (item.Image.split(':')|first).split('/')|last }}"
name: "{{ item.Names[0][1:] }}"
- debug:
var: containerlist
give
containerlist:
egacustomer:
name: registrator
webproxy:
name: customer1
But, the result is not a list. It's a dictionary. If you want a list use this
- set_fact:
containerlist: "{{ containerlist|default([]) +
[{key: {'name': name}}] }}"
loop: "{{ result.containers }}"
vars:
key: "{{ (item.Image.split(':')|first).split('/')|last }}"
name: "{{ item.Names[0][1:] }}"
- debug:
var: containerlist
give
containerlist:
- webproxy:
name: customer1
- egacustomer:
name: registrator
I have dictionary like this:
abc:
xyz1:
url: "{{ url }}"
api_key: "{{ key }}"
xyz2:
url: "{{ url }}"
api_key: "{{ key }}"
xyz3:
url: "{{ url }}"
api_key: "{{ key }}"
I know that all xyz{number} have the same values in url and api_key and will have same values in the future.
I need this nested format, but what will be more elegant way to write this instead the way I did it (which will be quite long with few more elements)?
Create template
shell> cat myvars.yml.j2
abc:
{% for index in range(1, size+1) %}
xyz{{ index }}:
url: "{{ '{{' }} url {{ '}}' }}"
api_key: "{{ '{{' }} key {{ '}}' }}"
{% endfor %}
The playbook
- hosts: localhost
vars:
size: 3
key: mykey
url: myurl
tasks:
- template:
src: myvars.yml.j2
dest: myvars.yml
- include_vars: myvars.yml
- debug:
var: abc
will create file myvars.yml
shel> cat myvars.yml
abc:
xyz1:
url: "{{ url }}"
api_key: "{{ key }}"
xyz2:
url: "{{ url }}"
api_key: "{{ key }}"
xyz3:
url: "{{ url }}"
api_key: "{{ key }}"
and debug will display the included variable
"abc": {
"xyz1": {
"api_key": "mykey",
"url": "myurl"
},
"xyz2": {
"api_key": "mykey",
"url": "myurl"
},
"xyz3": {
"api_key": "mykey",
"url": "myurl"
}
}
I have a set of data objects I'm passing to a template, and when I render the template I want to omit a given line if the value in the array is null.
Example array:
[
{
'name': 'one'
'place': 'high'
'value': 'set'
}
{
'name': 'two'
'place': null
'value': 'unset'
}
{
'name': 'three'
'place': 'low'
'value': 'whyme'
}
]
Sample template:
{% for item in array %}
- name: {{ item.name }}
place: {{ item.place | default (omit) }}
{% endfor %}
The default(omit) filter isn't working the way I want it to. It's putting the "place:" line into the output with no value. I want the "place:" line to not appear in the output at all.
Actual output:
- name: one
place: high
- name: two
place:
- name: three:
place: low
Desired output:
- name: one
place: high
- name: two
- name: three
place: low
The template below does the job
{% for item in array %}
- name: {{ item.name }}
{% if item.place %} place: {{ item.place }}
{% endif %}
{% endfor %}
gives
- name: one
place: high
- name: two
- name: three
place: low
with the data properly structured
array: [
{
'name': 'one',
'place': 'high',
'value': 'set',
},
{
'name': 'two',
'place': null,
'value': 'unset',
},
{
'name': 'three',
'place': 'low',
'value': 'whyme',
}
]
This question already has answers here:
How do I get an Ansible template to honor new lines after a conditional
(5 answers)
Closed 4 years ago.
Trying to build a JSON file from a template. It works ok as such, but for some reason newlines within loop constructs go missing, which I find rather irksome; the file "works" (is machine readable just fine), but for human consumption it's pretty ill-suited.
Here's my template:
{
"Users":
[
{% for username,user in _vpn_user_accounts.items() %}
{
"Name" : "{{ user.name }}",
"Hash" : "{{ user.hash }}",
"Cns" : [
{% for cn in user.cns.get(server_name, []) %}
"{{ cn }}"{% if not loop.last -%},{% endif %}
{% endfor %}
],
"key_ids" : [
{% for key in user.get( 'keys' , []) %}
{% if key.public is defined %}
"{{ key.public }}"{% if not loop.last %},{% endif %}
{% endif %}
{% endfor %}
],
"comment" : "{{ user.get( 'comment', '' ) }}"
} {% if not loop.last %},{% endif %}
{% endfor %}
]
}
Here's some sample data:
- andrej:
name: "andrej"
hash: "$2b$10$8EF3H.../Wj0RchEqU6"
cns:
h:
- "andrej_linux_h_201808171440"
- "andrej_linuxvm_h_201809131031"
- "andrej_mac_h_201808171441"
- "andrej_phone_h_201808171441"
w:
- "andrej_linux_w_201808171439"
- "andrej_linuxvm_w_201809131031"
- "andrej_mac_w_201808171441"
- "andrej_phone_w_201808171441"
keys:
- name: "andrej"
public: "kbjrvtni"
- name: "andrej2"
public: "ijrltifu"
- name: "andrej3"
public: "rbcvncbt"
comment: "systems"
This is my desired outcome (running against server "w"):
{
"Users":
[
{
"Name" : "andrej",
"Hash" : "$2b$10$8EF3H.../Wj0RchEqU6",
"Cns" : [
"andrej_linux_w_201808171439",
"andrej_linuxvm_w_201809131031",
"andrej_mac_w_201808171441",
"andrej_phone_w_201808171441"
],
"key_ids" : [
"kbjrvtni",
"ijrltifu",
"rbcvncbt"
],
"comment" : "systems guy"
}
]
}
This is what I get:
{
"Users":
[
{
"Name" : "andrej",
"Hash" : "$2b$10$8EF3H.../Wj0RchEqU6",
"Cns" : [
"andrej_linux_w_201808171439", "andrej_linuxvm_w_201809131031", "andrej_mac_w_201808171441", "andrej_phone_w_201808171441" ],
"key_ids" : [
"kbjrvtni", "ijrltifu", "rbcvncbt" ],
"comment" : "systems guy"
}
]
}
I have experimented with #Jinja2: trim_blocks and #Jinja2: keep_newline, neither of which showed the desired result. Well, trim_blocks kind of did, but it also gave me a bunch of empty lines where the jinja conditionals were ... unsatisfactory.
Any hints on how to resolve this? As I said, it works, but it irks me immensely that I can't get human readable, nice output.
And this little change actually made the problem go away in the end.
#jinja2: trim_blocks:False
{
"Users":
[
{% for username,user in _vpn_user_accounts.items() %}
{
"Name" : "{{ user.name }}",
"Hash" : "{{ user.hash }}",
"Cns" : [
{%- for cn in user.cns.get(server_name, []) %}
"{{ cn }}"{% if not loop.last -%},{% endif %}
{%- endfor %}
],
"key_ids" : [
{%- for key in user.get( 'keys' , []) %}
{% if key.public is defined %}
"{{ key.public }}"{% if not loop.last %},{% endif %}
{% endif %}
{%- endfor %}
],
"comment" : "{{ user.get( 'comment', '' ) }}"
} {% if not loop.last %},{% endif %}
{% endfor %}
]
}