Ansible playbooks
playbook是由一個或多個“play”組成的列表。play的主要功能在於將事先歸並為一組的主機裝扮成事先通過ansible中的task定義好的角色。從根本上來講,所謂task無非是調用ansible的一個module。將多個play組織在一個playbook中,即可以讓它們聯同起來按事先編排的機制同唱一台大戲。下面是一個簡單示例。
- hosts: webnodes //webnodes定義一個主機組,表示應用的目標主機。下面定義的任務只對此組內的主機生效
vars: //這里是一個鍵值對,vars是鍵,它的值是一個字典
http_port: 80
max_clients: 256
remote_user:root //表示鏈接遠程主機以哪個主機的身份進行
tasks: //定義接下來要執行的任務
- name: ensure apache is at the latest version //第一個任務,
yum: name=httpd state=latest //基於yum模塊安裝httpd程序包
- name: ensure apache is running //第二個任務
service: name=httpd state=started //基於service模塊啟動httpd服務
handlers:
- name: restart apache
service: name=httpd state=restarted
1、playbook基礎組件
1.1 Hosts和Users
playbook中的每一個play的目的都是為了讓某個或某些主機以某個指定的用戶身份執行任務。hosts用於指定要執行指定任務的主機(這些主機一定是在Inventory定義的主機),其可以是一個或多個由冒號分隔主機組;remote_user則用於指定遠程主機上的執行任務的用戶。如上面示例中的
- hosts: webnodes
remote_user: root
不過,remote_user也可用於各task中。也可以通過指定其通過sudo的方式在遠程主機上執行任務,其可用於play全局或某任務;此外,甚至可以在sudo時使用sudo_user指定sudo時切換的用戶。
編寫playbooks定義了hosts和users之后,接下來就是定義任務列表。任務可以有多個,所以每一個都要使用“-”引導。
在playbooks中一個劇本應用於不同主機上操作有很多,所以每一個主機組都應該使用"-"來引導
- hosts: webnodes
remote_user: mageedu
tasks:
- name: test connection
ping:
remote_user: dongshi //此tasks中定義了在遠程主機主機上執行任務的用戶,這里的優先級最高,不再使用全局中定義的remote_user。
sudo: yes //表示以dongshi用戶的身份切入到遠程主機上,以dongshi這個用戶的身份sudo到root用戶在遠程主機來運行命令,這樣做的好處是在管控端保存的普通用戶身份、 //權限信息在遭到泄露時不知道導致太大的風險。
基本結構:
- host:websrvs
remote_user:
tasks: //play的主題部分
- task1 //在所有主機上完成第一個任務,才開始在所有主機上執行第二個任務
module_name:module_args
- task2
1.2 任務列表和action
play的主體部分是task list。task list中的各任務按次序逐個在hosts中指定的所有主機上執行,即在所有主機上完成第一個任務后再開始第二個。
在運行自下而下某playbook時,如果中途發生錯誤,所有已執行任務都可能將回滾(有些任務無法回滾),因此,在更正playbook后重新執行一次即可。
task的目的是使用指定的參數執行模塊,而在模塊參數中可以使用變量。模塊執行是冪等的,這意味着多次執行是安全的,因為其結果均一致。
每個task都應該有其name,用於playbook的執行結果輸出,建議其內容盡可能清晰地描述任務執行步驟。如果未提供name,則action的結果將用於輸出。
定義task的可以使用“action: module options”或“module: options”的格式,推薦使用后者以實現向后兼容。如果action一行的內容過多,也中使用在行首使用幾個空白字符進行換行。
tasks:
- name: make sure apache is running
service: name=httpd state=running
在眾多模塊中,只有command和shell模塊僅需要給定一個列表而無需使用“key=value”格式,例如:
tasks:
- name: disable selinux //變量后的":"與值用空格隔開
command: /sbin/setenforce 0
如果某個命令或腳本運行失敗,退出碼不為零的情況下,可能會阻止playnook繼續向后運行,為了避免此情況的出現,可以在某個命令運行結束以后,可以強行讓它輸出正確的信息。
可以使用如下方式替代:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true //此處命令執行成功了,就返回0,如果執行不成功就返回true,所以不會阻止后面的命令繼續執行
或者使用ignore_errors來忽略錯誤信息:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True //即使出錯無不管不問,繼續向后運行。
示例:在3台被管控主機上都創建系統組叫nginx,創建用戶也叫nginx
# vim nginx.yml //由哪個用戶的身份在哪些主機上運行什么樣的任務
- hosts: websrvs //定義主機組 remote_user: root //定義用戶的身份 tasks: //定義運行什么樣的任務 - name: create nginx group //第一個任務。創建nginx組 group: name=nginx system=yes gid=208 - name: create nginx user //第二個任務,創建nginx用戶 user: name=nginx uid=208 group=nginx system=yes - host: dbsrvs remote_user: root tasks: - name: copy file to dbsrvs copy: src=/etc/inittab dest=/tmp/inittab.ans
# ansible-playbook nginx.yml //執行playbook
PLAY [websrvs] ********************//首先在websrvs主機組上執行任務************************************************************************ TASK [Gathering Facts] ************//在websrvs組主機上執行任務前,每一個被管控主機首先要向管控端報告跟自身主機相關的各種變量,即facts*************** ok: [192.168.184.142] ok: [192.168.184.143] ok: [192.168.184.145] TASK [create nginx group] *********//創建nginx組**************************************************************************************** changed: [192.168.184.142] //顯示changed表示任務執行成功。表示目標主機不處於已定義(即tasks中的定義)的目標狀態,所以要對目標做修改。 changed: [192.168.184.143] //比如nginx組不存在,所以就在被管控主機上創建,就顯示changed。 changed: [192.168.184.145] TASK [create nginx user] **********//創建nginx用戶************************************************************************************** changed: [192.168.184.142] changed: [192.168.184.143] changed: [192.168.184.145] PLAY [dbsrvs] **********************//然后在dbsrvs主機組上執行任務************************************************************************ TASK [Gathering Facts] *************************************************************************************************************** ok: [192.168.184.142] ok: [192.168.184.145] TASK [copy file to dbsrvs] *********************************************************************************************************** changed: [192.168.184.142] changed: [192.168.184.145] PLAY RECAP **************************//在所有任務都執行完成后,會有一個報告****************************************************************** 192.168.184.142 : ok=5 changed=3 unreachable=0 failed=0 //比如1422主機上執行任務ok是的數量是5,其中包括changed和Gathering Facts,changed是3 192.168.184.143 : ok=3 changed=2 unreachable=0 failed=0 //unreached和failed都為0,表示沒有執行失敗的 192.168.184.145 : ok=5 changed=3 unreachable=0 failed=0
# ansible-playbook nginx.yml //在執行一邊playbook與上面對比
PLAY [websrvs] *********************************************************************************************************************** TASK [Gathering Facts] *************************************************************************************************************** ok: [192.168.184.142] ok: [192.168.184.143] ok: [192.168.184.145] TASK [create nginx group] ************************************************************************************************************ ok: [192.168.184.145] //這里就顯示ok,並不是創建nginx組ok,而是被管控主機所有的數據都存在,而且滿足tasks定義的需要,就報告為ok ok: [192.168.184.143] ok: [192.168.184.142] TASK [create nginx user] ************************************************************************************************************* ok: [192.168.184.145] ok: [192.168.184.143] ok: [192.168.184.142] PLAY [dbsrvs] ************************************************************************************************************************ TASK [Gathering Facts] *************************************************************************************************************** ok: [192.168.184.142] ok: [192.168.184.145] TASK [copy file to dbsrvs] *********************************************************************************************************** ok: [192.168.184.142] ok: [192.168.184.145] PLAY RECAP *************************************************************************************************************************** 192.168.184.142 : ok=5 changed=0 unreachable=0 failed=0 192.168.184.143 : ok=3 changed=0 unreachable=0 failed=0 192.168.184.145 : ok=5 changed=0 unreachable=0 failed=0
1.3 handlers 處理器
用於當關注的資源發生變化時采取一定的操作。
在一個服務的配置文件發生改變時,應該讓程序重讀配置文件或者重啟程序。
默認情況下,多次執行一個任務的時候,如果那個任務已經執行過了,為了保持冪等性,它是不會再次執行的,所以就不可能重啟。
handler就是為了解決這種問題的,它可以監控另外一個task,如果所監控的task做了某些修改,才執行指定的任務。
所以handler也是一個任務,這個任務不是上來就執行的,只有某個條件滿足時才執行。
“notify”這個action可用於在每個play的最后被觸發,這樣可以避免多次有改變發生時每次都執行指定的操作,取而代之,僅在所有的變化發生完成后一次性地執行指定操作。
在notify中列出的操作稱為handler,也即notify中調用handler中定義的操作。
- name: template configuration file //定義的任務,配置文件
template: src=template.j2 dest=/etc/foo.conf
notify: //如果定義的文件發生改變后就通知給另外一個任務
- restart memcached //任務的名字,哪個任務呢?就是下面在handlers中定義的name的名字
- restart apache
handler是task列表,這些task與前述的task並沒有本質上的不同。
handlers:
- name: restart memcached //即上面notify下面任務的名字
service: name=memcached state=restarted
- name: restart apache
service: name=apache state=restarted
上述的意思是某一個資源或配置文件發生改變后,必須要觸發另外的操作時,就是用notify指明觸發哪一個handler,事先把觸發的操作定義好,每一個操作就叫一個handler。
示例演示
# yum install httpd -y //確保管控主機安裝了httpd
# mkdir conf
# cp /etc/httpd/conf/httpd.conf conf/ //把httpd的配置文件httpd.conf復制到創建的目錄中
# vim conf/httpd.conf
Listen 8080 //讓httpd監聽在8080端口
# vim apache.yml
- hosts: websrvs remote_user: root tasks: - name: install httpd package yum: name=httpd state=latest - name: install configuration file for httpd copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf //把目標文件覆蓋掉 - name: start httpd service service: enabled=true name=httpd state=started
# ansible-playbook apahce.yml //都可以執行成功
# netstat -tunlp //在被管控主機上都可以查看到8080端口
那么問題來了,假如源配置文件src=/root/conf/httpd.conf 發生改變了,比如配置文件的監聽端口改變為80,其他都不改變,那么再執行# ansible-playbook apahce.yml 后,httpd服務要不要重新啟動呢?會不會根據配置文件httpd.conf的修改監聽80端口呢?
# vim conf/httpd.conf //修改配置文件,把端口修改為80
Listen 80 //讓httpd監聽在80端口
# ansible-playbook apache.yml //再次執行此劇本
PLAY [websrvs] *********************************************************************************************************************** TASK [Gathering Facts] *************************************************************************************************************** ok: [192.168.184.143] ok: [192.168.184.142] TASK [install httpd package] ********************************************************************************************************* ok: [192.168.184.143] ok: [192.168.184.142] TASK [install configuration file for httpd] ****************************************************************************************** changed: [192.168.184.143] //這里的changed是因為發現httpd.conf文件中監聽的端口從8080改為80,所以重新把配置文件從管控端復制到被管控端,所以發生了改變 changed: [192.168.184.142] TASK [start httpd service] *********************************************************************************************************** ok: [192.168.184.142] ok: [192.168.184.143] PLAY RECAP *************************************************************************************************************************** 192.168.184.142 : ok=4 changed=1 unreachable=0 failed=0 192.168.184.143 : ok=4 changed=1 unreachable=0 failed=0
再次查看被管控端的端口,可以看出監聽的端口依然是8080端口,沒有發生改變,即httpd並沒有在配置文件更改后自動重啟。
在一個服務的配置文件發生改變時,應該讓程序重讀配置文件或者重啟程序。
默認情況下,多次執行一個任務的時候,如果那個任務已經執行過了,為了保持冪等性,它是不會再次執行的,所以就不可能重啟。
handler就是為了解決這種問題的,它可以監控另外一個task,如果所監控的task做了某些修改,才執行指定的任務。
所以handler也是一個任務,這個任務不是上來就執行的,只有某個條件滿足時才執行。
# vim apache.yml //再次修改劇本,添加紅色部分
- hosts: websrvs remote_user: root tasks: - name: install httpd package yum: name=httpd state=latest - name: install configuration file for httpd copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf notify: //如果通知有多個,每一個要使用列表,這里雖然只有一個,但仍然使用列表進行描述。表示會觸發一個事件,觸發restart httpd這個處理器 - restart httpd - name: start httpd service service: name=httpd enabled=true state=started handlers: //和tasks是同級別的,handlers可能有多個,每一個handler都用一個"-"來引導。handler定義方式和task是一樣的,只不過handler不會直接上來就執行,只有在某個條件被觸發時,才會執行 - name: restart httpd //這里要和notify定義的保持一致 service: name=httpd state=resarted
# ansible-playbook apache.yml //再次運行此腳本,注意如果apache.yml中定義的源配置文件不發生改變,是不會觸發handler的
PLAY [websrvs] *********************************************************************************************************************** TASK [Gathering Facts] *************************************************************************************************************** ok: [192.168.184.143] ok: [192.168.184.142] TASK [install httpd package] ********************************************************************************************************* ok: [192.168.184.143] ok: [192.168.184.142] TASK [install configuration file for httpd] ****************************************************************************************** changed: [192.168.184.143] changed: [192.168.184.142] TASK [start httpd service] *********************************************************************************************************** ok: [192.168.184.143] ok: [192.168.184.142] RUNNING HANDLER [restart httpd] **********//這里handler已經執行************************************************************************* changed: [192.168.184.143] //重新啟動了被管控主機的httpd服務 changed: [192.168.184.142] PLAY RECAP *************************************************************************************************************************** 192.168.184.142 : ok=5 changed=2 unreachable=0 failed=0 192.168.184.143 : ok=5 changed=2 unreachable=0 failed=0
如何在playbook中使用變量
- hosts: webnodes
vars: //在定義任何一個playbook的時候,可以使用vars定義變量,定義完之后可以直接引用變量
http_port: 80 //比如我們傳遞給playbook時的某個配置文件中來調用此變量的值即可
max_clients: 256
remote_user: root
1、示例:基於前面的修改進行演示
# vim apache.yml
- hosts: websrvs remote_user: root vars: //使用變量的化,在此處使用vars定義變量,變量是多個,肯定是一個序列,要用"-"來引導, - package: httpd //pachage是變量名,httpd是變量的值,這里定義了一個報名 - service: httpd //這里定義服務名。變量名只能包含數字、字母和下划線,而且只能以字母開頭 tasks: - name: install httpd package yum: name={{ package }} state=latest //此處引用包名,即引用變量package的值httpd來替代 - name: install configuration file for httpd copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf notify: - restart httpd - name: start httpd service service: name={{ service }} enabled=true state=started //這里同上,要用花括號{{}},注意空格 handlers: - name: restart httpd service: name=httpd state=restarted
# ansible-playbook apache.yml //重新執行,毫無問題
PLAY [websrvs] *********************************************************************************************************************** TASK [Gathering Facts] *************************************************************************************************************** ok: [192.168.184.143] ok: [192.168.184.142] TASK [install httpd package] ********************************************************************************************************* ok: [192.168.184.143] ok: [192.168.184.142] TASK [install configuration file for httpd] ****************************************************************************************** ok: [192.168.184.143] ok: [192.168.184.142] TASK [start httpd service] *********************************************************************************************************** ok: [192.168.184.142] ok: [192.168.184.143] PLAY RECAP *************************************************************************************************************************** 192.168.184.142 : ok=4 changed=0 unreachable=0 failed=0 192.168.184.143 : ok=4 changed=0 unreachable=0 failed=0
注意:在playbook中使用的變量,不僅僅有上述定義的變量,也可以是ansible中所定義的所有變量。
2、根據上述進行演示其他變量形式的使用:
# vim test.yml
- hosts: websrvs remote_user: root tasks: - name: copy file copy: content="{{ ansible_all_ipv4_addresses }}" dest=/tmp/vars.ans //copy模塊在copy時指定內容有兩種方式,一種是src指明,另一種是使用content直接生成。
//此時content調用的是ansible中的變量。
其中nsible_all_ipv4_addresses可以根據以下方式獲得:
# ansible 192.168.184.141 -m setup | less
# ansible-playbook test.yml //已經完成
PLAY [websrvs] *********************************************************************************************************************** TASK [Gathering Facts] *************************************************************************************************************** ok: [192.168.184.143] ok: [192.168.184.142] TASK [copy file] ********************************************************************************************************************* changed: [192.168.184.143] changed: [192.168.184.142] PLAY RECAP *************************************************************************************************************************** 192.168.184.142 : ok=2 changed=1 unreachable=0 failed=0 192.168.184.143 : ok=2 changed=1 unreachable=0 failed=0
# cat /tmp/vars.ans //在被管控端的主機查看生成的內容
["192.168.184.142"]
所以有些變量不用定義就可以調用,這些變量就像ansible facts就可以實現
3、另外,在/etc/ansible/hosts的inventory中定義的主機變量也是可以直接引用的;示例如下
# vim /etc/ansible/hosts
[websrvs]
192.168.184.142 testvar=182.142
192.168.184.143 testvar=182.143
# vim test.yml
- hosts: websrvs
remote_user: root
tasks:
- name: copy file
copy: content="{{ ansible_all_ipv4_addresses }} {{ testvar }}" dest=/tmp/vars.ans
# ansible-playbook test.yml //執行成功
PLAY [websrvs] *********************************************************************************************************************** TASK [Gathering Facts] *************************************************************************************************************** ok: [192.168.184.142] ok: [192.168.184.143] TASK [copy file] ********************************************************************************************************************* changed: [192.168.184.142] changed: [192.168.184.143] PLAY RECAP *************************************************************************************************************************** 192.168.184.142 : ok=2 changed=1 unreachable=0 failed=0 192.168.184.143 : ok=2 changed=1 unreachable=0 failed=0
# cat /tmp/vars.ans //在被管控主機上查看內容
[u'192.168.184.142'] 182.142
4、ansible基於ssh連接inventory中指定的遠程主機時,可以通過參數指定其交互方式,示例如下:
# vim /etc/ansible/hosts
[websrvs]
192.168.184.142 ansible_ssh_user=root ansible_ssh_pass=123456
192.168.184.143 ansible_ssh_user=root ansible_ssh_pass=dongshi
如何在playbook中使用條件測試
條件測試
如果需要根據變量、facts或此前任務的執行結果來做為某task執行與否的前提時要用到條件測試。
1.1 when語句
在task后添加when子句即可使用條件測試;when語句支持Jinja2表達式語法。例如:
tasks:
- name: "shutdown Debian flavored systems"
command: /sbin/shutdown -h now
when: ansible_os_family == "Debian" //當ansible報告的os_family是Debian,那么就執行上面兩行的任務即立刻關機
示例演示:假如被管控主機的ansible_fqdn為node2,那么就添加一個用戶
# ansible 192.168.184.142 -m setup | less
或
# ansible 192.168.184.142 -m setup | grep fqdn
"ansible_fqdn": "node2",
# vim cond.yml //定義yml文件
- hosts: all remote_user: root vars: //定義變量 - username: user1 tasks: - name: create {{ username }} user //這里引用變量 user: name={{ username }} when: ansible_fqdn == "node2"
# ansible-playbook cond.yml
PLAY [all] *************************************************************************************************************************** TASK [Gathering Facts] *************************************************************************************************************** ok: [192.168.184.143] ok: [192.168.184.142] ok: [192.168.184.141] ok: [192.168.184.145] TASK [create user1 user] ************************************************************************************************************* skipping: [192.168.184.141] skipping: [192.168.184.145] skipping: [192.168.184.143] //凡是跳過的都不符合條件 changed: [192.168.184.142] //只有142符合條件,所以改變 PLAY RECAP *************************************************************************************************************************** 192.168.184.141 : ok=1 changed=0 unreachable=0 failed=0 192.168.184.142 : ok=2 changed=1 unreachable=0 failed=0 192.168.184.143 : ok=1 changed=0 unreachable=0 failed=0 192.168.184.145 : ok=1 changed=0 unreachable=0 failed=0
when語句中還可以使用Jinja2的大多"filter",例如要忽略此前某語句的錯誤並基於其結果(failed或者sucess)運行后面指定的語句,可使用類似如下形式:
tasks:
- command: /bin/false
register: result
ignore_errors: True
- command: /bin/something
when: result|failed
- command: /bin/something_else
when: result|success
- command: /bin/still/something_else
when: result|skipped
此外,when語句中還可以使用facts或playbook中定義的變量。
1.4 迭代
重復同類tasks時使用,當有需要重復性執行的任務時,可以使用迭代機制。其使用格式為將需要迭代的內容定義為item變量引用,並通過with_items語句來指明迭代的元素列表即可。例如:
- name: add several users
user: name={{ item }} state=present groups=wheel //item是固定變量名,表示會循環的使用with_items定義的列表中的每一個元素
with_items:
- testuser1
- testuser2
上面語句的功能等同於下面的語句:
- name: add user testuser1
user: name=testuser1 state=present groups=wheel
- name: add user testuser2
user: name=testuser2 state=present groups=wheel
事實上,with_items中可以使用元素還可為hashes,例如:
- name: add several users
user: name={{ item.name }} state=present groups={{ item.groups }} //這里的item等於下文的{ name: 'testuser1', groups: 'wheel' }
with_items:
- { name: 'testuser1', groups: 'wheel' } //item.name是引用此元素中的鍵name的值testuser1
- { name: 'testuser2', groups: 'root' } //item.groups調用的是此元素中鍵groups的值root
ansible的循環機制還有更多的高級功能,具體請參見官方文檔(http://docs.ansible.com/playbooks_loops.html)。
Templates詳解
playbooks包括:
tasks
variables
templates:模板
handlers
roles
如果兩個節點默認監聽的端口不同,比如為websrvs組中被管控的主機安裝httpd服務,在它們的配置文件中,192.168.184.142監聽的是80端口,而143監聽的是8080端口。另外142的配置文件中max_client=100,而143的配置文件中max_client=200,有兩處不相同,因此就無法為存在多處不同的配置文件提供一次性ansible配置。這就需要配置兩個ansible任務文件,但是這樣管理起來很不讓便。於師在這種情況下,可以嘗試引用變量的方式來定義。
示例如下:
# mkdir templates //先在根目錄下創建一個存放模板的目錄
# cp conf/httpd.conf templates/httpd.conf.j2 //把之前配置的httpd服務的復制到templates目錄下,並以.j2結尾,表示jinja2的模板
# vim templates/httpd.conf.j2 //這個模板在復制到每一個節點時,都應該把定義在模板中的變量替換成對應的值。這種情況下,像調用的變量以及使用的jinjia2 //的模板語言的語法,就稱為模板。模板語言用的是jinjia2,支持條件判斷、循環等格式,這里是把某個經常發生的變化的參數改成某個變量的值。
Listen {{ http_port }} //把80改為變量http_port,變量會在/etc/ansible/hosts中定義,當調用httpd.conf.j2這個模板時,就會取得http_port的值
ServerName {{ ansible_fqdn }} //定義主機名變量,每一個被管控主機在被管理事都會向管控主機報告自己的ansible facts,可以直接被調用,不需要另外定義
# vim /etc/ansible/hosts //在此處定義模板httpd.conf.j2中的變量的值。此變量也可以在playbooks中定義,但是無法區別變量名相同而值不同。
[websrvs]
192.168.184.142 http_port=80
192.168.184.143 http_port=8080
# vim apache.yml
- hosts: websrvs remote_user: root vars: - package: httpd - service: httpd tasks: - name: install httpd package yum: name={{ package }} state=latest - name: install configuration file for httpd template: src=/root/templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf //此處是模板 notify: - restart httpd - name: start httpd service service: name={{ service }} enabled=true state=started handlers: - name: restart httpd service: name=httpd state=restarted
# ansible-playbook apache.yml
PLAY [websrvs] *********************************************************************************************************************** TASK [Gathering Facts] *************************************************************************************************************** ok: [192.168.184.143] ok: [192.168.184.142] TASK [install httpd package] ********************************************************************************************************* ok: [192.168.184.143] ok: [192.168.184.142] TASK [install configuration file for httpd] ****************************************************************************************** changed: [192.168.184.142] //這里被管控端的主機替換成了管控端的模板,並且把模板中的變量替換為定義的值 changed: [192.168.184.143] TASK [start httpd service] *********************************************************************************************************** ok: [192.168.184.142] ok: [192.168.184.143] RUNNING HANDLER [restart httpd] ****************************************************************************************************** changed: [192.168.184.142] //重啟成功 changed: [192.168.184.143] PLAY RECAP *************************************************************************************************************************** 192.168.184.142 : ok=5 changed=2 unreachable=0 failed=0 192.168.184.143 : ok=5 changed=2 unreachable=0 failed=0
查看被管控主機的httpd配置文件,與配置模板要求的是一樣的。
在一個模板文件中直接使用變量引用,它在復制到目標文件上之前會收集每一個變量,並把這個變量的值替換到模板文件中,而后把模板作為文件復制到目標主機上,所以就可以以一個文件為不同的主機提供不同的配置。
Jinja2相關
1 字面量
表達式最簡單的形式就是字面量。字面量表示諸如字符串和數值的Python對象。下面的字面量是可用的:
"Hello World":
雙引號或單引號中間的一切都是字符串。無論何時你需要在模板中使用一個字符串(比如函數調用、過濾器或只是包含或繼承一個模板的參數),它們都是有用的。
42 / 42.23:
直接寫下數值就可以創建整數和浮點數。如果有小數點,則為浮點數,否則為整數。記住在Python里,42和42.0是不一樣的。
['list', 'of', 'objects']:
一對中括號括起來的東西是一個列表。列表用於存儲和迭代序列化的數據。例如 你可以容易的在for循環中用列表和元組創建一個鏈接的列表:
<ul>
{% for href, caption in [('index.html', 'Index'), ('about.html', 'About'),
('downloads.html', 'Downloads')] %}
<li><a href="{{ href }}">{{ caption }}</a></li>
{% endfor %}
</ul>
('tuple', 'of', 'values'):
元組與列表類似,只是你不能修改元組。如果元組中只有一個項,你需要以逗號 結尾它。元組通常用於表示兩個或更多元素的項。更多細節見上面的例子。
{'dict': 'of', 'key': 'and', 'value': 'pairs'}:
Python 中的字典是一種關聯鍵和值的結構。鍵必須是唯一的,並且鍵必須只有一個 值。字典在模板中很少使用,罕用於諸如 xmlattr() 過濾器之類。
true / false:
true 永遠是 true ,而 false 始終是 false 。
2 算術運算
Jinja 允許你用計算值。這在模板中很少用到,但是為了完整性允許其存在。支持下面的 運算符:
+ 把兩個對象加到一起。通常對象是素質,但是如果兩者是字符串或列表,你可以用這 種方式來銜接它們。無論如何這不是首選的連接字符串的方式!連接字符串見 ~ 運算符。 {{ 1 + 1 }} 等於 2 。
- 用第一個數減去第二個數。 {{ 3 - 2 }} 等於 1 。
/ 對兩個數做除法。返回值會是一個浮點數。 {{ 1 / 2 }} 等於 {{ 0.5 }} 。
// 對兩個數做除法,返回整數商。 {{ 20 // 7 }} 等於 2 。
% 計算整數除法的余數。 {{ 11 % 7 }} 等於 4 。
* 用右邊的數乘左邊的操作數。 {{ 2 * 2 }} 會返回 4 。也可以用於重 復一個字符串多次。 {{ ‘=’ * 80 }} 會打印 80 個等號的橫條。
** 取左操作數的右操作數次冪。 {{ 2**3 }} 會返回 8 。
3 比較操作符
== 比較兩個對象是否相等。
!= 比較兩個對象是否不等。
> 如果左邊大於右邊,返回 true 。
>= 如果左邊大於等於右邊,返回 true 。
< 如果左邊小於右邊,返回 true 。
<= 如果左邊小於等於右邊,返回 true 。
4 邏輯運算符
對於 if 語句,在 for 過濾或 if 表達式中,它可以用於聯合多個表達式:
and 如果左操作數和右操作數同為真,返回 true 。
or 如果左操作數和右操作數有一個為真,返回 true 。
not 對一個表達式取反(見下)。
(expr) 表達式組。