mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-09-23 04:20:27 +00:00
Command (#2134)
* [Update] 任务区分org * [Update] 修改翻译 * [Update] 使用id而不是hostname * [Update] 执行命令 * [Update] 修改一些东西 * [Update] 暂存 * [Update] 用户执行命令 * [Update] 添加资产授权模块-tree * [Update] 暂时这样 * [Update] 批量命令执行 * [Update] 修改表结构 * [Update] 更新翻译 * [Update] 删除cloud模块无效中文翻译
This commit is contained in:
@@ -1,18 +1,16 @@
|
||||
# ~*~ coding: utf-8 ~*~
|
||||
|
||||
import sys
|
||||
import datetime
|
||||
from collections import defaultdict
|
||||
|
||||
from ansible import constants as C
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
from ansible.plugins.callback.default import CallbackModule
|
||||
|
||||
from .display import TeeObj
|
||||
from ansible.plugins.callback.minimal import CallbackModule as CMDCallBackModule
|
||||
|
||||
|
||||
class AdHocResultCallback(CallbackModule):
|
||||
"""
|
||||
Task result Callback
|
||||
"""
|
||||
def __init__(self, display=None, options=None, file_obj=None):
|
||||
class CallbackMixin:
|
||||
def __init__(self, display=None):
|
||||
# result_raw example: {
|
||||
# "ok": {"hostname": {"task_name": {},...},..},
|
||||
# "failed": {"hostname": {"task_name": {}..}, ..},
|
||||
@@ -20,63 +18,129 @@ class AdHocResultCallback(CallbackModule):
|
||||
# "skipped": {"hostname": {"task_name": {}, ..}, ..},
|
||||
# }
|
||||
# results_summary example: {
|
||||
# "contacted": {"hostname",...},
|
||||
# "contacted": {"hostname": {"task_name": {}}, "hostname": {}},
|
||||
# "dark": {"hostname": {"task_name": {}, "task_name": {}},...,},
|
||||
# "success": True
|
||||
# }
|
||||
self.results_raw = dict(ok={}, failed={}, unreachable={}, skipped={})
|
||||
self.results_summary = dict(contacted=[], dark={})
|
||||
self.results_raw = dict(
|
||||
ok=defaultdict(dict),
|
||||
failed=defaultdict(dict),
|
||||
unreachable=defaultdict(dict),
|
||||
skippe=defaultdict(dict),
|
||||
)
|
||||
self.results_summary = dict(
|
||||
contacted=defaultdict(dict),
|
||||
dark=defaultdict(dict),
|
||||
success=True
|
||||
)
|
||||
self.results = {
|
||||
'raw': self.results_raw,
|
||||
'summary': self.results_summary,
|
||||
}
|
||||
super().__init__()
|
||||
if file_obj is not None:
|
||||
sys.stdout = TeeObj(file_obj)
|
||||
if display:
|
||||
self._display = display
|
||||
self._display.columns = 79
|
||||
|
||||
def gather_result(self, t, res):
|
||||
self._clean_results(res._result, res._task.action)
|
||||
host = res._host.get_name()
|
||||
task_name = res.task_name
|
||||
task_result = res._result
|
||||
def display(self, msg):
|
||||
self._display.display(msg)
|
||||
|
||||
if self.results_raw[t].get(host):
|
||||
self.results_raw[t][host][task_name] = task_result
|
||||
else:
|
||||
self.results_raw[t][host] = {task_name: task_result}
|
||||
def gather_result(self, t, result):
|
||||
self._clean_results(result._result, result._task.action)
|
||||
host = result._host.get_name()
|
||||
task_name = result.task_name
|
||||
task_result = result._result
|
||||
|
||||
self.results_raw[t][host][task_name] = task_result
|
||||
self.clean_result(t, host, task_name, task_result)
|
||||
|
||||
|
||||
class AdHocResultCallback(CallbackMixin, CallbackModule, CMDCallBackModule):
|
||||
"""
|
||||
Task result Callback
|
||||
"""
|
||||
def clean_result(self, t, host, task_name, task_result):
|
||||
contacted = self.results_summary["contacted"]
|
||||
dark = self.results_summary["dark"]
|
||||
if t in ("ok", "skipped") and host not in dark:
|
||||
if host not in contacted:
|
||||
contacted.append(host)
|
||||
else:
|
||||
if dark.get(host):
|
||||
dark[host][task_name] = task_result.values
|
||||
|
||||
if task_result.get('rc') is not None:
|
||||
cmd = task_result.get('cmd')
|
||||
if isinstance(cmd, list):
|
||||
cmd = " ".join(cmd)
|
||||
else:
|
||||
dark[host] = {task_name: task_result}
|
||||
if host in contacted:
|
||||
contacted.remove(host)
|
||||
cmd = str(cmd)
|
||||
detail = {
|
||||
'cmd': cmd,
|
||||
'stderr': task_result.get('stderr'),
|
||||
'stdout': task_result.get('stdout'),
|
||||
'rc': task_result.get('rc'),
|
||||
'delta': task_result.get('delta'),
|
||||
'msg': task_result.get('msg', '')
|
||||
}
|
||||
else:
|
||||
detail = {
|
||||
"changed": task_result.get('changed', False),
|
||||
"msg": task_result.get('msg', '')
|
||||
}
|
||||
|
||||
if t in ("ok", "skipped"):
|
||||
contacted[host][task_name] = detail
|
||||
else:
|
||||
dark[host][task_name] = detail
|
||||
|
||||
def v2_runner_on_failed(self, result, ignore_errors=False):
|
||||
self.results_summary['success'] = False
|
||||
self.gather_result("failed", result)
|
||||
super().v2_runner_on_failed(result, ignore_errors=ignore_errors)
|
||||
|
||||
if result._task.action in C.MODULE_NO_JSON:
|
||||
CMDCallBackModule.v2_runner_on_failed(self,
|
||||
result, ignore_errors=ignore_errors
|
||||
)
|
||||
else:
|
||||
super().v2_runner_on_failed(
|
||||
result, ignore_errors=ignore_errors
|
||||
)
|
||||
|
||||
def v2_runner_on_ok(self, result):
|
||||
self.gather_result("ok", result)
|
||||
super().v2_runner_on_ok(result)
|
||||
if result._task.action in C.MODULE_NO_JSON:
|
||||
CMDCallBackModule.v2_runner_on_ok(self, result)
|
||||
else:
|
||||
super().v2_runner_on_ok(result)
|
||||
|
||||
def v2_runner_on_skipped(self, result):
|
||||
self.gather_result("skipped", result)
|
||||
super().v2_runner_on_skipped(result)
|
||||
|
||||
def v2_runner_on_unreachable(self, result):
|
||||
self.results_summary['success'] = False
|
||||
self.gather_result("unreachable", result)
|
||||
super().v2_runner_on_unreachable(result)
|
||||
|
||||
def on_playbook_start(self, name):
|
||||
date_start = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
self.display(
|
||||
"{} Start task: {}\r\n".format(date_start, name)
|
||||
)
|
||||
|
||||
def on_playbook_end(self, name):
|
||||
date_finished = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
self.display(
|
||||
"{} Task finish\r\n".format(date_finished)
|
||||
)
|
||||
|
||||
def display_skipped_hosts(self):
|
||||
pass
|
||||
|
||||
def display_ok_hosts(self):
|
||||
pass
|
||||
|
||||
|
||||
class CommandResultCallback(AdHocResultCallback):
|
||||
"""
|
||||
Command result callback
|
||||
"""
|
||||
def __init__(self, display=None):
|
||||
def __init__(self, display=None, **kwargs):
|
||||
# results_command: {
|
||||
# "cmd": "",
|
||||
# "stderr": "",
|
||||
|
@@ -17,7 +17,7 @@ from common.utils import get_logger
|
||||
from .exceptions import AnsibleError
|
||||
|
||||
|
||||
__all__ = ["AdHocRunner", "PlayBookRunner"]
|
||||
__all__ = ["AdHocRunner", "PlayBookRunner", "CommandRunner"]
|
||||
C.HOST_KEY_CHECKING = False
|
||||
logger = get_logger(__name__)
|
||||
|
||||
@@ -45,7 +45,7 @@ def get_default_options():
|
||||
listtasks=False,
|
||||
listhosts=False,
|
||||
syntax=False,
|
||||
timeout=60,
|
||||
timeout=30,
|
||||
connection='ssh',
|
||||
module_path='',
|
||||
forks=10,
|
||||
@@ -145,7 +145,7 @@ class AdHocRunner:
|
||||
)
|
||||
|
||||
def get_result_callback(self, file_obj=None):
|
||||
return self.__class__.results_callback_class(file_obj=file_obj)
|
||||
return self.__class__.results_callback_class()
|
||||
|
||||
@staticmethod
|
||||
def check_module_args(module_name, module_args=''):
|
||||
@@ -177,17 +177,16 @@ class AdHocRunner:
|
||||
options = self.__class__.default_options
|
||||
return options
|
||||
|
||||
def run(self, tasks, pattern, play_name='Ansible Ad-hoc', gather_facts='no', file_obj=None):
|
||||
def run(self, tasks, pattern, play_name='Ansible Ad-hoc', gather_facts='no'):
|
||||
"""
|
||||
:param tasks: [{'action': {'module': 'shell', 'args': 'ls'}, ...}, ]
|
||||
:param pattern: all, *, or others
|
||||
:param play_name: The play name
|
||||
:param gather_facts:
|
||||
:param file_obj: logging to file_obj
|
||||
:return:
|
||||
"""
|
||||
self.check_pattern(pattern)
|
||||
self.results_callback = self.get_result_callback(file_obj)
|
||||
self.results_callback = self.get_result_callback()
|
||||
cleaned_tasks = self.clean_tasks(tasks)
|
||||
|
||||
play_source = dict(
|
||||
@@ -211,10 +210,6 @@ class AdHocRunner:
|
||||
stdout_callback=self.results_callback,
|
||||
passwords=self.options.passwords,
|
||||
)
|
||||
print("Get matched hosts: {}".format(
|
||||
self.inventory.get_matched_hosts(pattern)
|
||||
))
|
||||
|
||||
try:
|
||||
tqm.run(play)
|
||||
return self.results_callback
|
||||
@@ -229,16 +224,14 @@ class CommandRunner(AdHocRunner):
|
||||
results_callback_class = CommandResultCallback
|
||||
modules_choices = ('shell', 'raw', 'command', 'script')
|
||||
|
||||
def execute(self, cmd, pattern, module=None):
|
||||
def execute(self, cmd, pattern, module='shell'):
|
||||
if module and module not in self.modules_choices:
|
||||
raise AnsibleError("Module should in {}".format(self.modules_choices))
|
||||
else:
|
||||
module = "shell"
|
||||
|
||||
tasks = [
|
||||
{"action": {"module": module, "args": cmd}}
|
||||
]
|
||||
hosts = self.inventory.get_hosts(pattern=pattern)
|
||||
name = "Run command {} on {}".format(cmd, ", ".join([host.name for host in hosts]))
|
||||
name = "Run command {} on {}'s hosts".format(cmd, len(hosts))
|
||||
return self.run(tasks, pattern, play_name=name)
|
||||
|
||||
|
Reference in New Issue
Block a user