ansible回撥外掛介紹(待完成)
簡介
ansible回撥外掛(callback plugins)允許為事件新增一些額外響應。這裡的事件包括了執行任務(task)的結果,例如(ok、failed、unreachable、skipped),以及執行劇本(playbook)的過程(start、hosts_matched、task_start、stats)等等。豐富的事件回撥使得回撥外掛能夠做非常多的事情,不過,大多數時候他們都用來提供各種各樣的輸出,或者將日誌傳輸到日誌採集器,又或者當遇到特定事件時觸發某些特定的任務。
使用
配置項
回撥外掛的配置項與其他ansible配置項類似,既可以通過環境變數定義,也可以在ansible.cfg配置檔案中定義,優先順序順序為:ANSIBLE_CONFIG --> ansible.cfg --> ~/.ansible.cfg --> /etc/ansible/ansible.cfg
內建外掛相關的配置項如下:
# 啟用的回撥外掛
callbacks_enabled=<list>
# 回撥外掛預設搜尋路徑
callback_plugins=~/.ansible/plugins/callback:/usr/share/ansible/plugins/callback
# 標準輸出回撥外掛,可以執行多個回撥外掛,但只可以執行一個標準輸出型別的回撥外掛
stdout_callback=default
內建外掛示例
通過ansible-doc -t callback -l
命令,能夠列出所有可用的外掛;通過ansible-doc -t callback <plugin name>
# ansible-doc -t callback -l ... default default Ansible screen output junit write playbook output to a JUnit file minimal minimal Ansible screen output oneline oneline Ansible screen output ovirt.ovirt.stdout Output the log of ansible theforeman.foreman.foreman Sends events to Foreman tree Save host events to files # ansible-doc -t callback oneline > ANSIBLE.BUILTIN.ONELINE (/usr/local/lib/python3.9/site-packages/ansible/plugins/callback/oneline.py) This is the output callback used by the -o/--one-line command line option. NAME: oneline TYPE: stdout VERSION_ADDED_COLLECTION: ansible.builtin
其中,default是ansible-playbook所使用的預設回撥外掛,我們執行ansible-playbook時看到的大部分輸出都是執行這個外掛的結果。
default回撥外掛示例:
minimal是ansible命令列(ad-hoc)的預設回撥外掛。修改stdout_callback=minimal後,輸出結果如下:
oneline會將每個任務的輸出限制為一行:
tree則會將執行的結果以json格式儲存在指定目錄中,目錄預設為~/.ansible/tree
,可通過callback_tree
配置項修改。
這個網站很好的展示了所有內建回撥外掛的用法,包括svg視訊和文字兩種展示方式:Ansible Callback-Plugins (rndmh3ro.github.io)。
開發
ansible支援自定義回撥外掛,如果內建外掛中沒有自己想要的功能,那麼可以自行開發外掛以實現自己想要的功能。
一個回撥外掛即是一個python檔案,其中定義了一系列特別的回撥函式,在這些回撥函式中編寫自定義的程式碼,即可在ansible playbook執行到特定地方時呼叫這些程式碼,從而實現自己想要的功能。
ansible支援的回撥函式均定義於ansible/plugins/callback/__init.py
檔案的CallbackBase類中,其所定義的回撥函式非常豐富,卻沒有詳盡的文件描述它們的作用,如果想要知道每個函式的觸發點,需要自己查詢原始碼,希望這一段空缺以後能夠補上。
經常用到的回撥函式如下:
# task開始時執行
def v2_runner_on_start(self, host, task):
# task結束後執行(failed、ok、skipped、unreachable)
def v2_runner_on_failed(self, result, ignore_errors=False):
def v2_runner_on_ok(self, result):
def v2_runner_on_skipped(self, result):
def v2_runner_on_unreachable(self, result):
# playbook開始時執行
def v2_playbook_on_start(self, playbook):
# playbook結束時執行
def v2_playbook_on_stats(self, stats):
在執行playbook時,往往會遇到如下問題:當任務由於各種問題失敗時,我們需要修復問題,然後再重新執行playbook,可是直接重新執行的話需要跑很長一段重複的步驟,而如果直接在失敗的步驟開始的話,又有可能會有變數未定義的錯誤(定義變數的步驟沒有執行)。這個時候,有一種折中的方案是在失敗步驟所在的role重新執行,當playbook指令碼邏輯規範得當時,這種方法能夠保證在絕大多數步驟失敗時得到恰當的解決。
每次人力尋找失敗步驟所在的role耗時耗力,這種事情可以交給回撥外掛進行。如下自定義外掛用來在任務失敗時儲存最後執行的role,以便於重新執行playbook時指定開始的任務。其中,當每個task開始時會儲存當前執行的role以及此role的第一個task;當task失敗時則會將role的第一個task儲存在/tmp/ansible_failed_role檔案中。
# ~/.ansible/plugins/callback/lastrole.py
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = '''
name: lastrole
type: stdout
short_description: store last role when playbook failed.
version_added: historical
description:
- store last role to /tmp/ansible_failed_role when playbook failed.
'''
from ansible.plugins.callback import CallbackBase
from ansible import constants as C
class CallbackModule(CallbackBase):
CALLBACK_VERSION = 2.0
CALLBACK_TYPE = 'aggregate'
CALLBACK_NAME = 'lastrole'
def __init__(self):
self.task = None
self.role = None
self.role_first_task = None
super(CallbackModule, self).__init__()
def v2_playbook_on_task_start(self, task, is_conditional):
self.task = task.get_name()
if task._role:
if task._role._role_name != self.role:
self.role_first_task = self.task
self.role = task._role._role_name
def v2_runner_on_failed(self, result, ignore_errors=False):
if ignore_errors==True:
return
with open('/tmp/ansible_failed_role','w') as f:
f.write('%s\n'%(self.role_first_task))
將此檔案儲存在~/.ansible/plugins/callback/
(或任一callback_plugins配置項中的搜尋路徑)目錄下,隨後在callbacks_enabled配置項中追加lastrole外掛,即可在playbook執行時呼叫該外掛。
執行playbook失敗後檢視/tmp/ansible_failed_role檔案。
# cat /tmp/ansible_failed_role
pre_deploy : get external ip
再次執行playbook時從此task開始。
ansible-playbook -i inventory/hosts.ini playbooks/setup.yml --start-at-task='pre_deploy : get external ip'
一般來說,在專案中都是由程式執行playbook,這時也可自行編寫邏輯,將ansible_failed_role寫入到資料庫中,在執行playbook時判斷並傳入該引數,更為自動化。
附錄
回撥函式的除錯
ansible通過TaskQueueManager的send_callback方法呼叫回撥函式,在playbook的執行過程中有各種地方都呼叫了這個方法。如果想要快速地瞭解知道ansible playbook在執行中到底在何時呼叫了什麼回撥函式,可以通過在程式碼中新增debug資訊的方式得知。
# ansible/executor/task_queue_manager.py
...
class TaskQueueManager:
...
def send_callback(self, method_name, *args, **kwargs):
# 新增debug資訊
print(f'* send_callback, method_name: {method_name} args: {args} kwargs: {kwargs}')
...
除錯能夠精確地得出各個回撥函式的執行順序,下圖展示了主要回調函式的執行過程。
除此之外,有一個特別的回撥函式為def v2_on_any(self, *args, **kwargs):
,ansible呼叫任何回撥函式之後,都會呼叫一次該函式,一般用於除錯。
目前所有的回撥函式:
def v2_on_any(self, *args, **kwargs):
def v2_runner_on_failed(self, result, ignore_errors=False):
def v2_runner_on_ok(self, result):
def v2_runner_on_skipped(self, result):
def v2_runner_on_unreachable(self, result):
def v2_runner_on_async_poll(self, result):
def v2_runner_on_async_ok(self, result):
def v2_runner_on_async_failed(self, result):
def v2_playbook_on_start(self, playbook):
def v2_playbook_on_notify(self, handler, host):
def v2_playbook_on_no_hosts_matched(self):
def v2_playbook_on_no_hosts_remaining(self):
def v2_playbook_on_task_start(self, task, is_conditional):
def v2_playbook_on_cleanup_task_start(self, task):
def v2_playbook_on_handler_task_start(self, task):
def v2_playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None, unsafe=None):
def v2_playbook_on_import_for_host(self, result, imported_file):
def v2_playbook_on_not_import_for_host(self, result, missing_file):
def v2_playbook_on_play_start(self, play):
def v2_playbook_on_stats(self, stats):
def v2_on_file_diff(self, result):
def v2_playbook_on_include(self, included_file):
def v2_runner_item_on_ok(self, result):
def v2_runner_item_on_failed(self, result):
def v2_runner_item_on_skipped(self, result):
def v2_runner_retry(self, result):
def v2_runner_on_start(self, host, task):
參考文件
[Callback plugins — Ansible Documentation](