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