spug/spug_api/apps/schedule/executors.py

55 lines
1.8 KiB
Python

# Copyright: (c) OpenSpug Organization. https://github.com/openspug/spug
# Copyright: (c) <spug.dev@gmail.com>
# Released under the AGPL-3.0 License.
from queue import Queue
from threading import Thread
from libs.ssh import AuthenticationException
from apps.host.models import Host
from django.db import close_old_connections
import subprocess
import socket
import time
def local_executor(q, command):
exit_code, out, now = -1, None, time.time()
try:
task = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
exit_code = task.wait()
out = task.stdout.read() + task.stderr.read()
finally:
q.put(('local', exit_code, round(time.time() - now, 3), out.decode()))
def host_executor(q, host, command):
exit_code, out, now = -1, None, time.time()
try:
cli = host.get_ssh()
exit_code, out = cli.exec_command(command)
out = out if out else None
except AuthenticationException:
out = 'ssh authentication fail'
except socket.error as e:
out = f'network error {e}'
finally:
q.put((host.id, exit_code, round(time.time() - now, 3), out))
def dispatch(command, targets, in_view=False):
if not in_view:
close_old_connections()
threads, q = [], Queue()
for t in targets:
if t == 'local':
threads.append(Thread(target=local_executor, args=(q, command)))
elif isinstance(t, int):
host = Host.objects.filter(pk=t).first()
if not host:
raise ValueError(f'unknown host id: {t!r}')
threads.append(Thread(target=host_executor, args=(q, host, command)))
else:
raise ValueError(f'invalid target: {t!r}')
for t in threads:
t.start()
return [q.get() for _ in threads]