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