#!/usr/bin/python3 import sys import time from collections import namedtuple import pexpect 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): try: sys.stdout.write(bstring.decode()) except UnicodeDecodeError: print("Dropping broken unicode line") 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()