一:when語句 1:基礎瞭解 說到底,還是有多個表達式來組成一個判斷語句,很多種的判斷語句 1、 為什麼需要判斷語句: 有的時候play的結果需要依賴於變數,fact或者是前一個任務的執行結果,或者基於上一個task執行返回的結果而決定如何執行後續的task,這個時候就需要條件的判斷了,一個很簡單 ...
一:when語句
1:基礎瞭解
說到底,還是有多個表達式來組成一個判斷語句,很多種的判斷語句
1、 為什麼需要判斷語句:
有的時候play的結果需要依賴於變數,fact或者是前一個任務的執行結果,或者基於上一個task執行返回的結果而決定如何執行後續的task,這個時候就需要條件的判斷了,一個很簡單的案例,就是掛載磁碟,不需要到被控節點上面去看是否掛成功了,直接使用一個判斷,看那個task任務的執行的結果,為0則代表著成功,就進行下一步的任務的執行
2、使用場景
1)目標主機上定義了一個硬限制,比如目標主機的最小記憶體必須達到多少,才能執行task任務
2)捕獲一個命令的輸出,根據輸出的結果不同來觸發不同的task
3)根據不同的目標主機的facts,來執行不同的tasks,如果是node1就是執行A任務,如果是node2就執行B任務
等等等
3、when理解
當判斷的結果是一致的話,那麼執行task任務,否則的話,就跳過這個任務
ansible中判斷語句是when判斷,預設when判斷,就識別變數,所以的話,不需要使用"{{}}"來引用變數,when inventory_hostname == 'node1'
還有一個點就是如果不使用變數的話,就只使用這個值的話,那麼的話就要帶上這個雙引號,並且裡面還要有單引號即可
when與模塊的層級是一樣的
2:判斷的表達式
1:比較運算符
== 比較2邊是否相等的,比較字元串和數字
!= 2邊是否一致,不一致則為真
>= 比較大小,左邊大於右邊為真
<= 右邊大於左邊為真
> 左邊大於右邊為真
< 右邊大於左邊為真
案例:
判斷運行的task任務的主機是不是node1,如果是的node1則執行任務,
判斷主機的freemem大小是否大於1000,如果是的話,則執行任務
//通過facts變數來獲取這個記憶體,然後通過魔法變數來獲取這個node1 - name: memfree hosts: node1 tasks: - name: use when debug: msg: dayu1000 when: ansible_memtotal_mb > 1000 - name: node1 debug: msg: hostname is node1 when: inventory_hostname == 'node1'
2:邏輯運算符
and | 邏輯與,2邊都為真,則返回真 |
or | 邏輯或,有一個為真,則返回為真 |
not | 邏輯否,對錶達式取反,真為假,假為真,在表達式的前面寫上 |
() | 當一組的表達式組合在一起後,形成一個更大的表達式,組合內的所有表達式都是邏輯與的關係 |
案例:
#判斷主機名為node1,ip地址為10,則列印hello rhce [root@controller mnt]# cat f4.yml - name: use debug hosts: node1 tasks: - debug: msg: hello rhce when: inventory_hostname == 'node1' and ansible_ens160.ipv4.address == '172.25.250.11' #判斷主機名是否為node1或者ip地址是30的,則列印rhce [root@controller mnt]# cat f5.yaml - name: hosts: all tasks: - debug: msg: rhce when: inventory_hostname == 'node1' or ansible_ens160.ipv4.address == '172.25.250.30' #使用not來進行判斷,判斷不是node1的主機即執行任務 應該放在最前面 - name: user kkk hosts: all tasks: - name: debug: msg: hello when: not ansible_hostname == 'node1' #()的使用,主機名是node1並且ip地址是11或者系統是redhat,並且版本是9的則執行任務 ()裡面是邏輯與的關係,多個表達式一起表達 [root@controller mnt]# cat f7.yml - name: use debug hosts: all tasks: - debug: msg: hello rhce when: (ansible_hostname == 'node1' and ansible_ens160.ipv4.address == '172.25.250.11') or (ansible_distribution_major_version == '9' and ansible_os_family == 'RedHat')
3:根據rc的返回值來進行判斷task任務是否執行成功
根據註冊變數,這個能保存上一個tasks任務的執行信息,就是根據rc的值為0則表示執行成功,執行任務,不成功,執行另外的一個任務
[root@controller mnt]# cat f8.yml - hosts: node1 tasks: - shell: ls /etc/passsssss register: get_status ignore_errors: yes - debug: msg: rc is 0 when: get_status.rc == 0 - debug: msg: rc is error when: get_status.rc != 0
4:通過條件判斷路徑是否存在
shell腳本也有這個使用test -f 路徑,判斷是否是一個文件,-d判斷是否是一個目錄,-e 路徑,判斷路徑是否存在
ansible中,判斷的格式如下
file:判斷指定路徑是否為一個文件,是則為真
directory:判斷指定路徑是否是一個目錄,是則為真
link:判斷指定路徑是否為一個軟連接,是則為真
mount:判斷路徑是否為掛載點,是則為真
exists:判斷指定路徑是否存在,存在則為真
使用when來進行判斷 when "'/etc/passwd' is exists "
使用的關鍵字就是is
使用變數的值進行判斷
#/etc/passwd存在的話,就執行任務 #when直接使用值的話需要使用雙引號裡面的值在加上單引號即可 [root@controller mnt]# cat f9.yaml - hosts: all tasks: - debug: msg: exist when: "'/etc/passwd is exists'"
5:通過判斷tasks任務的執行結果(是對整個task任務進行判斷)
ok:目標狀態和期望值一致,沒有發生變更
change或changed:目標發生變更,與期望值一樣
sucess或succeeded:目標狀態與期望值一樣,或者任務執行成功了
failure或failed:任務失敗
skip或skipped:任務跳過,註意,如果一個錯誤的任務使用ignore_errors忽略了這個錯誤,會跳過,但是實際上這個任務的執行是失敗的,並沒有跳過(註意)
案例:
#使用一個錯誤的任務,錯誤的結果就執行任務 - hosts: all tasks: - shell: ls /etc/passssss register: get_status ignore_errors: yes - debug: msg: is filed when: get_status is failed - debug: msg: is skipped when: get_status is skip
6:通過對變數進行判斷
defined:判斷變數是否已定義了,定義了則返回真
undefined:判斷變數是否未定義,未定義則返回真
none:判斷變數的值是否為空,如果變數的已定義但是值為空的話,則返回真,定義了這個變數名,但是沒有值
案例:
#定義一個變數,然後不給他的值,則執行任務 - hosts: node1 vars: rhel: tasks: - debug: msg: is none when: rhel is none - debug: msg: is undefined when: rhel is undefined
7:通過字元串進行判斷大小寫字母
lower:判斷字元串是否是小寫字母
upper:判斷字元串是否是大寫字母
[root@controller mnt]# cat f12.yml - hosts: node1 vars: rhel: qqqq tasks: - debug: msg: lower when: rhel is lower
8:通過數字來進行判斷
even:判斷數值是否為偶數,是則為真
odd:判斷數值是否為奇數,,是則為真
divisibleby(num):判斷是否可以整除指定的數值,是則為真
#判斷能被2整除嗎。是的話就執行任務 [root@controller mnt]# cat f12.yml - hosts: node1 vars: rhel: 10 tasks: - debug: msg: oushu when: rhel is divisibleby(2)
9:通過判斷是否是子集或者是父集,in的判斷
數字和字元都行
subset():判斷一個list是不是另外一個list的子集,when: a is subnet(b)
就是判斷a是不是b的子集,就是a是不是被包含在b裡面,小的
superset():判斷一個list是不是另外一個list的父集;when: b is superset(a)
判斷a是不是b的父集,就是a是不是包含b,大的
寫法的話就是使用列表的形式來編寫,不能使用字典的形式,會出現錯誤
案例:
[root@controller mnt]# cat f13.yml - hosts: node1 vars: f: - qqq - www w: - qqq tasks: - debug: msg: fuji when: f is superset(w)
判斷字元串是否位於一個列表中的(非常重要的,經常使用的)
判斷ens160網卡是不是在ansible_intreafces裡面
[root@controller mnt]# cat f3.yml - hosts: node1 tasks: - debug: msg: ens160 exists when: "'ens160' in ansible_interfaces"
10:判斷對象是否是字元串或者數字
string:判斷是否是字元串
numbber:判斷是否是數字
[root@controller mnt]# cat f14.yml - hosts: node1 vars: rhel: 9 tasks: - debug: msg: 9 is number when: rhel is number
3:when判斷和其他的關鍵字
1、block關鍵字
使用when判斷的時候,每一個when判斷只會判斷一個task任務,如果有多個的話,就需要編寫多次的,這樣的話,代碼就非常的多且不必要了
解決的方法就是:
ansible通過block包裹多個tasks的任務,直接對block進行when判斷,如果判斷成功,則執行block中的所有tasks任務
,通俗來講就是block是一個塊,把多個tasks任務作為一個整體,對block進行判斷,如果成立則block中的tasks任務執行
案例:
創建一個文件,創建一個目錄,然後對其進行判斷,直接對這個block進行判斷,判斷主機名是node1執行
#上面所述就有2個tasks任務,如果使用when的話,要使用2次,使用block的話,直接對這個block這個整體進行判斷,即能執行 block的層級是包裹這些任務的,然後when對這個block進行判斷,成功,則執行這個任務 - name: use block hosts: all tasks: - block: - file: path: /mnt/1.txt state: touch - file: path: /mnt/1.dir state: directory when: inventory_hostname == 'node1'
2、resuce關鍵字
層級與block一樣的,錯誤拯救,對於block塊的話,如果block中的任務執行失敗,則會執行resuce下麵的任務,如果沒有失敗的話,則不會觸發resuce關鍵字下的task任務
- name: rescue hosts: all tasks: - block: - shell: ls /etc/p11111 - file: path: /etc/passwd state: file rescue: - debug: msg: rescue when: inventory_hostname == 'node1'
3、always關鍵字
無論block任務執行成功還是失敗,都要執行always關鍵字的中task任務
- name: rescue hosts: all tasks: - block: - shell: ls /etc/p11111 - file: path: /etc/passwd state: file rescue: - debug: msg: rescue always: - debug: msg: always when: inventory_hostname == 'node1'
4、fail和failed_when
如果一個task任務執行失敗的話,後面的task任務也沒有必要執行,需要執行退出
就是掛載都沒有掛上去,就不需要寫yum倉庫等等
案例:
- name: faile hosts: node1 tasks: - shell: ls /etc/lllll ignore_errors: yes register: get_status - fail: msg: juben exit when: get_status.rc != 0 - debug: msg: a 思路: 忽略了錯誤,繼續像下麵執行任務,本來要列印這個a的,使用了fail關鍵字,符合條件就退出這個劇本
failed_when:關鍵字
案例:
- name: faile hosts: node1 tasks: - shell: ls /etc/lllll ignore_errors: yes register: get_status - debug: msg: juben exit failed_when: get_status.rc != 0 - debug: msg: a
二:ansible迴圈語句
迴圈語句進行批量化的操作,創建用戶,創建文件等
1:基於列表的迴圈(with_items)
不能使用對象(字典)的方式進行迴圈,會報錯的,item固定的格式
2種寫法 第一種,利用變數的形式 - name: item hosts: node1 vars: users: - zhangsan - lisi - wangwu tasks: - debug: msg: "{{item}}" with_items: "{{users}}" #with_items遍歷users裡面的元素 第二種寫法: 直接在with_items後面寫 - name: item hosts: node1 tasks: - debug: msg: "{{item}}" with_items: - zhangsan - lisi - wangwu 但是這種方式不常用
2:基於字典的迴圈(with_dict)
就是鍵值對的方式來進行迴圈
- name: dict hosts: node1 vars: users: q1: uid: 2022 name: zhangsan q2: uid: 2023 name: lisi tasks: - debug: msg: "{{item.value.name}}" with_dict: "{{users}}" ###輸出的結果 ok: [node1] => (item={'key': 'q1', 'value': {'uid': 2022, 'name': 'zhangsan'}}) => { "msg": "zhangsan" } ok: [node1] => (item={'key': 'q2', 'value': {'uid': 2023, 'name': 'lisi'}}) => { "msg": "lisi" } //思路 key是q1,value是uid,name,然後想要輸出什麼就以.連接
3:loop迴圈
天生是用來遍歷列表的,但是也可以遍歷字典,需要過濾器等
- name: loop hosts: node1 vars: users: - zhangsan - lisi - wangwu tasks: - debug: msg: "{{item}}" loop: "{{users}}"
過濾器等
dict2items將字典轉換成列表
用戶的密碼password_hash等
三:總結
when判斷有很多的方式來進行判斷,facts變數,註冊變數,in判斷等等
還有幾個關鍵字,block,rescue,always,fail,failed_when
迴圈語句,最常用的就是loop迴圈