import json import threading import queue import time import traceback from mod.base.ssh_executor import SSHExecutor from mod.project.node.dbutil import ServerNodeDB, ExecutorDB, ExecutorLog class Task(object): def __init__(self, task_id: int, log_id: int): self._edb = ExecutorDB() self.task = self._edb.ExecutorTask.find("id = ?", (task_id,)) if not self.task: raise RuntimeError("The specified task does not exist") if log_id == 0: self.task.elogs = self._edb.ExecutorLog.query("executor_task_id = ?", (self.task.id,)) else: self.task.elogs = [self._edb.ExecutorLog.find("executor_task_id = ? AND id = ?", (self.task.id, log_id))] if not self.task.elogs: raise RuntimeError("Task has no execution entry") self.end_queue = queue.Queue() self.end_status = False def end_func(self): self._edb = ExecutorDB() while not self.end_queue.empty() or not self.end_status: if self.end_queue.empty(): time.sleep(0.1) elog: ExecutorLog = self.end_queue.get() self._edb.ExecutorLog.update(elog) def start(self): thread_list = [] s_db = ServerNodeDB() for log in self.task.elogs: node = s_db.get_node_by_id(log.server_id) if not node: log.status = 2 log.update_log("Node data loss, unable to execute\n") self._edb.ExecutorLog.update(log) ssh_conf = json.loads(node["ssh_conf"]) if not ssh_conf: log.status = 2 log.update_log("Node SSH configuration data lost, unable to execute\n") self._edb.ExecutorLog.update(log) thread = threading.Thread(target=self.run_one, args=(ssh_conf, log)) thread.start() thread_list.append(thread) self._edb.close() end_th = threading.Thread(target=self.end_func) end_th.start() for i in thread_list: i.join() self.end_status = True end_th.join() def run_one(self, ssh_conf: dict, elog: ExecutorLog): ssh = SSHExecutor( host=ssh_conf["host"], port=ssh_conf["port"], username=ssh_conf["username"], password=ssh_conf["password"], key_data=ssh_conf["pkey"], passphrase=ssh_conf["pkey_passwd"]) elog.write_log("Start executing the task\nStart establishing SSH connection...\n") try: ssh.open() def on_stdout(data): if isinstance(data, bytes): data = data.decode() print(data) elog.write_log(data) elog.write_log("Start executing script...\n\n") t = time.time() res_code = ssh.execute_script_streaming( script_content=self.task.script_content, script_type=self.task.script_type, timeout=60*60, on_stdout=on_stdout, on_stderr=on_stdout ) take_time = round((time.time() - t)* 1000, 2) elog.write_log("\n\nExecution completed, time-consuming [{}ms]\n".format(take_time)) if res_code == 0: elog.status = 1 elog.write_log("Mission accomplished\n", is_end_log=True) else: elog.status = 3 elog.write_log("Task exception, return status code is:{}\n".format(res_code), is_end_log=True) self.end_queue.put(elog) except Exception as e: traceback.print_exc() elog.status = 2 elog.write_log("\nTask failed, error:" + str(e), is_end_log=True) self.end_queue.put(elog) return # log_id 要执行的子任务,默认为 0,表示执行所有子任务 def run_executor_task(task_id: int, log_id: int = 0): t = Task(task_id, log_id) t.start()