Ansible開發實戰:解決callback中只能識別原生模塊名稱的問題

(本文基於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的名稱

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章