目錄python
在有的時候play的結果依賴於變量、fact或者是前一個任務的執行結果,或者有的時候,咱們會基於上一個task執行返回的結果而決定如何執行後續的task。這個時候就須要用到條件判斷。linux
條件語句在Ansible中的使用場景:shell
在ansible中,使用條件判斷的關鍵字就是when。apache
如在安裝包的時候,須要指定主機的操做系統類型,或者是當操做系統的硬盤滿了以後,須要清空文件等,可使用when語句來作判斷 。when關鍵字後面跟着的是python的表達式,在表達式中你可以使用任何的變量或者fact,當表達式的結果返回的是false,便會跳過本次的任務ubuntu
下面是一個基本的用法示例:vim
--- - name: Install vim hosts: all tasks: - name:Install VIM via yum yum: name: vim-enhanced state: installed when: ansible_os_family =="RedHat" - name:Install VIM via apt apt: name: vim state: installed when: ansible_os_family =="Debian" - name: Unexpected OS family debug: msg="OS Family {{ ansible_os_family }} is not supported" fail=yes when: not ansible_os_family =="RedHat" or ansible_os_family =="Debian"
在上面的示例當中,咱們使用了"=="的比較運算符,在ansible中,還支持以下比較運算符:ide
==
:比較兩個對象是否相等,相等則返回真。可用於比較字符串和數字!=
:比較兩個對象是否不等,不等則爲真。>
:比較兩個對象的大小,左邊的值大於右邊的值,則爲真<
:比較兩個對象的大小,左邊的值小於右邊的值,則爲真>=
:比較兩個對象的大小,左邊的值大於等於右邊的值,則爲真<=
:比較兩個對象的大小,左邊的值小於等於右邊的值,則爲真下面是一些簡單的示例:oop
when: ansible_machine == "x86_64" when: max_memory <= 512
在Ansible中,除了比較運算符,還支持邏輯運算符:post
示例:性能
# 邏輯或 when: ansible_distribution == "RedHat" or ansible_distribution == "Fedora" # 邏輯與 when: ansible_distribution_version == "7.5" and ansible_kernel == "3.10.0-327.el7.x86_64" when: - ansible_distribution_version == "7.5" - ansible_kernel == "3.10.0-327.el7.x86_64" # 組合 when: => ( ansible_distribution == "RedHat" and ansible_distribution_major_version == "7" ) or ( ansible_distribution == "Fedora" and ansible_distribution_major_version == "28")
一個完整的例子:
# 判斷register註冊變量的返回結果 - name: restart httpd if postfix is running hosts: test tasks: - name: get postfix server status command: /usr/bin/systemctl is-active postfix ignore_errors: yes register: result - name: restart apache httpd based on postfix status service: name: httpd state: restarted when: result.rc == 0
在shell當中,咱們可以使用test命令來進行一些經常使用的判斷操做,以下:
# 判斷/test文件是否存在 test -e /test # 判斷/testdir是否存在且爲一個目錄 test -d /testdir
事實上,在ansible中也有相似的用法,只不過ansible沒有使用linux的test命令,而是jinja2模板的tests。
下面是一個簡單示例:
# 經過條件語句判斷testpath的路徑是否存在 - hosts: test vars: testpath: /testdir tasks: - debug: msg: "file exist" when: testpath is exists
上面的示例中,咱們使用了is exists
用於路徑存在時返回真,也可使用is not exists
用於路徑不存在時返回真。也能夠在整個條件表達式的前面使用not以取反:
- hosts: test vars: testpath: /testdir1 tasks: - debug: msg: "file not exist" when: not testpath is exists
在ansible中,除了可以使用exists這種tests以外,還有一些別的tests。接下來咱們詳細說一說。
示例:
- hosts: test gather_facts: no vars: testvar: "test" testvar1: tasks: - debug: msg: "testvar is defined" when: testvar is defined - debug: msg: "testvar2 is undefined" when: testvar2 is undefined - debug: msg: "testvar1 is none" when: testvar1 is none
示例:
- hosts: test gather_facts: no vars: doshell: true tasks: - shell: 'cat /testdir/aaa' when: doshell register: result ignore_errors: true - debug: msg: "success" when: result is success - debug: msg: "failed" when: result is failure - debug: msg: "changed" when: result is change - debug: msg: "skip" when: result is skip
特別注意:關於路徑的全部判斷均是判斷主控端上的路徑,而非被控端上的路徑
示例:
- hosts: test gather_facts: no vars: testpath1: "/testdir/test" testpath2: "/testdir" tasks: - debug: msg: "file" when: testpath1 is file - debug: msg: "directory" when: testpath2 is directory
- hosts: test gather_facts: no vars: str1: "abc" str2: "ABC" tasks: - debug: msg: "str1 is all lowercase" when: str1 is lower - debug: msg: "str2 is all uppercase" when: str2 is upper
示例:
- hosts: test gather_facts: no vars: num1: 6 num2: 8 num3: 15 tasks: - debug: msg: "num1 is an even number" when: num1 is even - debug: msg: "num2 is an odd number" when: num2 is odd - debug: msg: "num3 can be divided exactly by" when: num3 is divisibleby(3)
version
可用於對比兩個版本號的大小,或者與指定的版本號進行對比,使用語法爲version("版本號","比較操做符")
- hosts: test vars: ver1: 1.2 ver2: 1.3 tasks: - debug: msg: "ver1 is greater than ver2" when: ver1 is version(ver2,">") - debug: msg: "system version {{ ansible_distribution_version }} greater than 7.3" when: ansible_distribution_version is version("7.3","gt")
superset
判斷一個list是否是另外一個list的父集"
- hosts: test gather_facts: no vars: a: - 2 - 5 b: [1,2,3,4,5] tasks: - debug: msg: "A is a subset of B" when: a is subset(b) - debug: msg: "B is the parent set of A" when: b is superset(a)
in
判斷一個字符串是否存在於另外一個字符串中,也可用於判斷某個特定的值是否存在於列表中
- hosts: test vars: supported_distros: - RedHat - CentOS tasks: - debug: msg: "{{ ansible_distribution }} in supported_distros" when: ansible_distribution in supported_distros
number
判斷對象是否爲一個數字,是則爲真
- hosts: test gather_facts: no vars: var1: 1 var2: "1" var3: a tasks: - debug: msg: "var1 is a number" when: var1 is number - debug: msg: "var2 is a string" when: var2 is string - debug: msg: "var3 is a string" when: var3 is string
咱們在前面使用when作條件判斷時,若是條件成立則執行對應的任務。但這就面臨一個問題,當咱們要使用同一個條件判斷執行多個任務的時候,就意味着咱們要在某一個任務下面都寫一下when語句,並且判斷條件徹底同樣。這種方式不只麻煩並且顯得low。Ansible提供了一種更好的方式來解決這個問題,即block。
在ansible中,使用block將多個任務進行組合,看成一個總體。咱們能夠對這一個總體作條件判斷,當條件成立時,則執行塊中的全部任務:
- hosts: test tasks: - debug: msg: "task1 not in block" - block: - debug: msg: "task2 in block1" - debug: msg: "task3 in block1" when: 2 > 1
下面是一個稍微有用點兒的例子:
- hosts: test tasks: - name: set /etc/resolv.conf template: src: resolv.conf.j2 dest: /etc/resolv.conf owner: root group: root mode: 0644 - block: - name: ensure /etc/resolvconf/resolv.conf.d/base file for ubuntu 16.04 template: src: resolv.conf.j2 dest: /etc/resolvconf/resolv.conf.d/base - name: config dns for ubuntu 16.04 template: src: resolv.conf.j2 dest: /etc/resolv.conf when: ansible_distribution == "Ubuntu" and ansible_distribution_major_version == "16"
使用block注意事項:
block除了能和when一塊兒使用以外,還能做錯誤處理。這個時候就須要用到rescue關鍵字:
- hosts: test tasks: - block: - shell: 'ls /testdir' rescue: - debug: msg: '/testdir is not exists'
在上面的例子中,當block中的任務執行失敗時,則運行rescue中的任務。若是block中的任務正常執行,則rescue的任務就不會被執行。若是block中有多個任務,則任何一個任務執行失敗,都會執行rescue。block中能夠定義多個任務,一樣rescue當中也能夠定義多個任務。
當block執行失敗時,rescue中的任務纔會被執行;而不管block執行成功仍是失敗,always中的任務都會被執行:
- hosts: test tasks: - block: - shell: 'ls /testdir' rescue: - debug: msg: '/testdir is not exists' always: - debug: msg: 'This task always executes'
在上面講block的使用方法的時候,咱們說block除了能夠將多個任務組合到一塊兒,還有錯誤處理的功能。接下來咱們繼續說一說錯誤處理。
在shell中,可能會有這樣的需求:當腳本執行至某個階段時,須要對某個條件進行判斷,若是條件成立,則當即終止腳本的運行。在shell中,能夠直接調用"exit"便可執行退出。事實上,在playbook中也有相似的模塊能夠作這件事。即fail模塊。
fail模塊用於終止當前playbook的執行,一般與條件語句組合使用,當知足條件時,終止當前play的運行。
選項只有一個:
示例:
# 使用fail模塊中斷playbook輸出 - hosts: test tasks: - shell: echo "Just a test--error" register: result - fail: msg: "Conditions established,Interrupt running playbook" when: "'error' in result.stdout" - debug: msg: "Inever execute,Because the playbook has stopped"
事實上,當fail和when組合使用的時候,還有一個更簡單的寫法,即failed_when
,當知足某個條件時,ansible主動觸發失敗。
# 若是在command_result存在錯誤輸出,且錯誤輸出中,包含了`FAILED`字串,即返回失敗狀態: - name: this command prints FAILED when it fails command: /usr/bin/example-command -x -y -z register: command_result failed_when: "'FAILED' in command_result.stderr"
也能夠直接經過fail
模塊和when
條件語句,寫成以下:
- name: this command prints FAILED when it fails command: /usr/bin/example-command -x -y -z register: command_result ignore_errors: True - name: fail the play if the previous command did not succeed fail: msg="the command failed" when: " command_result.stderr and 'FAILED' in command_result.stderr"
ansible一旦執行返回失敗,後續操做就會停止,因此failed_when一般能夠用於知足某種條件時主動停止playbook運行的一種方式。
ansible默認處理錯誤的機制是遇到錯誤就中止執行。但有些時候,有些錯誤是計劃之中的。咱們但願忽略這些錯誤,以讓playbook繼續往下執行。這個時候就可使用
ignore_errors
忽略錯誤,從而讓playbook繼續往下執行。
當咱們控制一些遠程主機執行某些任務時,當任務在遠程主機上成功執行,狀態發生更改時,會返回changed狀態響應,狀態未發生更改時,會返回OK狀態響應,當任務被跳過期,會返回skipped狀態響應。咱們能夠經過changed_when
來手動更改changed
響應狀態。示例以下:
- shell: /usr/bin/billybass --mode="take me to the river" register: bass_result changed_when: "bass_result.rc != 2" #只有該條task執行之後,bass_result.rc的值不爲2時,纔會返回changed狀態 # this will never report 'changed' status - shell: wall 'beep' changed_when: False #當changed_when爲false時,該條task在執行之後,永遠不會返回changed狀態
# 只打印大於5的值 tasks: - command: echo {{ item }} loop: [ 0, 2, 4, 6, 8, 10 ] when: item > 5
# 確保將mariadb-server安裝到根分區且根分區的可用空間要大於300M - name: install mariadb-server if enough space on root yum: name: mariadb-server state;拉特st loop: "{{ ansible_mounts }}" when: item.mount == "/" and item.size_available > 300000000