How to create dynamic files? - ansible

i´m trying to rename ethernet-interfaces on Linux. Each interface with the name enp0s* have to be eth*. First, i create udev-rules for renaming. that works fine. Secondly i have to create new configuration-files for each interface ( ' etc/sysconfig/network-scripts/ifcfg-eth* ' ). I don´t know, how to create the loop to place parameters in each interface. Can somneone help me?
Thats an extract of my playbook:
- name: Get new interface-names of the new created udev-rules
become: yes
shell: cat /etc/udev/rules.d/70-persisten-ipoib.rules.cfg | egrep -i 'eth.'
register: car
- name: Create new-ifcfg-eth* files
template:
with_items: "{{ car.stdout_lines }}"
register: cat
template: src= roles/configure_network/templates/create_ifcfg.cfg.j2 dest=/etc/sysconfig/network-scripts/ifcfg-{{ item }}
# Template: roles/configure_network/templates/create_ifcfg.cfg.j2
{% for interface in cat.results %}
NAME="eth{{ item.name }}
TYPE=Ethernet
BOOTPROTO={{item.bootproto|default('dhcp')}}
IPV4_FAILURE_FATAL=no
IPV6INIT=no
{% if item.ipaddress is defined %}
IPADDR={{item.ipaddress}}
{% endif %}
{% if item.netmask is defined %}
NETMASK={{item.netmask}}
{% endif %}
{% if item.gateway is defined %}
GATEWAY={{item.gateway}}
{% endif %}
PEERDNS=no
{% if item.dns is defined %}
DNS1={{item.dns}}
{% endif %}
ONBOOT={{item.onboot|default('yes')}}
{% endfor %}

Just fix your syntax:
- name: Create new-ifcfg-eth* files
template:
src: create_ifcfg.cfg.j2
dest: /etc/sysconfig/network-scripts/ifcfg-{{ item }}
with_items: "{{ car.stdout_lines }}"
register: cat
Remove double template call, use relative path (no need to define full path to role's own templates), use YAML syntax instead of key=value (you had spaces in them, which are not allowed).

Related

"AnsibleError: template error while templating string: unexpected 'end of statement block'

I have a jinja2 template that looks like this:
token: {{ RANCHER_SERVER_TOKEN}}
server: https://{{ RANCHER_RKE2_SERVER }}:9345
{% endif %}{% if RANCHER_TLS_SAN is defined %}
tls-san:{% for item in RANCHER_TLS_SAN +%}
- {{ item }}{% endfor +%}
{% endif %}
{% if RANCHER_NODE_LABELS is defined %}
node-label:{% for item in RANCHER_NODE_LABELS +%}
- {{ item }}{% endfor +%}
{% endif %}
{% if RANCHER_NODE_TAINTS is defined %}
node-taint:{% for item in RANCHER_NODE_TAINTS +%}
- {{ item }}{% endfor +%}
{% endif %}
in my inventory group in group_vars I have this data structure
---
RANCHER_TLS_SAN:
- k3-crontroller-1.prometheus.internal
RANCHER_NODE_TAINTS:
- "CriticalAddonsOnly=true:NoExecute"
I test it through this link: https://ansible.sivel.net/test/
and it renders out great.
However I get this issue when running the playbook:
fatal: [k3-rancher-controller-1]: FAILED! => {"changed": false, "msg": "AnsibleError: template error while templating string: unexpected 'end of statement block'. String: {%if RANCHER_DOWNSTREAM_SERVER_AGENT_NODE is defined %}\ntoken: {{ RANCHER_SERVER_TOKEN }}\nserver: https://{{ RANCHER_RKE2_SERVER }}:9345\n{% endif %}{% if RANCHER_TLS_SAN is defined %}\ntls-san:{% for item in RANCHER_TLS_SAN +%}\n - {{ item }}{% endfor %}\n{% endif %}\n{% if RANCHER_NODE_LABELS is defined %}\nnode-label:{% for item in RANCHER_NODE_LABELS +%}\n - {{ item }}{% endfor %}\n{% endif %}\n{% if RANCHER_NODE_TAINTS is defined +%}\nnode-taint:{% for item in RANCHER_NODE_TAINTS +%}\n - {{ item }}{% endfor %}\n{% endif %}"}
My playbook looks like this:
---
- name: Create VM for Rancher Kubernetes Control Plane Nodes
hosts: master
gather_facts: no
become: yes
become_user: root
tasks:
- name: create directory /etc/rancher/rke2
file:
path: /etc/rancher/rke2
state: directory
- name: Create template and copy to Agent nodes
template:
src: playbooks/templates/config.j2
dest: /etc/rancher/rke2/config.yaml
I am using ansible 2.9.27.
Does anyone know what is going on?
Any help is much appreciated. Many thanks

Problems with Jinja2 and ansible making a sub dict

I need to read a csv file with diferent IPs and make a dictionary with a jinja2 filter for modificate the IP depending the IPNumber value. The yml file is like:
- read_csv:
path: vms.csv
key: Number
fieldnames: Name,IP1,IP2,IP3,IP4,IPNumber
delimiter: ';'
register: vms
- name: vms to dict
debug:
msg:
- {{'Name':{{ item.value.Name }},
{% if item.value.IPNumber == "1" %}
'IP':{{ item.value.IP1 }},
{% endif %}
{% if item.value.IPNumber == "2"%}
'IP':{{ item.value.IP2 }},
{% endif %}
{% if item.value.IPNumber == "3"%}
'IP':{{ item.value.IP3 }},
{% endif %}
{% if item.value.IPNumber == "4"%}
'IP':{{ item.value.IP4 }},
{% endif %}}}
loop: "{{ vms.dict | dict2items }}"
register: vms2
But I get the error:
The error appears to be in '/etc/ansible/roles/vms.yml': line 17, column 16, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
'Name':{{ item.value.Name}},
{% if item.value.IPNumber == "1" %}
^ here
I know is a syntax problem but I dont guess where the problem is.
I need some help.
The following task should create your dictionary as per your requirement inside a var you can reuse elsewhere. Rename my_ip_dict to whatever suits your project better.
- name: Create my IP dictionary
set_fact:
my_ip_dict: >-
{{
my_ip_dict | default({})
| combine({item.value.Name: item.value['IP' + item.value.IPNumber]})
}}
loop: "{{ vms.dict | dict2items }}"
- name: Check the result:
debug:
var: my_ip_dict
Note that I have dropped all the if/else structures by calling directly the correct field depending on IPNumber. I took for granted it always has a value in the valid scope or the other existing IP* fields. If this is not the case, you can always default that value e.g. item.value['IP' + item.value.IPNumber] | default('N/A')
You should put only variables/expressions within {{ or {%. To me 'Name' looks like normal text and should be outside.
Example:
# Notice the quotes `"` symbol at the beginning and end of debug message
- debug:
msg:
- "Name: {{ item.value.Name }},
{% if item.value.IPNumber == "1" %}
IP: {{ item.value.IP1 }}
# and so on...
{% endif %}"
This at least should address the error message.

Creating text file from jinja template with inputs from csv file

I'm trying to create a text file which goes through the CSV file and populates variables into specific fields.
playbook.yml:
- hosts: localhost
tasks:
- name: "Reading user information"
read_csv:
path: /home/test/vlans.csv
delimiter: ','
register: vlans
- debug: var=vlans
- name: Creating VLANs configuration
template:
src: vlan.conf.j2
dest: /tmp/vlan.conf
Jinja2 Template vlan.conf.j2:
{% for item in vlans %}
!
vlan {{ item.VLAN }}
name {{ item.Description }}
vn-segment {{ item.VNI }}
interface nve1
member vni {{ item.VNI }}
{% endfor %}
and this is a test vlans.csv file:
Tenant,VRF ,VLAN,VNI,Subnet,Description,Good to go
Test,,5,20005,,LAB-Checkpoint-FW-Mgmt,Yes
Test,,208,20208,,LAB-DMZ,Yes Test,,209,20209,,LAB-CSR-MGMT,Yes
Test,10000,210,20210,192.168.12.1/28,LAB-VRF-to-FW,Yes
Prod,,761,20761,,PROD-CORE,Yes
Prod,105,840,20840,172.18.33.1/24,Backups,Yes
Prod,,841,20841,,Transport,Yes
I want to end up with file like in jinja2 template and not repeating line "interface nve 1"
In your question, interface nve1 is inside a loop. It will repeat multiple times in the resulting vlan.conf file.
Use multiple loops in the jinja template to decide what is repeated and what isn't:
{% for item in vlans.list %}
vlan {{ item.VLAN }}
name {{ item.Description }}
vn-segment {{ item.VNI }}
{% endfor %}
interface nve1
{% for item in vlans.list %}
member vni {{ item.VNI }}
{% endfor %}
Note that I've referred to vlans.list in the start of the loops instead of vlans. This is correct as per documentation, but different to the example in the question so it may need adjusting.

Ansible concat vars to string

I've spent most of the day trying to solve this problem and have thus far failed. I am building some playbooks to automate functions in Splunk, and am attempting to convert a list of hosts from an inventory group E.G.
[search_head]
1.2.3.4
5.6.7.8
My expected (desired) result from the debug output of the play should be:
https://1.2.3.4:8089, https://5.6.7.8:8089
I am attempting to complete this by running the following playbook against a running host:
---
- name: Build search head list to initialize the captain
hosts: search_head
remote_user: ansible
vars:
inventory_file: ./inventory-ec2-single-site
search_head_uri: "{{ lookup('template', './bootstrap-sh-deployer.j2') }}"
pre_tasks:
- include_vars:
dir: 'group_vars'
extensions:
- yml
- yaml
tasks:
- name: dump array
debug:
msg: "{{ search_head_uri }}"`
With the template bootstrap-sh-deployer.j2:
{%- set search_head_uri = [] %}
{% for host in groups['search_head'] %}
{%- if search_head_uri.append("https://{{ host }}:8089") %}
{%- endif %}
{%- if not loop.last %}, {% endif -%}
{%- endfor %}
However, the current play returns search_head_uri: ", " which tells me that the loop is running, but {{ host }} is not resolving.
Once you open a Jinja2 expression or a statement you should use Jinja2 syntax. You cannot nest them (i.e. you can't use {{ }} inside {% %}).
{%- if search_head_uri.append("https://" + host + ":8089") %}
This worked - Combination of the answer above to fix jinja formatting and using hostvars to get to the ansible_nodename.
{%- set search_head_uri = [] %}
{% for host in groups['search_head'] %}
{{ "https://" + hostvars[host]['ansible_nodename'] + ":8089" }}
{%- if not loop.last %}, {% endif -%}
{%- endfor %}

How to set concatenated string variable in Ansible template based on a condition

I need to create a string in a template that can change between hosts, and it needs to be in the form of:
"cores": "0,1,2,3"
And the reason the string is "0,1,2,3" in this example is because the host has 4 processor cores.
So I got stuck with something which seems too convoluted to me and I'm not even sure how to use this core_count variable in my template file.
{% set core_count = '' %}
{% for i in range(ansible_processor_cores) %}
{% set core_count = core_count ~ i %}
{% if not loop.last %}
{% set core_count = core_count ~ ',' %}
{% endif %}
{% endfor %}
There are many handy lookup plugins in Ansible. Take sequence:
- hosts: localhost
gather_facts: yes
tasks:
- debug:
msg: '"cores": "{{ lookup("sequence","start=0 count="+(ansible_processor_cores|string)) }}"'

Resources