class Executor(CmdExecutor): __slots__ = 'history', 'counter', 'exchanger' def __init__(self, history): super(Executor, self).__init__() self.history = history self.counter = 0 self.exchanger = KVExchanger(self.CANCEL_PREFIX + str(self.history.id)) @property def output(self): return self.history.raw_stdout @output.setter def output(self, value): pass # nocv def working_handler(self, proc): if proc.poll() is None and self.exchanger.get() is not None: self.write_output("\n[ERROR]: User interrupted execution") self.exchanger.delete() proc.kill() proc.wait() super(Executor, self).working_handler(proc) def write_output(self, line): self.counter += 1 self.history.write_line(line, self.counter, '\n') def execute(self, cmd, cwd): pm_ansible_path = ' '.join(self.pm_ansible()) self.history.raw_args = " ".join(cmd).replace(pm_ansible_path, '').lstrip() return super(Executor, self).execute(cmd, cwd)
def cancel(self, request, *args, **kwargs): ''' Cencel working task. ''' obj = self.get_object() exch = KVExchanger(utils.CmdExecutor.CANCEL_PREFIX + str(obj.id)) exch.send(True, 60) if obj.working else None return base.Response("Task canceled: {}".format(obj.id), status.HTTP_200_OK).resp
def __init__(self, history: History): super(Executor, self).__init__() self.history = history self.counter = 0 self.exchanger = KVExchanger(self.CANCEL_PREFIX + str(self.history.id)) env_vars = {} if self.history.project is not None: env_vars = self.history.project.env_vars self.env = env_vars
class Executor(CmdExecutor): __slots__ = 'history', 'counter', 'exchanger' def __init__(self, history: History): super(Executor, self).__init__() self.history = history self.counter = 0 self.exchanger = KVExchanger(self.CANCEL_PREFIX + str(self.history.id)) env_vars = {} if self.history.project is not None: env_vars = self.history.project.env_vars self.env = env_vars @property def output(self) -> Text: # Optimize for better performance. return '' @output.setter def output(self, value) -> NoReturn: pass # nocv def working_handler(self, proc: Popen): if proc.poll() is None and self.exchanger.get() is not None: # nocv self.write_output("\n[ERROR]: User interrupted execution") self.exchanger.delete() for _ in range(5): try: os.kill(-proc.pid, signal.SIGTERM) except Exception: # nocv break proc.send_signal(signal.SIGINT) time.sleep(5) proc.terminate() proc.kill() proc.wait() super(Executor, self).working_handler(proc) def write_output(self, line: Text): self.counter += 1 self.history.write_line(line, self.counter, '\n') def execute(self, cmd: Iterable[Text], cwd: Text): pm_ansible_path = ' '.join(self.pm_ansible()) new_cmd = list() for one_cmd in cmd: if isinstance(one_cmd, str): with raise_context(): one_cmd = one_cmd.decode('utf-8') new_cmd.append(one_cmd) self.history.raw_args = " ".join(new_cmd).replace(pm_ansible_path, '').lstrip() return super(Executor, self).execute(new_cmd, cwd)
def line_handler(self, proc, line): if KVExchanger(self.CANCEL_PREFIX + str(self.history.id)).get() is not None: self.write_output("\n[ERROR]: User interrupted execution") proc.kill() proc.wait() return True return super(Executor, self).line_handler(proc, line)
class Executor(CmdExecutor): __slots__ = 'history', 'counter', 'exchanger' def __init__(self, history): super(Executor, self).__init__() self.history = history self.counter = 0 self.exchanger = KVExchanger(self.CANCEL_PREFIX + str(self.history.id)) env_vars = {} if self.history.project is not None: env_vars = self.history.project.env_vars self.env = env_vars @property def output(self): return self.history.raw_stdout @output.setter def output(self, value): pass # nocv def working_handler(self, proc): if proc.poll() is None and self.exchanger.get() is not None: # nocv self.write_output("\n[ERROR]: User interrupted execution") self.exchanger.delete() proc.kill() proc.wait() super(Executor, self).working_handler(proc) def write_output(self, line): self.counter += 1 self.history.write_line(line, self.counter, '\n') def execute(self, cmd, cwd): pm_ansible_path = ' '.join(self.pm_ansible()) new_cmd = list() for one_cmd in cmd: if isinstance(one_cmd, six.string_types): with raise_context(): one_cmd = one_cmd.decode('utf-8') new_cmd.append(one_cmd) self.history.raw_args = " ".join(new_cmd).replace(pm_ansible_path, '').lstrip() return super(Executor, self).execute(new_cmd, cwd)
def test_executor(self): # test output on `sleep --help` output = [] def add_line(line, line_number, endl=''): # pylint: disable=unused-argument output.append(line) history = MagicMock() history.id = 999 history.write_line = add_line executor = Executor(history) executor.execute(['echo', 'Hello'], '/') result = "\n".join(output) self.assertIn("Hello", result) # test interrupt on `sleep 5m` KVExchanger(Executor.CANCEL_PREFIX + str(history.id)).send(True, 10) executor = Executor(history) with self.assertRaises(CalledProcessError): executor.execute(['bash', '-c', '"exit 1"'], '/')
def __init__(self, history): super(Executor, self).__init__() self.history = history self.counter = 0 self.exchanger = KVExchanger(self.CANCEL_PREFIX + str(self.history.id))
def cancel_task_on_delete_history(instance: History, **kwargs) -> NoReturn: exchange = KVExchanger(CmdExecutor.CANCEL_PREFIX + str(instance.id)) exchange.send(True, 60) if instance.working else None
def cancel(self, request, *args, **kwargs): obj = self.get_object() exch = KVExchanger(utils.CmdExecutor.CANCEL_PREFIX + str(obj.id)) exch.send(True, 10) return base.Response("Task canceled: {}".format(obj.id), 200).resp