mirror of https://github.com/jumpserver/jumpserver
				
				
				
			
		
			
				
	
	
		
			185 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			185 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Python
		
	
	
import os
 | 
						|
from collections import defaultdict
 | 
						|
from functools import reduce
 | 
						|
 | 
						|
from django.conf import settings
 | 
						|
 | 
						|
 | 
						|
class DefaultCallback:
 | 
						|
    STATUS_MAPPER = {
 | 
						|
        "successful": "success",
 | 
						|
        "failure": "failed",
 | 
						|
        "failed": "failed",
 | 
						|
        "running": "running",
 | 
						|
        "pending": "pending",
 | 
						|
        "timeout": "timeout",
 | 
						|
        "unknown": "unknown",
 | 
						|
    }
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        self.result = dict(
 | 
						|
            ok=defaultdict(dict),
 | 
						|
            failures=defaultdict(dict),
 | 
						|
            dark=defaultdict(dict),
 | 
						|
            skipped=defaultdict(dict),
 | 
						|
            ignored=defaultdict(dict),
 | 
						|
        )
 | 
						|
        self.summary = dict(
 | 
						|
            ok=[],
 | 
						|
            failures={},
 | 
						|
            dark={},
 | 
						|
            skipped=[],
 | 
						|
        )
 | 
						|
        self.status = "running"
 | 
						|
        self.finished = False
 | 
						|
        self.local_pid = 0
 | 
						|
        self.private_data_dir = None
 | 
						|
 | 
						|
    @property
 | 
						|
    def host_results(self):
 | 
						|
        results = defaultdict(dict)
 | 
						|
        for state, hosts in self.result.items():
 | 
						|
            for host, items in hosts.items():
 | 
						|
                results[host][state] = items
 | 
						|
        return results
 | 
						|
 | 
						|
    def is_success(self):
 | 
						|
        return self.status != "success"
 | 
						|
 | 
						|
    def event_handler(self, data, **kwargs):
 | 
						|
        event = data.get("event", None)
 | 
						|
        if not event:
 | 
						|
            return
 | 
						|
 | 
						|
        pid = data.get("pid", None)
 | 
						|
        if pid:
 | 
						|
            self.write_pid(pid)
 | 
						|
 | 
						|
        event_data = data.get("event_data", {})
 | 
						|
        host = event_data.get("remote_addr", "")
 | 
						|
        task = event_data.get("task", "")
 | 
						|
        res = event_data.get("res", {})
 | 
						|
        handler = getattr(self, event, self.on_any)
 | 
						|
        handler(event_data, host=host, task=task, res=res)
 | 
						|
 | 
						|
    def runner_on_ok(self, event_data, host=None, task=None, res=None):
 | 
						|
        detail = {
 | 
						|
            "action": event_data.get("task_action", ""),
 | 
						|
            "res": res,
 | 
						|
            "rc": res.get("rc", 0),
 | 
						|
            "stdout": res.get("stdout", ""),
 | 
						|
        }
 | 
						|
        self.result["ok"][host][task] = detail
 | 
						|
 | 
						|
    def runner_on_skipped(self, event_data, host=None, task=None, **kwargs):
 | 
						|
        detail = {
 | 
						|
            "action": event_data.get("task_action", ""),
 | 
						|
            "res": {},
 | 
						|
            "rc": 0,
 | 
						|
        }
 | 
						|
        self.result["skipped"][host][task] = detail
 | 
						|
 | 
						|
    def runner_on_failed(self, event_data, host=None, task=None, res=None, **kwargs):
 | 
						|
        detail = {
 | 
						|
            "action": event_data.get("task_action", ""),
 | 
						|
            "res": res,
 | 
						|
            "rc": res.get("rc", 0),
 | 
						|
            "stdout": res.get("stdout", ""),
 | 
						|
            "stderr": ";".join([res.get("stderr", ""), res.get("msg", "")]).strip(";"),
 | 
						|
        }
 | 
						|
        ignore_errors = event_data.get("ignore_errors", False)
 | 
						|
        error_key = "ignored" if ignore_errors else "failures"
 | 
						|
        self.result[error_key][host][task] = detail
 | 
						|
 | 
						|
    def runner_on_unreachable(
 | 
						|
        self, event_data, host=None, task=None, res=None, **kwargs
 | 
						|
    ):
 | 
						|
        detail = {
 | 
						|
            "action": event_data.get("task_action", ""),
 | 
						|
            "res": res,
 | 
						|
            "rc": 255,
 | 
						|
            "stderr": ";".join([res.get("stderr", ""), res.get("msg", "")]).strip(";"),
 | 
						|
        }
 | 
						|
        self.result["dark"][host][task] = detail
 | 
						|
 | 
						|
    def runner_on_start(self, event_data, **kwargs):
 | 
						|
        pass
 | 
						|
 | 
						|
    def runner_retry(self, event_data, **kwargs):
 | 
						|
        pass
 | 
						|
 | 
						|
    def runner_on_file_diff(self, event_data, **kwargs):
 | 
						|
        pass
 | 
						|
 | 
						|
    def runner_item_on_failed(self, event_data, **kwargs):
 | 
						|
        pass
 | 
						|
 | 
						|
    def runner_item_on_skipped(self, event_data, **kwargs):
 | 
						|
        pass
 | 
						|
 | 
						|
    def playbook_on_play_start(self, event_data, **kwargs):
 | 
						|
        pass
 | 
						|
 | 
						|
    def playbook_on_stats(self, event_data, **kwargs):
 | 
						|
        error_func = (
 | 
						|
            lambda err, task_detail: err
 | 
						|
            + f"{task_detail[0]}: {task_detail[1]['stderr']};"
 | 
						|
        )
 | 
						|
        for tp in ["dark", "failures"]:
 | 
						|
            for host, tasks in self.result[tp].items():
 | 
						|
                error = reduce(error_func, tasks.items(), "").strip(";")
 | 
						|
                self.summary[tp][host] = error
 | 
						|
        failures = list(self.result["failures"].keys())
 | 
						|
        dark_or_failures = list(self.result["dark"].keys()) + failures
 | 
						|
 | 
						|
        for host, tasks in self.result.get("ignored", {}).items():
 | 
						|
            ignore_errors = reduce(error_func, tasks.items(), "").strip(";")
 | 
						|
            if host in failures:
 | 
						|
                self.summary["failures"][host] += ignore_errors
 | 
						|
 | 
						|
        self.summary["ok"] = list(set(self.result["ok"].keys()) - set(dark_or_failures))
 | 
						|
        self.summary["skipped"] = list(
 | 
						|
            set(self.result["skipped"].keys()) - set(dark_or_failures)
 | 
						|
        )
 | 
						|
 | 
						|
    def playbook_on_include(self, event_data, **kwargs):
 | 
						|
        pass
 | 
						|
 | 
						|
    def playbook_on_notify(self, event_data, **kwargs):
 | 
						|
        pass
 | 
						|
 | 
						|
    def playbook_on_vars_prompt(self, event_data, **kwargs):
 | 
						|
        pass
 | 
						|
 | 
						|
    def playbook_on_handler_task_start(self, event_data, **kwargs):
 | 
						|
        pass
 | 
						|
 | 
						|
    def playbook_on_no_hosts_matched(self, event_data, **kwargs):
 | 
						|
        pass
 | 
						|
 | 
						|
    def playbook_on_no_hosts_remaining(self, event_data, **kwargs):
 | 
						|
        pass
 | 
						|
 | 
						|
    def playbook_on_start(self, event_data, **kwargs):
 | 
						|
        if settings.DEBUG_DEV:
 | 
						|
            print("DEBUG: delete inventory: ", os.path.join(self.private_data_dir, 'inventory'))
 | 
						|
        inventory_path = os.path.join(self.private_data_dir, 'inventory', 'hosts')
 | 
						|
        if os.path.exists(inventory_path):
 | 
						|
            os.remove(inventory_path)
 | 
						|
 | 
						|
    def warning(self, event_data, **kwargs):
 | 
						|
        pass
 | 
						|
 | 
						|
    def on_any(self, event_data, **kwargs):
 | 
						|
        pass
 | 
						|
 | 
						|
    def status_handler(self, data, **kwargs):
 | 
						|
        status = data.get("status", "")
 | 
						|
        self.status = self.STATUS_MAPPER.get(status, "unknown")
 | 
						|
        self.private_data_dir = data.get("private_data_dir", None)
 | 
						|
 | 
						|
    def write_pid(self, pid):
 | 
						|
        pid_filepath = os.path.join(self.private_data_dir, "local.pid")
 | 
						|
        with open(pid_filepath, "w") as f:
 | 
						|
            f.write(str(pid))
 |