blob: c4940a9155c014be5e1821e24a8050d6b8e80d37 [file] [log] [blame]
Andrew Jefferyba3fb502019-03-22 16:03:41 +10301#!/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):
Andrew Jefferyfa8dbcf2019-04-08 17:11:33 +093055 try:
56 sys.stdout.write(bstring.decode())
57 except UnicodeDecodeError:
58 print("Dropping broken unicode line")
Andrew Jefferyba3fb502019-03-22 16:03:41 +103059
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()