diff --git a/eoptasks/eoptasks.py b/eoptasks/eoptasks.py index d697247..3ab8e76 100755 --- a/eoptasks/eoptasks.py +++ b/eoptasks/eoptasks.py @@ -38,6 +38,7 @@ import json import os import random import re +import subprocess import socket import sys import time @@ -64,12 +65,6 @@ class Server: def __repr__(self): return '' % (self.name, self.keywords) - def shell(self): - return 'ssh %s' % self.name - - def cmd(self, cmd, *args): - return 'ssh -t %s "%s %s"' % (self.name, cmd, ' '.join(args)) - def get_servers(): servers = [] @@ -97,6 +92,8 @@ def parse_args(): parser.add_argument('-l', '--list-servers', action='store_true') parser.add_argument('--session-name', dest='session_name', type=str) parser.add_argument('--status-window', action='store_true') + parser.add_argument('--command-window', action='store_true') + parser.add_argument('--command-server-name', dest='command_server_name', type=str) parser.add_argument('-k', dest='keywords', type=str) parser.add_argument('cmd', type=str, nargs='?', default=None) parser.add_argument('args', nargs=argparse.REMAINDER) @@ -118,7 +115,8 @@ def filter_servers(servers, args): selected_servers = servers return selected_servers -def status_window(session_name): +def status_window(args): + session_name = args.session_name curses.setupterm() window = curses.initscr() window.addstr(0, 0, 'eoptasks', curses.A_STANDOUT) @@ -130,6 +128,7 @@ def status_window(session_name): sock.bind(server_address) sock.listen(1) e = None + servers_results = {} while True: connection, client_address = sock.accept() try: @@ -139,10 +138,15 @@ def status_window(session_name): if not data: break json_msg += data - servers_info = json.loads(json_msg.decode('utf-8')) + msg = json.loads(json_msg.decode('utf-8')) finally: connection.close() + if msg.get('@type') == 'servers-info': + servers_info = msg['info'] + elif msg.get('@type') == 'server-result': + servers_results.update(msg['info']) + try: height, width = window.getmaxyx() max_length = max([len(x) for x in servers_info.keys()]) + 4 @@ -156,6 +160,8 @@ def status_window(session_name): 'running': '⏳', 'done': '🆗', }.get(servers_info[server_name]['status'], '💤') + if servers_results.get(server_name) == 'error': + status_icon = '❗' window.addstr(y, x, status_icon) if y > height-4: break @@ -174,10 +180,57 @@ def status_window(session_name): time.sleep(5) +def send_status_message(tmux_session_name, msg): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + server_address = '/tmp/.eoptasks.%s' % tmux_session_name + try: + sock.connect(server_address) + except socket.error as e: + return + sock.sendall(json.dumps(msg).encode('utf-8')) + sock.close() + + +def command_window(args): + tmux_session_name = args.session_name + cmd = { + 'apt.update': 'sudo apt update', + 'apt.upgrade': 'sudo apt update && sudo apt full-upgrade -y', + # collectstatic is useful after an upgrade of gadjo. + 'collectstatic': '''sudo -u authentic-multitenant authentic2-multitenant-manage collectstatic --noinput; + sudo -u bijoe bijoe-manage collectstatic --noinput; + sudo -u chrono chrono-manage collectstatic --noinput; + sudo -u combo combo-manage collectstatic --noinput; + sudo -u corbo corbo-manage collectstatic --noinput; + sudo -u fargo fargo-manage collectstatic --noinput; + sudo -u hobo hobo-manage collectstatic --noinput; + sudo -u passerelle passerelle-manage collectstatic --noinput; + sudo -u wcs wcs-manage collectstatic; + /bin/true'''.replace('\n', ''), + # combo.reload is useful to get a new {% start_timestamp %} after an + # upgrade of publik-base-theme. + 'combo.reload': '''sudo service combo reload; /bin/true''', + # hobo-agent.restart is the fastest way to get the number of threads + # used by celery under control :/ + 'hobo-agent.restart': '''test -e /etc/hobo-agent/settings.py && sudo supervisorctl restart hobo-agent''', + }.get(args.cmd, args.cmd) + if args.args: + cmd += ' ' + ' '.join(['"%s"' % x for x in args.args]) + rc = subprocess.call(['ssh', '-t', args.command_server_name] + [cmd]) + if rc != 0: + send_status_message(tmux_session_name, + {'@type': 'server-result', + 'info': {args.command_server_name: 'error'}}) + input('type enter to quit --> ') + args = parse_args() -if args.session_name and args.status_window: - status_window(args.session_name) +if args.status_window: + status_window(args) + sys.exit(0) + +if args.command_window: + command_window(args) sys.exit(0) servers = get_servers() @@ -203,6 +256,7 @@ def init_tmux_session(): os.unlink(server_address) except OSError: pass + os.environ['SHELL'] = '/bin/sh' os.system('tmux new-session -s %s -n 🌑 -d %s --status-window --session-name %s' % ( tmux_session_name, sys.argv[0], tmux_session_name)) return tmux_session_name @@ -220,28 +274,6 @@ else: tmux = libtmux.Server() session = tmux.find_where({'session_name': tmux_session_name}) - cmd = { - 'apt.update': 'sudo apt update', - 'apt.upgrade': 'sudo apt update && sudo apt full-upgrade -y', - # collectstatic is useful after an upgrade of gadjo. - 'collectstatic': '''sudo -u authentic-multitenant authentic2-multitenant-manage collectstatic --noinput; - sudo -u bijoe bijoe-manage collectstatic --noinput; - sudo -u chrono chrono-manage collectstatic --noinput; - sudo -u combo combo-manage collectstatic --noinput; - sudo -u corbo corbo-manage collectstatic --noinput; - sudo -u fargo fargo-manage collectstatic --noinput; - sudo -u hobo hobo-manage collectstatic --noinput; - sudo -u passerelle passerelle-manage collectstatic --noinput; - sudo -u wcs wcs-manage collectstatic; - /bin/true'''.replace('\n', ''), - # combo.reload is useful to get a new {% start_timestamp %} after an - # upgrade of publik-base-theme. - 'combo.reload': '''sudo service combo reload; /bin/true''', - # hobo-agent.restart is the fastest way to get the number of threads - # used by celery under control :/ - 'hobo-agent.restart': '''test -e /etc/hobo-agent/settings.py && sudo supervisorctl restart hobo-agent''', - }.get(args.cmd, args.cmd) - status_window = session.attached_window all_servers = selected_servers[:] @@ -260,15 +292,7 @@ else: server_info['status'] = 'running' elif server_info['status'] == 'running': server_info['status'] = 'done' - - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - server_address = '/tmp/.eoptasks.%s' % tmux_session_name - try: - sock.connect(server_address) - except socket.error: - return - sock.sendall(json.dumps(servers_info).encode('utf-8')) - sock.close() + send_status_message(tmux_session_name, {'@type': 'servers-info', 'info': servers_info}) while selected_servers: current_clusters = [cluster_name(x.name) for x in session.list_windows()] @@ -276,10 +300,16 @@ else: if cluster_name(server.name) in current_clusters: continue selected_servers.remove(server) + window_cmd = '%s --session-name %s --command-window --command-server-name %s "%s" %s' % ( + sys.argv[0], + tmux_session_name, + server.name, + args.cmd, + ' '.join(['"%s"' % x for x in args.args])) session.new_window( attach=False, window_name=server.name, - window_shell=server.cmd(cmd, *args.args)) + window_shell=window_cmd) break else: time.sleep(0.1)