Ansible 源碼解析: shell模塊的實現方式

(本文基於Ansible 2.7)
Ansible的Shell模塊(lib/ansible/modules/commands/shell.py)中幾乎不包含python代碼,註釋表明其實際上運行的是command模塊:

# # There is no actual shell module source, when you use 'shell' in ansible,
# it runs the 'command' module with special arguments and it behaves differently.
# See the command source and the comment "#USE_SHELL".

command模塊(lib/ansible/modules/commands/command.py)實際上是通過調用AnsibleModule.run_command()來運行命令的:
在195行,爲shell賦值:

shell = module.params['_uses_shell']

257-263行

if not module.check_mode:
        rc, out, err = module.run_command(args, executable=executable, use_unsafe_shell=shell, encoding=None, data=stdin)
    elif creates or removes:
        rc = 0
        out = err = b'Command would have run if not in check mode'
    else:
        module.exit_json(msg="skipped, running in check mode", skipped=True)

其中,use_unsafe_shell=shell這個參數的處理,在lib/ansible/module_utils/basic.py的2742-2768行,與本文主題相關度不高,代碼就不貼了。
那麼shell模塊是如何與command模塊建立起聯繫,_uses_shell又是從哪裏傳入的呢?答案是,通過plugin。
下面是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

可以看到_uses_shell值被顯式指定爲True。

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