At the company I work at, we have no real way to quickly execute shell commands on all of our customers systems, which often results in what we call
Tiny Tim tasks, where the list of all of our systems is split between the 5 devs we have, and we simply go through one-by-one, SSHing into each one and executing the necessary commands.
To streamline this process, I created a script in Python3 using Paramiko for SSH.
The script takes the path to a private OpenSSH key from command-line args, reads a list of hosts from a file called
hosts.txt (lines in this file can be commented by prepending them with
--), and a list of shell commands from a file called
cmds.txt. Due to the way we set up our customers' systems, each domain has 2 servers, so the script loops over each host in the list twice, prepending
disc2. respectively to send the commands to both servers.
from paramiko.client import AutoAddPolicy from paramiko.client import SSHClient import sys from sys import argv if len(argv) < 2: print("Invalid args!") print("Usage: python3 run.py <private ssh key filepath>") exit() with open('cmds.txt') as c: cmds = c.readlines() with open('hosts.txt') as f: lines = f.readlines() for line in lines: for i in range(1, 3): line = line.strip() host = "disc%s.%s" % (i, line) if line.startswith('--'): print("Host %s began with --, skipping" % line) continue client = SSHClient() client.set_missing_host_key_policy(AutoAddPolicy) client.load_system_host_keys() try: print("[%s]> Connecting as root on port 22..." % host) client.connect(host, 22, 'root', None, None, argv) except KeyboardInterrupt: break except Exception as err: print("[%s]> Connection failed: %s" % (host, err)) continue for c in cmds: print("[%s]> Executing %s..." % (host, c.strip())) stdin, stdout, stderr = client.exec_command(c) print(stdout.read().decode('utf-8')) print(stderr.read().decode('utf-8')) client.close() print("[%s]> Done" % host)
I ran it through PEP8 and surprisingly didn't get any errors or warnings, but it's still quite messy and I'd appreciate feedback.