|  | #!/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() |