1*cf3c1e67SAndrew Jeffery#!/usr/bin/python3 2*cf3c1e67SAndrew Jeffery 3*cf3c1e67SAndrew Jefferyimport argparse 4*cf3c1e67SAndrew Jefferyimport pexpect 5*cf3c1e67SAndrew Jefferyimport sys 6*cf3c1e67SAndrew Jefferyimport time 7*cf3c1e67SAndrew Jeffery 8*cf3c1e67SAndrew Jefferyfrom collections import namedtuple 9*cf3c1e67SAndrew Jeffery 10*cf3c1e67SAndrew JefferyEndpoint = namedtuple("Endpoint", "host, port") 11*cf3c1e67SAndrew JefferyCredentials = namedtuple("Credentials", "username, password") 12*cf3c1e67SAndrew JefferyTarget = namedtuple("Target", "credentials, endpoint") 13*cf3c1e67SAndrew JefferyEntity = namedtuple("Entity", "console, ssh") 14*cf3c1e67SAndrew JefferyMachine = namedtuple("Machine", "bmc, host") 15*cf3c1e67SAndrew Jeffery 16*cf3c1e67SAndrew Jefferyclass Obmcutil(object): 17*cf3c1e67SAndrew Jeffery BMC_READY = "xyz.openbmc_project.State.BMC.BMCState.Ready" 18*cf3c1e67SAndrew Jeffery BMC_NOT_READY = "xyz.openbmc_project.State.BMC.BMCState.NotReady" 19*cf3c1e67SAndrew Jeffery 20*cf3c1e67SAndrew Jeffery HOST_OFF = "xyz.openbmc_project.State.Host.HostState.Off" 21*cf3c1e67SAndrew Jeffery HOST_ON = "xyz.openbmc_project.State.Host.HostState.Running" 22*cf3c1e67SAndrew Jeffery HOST_QUIESCED = "xyz.openbmc_project.State.Host.HostState.Quiesced" 23*cf3c1e67SAndrew Jeffery 24*cf3c1e67SAndrew Jeffery def __init__(self, session, prompt): 25*cf3c1e67SAndrew Jeffery self.session = session 26*cf3c1e67SAndrew Jeffery self.prompt = prompt 27*cf3c1e67SAndrew Jeffery 28*cf3c1e67SAndrew Jeffery def _clear(self): 29*cf3c1e67SAndrew Jeffery self.session.expect([".+".encode(), pexpect.TIMEOUT], timeout=5) 30*cf3c1e67SAndrew Jeffery 31*cf3c1e67SAndrew Jeffery def _state(self, cmd, needle): 32*cf3c1e67SAndrew Jeffery self.session.sendline() 33*cf3c1e67SAndrew Jeffery self._clear() 34*cf3c1e67SAndrew Jeffery self.session.sendline("obmcutil -w {}".format(cmd).encode()) 35*cf3c1e67SAndrew Jeffery self.session.expect(needle, timeout=None) 36*cf3c1e67SAndrew Jeffery rc = self.session.after.decode() 37*cf3c1e67SAndrew Jeffery return rc 38*cf3c1e67SAndrew Jeffery 39*cf3c1e67SAndrew Jeffery def hoststate(self): 40*cf3c1e67SAndrew Jeffery return self._state("hoststate", "xyz\.openbmc_project\.State\.Host\.HostState\.(Off|Running|Quiesced)") 41*cf3c1e67SAndrew Jeffery 42*cf3c1e67SAndrew Jeffery def bmcstate(self): 43*cf3c1e67SAndrew Jeffery return self._state("bmcstate", "xyz\.openbmc_project\.State\.BMC\.BMCState\.(Not)?Ready") 44*cf3c1e67SAndrew Jeffery 45*cf3c1e67SAndrew Jeffery def poweron(self): 46*cf3c1e67SAndrew Jeffery self.session.sendline("obmcutil -w poweron") 47*cf3c1e67SAndrew Jeffery self.session.expect(self.prompt) 48*cf3c1e67SAndrew Jeffery 49*cf3c1e67SAndrew Jeffery def chassisoff(self): 50*cf3c1e67SAndrew Jeffery self.session.sendline("obmcutil -w chassisoff") 51*cf3c1e67SAndrew Jeffery self.session.expect(self.prompt) 52*cf3c1e67SAndrew Jeffery 53*cf3c1e67SAndrew Jefferyclass PexpectLogger(object): 54*cf3c1e67SAndrew Jeffery def write(self, bstring): 55*cf3c1e67SAndrew Jeffery try: 56*cf3c1e67SAndrew Jeffery sys.stdout.write(bstring.decode()) 57*cf3c1e67SAndrew Jeffery except UnicodeDecodeError: 58*cf3c1e67SAndrew Jeffery print("Dropping broken unicode line") 59*cf3c1e67SAndrew Jeffery 60*cf3c1e67SAndrew Jeffery def flush(self): 61*cf3c1e67SAndrew Jeffery sys.stdout.flush() 62*cf3c1e67SAndrew Jeffery 63*cf3c1e67SAndrew Jeffery 64*cf3c1e67SAndrew Jefferyclass Bmc(object): 65*cf3c1e67SAndrew Jeffery def __init__(self, entity): 66*cf3c1e67SAndrew Jeffery self.getty = "login: ".encode() 67*cf3c1e67SAndrew Jeffery self.shell = "# ".encode() 68*cf3c1e67SAndrew Jeffery self.entity = entity 69*cf3c1e67SAndrew Jeffery fargs = (entity.console.endpoint.host, entity.console.endpoint.port) 70*cf3c1e67SAndrew Jeffery self.session = pexpect.spawn("telnet {} {}".format(*fargs)) 71*cf3c1e67SAndrew Jeffery self.session.logfile = PexpectLogger() 72*cf3c1e67SAndrew Jeffery self.obmcutil = Obmcutil(self.session, self.shell) 73*cf3c1e67SAndrew Jeffery self.session.sendline() 74*cf3c1e67SAndrew Jeffery rc = self.session.expect([self.getty, self.shell]) 75*cf3c1e67SAndrew Jeffery if rc == 0: 76*cf3c1e67SAndrew Jeffery self.login() 77*cf3c1e67SAndrew Jeffery 78*cf3c1e67SAndrew Jeffery def login(self): 79*cf3c1e67SAndrew Jeffery self.session.sendline(self.entity.console.credentials.username.encode()) 80*cf3c1e67SAndrew Jeffery self.session.expect("Password: ".encode()) 81*cf3c1e67SAndrew Jeffery self.session.sendline(self.entity.console.credentials.password.encode()) 82*cf3c1e67SAndrew Jeffery self.session.expect(self.shell) 83*cf3c1e67SAndrew Jeffery 84*cf3c1e67SAndrew Jeffery def reboot(self): 85*cf3c1e67SAndrew Jeffery self.session.sendline("reboot") 86*cf3c1e67SAndrew Jeffery self.session.expect("Hit any key to stop autoboot:".encode(), timeout=None) 87*cf3c1e67SAndrew Jeffery self.session.expect(self.getty, timeout=None) 88*cf3c1e67SAndrew Jeffery self.login() 89*cf3c1e67SAndrew Jeffery state = self.obmcutil.bmcstate() 90*cf3c1e67SAndrew Jeffery while state != self.obmcutil.BMC_READY: 91*cf3c1e67SAndrew Jeffery print("Wanted state '{}', got state '{}'".format(self.obmcutil.BMC_READY, state)) 92*cf3c1e67SAndrew Jeffery time.sleep(5) 93*cf3c1e67SAndrew Jeffery state = self.obmcutil.bmcstate() 94*cf3c1e67SAndrew Jeffery 95*cf3c1e67SAndrew Jeffery def chassisoff(self): 96*cf3c1e67SAndrew Jeffery self.obmcutil.chassisoff() 97*cf3c1e67SAndrew Jeffery 98*cf3c1e67SAndrew Jeffery def poweron(self): 99*cf3c1e67SAndrew Jeffery hs = self.obmcutil.hoststate() 100*cf3c1e67SAndrew Jeffery print("Host state is: {}".format(hs)) 101*cf3c1e67SAndrew Jeffery if hs in (self.obmcutil.HOST_ON, self.obmcutil.HOST_QUIESCED): 102*cf3c1e67SAndrew Jeffery self.obmcutil.chassisoff() 103*cf3c1e67SAndrew Jeffery self.obmcutil.poweron() 104*cf3c1e67SAndrew Jeffery 105*cf3c1e67SAndrew Jefferyclass Host(object): 106*cf3c1e67SAndrew Jeffery def __init__(self, entity, bmc): 107*cf3c1e67SAndrew Jeffery self.shell = "/? *#".encode() 108*cf3c1e67SAndrew Jeffery self.petitboot = "Petitboot".encode() 109*cf3c1e67SAndrew Jeffery self.session = None 110*cf3c1e67SAndrew Jeffery self.entity = entity 111*cf3c1e67SAndrew Jeffery self.bmc = bmc 112*cf3c1e67SAndrew Jeffery self.connect() 113*cf3c1e67SAndrew Jeffery 114*cf3c1e67SAndrew Jeffery def connect(self): 115*cf3c1e67SAndrew Jeffery fargs = (self.entity.console.endpoint.port, 116*cf3c1e67SAndrew Jeffery self.entity.console.credentials.username, 117*cf3c1e67SAndrew Jeffery self.entity.console.endpoint.host) 118*cf3c1e67SAndrew Jeffery self.session = pexpect.spawn("ssh -p{} {}@{}".format(*fargs)) 119*cf3c1e67SAndrew Jeffery self.session.logfile = PexpectLogger() 120*cf3c1e67SAndrew Jeffery self.session.expect("password:".encode()) 121*cf3c1e67SAndrew Jeffery self.session.sendline(self.entity.console.credentials.password.encode()) 122*cf3c1e67SAndrew Jeffery 123*cf3c1e67SAndrew Jeffery def poweron(self): 124*cf3c1e67SAndrew Jeffery self.bmc.chassisoff() 125*cf3c1e67SAndrew Jeffery self.bmc.poweron() 126*cf3c1e67SAndrew Jeffery self.session.send('\f') 127*cf3c1e67SAndrew Jeffery rc = self.session.expect([self.petitboot, self.shell], timeout=None) 128*cf3c1e67SAndrew Jeffery if rc == 0: 129*cf3c1e67SAndrew Jeffery self.session.sendline() 130*cf3c1e67SAndrew Jeffery self.session.expect(self.shell) 131*cf3c1e67SAndrew Jeffery 132*cf3c1e67SAndrew Jeffery def reboot(self): 133*cf3c1e67SAndrew Jeffery self.session.send('\f') 134*cf3c1e67SAndrew Jeffery rc = self.session.expect([self.petitboot, self.shell], timeout=None) 135*cf3c1e67SAndrew Jeffery if rc == 0: 136*cf3c1e67SAndrew Jeffery self.session.sendline() 137*cf3c1e67SAndrew Jeffery self.session.expect(self.shell) 138*cf3c1e67SAndrew Jeffery self.session.sendline("reboot".encode()) 139*cf3c1e67SAndrew Jeffery self.session.expect("INIT: Waiting for kernel...".encode(), timeout=None) 140*cf3c1e67SAndrew Jeffery self.session.expect("Petitboot".encode(), timeout=None) 141*cf3c1e67SAndrew Jeffery self.session.sendline() 142*cf3c1e67SAndrew Jeffery self.session.expect(self.shell) 143*cf3c1e67SAndrew Jeffery 144*cf3c1e67SAndrew Jefferydef rpp(machine): 145*cf3c1e67SAndrew Jeffery bmc = Bmc(machine.bmc) 146*cf3c1e67SAndrew Jeffery host = Host(machine.host, bmc) 147*cf3c1e67SAndrew Jeffery host.poweron() 148*cf3c1e67SAndrew Jeffery while True: 149*cf3c1e67SAndrew Jeffery bmc.reboot() 150*cf3c1e67SAndrew Jeffery host.connect() 151*cf3c1e67SAndrew Jeffery host.reboot() 152*cf3c1e67SAndrew Jeffery 153*cf3c1e67SAndrew Jefferydef main(): 154*cf3c1e67SAndrew Jeffery bmccreds = Credentials("root", "0penBmc") 155*cf3c1e67SAndrew Jeffery b = Entity(Target(bmccreds, Endpoint("serial.concentrator.somewhere.com", 1234)), 156*cf3c1e67SAndrew Jeffery Target(bmccreds, Endpoint("bmc.somewhere.com", 22))) 157*cf3c1e67SAndrew Jeffery h = Entity(Target(bmccreds, Endpoint("bmc.somewhere.com", 2200)), 158*cf3c1e67SAndrew Jeffery Target(Credentials("user", "password"), Endpoint("host.somewhere.com", 22))) 159*cf3c1e67SAndrew Jeffery m = Machine(b, h) 160*cf3c1e67SAndrew Jeffery return rpp(m) 161*cf3c1e67SAndrew Jeffery 162*cf3c1e67SAndrew Jefferyif __name__ == "__main__": 163*cf3c1e67SAndrew Jeffery main() 164