Skip to content

Instantly share code, notes, and snippets.

@mbruzek
Created February 4, 2020 15:54
Show Gist options
  • Save mbruzek/f5304105b86dc257b0b816f45ce35546 to your computer and use it in GitHub Desktop.
Save mbruzek/f5304105b86dc257b0b816f45ce35546 to your computer and use it in GitHub Desktop.
Automating an un-automatable network switch required some creative programming. Create an SSH session inside a pseudo terminal (pty), then read and write the file descriptor.
#!/usr/bin/python3
import argparse
import getpass
import os
import pty
import re
import sys
import time
commands_iterator = None
logfile = None
ssh_password = None
def interact(fd):
""" The function that operates on the pty session's file descriptor. """
password_pattern = b"(.+)@(.+)'s password: "
prompt_pattern = b"[$#>]\s+$"
# The spawn command recommends reading 1024 bytes at a time.
data = os.read(fd, 1024)
if re.search(password_pattern, data):
# The ssh password prompt signature found, write the password.
os.write(fd, (ssh_password + "\n").encode("utf-8"))
elif re.search(prompt_pattern, data):
# The prompt signature was found, write the next command.
os.write(fd, next(commands_iterator).encode("utf-8"))
if logfile:
logfile.write(data)
logfile.flush()
return data
def main():
""" The main function makes this script an applicaiton. """
parser = argparse.ArgumentParser(description="Use a pseudo terminal (pty) to run a list of commands via ssh.")
parser.add_argument("-u", "--user", help="the user to use for ssh")
parser.add_argument("-a", "--address", help="the host address to ssh to")
parser.add_argument("-p", "--password", help="the ssh password to use")
parser.add_argument("file", help="the path to the file of commands")
args = parser.parse_args()
if not os.path.isfile(args.file):
print("The path to the commands file does not exist.")
exit(-1)
with open(args.file) as commands_file:
global command_iterator
commands_iterator = iter(commands_file.readlines())
logfilename = "{0}.log".format(os.path.splitext(args.file)[0])
global logfile
logfile = open(logfilename, "ab")
global ssh_password
if args.password:
ssh_password = args.password
else:
ssh_password = getpass.getpass()
ssh = [
"ssh",
"-o StrictHostKeyChecking=no",
"{0}@{1}".format(args.user, args.address)
]
# Spawn a new ssh session within a pty, the interact function will read and write to the file descriptor.
pty.spawn(ssh, interact)
print("{0} completed successfully.".format(sys.argv[0]))
sys.exit(0)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment