(本文基於Ansible 2.7)
近來在開發過程中遇到一個問題:所有基於command模塊編寫的action plugin在callback中取result._task_fields[‘action’],均被識別爲command模塊。
這個問題雖然並不影響任務執行,但對後期的數據收集、統計和分析造成了麻煩,無法進行更細緻的分類查詢。
在Ansible 源碼解析: shell模塊的實現方式和Ansible開發實戰: 基於command模塊的Oracle Listener控制模塊(附趟雷過程及樣例)這兩篇文章中,我們討論瞭如何基於command模塊開發定製plugin,本文以shell模塊的實現方式爲例:
lib/ansible/plugins/action/shell.py:
# Copyright: (c) 2017, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.plugins.action import ActionBase
from ansible.utils.vars import merge_hash
class ActionModule(ActionBase):
def run(self, tmp=None, task_vars=None):
del tmp # tmp no longer has any effect
# Shell module is implemented via command
self._task.action = 'command'
self._task.args['_uses_shell'] = True
command_action = self._shared_loader_obj.action_loader.get('command',
task=self._task,
connection=self._connection,
play_context=self._play_context,
loader=self._loader,
templar=self._templar,
shared_loader_obj=self._shared_loader_obj)
result = command_action.run(task_vars=task_vars)
return result
這裏run方法最後的返回值result實際上就是callback裏的result._result(可以參見lib/ansible/executor/task_executor.py),是字典類型。所以如果僅想將plugin的名字傳給callback是很簡單的,在run方法返回之前給result增加一個字段即可,例如:
result['orig_action'] = 'shell'
我們目前採用的即是這個方案,它的好處是不用修改ansible的源碼,方便以後的更新。而這樣做的缺點是不得不在callback中增加新的邏輯分支,先在result._result中查詢這個字段是否存在,再決定是否使用result._taskfields[‘action’],未免顯得有些繁冗。
那麼爲什麼我們不直接修改taskfields呢?在task_executor中我們可以看到task_fields的取值是task.dump_attrs()(338行)。ansible在讀取task的attributes的時候是做了檢查的(有空會寫一下這個檢查的過程),檢查未通過的attribute會被丟棄。
self._task.action = 'command'
這一行我們是不能修改的,畢竟任務的實際執行是通過command模塊實現的。
self._task.orig_action = 'command'
如果加入這一行,則任務可以正常運行,但orig_action 並不會被包含在result._task_fields裏,被丟掉了。
如果一定想通過_task_fields傳這個值,可以修改task的源碼來實現(lib/ansible/playbook/task.py),在task類中加入_orig_action的定義:
_orig_action = FieldAttribute(isa='string')
就可以了
2019-05-13:
在允許修改Ansible源碼的前提之下,本問題已經有更優的解決辦法,詳見:
Ansible開發實戰:在結果輸出Action Plugin的名稱