blob: 78009c2baa8a9f4c71ab3616136ab0a17e22e0e0 [file] [log] [blame]
#!/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()