一、Ansible處理任務失敗
1、管理play中任務錯誤
1️⃣:Ansible評估任務的返回代碼,從而確定任務是成功還是失敗
2️⃣:通常而言,當任務失敗時,Ansible將立即在該主機上中止play的其余部分並且跳過所有后續任務,但有些時候,可能希望即使在任務失敗時也繼續執行play
2、忽略任務失敗
1️⃣:默認情況下,任務失敗時play會中止。不過,可以通過忽略失敗的任務來覆蓋此行為。可以在任務中使用ignore_errors關鍵字來實現此目的
- 演示實例:
//查看playbook [root@localhost project]# cat playbook.yaml --- - hosts: all gather_facts: no tasks: - name: install httpd yum: name: packages //沒有這個包 state: present ignore_errors: yes //可選{yes、no} - name: shoe some massage debug: msg: "hello word" //執行play [root@localhost project]# ansible-playbook playbook.yaml PLAY [all] **************************************************************************************************************************************************************** TASK [install httpd] ****************************************************************************************************************************************************** fatal: [client.example.com]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": false, "failures": ["No package packages available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []} ...ignoring //已經忽略這個任務出錯 TASK [shoe some massage] ************************************************************************************************************************************************** ok: [client.example.com] => { "msg": "hello word" } PLAY RECAP **************************************************************************************************************************************************************** client.example.com : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
3、任務失敗也強制執行處理程序(handlers)
1️⃣:在play中設置force_handlers: yes關鍵字,則即使play因為后續任務失敗而中止也會調用被通知的處理程序(force:促使,推動)
- 演示實例:
//查看playbook [root@localhost project]# cat playbook.yaml --- - hosts: all force_handlers: yes //可選{yes、no} tasks: - name: install httpd shell: ls //這條命令一定會執行成功,從而保證handlers處理程序一定會被觸發 notify: - massage - name: install httpd yum: name: packages //沒有這個包,肯定會出錯 state: present handlers: - name: massage debug: msg: "hello word" //執行play [root@localhost project]# ansible-playbook playbook.yaml PLAY [all] **************************************************************************************************************************************************************** TASK [Gathering Facts] **************************************************************************************************************************************************** ok: [client.example.com] TASK [install httpd] ****************************************************************************************************************************************************** changed: [client.example.com] TASK [install httpd] ***************************************************************************************************************************************************** fatal: [client.example.com]: FAILED! => {"changed": false, "failures": ["No package packages available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []} RUNNING HANDLER [massage] ************************************************************************************************************************************************* ok: [client.example.com] => { "msg": "hello word" } PLAY RECAP **************************************************************************************************************************************************************** client.example.com : ok=3 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
2️⃣:處理程序會在任務報告changed結果時獲得通知,而在任務報告ok或failed結果時不會獲得通知
4、指定任務失敗的條件
1️⃣:在任務中使用failed_when關鍵字來指定表示任務已失敗的條件;通常與命令模塊搭配使用,這些模塊可能成功執行了某一命令,但命令的輸出可能指示了失敗
- 演示實例一:使用failed_when關鍵字
//查看使用的腳本 [root@localhost project]# cat files/test.sh #!/bin/bash cat /root //這句肯定會出錯 echo "hello word" //注意:在playbook中執行腳本會以最后一個命令作為錯誤判斷標准,中間錯誤命令不會影響整體的出錯,同樣也不會因為中間出錯而報錯 //查看playbook,執行一次看是否成功 [root@localhost project]# cat playbook.yaml --- - hosts: all tasks: - name: test script: files/test.sh [root@localhost project]# ansible-playbook playbook.yaml PLAY [all] **************************************************************************************************************************************************************** TASK [Gathering Facts] **************************************************************************************************************************************************** ok: [client.example.com] TASK [test] *************************************************************************************************************************************************************** changed: [client.example.com] PLAY RECAP **************************************************************************************************************************************************************** client.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 //這樣無法判斷是否都執行成功 //添加任務失敗判斷語句 [root@localhost project]# cat playbook.yaml --- - hosts: all tasks: - name: test script: files/test.sh register: result failed_when: "'Is a directory' in result['stdout']" [root@localhost project]# ansible-playbook playbook.yaml PLAY [all] **************************************************************************************************************************************************************** TASK [Gathering Facts] **************************************************************************************************************************************************** ok: [client.example.com] TASK [test] *************************************************************************************************************************************************************** fatal: [client.example.com]: FAILED! => {"changed": true, "failed_when_result": true, "rc": 0, "stderr": "Shared connection to client.example.com closed.\r\n", "stderr_lines": ["Shared connection to client.example.com closed."], "stdout": "cat: /root: Is a directory\r\nhello word\r\n", "stdout_lines": ["cat: /root: Is a directory", "hello word"]} PLAY RECAP **************************************************************************************************************************************************************** client.example.com : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
2️⃣:fail模塊也可用於強制任務失敗(主要是將雜亂的提示信息通過自己設置提示方式,達到簡單、明了的目的)
- 演示實例二:
//查看playbook [root@localhost project]# cat playbook.yaml --- - hosts: all tasks: - name: test script: files/test.sh register: result - fail: msg: "There have a failed" when: "'Is a directory' in result['stdout']" //執行play [root@localhost project]# ansible-playbook playbook.yaml PLAY [all] **************************************************************************************************************************************************************** TASK [Gathering Facts] **************************************************************************************************************************************************** ok: [client.example.com] TASK [test] *************************************************************************************************************************************************************** changed: [client.example.com] TASK [fail] *************************************************************************************************************************************************************** fatal: [client.example.com]: FAILED! => {"changed": false, "msg": "There have a failed"} PLAY RECAP **************************************************************************************************************************************************************** client.example.com : ok=2 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
5、指定何時任務報告“changed”結果
1️⃣:當任務對托管主機進行了更改時,會報告 changed 狀態並通知處理程序;如果任務不需要進行更改,則會報告ok並且不通知處理程序
2️⃣:使用changed_when關鍵字可用於控制任務在何時報告它已進行了更改
- 演示實例一:
//查看playbook [root@localhost project]# cat playbook.yaml --- - hosts: all tasks: - name: test shell: echo "hello word" //執行后發現,每次都是changed [root@localhost project]# ansible-playbook playbook.yaml PLAY [all] **************************************************************************************************************************************************************** TASK [Gathering Facts] **************************************************************************************************************************************************** ok: [client.example.com] TASK [test] *************************************************************************************************************************************************************** changed: [client.example.com] PLAY RECAP **************************************************************************************************************************************************************** client.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 //添加changed_when關鍵字,以便報告OK [root@localhost project]# cat playbook.yaml --- - hosts: all tasks: - name: test shell: echo "hello word" changed_when: false //可選{true、false} [root@localhost project]# ansible-playbook playbook.yaml PLAY [all] **************************************************************************************************************************************************************** TASK [Gathering Facts] **************************************************************************************************************************************************** ok: [client.example.com] TASK [test] *************************************************************************************************************************************************************** ok: [client.example.com] PLAY RECAP **************************************************************************************************************************************************************** client.example.com : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3️⃣:根據通過已注冊變量收集的模塊的輸出來報告changed
- 演示實例二:
//查看playbook [root@localhost project]# cat playbook.yaml --- - hosts: all tasks: - name: test command: echo "hello word" register: result changed_when: "'hello word' in result['stdout']" //執行play [root@localhost project]# ansible-playbook playbook.yaml PLAY [all] **************************************************************************************************************************************************************** TASK [Gathering Facts] **************************************************************************************************************************************************** ok: [client.example.com] TASK [test] *************************************************************************************************************************************************************** changed: [client.example.com] PLAY RECAP **************************************************************************************************************************************************************** client.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 //因為在result['stdout']中有hello word ,所以被認定為是true,所以就顯示changed
6、Ansible塊和錯誤處理
1️⃣:在playbook中,塊是對任務進行邏輯分組的子句,可用於控制任務的執行方式
2️⃣:通過塊,也可結合rescue和always語句來處理錯誤。如果塊中的任何任務失敗,則執行其rescue塊中的任務來進行恢復
3️⃣:在block子句中的任務以及rescue子句中的任務(如果出現故障)運行之后,always子句中的任務運行
4️⃣:總結:
- block:定義要運行的主要任務
- rescue:定義要在block子句中定義的任務失敗時運行的任務
- always:定義始終都獨立運行的任務,不論block和rescue子句中定義的任務是成功還是失敗
5️⃣:演示:
- 演示實例一:當只有block和rescue,且block語句執行成功時,只執行block語句而不執行rescue語句(rescue:營救、救援)
//查看playbook [root@localhost project]# cat playbook.yaml --- - hosts: all gather_facts: no tasks: - name: test block: - name: block shell: echo "hello word" rescue: - name: rescue shell: ls /root //執行play [root@localhost project]# ansible-playbook --syntax-check playbook.yaml playbook: playbook.yaml [root@localhost project]# an anacron ansible-config ansible-console ansible-galaxy ansible-playbook ansible-test ansible ansible-connection ansible-doc ansible-inventory ansible-pull ansible-vault [root@localhost project]# ansible-playbook playbook.yaml PLAY [all] **************************************************************************************************************************************************************** TASK [block] ************************************************************************************************************************************************************** changed: [client.example.com] PLAY RECAP **************************************************************************************************************************************************************** client.example.com : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 //可以發現,只執行了block語句,並沒有執行rescue語句
- 演示實例二:當只有block和rescue,且block語句執行失敗時,不執行block語句而執行rescue語句
//查看playbook [root@localhost project]# cat playbook.yaml --- - hosts: all gather_facts: no tasks: - name: test block: - name: block command: cat / //這句肯定會失敗 rescue: - name: rescue shell: ls /root //執行play [root@localhost project]# ansible-playbook playbook.yaml PLAY [all] **************************************************************************************************************************************************************** TASK [block] ************************************************************************************************************************************************************** fatal: [client.example.com]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": true, "cmd": ["cat", "/"], "delta": "0:00:00.005350", "end": "2020-09-08 10:59:18.381699", "msg": "non-zero return code", "rc": 1, "start": "2020-09-08 10:59:18.376349", "stderr": "cat: /: Is a directory", "stderr_lines": ["cat: /: Is a directory"], "stdout": "", "stdout_lines": []} TASK [rescue] ************************************************************************************************************************************************************* changed: [client.example.com] PLAY RECAP **************************************************************************************************************************************************************** client.example.com : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0 //可以看出,block語句執行失敗而執行了rescue語句
- 演示實例三:當block語句、rescue語句和always語句都有時,無論block語句是否失敗,always語句總是執行
//查看playbook [root@localhost project]# cat playbook.yaml --- - hosts: all gather_facts: no tasks: - name: test block: - name: block command: cat / rescue: - name: rescue shell: ls /root always: - name: always debug: msg: "This is my test" //執行play [root@localhost project]# ansible-playbook playbook.yaml PLAY [all] **************************************************************************************************************************************************************** TASK [block] ************************************************************************************************************************************************************** fatal: [client.example.com]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": true, "cmd": ["cat", "/"], "delta": "0:00:00.008993", "end": "2020-09-08 11:05:47.816489", "msg": "non-zero return code", "rc": 1, "start": "2020-09-08 11:05:47.807496", "stderr": "cat: /: Is a directory", "stderr_lines": ["cat: /: Is a directory"], "stdout": "", "stdout_lines": []} TASK [rescue] ************************************************************************************************************************************************************* changed: [client.example.com] TASK [always] ************************************************************************************************************************************************************* ok: [client.example.com] => { "msg": "This is my test" } PLAY RECAP **************************************************************************************************************************************************************** client.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0
6️⃣:block中的when條件也會應用到其rescue和always子句(若存在)
- 演示實例一:
//查看playbook [root@localhost project]# cat playbook.yaml --- - hosts: all gather_facts: no tasks: - name: test block: - name: block command: echo "hello word" //該語句沒有錯誤 when: ansible_facts['distribution'] == "CentOS" //條件判斷出錯會導致block語句不會執行 rescue: - name: rescue shell: ls /root always: - name: always debug: msg: "This is my test" //執行play [root@localhost project]# ansible-playbook playbook.yaml PLAY [all] **************************************************************************************************************************************************************** TASK [block] ************************************************************************************************************************************************************** fatal: [client.example.com]: FAILED! => {"msg": "The conditional check 'ansible_facts['distribution'] == \"CentOS\"' failed. The error was: error while evaluating conditional (ansible_facts['distribution'] == \"CentOS\"): 'dict object' has no attribute 'distribution'\n\nThe error appears to be in '/root/project/playbook.yaml': line 7, column 11, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n block:\n - name: block\n ^ here\n"} TASK [rescue] ************************************************************************************************************************************************************* changed: [client.example.com] TASK [always] ************************************************************************************************************************************************************* ok: [client.example.com] => { "msg": "This is my test" } PLAY RECAP **************************************************************************************************************************************************************** client.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0
- 演示實例二:
//查看playbook [root@localhost project]# cat playbook.yaml --- - hosts: all gather_facts: no tasks: - name: test block: - name: block command: echo "hello word" when: ansible_facts['distribution'] == "CentOS" rescue: - name: rescue shell: ls /root when: ansible_facts['distribution_major_version'] == "7" //這句when語句會執行失敗,導致rescue語句不會執行 always: - name: always debug: msg: "This is my test" //執行play [root@localhost project]# ansible-playbook playbook.yaml PLAY [all] **************************************************************************************************************************************************************** TASK [block] ************************************************************************************************************************************************************** fatal: [client.example.com]: FAILED! => {"msg": "The conditional check 'ansible_facts['distribution'] == \"CentOS\"' failed. The error was: error while evaluating conditional (ansible_facts['distribution'] == \"CentOS\"): 'dict object' has no attribute 'distribution'\n\nThe error appears to be in '/root/project/playbook.yaml': line 7, column 11, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n block:\n - name: block\n ^ here\n"} TASK [rescue] ************************************************************************************************************************************************************* fatal: [client.example.com]: FAILED! => {"msg": "The conditional check 'ansible_facts['distribution_major_version'] == \"7\"' failed. The error was: error while evaluating conditional (ansible_facts['distribution_major_version'] == \"7\"): 'dict object' has no attribute 'distribution_major_version'\n\nThe error appears to be in '/root/project/playbook.yaml': line 12, column 11, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n rescue:\n - name: rescue\n ^ here\n"} TASK [always] ************************************************************************************************************************************************************* ok: [client.example.com] => { "msg": "This is my test" } PLAY RECAP **************************************************************************************************************************************************************** client.example.com : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=1 ignored=0 //可以看出,block語句和rescue語句都沒執行
- 演示實例三:
//查看playbook [root@localhost project]# cat playbook.yaml --- - hosts: all gather_facts: no tasks: - name: test block: - name: block command: echo "hello word" rescue: - name: rescue shell: ls /root always: - name: always debug: msg: "This is my test" when: ansible_facts['distribution_version'] == "8" //when條件儲出錯沒回導致always語句執行失敗 //執行play [root@localhost project]# ansible-playbook playbook.yaml PLAY [all] **************************************************************************************************************************************************************** TASK [block] ************************************************************************************************************************************************************** changed: [client.example.com] TASK [always] ************************************************************************************************************************************************************* fatal: [client.example.com]: FAILED! => {"msg": "The conditional check 'ansible_facts['distribution_version'] == \"8\"' failed. The error was: error while evaluating conditional (ansible_facts['distribution_version'] == \"8\"): 'dict object' has no attribute 'distribution_version'\n\nThe error appears to be in '/root/project/playbook.yaml': line 15, column 11, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n always:\n - name: always\n ^ here\n"} PLAY RECAP **************************************************************************************************************************************************************** client.example.com : ok=1 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
- 注意:block執行會成功的話,如果用when條件判斷,即使判斷條件會成功,但block語句任然會失敗,而去執行rescue語句