| #!/usr/bin/env python3 | 
 |  | 
 | import argparse | 
 | import sys | 
 | import time | 
 | import toml | 
 | from os import path | 
 | from telnetlib import Telnet | 
 | from types import MethodType | 
 | from xdg import BaseDirectory | 
 |  | 
 | def expect_or_raise(conn, patterns, timeout=None): | 
 |     i, m, d = conn.expect([bytes(p, 'ascii') for p in patterns], timeout) | 
 |     if i == -1: | 
 |         msg = "Match failed, expected '%s', got '%s'" % (str(patterns), d) | 
 |         print(msg, file=sys.stderr) | 
 |         raise ValueError | 
 |     return i, m, d | 
 |  | 
 | def encode_and_write(conn, comm="", sep="\n"): | 
 |     # Slow down the writes to help poor ol' serial-over-telnet | 
 |     for c in comm + sep: | 
 |         conn.write(bytes(c, 'ascii')) | 
 |         time.sleep(0.01) | 
 |  | 
 | def init_telnet(host, port=0, timeout=None): | 
 |     conn = Telnet(host, port, timeout) | 
 |     conn.encode_and_write = MethodType(encode_and_write, conn) | 
 |     conn.expect_or_raise = MethodType(expect_or_raise, conn) | 
 |     return conn | 
 |  | 
 |  | 
 | def main(): | 
 |     parser = argparse.ArgumentParser() | 
 |     parser.add_argument("machine", nargs="?") | 
 |     parser.add_argument("-l", "--list-machines", action="store_true") | 
 |     parser.add_argument("-i", "--initramfs", action="store_true") | 
 |     args = parser.parse_args() | 
 |  | 
 |     confbase = BaseDirectory.save_config_path("obmc-scripts") | 
 |     conffile = path.join(confbase, "netboot") | 
 |     if not path.exists(conffile): | 
 |         print("Missing configuration file: %s" % (conffile)) | 
 |         sys.exit(1) | 
 |  | 
 |     conf = toml.load(conffile) | 
 |     if args.list_machines: | 
 |         print("Machines:", *list(sorted(conf.keys())), sep="\n\t") | 
 |         sys.exit(0) | 
 |  | 
 |     if not args.machine: | 
 |         print("Machine name required") | 
 |         sys.exit(1) | 
 |  | 
 |     mach = conf[args.machine] | 
 |     console = mach["console"] | 
 |     conn = init_telnet(console["host"], console["port"]) | 
 |  | 
 |     try: | 
 |         conn.encode_and_write() | 
 |         i, m, d = conn.expect_or_raise([ | 
 |             "%s login:" % (mach["platform"]), | 
 |             "root@%s:.*#" % (mach["platform"]), | 
 |             "root@%s:.*#" % (args.machine), | 
 |             "ast#", | 
 |             "# ", | 
 |         ], 5) | 
 |  | 
 |         if i != 3: | 
 |             if i == 0: | 
 |                 conn.encode_and_write(mach["user"]) | 
 |                 conn.read_until(b"Password:") | 
 |                 conn.encode_and_write(mach["password"]) | 
 |                 conn.expect_or_raise(["root@%s:.*#" % (mach["platform"])]) | 
 |  | 
 |             conn.encode_and_write("reboot") | 
 |  | 
 |             conn.expect_or_raise(["Hit any key to stop autoboot"]) | 
 |             conn.encode_and_write() | 
 |  | 
 |         for comm in mach["u-boot"]["commands"]: | 
 |             conn.encode_and_write(comm) | 
 |             if "tftp" in comm: | 
 |                 i, m, d = conn.expect_or_raise([ | 
 |                     r"Bytes transferred = \d+ \([0-9a-f]+ hex\)", | 
 |                     "Not retrying...", | 
 |                     r"## Warning:", | 
 |                     r"[*]{3} ERROR:", | 
 |                     "Abort", | 
 |                     "Retry count exceeded; starting again", | 
 |                 ]) | 
 |                 if i > 0: | 
 |                     print("Error detected, exiting", file=sys.stderr) | 
 |                     return | 
 |  | 
 |         if args.initramfs: | 
 |             conn.encode_and_write("setenv bootargs console=ttyS4,115200n root=/dev/ram rw earlyprintk debug") | 
 |             conn.read_until(b"ast#") | 
 |         else: | 
 |             conn.encode_and_write("printenv set_bootargs") | 
 |             i, m, d = conn.expect_or_raise([ | 
 |                 "set_bootargs=.*$", | 
 |                 "## Error: \"set_bootargs\" not defined", | 
 |             ], 1) | 
 |             if i == 0: | 
 |                 conn.encode_and_write("run set_bootargs") | 
 |                 conn.read_until(b"ast#") | 
 |  | 
 |         conn.encode_and_write("bootm") | 
 |         conn.read_until(b"Starting kernel") | 
 |     finally: | 
 |         conn.close() | 
 |  | 
 | if __name__ == "__main__": | 
 |     main() |