一、jinja2簡介解
Jinja2是Python下一個被廣泛應用的模版引擎,他的設計思想來源於Djanjo的模板引擎,並擴展了其語法和一系列強大的功能。ansible的模板配置文件就是用jinja2這種模板編程語言寫的,其中jinja2使用字面量有如下形式
1)字符串:使用單引號或雙引號引起來的部分
2)數字:支持整數,浮點數(小數)
3)列表:和python里的列表一樣,用中括號括起來,每個元素之間用逗號隔開,如[item1,item2,....]
4)元組:和python里的元組一樣,小括號括起來,每個元素之間用逗號隔開,如(item1,item2,....)
5)字典:同python里的字典一樣,大括號括起來,每個k/v(鍵值對)用逗號隔開,鍵和值用":"冒號隔開,如{key1:value1,key2:value2,....}
6)布爾型:同其他語言布爾型一樣,ture/false
7)支持算數運算:+,-,*,/,//(整除,地板除),%(取模,取余數),**(冪運算)
8)支持比較操作:==(比較兩個值是否相等),!=(不等),>,>=(大於等於),<,<=(小於等於)
9)支持邏輯運算:and(與),or(或),not(非)
10)支持for(循環) ,if(判斷),when(當某一條件滿足才開始執行when所在的代碼塊,作用類似if)
除此以外,jinja2還支持“test”測試語句,比如我們要判斷某個變量是否定義,可以使用defined來判斷,如 vars is defined ,如果vars定義則表達式返回true,相反返回false。類似的還有undefined(與defined相反),equalto(與“==”作用等效),even(判斷對象是否是偶數),iterable(判斷對象是否可迭代)
二、jinja2語法
jinja2有如下語法:
1)控制結構,它和我們寫別的語言的控制結構類似,唯一不同的是它的for循環要用”{%%}“給括起來,且必須寫在兩個百分號之間,后面結束有一個{%endfor$}來表示for循環的結束,同樣if語句也是,必須寫在"{%%}" 兩個百分號之間,后面結束也有個{%endif%}來表示if語句的結束,當然if語句支持elif ,else 這個同python里的if用法一樣。
2)變量引用,jinja2的變量引用同ansible的變量應用類似,都是用"{{}}" 雙大括號來表示中間括起來的內容表示變量
3)注釋用"{#"開始,中間部分表示注釋,以"#}"結束表示注釋結束,支持多行注釋和當行注釋
示例:
1)for循環使用
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
}
{% endfor %}
說明:以上模板表示,從nginx_vhosts列表里去循環,nginx_vhosts里有幾個元素,它將循環幾次,每次循環取的值用vhost變量代替,它的用法類型shell里的for循環和python里的for循環
2)if單分支選擇使用
{% if vhost.server_name is defined %}
server_name {{ vhost.server_name }}
{% endif %}
3)if多分支選擇使用
{%if vhost.port is undefined %}
http_port=80
{%elif vhost.port == 81%}
http_port=81
{%else%}
http_port = 83
{%endif%}
4)單行注釋
{#% for i in list %#}
5)多行注釋
{#
{% for i in list %}
i+=i
{% endfor %}
#}
三、playbook中使用模板
templates是ansible的一個模塊,其功能是根據模板文件動態生成配置文件,templates文件必須存放於templates目錄下,且命名為".j2"結尾,yaml/yml文件需要和templates目錄平級,這樣我們在yml文件中調用模板的時候,就不需要寫模板文件的路徑,否則需要描述模板文件的路徑,因為template模塊會自動去找templates目錄下的模板文件。目錄結構如下
. ├── temnginx.yml └── templates └── nginx.conf.j2
示例:playbook中template變量替換
利用tamplates同步nginx配置文件,其中修改nginx.conf.j2(worker_processes {{ ansible_processor_vcpus }};)指定其worker進程的個數由遠程主機的cpu個數決定
[root@test ~]#ll
總用量 4
-rw-r--r-- 1 root root 212 11月 18 14:08 temnginx.yml
drwxr-xr-x 2 root root 27 11月 18 14:05 templates
[root@test ~]#tree
.
├── temnginx.yml
└── templates
└── nginx.conf.j2
1 directory, 2 files
[root@test ~]#head templates/nginx.conf.j2
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes {{ ansible_processor_vcpus }};
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/nginx/README.dynamic.
[root@test ~]#cat temnginx.yml
---
- hosts: websers
remote_user: root
tasks:
- name: install nginx
yum: name=nginx
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
[root@test ~]#
說明:以上playbook里是使用template模板去動態生成的配置文件,不是拷貝,拷貝是將文件原封不動的拷貝過去,還需要注意的是template模塊不能在ad-hoc命令行里使用,只能在playbook里使用,且模板文件必須是".j2"結尾的
示例:playbook中template算數運算
還是以上的示例,我們可以這樣寫
vim nginx.conf.j2
worker_processes {{ ansible_processor_vcpus**2 }};
說明:我們可以用ansible內置變量做算術運算后的值作為模板文件的值,在playbook中還是用template模塊去調用就好了
示例:模板文件中 for循環的用法
[root@test ~]#tree
.
├── temnginx.yml
└── templates
└── nginx.conf.j2
1 directory, 2 files
[root@test ~]#cat templates/nginx.conf.j2
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
}
{% endfor %}
[root@test ~]#cat temnginx.yml
---
- hosts: websers
remote_user: root
vars:
nginx_vhosts:
- listen: 8080
tasks:
- name: install nginx
yum: name=nginx
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
[root@test ~]#
生成結果:
[root@test ~]#ansible-playbook temnginx.yml
PLAY [websers] ******************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************
ok: [192.168.0.128]
ok: [192.168.0.218]
TASK [install nginx] ************************************************************************************************
changed: [192.168.0.128]
changed: [192.168.0.218]
TASK [template config to remote hosts] ******************************************************************************
changed: [192.168.0.128]
changed: [192.168.0.218]
PLAY RECAP **********************************************************************************************************
192.168.0.128 : ok=3 changed=2 unreachable=0 failed=0
192.168.0.218 : ok=3 changed=2 unreachable=0 failed=0
[root@test ~]#ansible websers -m shell -a 'cat /etc/nginx/nginx.conf'
192.168.0.128 | SUCCESS | rc=0 >>
server {
listen 8080
}
192.168.0.218 | SUCCESS | rc=0 >>
server {
listen 8080
}
[root@test ~]#
示例:模板文件中if的用法
[root@test ~]#tree
.
├── temnginx.yml
└── templates
└── nginx.conf.j2
1 directory, 2 files
[root@test ~]#cat temnginx.yml
---
- hosts: websers
remote_user: root
vars:
nginx_vhosts:
- web1:
listen: 8080
server_name: "web1.test.com"
root: "/var/www/nginx/web1/"
- web2:
listen: 8080
root: "/var/www/nginx/web2/"
- web3:
listen: 8080
server_name: "web2.test.com"
root: "var/www/nginx/web3/"
tasks:
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
[root@test ~]#cat templates/nginx.conf.j2
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
{% if vhost.server_name is defined %}
server_name {{ vhost.server_name }}
{% endif %}
root {{ vhost.root }}
}
{% endfor %}
[root@test ~]#
生成結果:
[root@test ~]#ansible-playbook temnginx.yml
PLAY [websers] ******************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************
ok: [192.168.0.128]
ok: [192.168.0.218]
TASK [template config to remote hosts] ******************************************************************************
changed: [192.168.0.128]
changed: [192.168.0.218]
PLAY RECAP **********************************************************************************************************
192.168.0.128 : ok=2 changed=1 unreachable=0 failed=0
192.168.0.218 : ok=2 changed=1 unreachable=0 failed=0
[root@test ~]#ansible websers -m shell -a 'cat /etc/nginx/nginx.conf'
192.168.0.128 | SUCCESS | rc=0 >>
server {
listen 8080
server_name web1.test.com
root /var/www/nginx/web1/
}
server {
listen 8080
root /var/www/nginx/web2/
}
server {
listen 8080
server_name web2.test.com
root var/www/nginx/web3/
}
192.168.0.218 | SUCCESS | rc=0 >>
server {
listen 8080
server_name web1.test.com
root /var/www/nginx/web1/
}
server {
listen 8080
root /var/www/nginx/web2/
}
server {
listen 8080
server_name web2.test.com
root var/www/nginx/web3/
}
[root@test ~]#
說明:可以看到第二個server里是沒有server_name,因為定義的變量列表里web2沒有定義server_name
四、playbook中使用when條件測試
條件測試:如果需要根據變量、facts或此前任務的執行結果來作為某task執行與否的前提時需要用到條件測試,通過when語句實現,在task中使用jinja2的語法格式,when語句支持jinja2表達式語法;
示例:
[root@test ~]#cat test.yml
---
- hosts: all
remote_user: root
tasks:
- name: set hostname centos6
hostname: name=ansible_centos6
when: ansible_distribution_major_version == "6"
- name: set hostname centos7
hostname: name=ansible_centos7
when: ansible_distribution_major_version == "7"
[root@test ~]#ansible all -m shell -a 'hostname'
192.168.0.128 | SUCCESS | rc=0 >>
localhost
192.168.0.218 | SUCCESS | rc=0 >>
localhost.localdomain
192.168.0.217 | SUCCESS | rc=0 >>
centos7
[root@test ~]#ansible-playbook test.yml
PLAY [all] **********************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************
ok: [192.168.0.128]
ok: [192.168.0.218]
ok: [192.168.0.217]
TASK [set hostname centos6] *****************************************************************************************
skipping: [192.168.0.217]
changed: [192.168.0.218]
changed: [192.168.0.128]
TASK [set hostname centos7] *****************************************************************************************
skipping: [192.168.0.128]
skipping: [192.168.0.218]
changed: [192.168.0.217]
PLAY RECAP **********************************************************************************************************
192.168.0.128 : ok=2 changed=1 unreachable=0 failed=0
192.168.0.217 : ok=2 changed=1 unreachable=0 failed=0
192.168.0.218 : ok=2 changed=1 unreachable=0 failed=0
[root@test ~]#ansible all -m shell -a 'hostname'
192.168.0.128 | SUCCESS | rc=0 >>
ansible_centos6
192.168.0.218 | SUCCESS | rc=0 >>
ansible_centos6
192.168.0.217 | SUCCESS | rc=0 >>
ansible_centos7
[root@test ~]#
說明:以上playbook利用when語句判斷系統版本號,實現了通過不同的系統版本號,設置不同的主機名。
五、playbook迭代with_items
迭代:當有需要重復性執行的任務時,可使用迭代機制;對迭代項的引用,ansible有固定不變的變量,名為“item”;要在task中使用with_items給定要迭代的元素列表,列表格式可以為字符串、字典。
示例:批量創建用戶
[root@test ~]#cat adduser.yml
---
- hosts: websers
remote_user: root
tasks:
- name: add users
user: name={{ item }} state=present home=/home/{{ item }} groups=root,bin,wheel
with_items:
- user1
- user2
- user3
[root@test ~]#ansible-playbook adduser.yml
PLAY [websers] ******************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************
ok: [192.168.0.128]
ok: [192.168.0.218]
TASK [add users] ****************************************************************************************************
changed: [192.168.0.128] => (item=user1)
changed: [192.168.0.218] => (item=user1)
changed: [192.168.0.128] => (item=user2)
changed: [192.168.0.218] => (item=user2)
changed: [192.168.0.128] => (item=user3)
changed: [192.168.0.218] => (item=user3)
PLAY RECAP **********************************************************************************************************
192.168.0.128 : ok=2 changed=1 unreachable=0 failed=0
192.168.0.218 : ok=2 changed=1 unreachable=0 failed=0
[root@test ~]#ansible websers -m shell -a 'tail -3 /etc/passwd'
192.168.0.128 | SUCCESS | rc=0 >>
user1:x:503:503::/home/user1:/bin/bash
user2:x:504:504::/home/user2:/bin/bash
user3:x:505:505::/home/user3:/bin/bash
192.168.0.218 | SUCCESS | rc=0 >>
user1:x:1213:1213::/home/user1:/bin/bash
user2:x:1214:1214::/home/user2:/bin/bash
user3:x:1215:1215::/home/user3:/bin/bash
[root@test ~]#ansible websers -m shell -a 'id user1'
192.168.0.218 | SUCCESS | rc=0 >>
uid=1213(user1) gid=1213(user1) 組=1213(user1),0(root),1(bin),10(wheel)
192.168.0.128 | SUCCESS | rc=0 >>
uid=503(user1) gid=503(user1) 組=503(user1),0(root),1(bin),10(wheel)
[root@test ~]#
示例:迭代嵌套子變量
[root@test ~]#cat adduser2.yml
---
- hosts: websers
remote_user: root
tasks:
- name: create groups
group: name={{ item }}
with_items:
- group1
- group2
- group3
- name: create users
user: name={{ item.name }} group={{ item.group }} state=present
with_items:
- {name: 'test1',group: 'group1'}
- {name: 'test2',group: 'group2'}
- {name: 'test3',group: 'group3'}
[root@test ~]#ansible-playbook adduser2.yml
PLAY [websers] ******************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************
ok: [192.168.0.128]
ok: [192.168.0.218]
TASK [create groups] ************************************************************************************************
changed: [192.168.0.128] => (item=group1)
changed: [192.168.0.218] => (item=group1)
changed: [192.168.0.128] => (item=group2)
changed: [192.168.0.218] => (item=group2)
changed: [192.168.0.128] => (item=group3)
changed: [192.168.0.218] => (item=group3)
TASK [create users] *************************************************************************************************
changed: [192.168.0.128] => (item={u'group': u'group1', u'name': u'test1'})
changed: [192.168.0.218] => (item={u'group': u'group1', u'name': u'test1'})
changed: [192.168.0.128] => (item={u'group': u'group2', u'name': u'test2'})
changed: [192.168.0.218] => (item={u'group': u'group2', u'name': u'test2'})
changed: [192.168.0.128] => (item={u'group': u'group3', u'name': u'test3'})
changed: [192.168.0.218] => (item={u'group': u'group3', u'name': u'test3'})
PLAY RECAP **********************************************************************************************************
192.168.0.128 : ok=3 changed=2 unreachable=0 failed=0
192.168.0.218 : ok=3 changed=2 unreachable=0 failed=0
[root@test ~]#ansible websers -m shell -a 'tail -3 /etc/passwd'
192.168.0.128 | SUCCESS | rc=0 >>
test1:x:506:506::/home/test1:/bin/bash
test2:x:507:507::/home/test2:/bin/bash
test3:x:508:508::/home/test3:/bin/bash
192.168.0.218 | SUCCESS | rc=0 >>
test1:x:1216:1216::/home/test1:/bin/bash
test2:x:1217:1217::/home/test2:/bin/bash
test3:x:1218:1218::/home/test3:/bin/bash
[root@test ~]#ansible websers -m shell -a 'id test1'
192.168.0.218 | SUCCESS | rc=0 >>
uid=1216(test1) gid=1216(group1) 組=1216(group1)
192.168.0.128 | SUCCESS | rc=0 >>
uid=506(test1) gid=506(group1) 組=506(group1)
[root@test ~]#ansible websers -m shell -a 'id test2'
192.168.0.128 | SUCCESS | rc=0 >>
uid=507(test2) gid=507(group2) 組=507(group2)
192.168.0.218 | SUCCESS | rc=0 >>
uid=1217(test2) gid=1217(group2) 組=1217(group2)
[root@test ~]#ansible websers -m shell -a 'id test3'
192.168.0.128 | SUCCESS | rc=0 >>
uid=508(test3) gid=508(group3) 組=508(group3)
192.168.0.218 | SUCCESS | rc=0 >>
uid=1218(test3) gid=1218(group3) 組=1218(group3)
[root@test ~]#
說明:以上playbook實現了對應用戶創建時加入對應的組里
