blob: 78009c2baa8a9f4c71ab3616136ab0a17e22e0e0 [file] [log] [blame]
Andrew Jefferyba3fb502019-03-22 16:03:41 +10301#!/usr/bin/python3
2
Andrew Jefferyba3fb502019-03-22 16:03:41 +10303import sys
4import time
Andrew Jefferyba3fb502019-03-22 16:03:41 +10305from collections import namedtuple
6
Patrick Williamsa3db66b2022-12-04 16:27:08 -06007import pexpect
8
Andrew Jefferyba3fb502019-03-22 16:03:41 +10309Endpoint = namedtuple("Endpoint", "host, port")
10Credentials = namedtuple("Credentials", "username, password")
11Target = namedtuple("Target", "credentials, endpoint")
12Entity = namedtuple("Entity", "console, ssh")
13Machine = namedtuple("Machine", "bmc, host")
14
Patrick Williamsa3db66b2022-12-04 16:27:08 -060015
Andrew Jefferyba3fb502019-03-22 16:03:41 +103016class Obmcutil(object):
Patrick Williamsa3db66b2022-12-04 16:27:08 -060017 BMC_READY = "xyz.openbmc_project.State.BMC.BMCState.Ready"
Andrew Jefferyba3fb502019-03-22 16:03:41 +103018 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):
Patrick Williamsa3db66b2022-12-04 16:27:08 -060040 return self._state(
41 "hoststate",
42 "xyz\\.openbmc_project\\.State\\.Host\\.HostState\\."
43 + "(Off|Running|Quiesced)",
44 )
Andrew Jefferyba3fb502019-03-22 16:03:41 +103045
46 def bmcstate(self):
Patrick Williamsa3db66b2022-12-04 16:27:08 -060047 return self._state(
48 "bmcstate",
49 "xyz\\.openbmc_project\\.State\\.BMC\\.BMCState\\.(Not)?Ready",
50 )
Andrew Jefferyba3fb502019-03-22 16:03:41 +103051
52 def poweron(self):
53 self.session.sendline("obmcutil -w poweron")
54 self.session.expect(self.prompt)
55
56 def chassisoff(self):
57 self.session.sendline("obmcutil -w chassisoff")
58 self.session.expect(self.prompt)
59
Patrick Williamsa3db66b2022-12-04 16:27:08 -060060
Andrew Jefferyba3fb502019-03-22 16:03:41 +103061class PexpectLogger(object):
62 def write(self, bstring):
Andrew Jefferyfa8dbcf2019-04-08 17:11:33 +093063 try:
64 sys.stdout.write(bstring.decode())
65 except UnicodeDecodeError:
66 print("Dropping broken unicode line")
Andrew Jefferyba3fb502019-03-22 16:03:41 +103067
68 def flush(self):
69 sys.stdout.flush()
70
71
72class Bmc(object):
73 def __init__(self, entity):
74 self.getty = "login: ".encode()
75 self.shell = "# ".encode()
76 self.entity = entity
77 fargs = (entity.console.endpoint.host, entity.console.endpoint.port)
78 self.session = pexpect.spawn("telnet {} {}".format(*fargs))
79 self.session.logfile = PexpectLogger()
80 self.obmcutil = Obmcutil(self.session, self.shell)
81 self.session.sendline()
82 rc = self.session.expect([self.getty, self.shell])
83 if rc == 0:
84 self.login()
85
86 def login(self):
Patrick Williamsa3db66b2022-12-04 16:27:08 -060087 self.session.sendline(
88 self.entity.console.credentials.username.encode()
89 )
Andrew Jefferyba3fb502019-03-22 16:03:41 +103090 self.session.expect("Password: ".encode())
Patrick Williamsa3db66b2022-12-04 16:27:08 -060091 self.session.sendline(
92 self.entity.console.credentials.password.encode()
93 )
Andrew Jefferyba3fb502019-03-22 16:03:41 +103094 self.session.expect(self.shell)
95
96 def reboot(self):
97 self.session.sendline("reboot")
Patrick Williamsa3db66b2022-12-04 16:27:08 -060098 self.session.expect(
99 "Hit any key to stop autoboot:".encode(), timeout=None
100 )
Andrew Jefferyba3fb502019-03-22 16:03:41 +1030101 self.session.expect(self.getty, timeout=None)
102 self.login()
103 state = self.obmcutil.bmcstate()
104 while state != self.obmcutil.BMC_READY:
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600105 print(
106 "Wanted state '{}', got state '{}'".format(
107 self.obmcutil.BMC_READY, state
108 )
109 )
Andrew Jefferyba3fb502019-03-22 16:03:41 +1030110 time.sleep(5)
111 state = self.obmcutil.bmcstate()
112
113 def chassisoff(self):
114 self.obmcutil.chassisoff()
115
116 def poweron(self):
117 hs = self.obmcutil.hoststate()
118 print("Host state is: {}".format(hs))
119 if hs in (self.obmcutil.HOST_ON, self.obmcutil.HOST_QUIESCED):
120 self.obmcutil.chassisoff()
121 self.obmcutil.poweron()
122
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600123
Andrew Jefferyba3fb502019-03-22 16:03:41 +1030124class Host(object):
125 def __init__(self, entity, bmc):
Andrew Jefferyd568bb82019-04-08 17:12:18 +0930126 self.shell = "/? *#".encode()
Andrew Jefferyba3fb502019-03-22 16:03:41 +1030127 self.petitboot = "Petitboot".encode()
128 self.session = None
129 self.entity = entity
130 self.bmc = bmc
131 self.connect()
132
133 def connect(self):
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600134 fargs = (
135 self.entity.console.endpoint.port,
136 self.entity.console.credentials.username,
137 self.entity.console.endpoint.host,
138 )
Andrew Jefferyba3fb502019-03-22 16:03:41 +1030139 self.session = pexpect.spawn("ssh -p{} {}@{}".format(*fargs))
140 self.session.logfile = PexpectLogger()
141 self.session.expect("password:".encode())
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600142 self.session.sendline(
143 self.entity.console.credentials.password.encode()
144 )
Andrew Jefferyba3fb502019-03-22 16:03:41 +1030145
146 def poweron(self):
147 self.bmc.chassisoff()
148 self.bmc.poweron()
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600149 self.session.send("\f")
Andrew Jefferyba3fb502019-03-22 16:03:41 +1030150 rc = self.session.expect([self.petitboot, self.shell], timeout=None)
151 if rc == 0:
152 self.session.sendline()
153 self.session.expect(self.shell)
154
155 def reboot(self):
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600156 self.session.send("\f")
Andrew Jefferyba3fb502019-03-22 16:03:41 +1030157 rc = self.session.expect([self.petitboot, self.shell], timeout=None)
158 if rc == 0:
159 self.session.sendline()
160 self.session.expect(self.shell)
161 self.session.sendline("reboot".encode())
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600162 self.session.expect(
163 "INIT: Waiting for kernel...".encode(), timeout=None
164 )
Andrew Jefferyba3fb502019-03-22 16:03:41 +1030165 self.session.expect("Petitboot".encode(), timeout=None)
166 self.session.sendline()
167 self.session.expect(self.shell)
168
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600169
Andrew Jefferyba3fb502019-03-22 16:03:41 +1030170def rpp(machine):
171 bmc = Bmc(machine.bmc)
172 host = Host(machine.host, bmc)
173 host.poweron()
174 while True:
175 bmc.reboot()
176 host.connect()
177 host.reboot()
178
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600179
Andrew Jefferyba3fb502019-03-22 16:03:41 +1030180def main():
181 bmccreds = Credentials("root", "0penBmc")
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600182 b = Entity(
183 Target(bmccreds, Endpoint("serial.concentrator.somewhere.com", 1234)),
184 Target(bmccreds, Endpoint("bmc.somewhere.com", 22)),
185 )
186 h = Entity(
187 Target(bmccreds, Endpoint("bmc.somewhere.com", 2200)),
188 Target(
189 Credentials("user", "password"), Endpoint("host.somewhere.com", 22)
190 ),
191 )
Andrew Jefferyba3fb502019-03-22 16:03:41 +1030192 m = Machine(b, h)
193 return rpp(m)
194
Patrick Williamsa3db66b2022-12-04 16:27:08 -0600195
Andrew Jefferyba3fb502019-03-22 16:03:41 +1030196if __name__ == "__main__":
197 main()