3、Ansible playbooks(Hosts、Users、tasks、handlers、變量、條件測試(when、迭代)、templates)


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) 表達式組。 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM