Reboot ping-pong for OpenPOWER systems
Boot the host, then reboot the BMC and then the host ad infinitum.
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Change-Id: Ife6eb6372a94aad162f6b2471b7ca7dbd8538923
diff --git a/amboar/obmc-scripts/reboot-ping-pong/rpp b/amboar/obmc-scripts/reboot-ping-pong/rpp
new file mode 100755
index 0000000..99eae0a
--- /dev/null
+++ b/amboar/obmc-scripts/reboot-ping-pong/rpp
@@ -0,0 +1,160 @@
+#!/usr/bin/python3
+
+import argparse
+import pexpect
+import sys
+import time
+
+from collections import namedtuple
+
+Endpoint = namedtuple("Endpoint", "host, port")
+Credentials = namedtuple("Credentials", "username, password")
+Target = namedtuple("Target", "credentials, endpoint")
+Entity = namedtuple("Entity", "console, ssh")
+Machine = namedtuple("Machine", "bmc, host")
+
+class Obmcutil(object):
+ BMC_READY = "xyz.openbmc_project.State.BMC.BMCState.Ready"
+ BMC_NOT_READY = "xyz.openbmc_project.State.BMC.BMCState.NotReady"
+
+ HOST_OFF = "xyz.openbmc_project.State.Host.HostState.Off"
+ HOST_ON = "xyz.openbmc_project.State.Host.HostState.Running"
+ HOST_QUIESCED = "xyz.openbmc_project.State.Host.HostState.Quiesced"
+
+ def __init__(self, session, prompt):
+ self.session = session
+ self.prompt = prompt
+
+ def _clear(self):
+ self.session.expect([".+".encode(), pexpect.TIMEOUT], timeout=5)
+
+ def _state(self, cmd, needle):
+ self.session.sendline()
+ self._clear()
+ self.session.sendline("obmcutil -w {}".format(cmd).encode())
+ self.session.expect(needle, timeout=None)
+ rc = self.session.after.decode()
+ return rc
+
+ def hoststate(self):
+ return self._state("hoststate", "xyz\.openbmc_project\.State\.Host\.HostState\.(Off|Running|Quiesced)")
+
+ def bmcstate(self):
+ return self._state("bmcstate", "xyz\.openbmc_project\.State\.BMC\.BMCState\.(Not)?Ready")
+
+ def poweron(self):
+ self.session.sendline("obmcutil -w poweron")
+ self.session.expect(self.prompt)
+
+ def chassisoff(self):
+ self.session.sendline("obmcutil -w chassisoff")
+ self.session.expect(self.prompt)
+
+class PexpectLogger(object):
+ def write(self, bstring):
+ sys.stdout.write(bstring.decode())
+
+ def flush(self):
+ sys.stdout.flush()
+
+
+class Bmc(object):
+ def __init__(self, entity):
+ self.getty = "login: ".encode()
+ self.shell = "# ".encode()
+ self.entity = entity
+ fargs = (entity.console.endpoint.host, entity.console.endpoint.port)
+ self.session = pexpect.spawn("telnet {} {}".format(*fargs))
+ self.session.logfile = PexpectLogger()
+ self.obmcutil = Obmcutil(self.session, self.shell)
+ self.session.sendline()
+ rc = self.session.expect([self.getty, self.shell])
+ if rc == 0:
+ self.login()
+
+ def login(self):
+ self.session.sendline(self.entity.console.credentials.username.encode())
+ self.session.expect("Password: ".encode())
+ self.session.sendline(self.entity.console.credentials.password.encode())
+ self.session.expect(self.shell)
+
+ def reboot(self):
+ self.session.sendline("reboot")
+ self.session.expect("Hit any key to stop autoboot:".encode(), timeout=None)
+ self.session.expect(self.getty, timeout=None)
+ self.login()
+ state = self.obmcutil.bmcstate()
+ while state != self.obmcutil.BMC_READY:
+ print("Wanted state '{}', got state '{}'".format(self.obmcutil.BMC_READY, state))
+ time.sleep(5)
+ state = self.obmcutil.bmcstate()
+
+ def chassisoff(self):
+ self.obmcutil.chassisoff()
+
+ def poweron(self):
+ hs = self.obmcutil.hoststate()
+ print("Host state is: {}".format(hs))
+ if hs in (self.obmcutil.HOST_ON, self.obmcutil.HOST_QUIESCED):
+ self.obmcutil.chassisoff()
+ self.obmcutil.poweron()
+
+class Host(object):
+ def __init__(self, entity, bmc):
+ self.shell = "/ #".encode()
+ self.petitboot = "Petitboot".encode()
+ self.session = None
+ self.entity = entity
+ self.bmc = bmc
+ self.connect()
+
+ def connect(self):
+ fargs = (self.entity.console.endpoint.port,
+ self.entity.console.credentials.username,
+ self.entity.console.endpoint.host)
+ self.session = pexpect.spawn("ssh -p{} {}@{}".format(*fargs))
+ self.session.logfile = PexpectLogger()
+ self.session.expect("password:".encode())
+ self.session.sendline(self.entity.console.credentials.password.encode())
+
+ def poweron(self):
+ self.bmc.chassisoff()
+ self.bmc.poweron()
+ self.session.send('\f')
+ rc = self.session.expect([self.petitboot, self.shell], timeout=None)
+ if rc == 0:
+ self.session.sendline()
+ self.session.expect(self.shell)
+
+ def reboot(self):
+ self.session.send('\f')
+ rc = self.session.expect([self.petitboot, self.shell], timeout=None)
+ if rc == 0:
+ self.session.sendline()
+ self.session.expect(self.shell)
+ self.session.sendline("reboot".encode())
+ self.session.expect("INIT: Waiting for kernel...".encode(), timeout=None)
+ self.session.expect("Petitboot".encode(), timeout=None)
+ self.session.sendline()
+ self.session.expect(self.shell)
+
+def rpp(machine):
+ bmc = Bmc(machine.bmc)
+ host = Host(machine.host, bmc)
+ host.poweron()
+ while True:
+ bmc.reboot()
+ host.connect()
+ host.reboot()
+
+def main():
+ bmccreds = Credentials("root", "0penBmc")
+ b = Entity(Target(bmccreds, Endpoint("serial.concentrator.somewhere.com", 1234)),
+ Target(bmccreds, Endpoint("bmc.somewhere.com", 22)))
+ h = Entity(Target(bmccreds, Endpoint("bmc.somewhere.com", 2200)),
+ Target(Credentials("user", "password"), Endpoint("host.somewhere.com", 22)))
+ m = Machine(b, h)
+ return rpp(m)
+
+if __name__ == "__main__":
+ main()