Introduction to Jinja2
Jinja2 is a python-based template engine with functions similar to smarty in PHP, Freemarker and velocity in J2ee. It can fully support unicode, and has an integrated sandbox execution environment, which is widely used. Jinja2 uses BSD authorization
The syntax of Jinja2 is composed of variables and statements, as follows.
1. variables: Data can be output
` my_variables `
{{ some_dudes_name | capitalize }}
2. statements: Can be used to create conditions and loops, etc.
if Sentence: {% if my_conditional %} ... {% endif %} for Sentence: {% for item in all_items %} `item` …… {% endfor %}
As you can see from the second variable example above, jinja2 supports the use of Unix pipe operators with filters, and there are many built-in filters available. We can build almost any regular configuration file with just a bunch of simple if and for, but if you want to go further, the Jinja 2 documentation (http://jinja.pocoo.org/docs/dev/) contains a lot of interesting things to learn. We can see that ansible allows some additional template variables such as drawing time to be used in templates
First example: reference variables
#cd roles/template/ . ├── meta │ └── main.yml ├── tasks │ ├── template.yml │ └── main.yml ├── templates │ ├── order.j2 └── vars └── main.yml
The master dispatch yml file:
#cat templates.yml --- - hosts: 10.0.90.27 user: root gather_facts: false roles: - role: template
Note: Here - role: template and - template are the same!
Other yml files are as follows:
#cat tasks/main.yml - include: template.yml #cat tasks/template.yml - name: create {{ PROJECT }} directory file: dest=/data/{{ PROJECT }} state=directory - name: template transfor java dir template: src=order.j2 dest=/data/{{ PROJECT }}/order.conf #cat templates/order.j2 project: {{ PROJECT }} switch: {{ SWITCH }} dbport: {{ DBPORT }} #cat vars/main.yml PROJECT: "JAVA" SWITCH: "ON" DBPORT: "8080" //Test: # ansible-playbook templates.yml --syntax-check playbook: templates.yml //Implementation: # ansible-playbook templates.yml PLAY [10.0.90.27] ************************************************************** TASK [template : include] *************************************************** included: /etc/ansible/roles/template/tasks/template.yml for 10.0.90.27 TASK [template : create JAVA directory] ************************************* changed: [10.0.90.27] TASK [template : template transfor java dir] ******************************** changed: [10.0.90.27] PLAY RECAP ********************************************************************* 10.0.90.27 : ok=3 changed=2 unreachable=0 failed=0 //See the results at 10.0.90.27 #cat /data/JAVA/order.conf project: JAVA switch: ON dbport: 8080
Second example: for statement
To generate a list of servers for remote hosts, add the list from 192.168.13.201 web01.test.com to 192.168.13.211 web11.test.com. If you add it manually, it is not scientific. Here you need to use the jinja2 grammar for loop to generate the corresponding configuration files in batches through templates, as follows:
ansible directory structure:
#cd /etc/ansible/roles/test_hosts . ├── meta │ └── main.yml ├── tasks │ ├── file1.yml │ └── main.yml ├── templates │ └── test1.j2 └── vars └── main.yml
The contents of yml files in each directory:
# cat tasks/file1.yml - name: ansible jinja2 template for hosts config template: src=test1.j2 dest=/etc/httpd/conf/httpd.conf.test # cat tasks/main.yml - include: file1.yml # cat templates/test1.j2 {% for id in range(201,212) %} 192.168.13.{{ id }} web{{ "%03d" |format(id-200) }}.test.com {% endfor %} Interpretation: {{id}} extracts the corresponding variable ID value in the for loop "% 02d" calls python's built-in string formatted output (% D formatted integer) because it's 01,02, so it reserves 2 bits, so it uses 02. Then the result is passed to format function through the pipe character "|" for quadratic processing.
Implementation results:
#cat httpd.conf.test 192.168.13.201 web01.test.com 192.168.13.202 web02.test.com 192.168.13.203 web03.test.com 192.168.13.204 web04.test.com 192.168.13.205 web05.test.com 192.168.13.206 web06.test.com 192.168.13.207 web07.test.com 192.168.13.208 web08.test.com 192.168.13.209 web09.test.com 192.168.13.210 web10.test.com 192.168.13.211 web11.test.com
Third example: if statement
Description: If the port number is defined, the defined port number is bound. If the port number is not defined, the default port number is bound.
ansible Catalog results #cd /etc/ansible/roles/mysql_cnf #tree . ├── meta │ └── main.yml ├── tasks │ └── main.yml ├── templates │ └── test3.j2 └── vars
The main yml file is test3.j2 under the templates directory
# cat templates/test3.j2 {% if PORT %} bind_address=10.0.90.27:{{ PORT }} {% else %} bind_address=10.0.90.27:3306 {% endif %}
playbook master file
# cat jinj2_test.yml --- - hosts: 10.0.90.27 user: root gather_facts: false vars: PORT: 3136 tasks: - name: copy file to client template: src=/etc/ansible/roles/mysql_cnf/templates/test3.j2 dest=/root/my.cnf
Implementation:
# ansible-playbook jinj2_test.yml PLAY [10.0.90.27] ************************************************************** TASK [copy file to client] ***************************************************** changed: [10.0.90.27] PLAY RECAP ********************************************************************* 10.0.90.27 : ok=1 changed=1 unreachable=0 failed=0
See
# cat my.cnf bind_address=10.0.90.27:3136
If the vars variable is removed, the result is executed:
# cat jinj2_test.yml --- - hosts: 10.0.90.27 user: root gather_facts: false vars: PORT: false tasks: - name: copy file to client template: src=/etc/ansible/roles/mysql_cnf/templates/test3.j2 dest=/root/my.cnf
See:
# cat my.cnf bind_address=10.0.90.27:3306
3. Jinja default() setting
As everyone knows, default() default settings contribute to the robustness and simplicity of programs. Fortunately, Jinja also supports this feature. In the example above, the port definition in the Mysql configuration file is generated. If specified, PORT=3136, otherwise PORT=3306, we will change this case to try using default().
Editing/etc/ansible/roles/mysql_cnf/templates/test3.j2 is as follows, which is more concise.
bind_address=10.0.90.27:{{ PORT | default(3306) }}
2. Anible uses jiaja2 to generate apache multi-host configuration
1. Create a directory. After creating it, the following is done:
#cd /etc/ansible/roles/apache_conf # tree ./ ./ ├── meta │ └── main.yml ├── tasks │ ├── file.yml │ └── main.yml ├── templates │ └── apache.config.j2 └── vars └── main.yml 4 directories, 5 files
2. Create tasks scheduling file as follows:
#cat file.yml - name: ansible jinja2 template for apache config template: src=apache.config.j2 dest=/etc/httpd/conf/httpd.conf.template #cat main.yml - include: file.yml
3. Create apache jinja2 template file as follows:
#cat apache.config.j2 NameVirtualHost *:80 {% for vhost in apache_vhost %} <VirtualHost *:80> ServerName {{ vhost.servername }} DocumentRoot {{ vhost.documentroot }} {% if vhost.serveradmin is defined %} ServerAdmin {{ vhost.serveradmin }} {% endif %} <Directory "{{ vhost.documentroot }}"> AllowOverride All Options -Indexes FollowSymLinks Order allow,deny Allow from all </Directory> </VirtualHost> {% endfor %}
4. Create variables as follows:
#cat vars/main.yml apache_vhost: - {servername: "apache.test1.com", documentroot: "/data/test1/"} - {servername: "apache.test2.com", documentroot: "/data/test2/"}
5. Create a master scheduling yml file as follows:
#cat /etc/ansible/apache_test.yml --- - hosts: 10.0.90.27 user: root gather_facts: no roles: - { role: apache_conf }
6. Testing:
#ansible-playbook apache_test.yml --syntax-check playbook: apache_test.yml
7. Executing tests
#ansible-playbook apache_test.yml PLAY [10.0.90.27] ************************************************************** TASK [apache_conf : include] *************************************************** included: /etc/ansible/roles/apache_conf/tasks/file.yml for 10.0.90.27 TASK [apache_conf : ansible jinja2 template for apache config] ***************** changed: [10.0.90.27] PLAY RECAP ********************************************************************* 10.0.90.27 : ok=2 changed=1 unreachable=0 failed=0
8. Visit the Client
#cat httpd.conf.template NameVirtualHost *:80 <VirtualHost *:80> ServerName apache.test1.com DocumentRoot /data/test1/ <Directory "/data/test1/"> AllowOverride All Options -Indexes FollowSymLinks Order allow,deny Allow from all </Directory> </VirtualHost> <VirtualHost *:80> ServerName apache.test2.com DocumentRoot /data/test2/ <Directory "/data/test2/"> AllowOverride All Options -Indexes FollowSymLinks Order allow,deny Allow from all </Directory> </VirtualHost>
3. ansible uses jiaja2 to generate nginx template with different configurations
Description: Two Nginx Proxy and one Nginx Web generate the corresponding configuration through a set of templates
1. Anible directory structure:
# cd roles/nginx_conf/ #tree . ├── files ├── meta │ └── main.yml ├── tasks │ ├── file.yml │ └── main.yml ├── templates │ └── nginx.conf.j2 └── vars └── main.yml
2. The contents of files under tasks directory:
#cat tasks/file.yml - name: nginx.j2 template transfer example template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf.template #cat tasks/main.yml - include: file.yml
3. nginx template file
#cat templates/nginx.conf.j2 {% if nginx_use_proxy %} {% for proxy in nginx_proxies %} upstream {{ proxy.name }} #server 127.0.0.1:{{ proxy.port }}; server {{ ansible_eth0.ipv4.address }}:{{ proxy.port }}; } {% endfor %} {% endif%} server { listen 80; servername {{ nginx_server_name }}; access_log off; error_log /etc/nginx/nginx_error.log; rewrite ^ https://$server_name$request_uri? permanent; } server { listen 443 ssl; server_name {{ nginx_server_name }}; ssl_certificate /etc/nginx/ssl/{{ nginx_ssl_cert_name }}; ssl_certificate_key /etc/nginx/ssl/{{ nginx_ssl_cert_key }}; root {{ nginx_web_root }}; index index.html index.html; {% if nginx_use_auth %} auth_basic "Restricted"; auth_basic_user_file /etc/nginx/{{ project_name }}.htpasswd; {% endif %} {% if nginx_use_proxy %} {% for proxy in nginx_proxies %} location {{ proxy.location }} { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Url-Scheme $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_redirect off; proxy_pass http://{{ proxy.name }}; break; } {% endfor %} {% endif %} {% if nginx_server_static %} location / { try_files $url $url/ =404; } {% endif %} }
4. ansible variable file
cat vars/main.yml nginx_server_name: www.testnginx.com nginx_web_root: /data/html/ nginx_proxies: - name: suspicious location: / port: 1234 - name: suspicious-api location: /api port: 4567
ansible main playbook file
#cat nginx_test.yml ##The first roles - name: Nginx Proxy Server's Config Dynamic Create hosts: "10.0.90.25:10.0.90.26" remote_user: root vars: nginx_use_proxy: true nginx_ssl_cert_name: ifa.crt nginx_ssl_cert_key: ifa.key nginx_use_auth: true project_name: suspicious nginx_server_static: true gather_facts: true roles: - role: nginx_conf ##The second roles - name: Nginx WebServer's Config Dynamic Create hosts: 10.0.90.27 remote_user: root vars: nginx_use_proxy: false nginx_ssl_cert_name: ifa.crt nginx_ssl_cert_key: ifa.crt nginx_use_auth: false project_name: suspicious nginx_server_static: false gather_facts: false roles: - role: nginx_conf
5. Test and execute:
#ansible-playbook nginx_test.yml --syntax-check playbook: nginx_test.yml //Implementation: # ansible-playbook nginx_test.yml PLAY [Nginx Proxy Server's Config Dynamic Create] ****************************** TASK [setup] ******************************************************************* ok: [10.0.90.25] ok: [10.0.90.26] TASK [nginx_conf : include] **************************************************** included: /etc/ansible/roles/nginx_conf/tasks/file.yml for 10.0.90.25, 10.0.90.26 TASK [nginx_conf : nginx.j2 template transfer example] ************************* changed: [10.0.90.26] changed: [10.0.90.25] PLAY [Nginx WebServer's Config Dynamic Create] ********************************* TASK [nginx_conf : include] **************************************************** included: /etc/ansible/roles/nginx_conf/tasks/file.yml for 10.0.90.27 TASK [nginx_conf : nginx.j2 template transfer example] ************************* changed: [10.0.90.27] PLAY RECAP ********************************************************************* 10.0.90.25 : ok=3 changed=1 unreachable=0 failed=0 10.0.90.26 : ok=3 changed=1 unreachable=0 failed=0 10.0.90.27 : ok=2 changed=1 unreachable=0 failed=0
6. View the execution results of the detection
Go to the Nginx Proxy server to view the configuration file
#cat nginx.conf.template upstream suspicious #server 127.0.0.1:1234; server 10.0.90.26:1234; } upstream suspicious-api #server 127.0.0.1:4567; server 10.0.90.26:4567; } server { listen 80; servername www.testnginx.com; access_log off; error_log /etc/nginx/nginx_error.log; rewrite ^ https://$server_name$request_uri? permanent; } server { listen 443 ssl; server_name www.testnginx.com; ssl_certificate /etc/nginx/ssl/ifa.crt; ssl_certificate_key /etc/nginx/ssl/ifa.key; root /data/html/; index index.html index.html; auth_basic "Restricted"; auth_basic_user_file /etc/nginx/suspicious.htpasswd; location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Url-Scheme $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_redirect off; proxy_pass http://suspicious; break; } location /api { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Url-Scheme $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_redirect off; proxy_pass http://suspicious-api; break; } location / { try_files $url $url/ =404; } }
View the configuration file on the Nginx Web server
#cat nginx.conf.template server { listen 80; servername www.testnginx.com; access_log off; error_log /etc/nginx/nginx_error.log; rewrite ^ https://$server_name$request_uri? permanent; } server { listen 443 ssl; server_name www.testnginx.com; ssl_certificate /etc/nginx/ssl/ifa.crt; ssl_certificate_key /etc/nginx/ssl/ifa.crt; root /data/html/; index index.html index.html; }
It's over here. The same template can be used to complete the configuration of Nginx conf for different hosts through simple if and variable settings. Therefore, on the one hand, we need to understand the powerful template function of Ansible, and at the same time, we need to see the importance of template quality.
Reference link:
Http://mp.weixin.qqq.com/s?u biz=MzIyMDA1MzgyNw==&mid=2651968051&idx=1&sn=922b6cc8c8e6ff6e1c4b822e78ea31c3&scene=0_#wechat_redirect, a good public number of ansible Weixin, welcome to pay attention to common learning.