blob: 99eae0a9483660362be5aeaba698feeff75903ca [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):
55 sys.stdout.write(bstring.decode())
56
57 def flush(self):
58 sys.stdout.flush()
59
60
61class Bmc(object):
62 def __init__(self, entity):
63 self.getty = "login: ".encode()
64 self.shell = "# ".encode()
65 self.entity = entity
66 fargs = (entity.console.endpoint.host, entity.console.endpoint.port)
67 self.session = pexpect.spawn("telnet {} {}".format(*fargs))
68 self.session.logfile = PexpectLogger()
69 self.obmcutil = Obmcutil(self.session, self.shell)
70 self.session.sendline()
71 rc = self.session.expect([self.getty, self.shell])
72 if rc == 0:
73 self.login()
74
75 def login(self):
76 self.session.sendline(self.entity.console.credentials.username.encode())
77 self.session.expect("Password: ".encode())
78 self.session.sendline(self.entity.console.credentials.password.encode())
79 self.session.expect(self.shell)
80
81 def reboot(self):
82 self.session.sendline("reboot")
83 self.session.expect("Hit any key to stop autoboot:".encode(), timeout=None)
84 self.session.expect(self.getty, timeout=None)
85 self.login()
86 state = self.obmcutil.bmcstate()
87 while state != self.obmcutil.BMC_READY:
88 print("Wanted state '{}', got state '{}'".format(self.obmcutil.BMC_READY, state))
89 time.sleep(5)
90 state = self.obmcutil.bmcstate()
91
92 def chassisoff(self):
93 self.obmcutil.chassisoff()
94
95 def poweron(self):
96 hs = self.obmcutil.hoststate()
97 print("Host state is: {}".format(hs))
98 if hs in (self.obmcutil.HOST_ON, self.obmcutil.HOST_QUIESCED):
99 self.obmcutil.chassisoff()
100 self.obmcutil.poweron()
101
102class Host(object):
103 def __init__(self, entity, bmc):
104 self.shell = "/ #".encode()
105 self.petitboot = "Petitboot".encode()
106 self.session = None
107 self.entity = entity
108 self.bmc = bmc
109 self.connect()
110
111 def connect(self):
112 fargs = (self.entity.console.endpoint.port,
113 self.entity.console.credentials.username,
114 self.entity.console.endpoint.host)
115 self.session = pexpect.spawn("ssh -p{} {}@{}".format(*fargs))
116 self.session.logfile = PexpectLogger()
117 self.session.expect("password:".encode())
118 self.session.sendline(self.entity.console.credentials.password.encode())
119
120 def poweron(self):
121 self.bmc.chassisoff()
122 self.bmc.poweron()
123 self.session.send('\f')
124 rc = self.session.expect([self.petitboot, self.shell], timeout=None)
125 if rc == 0:
126 self.session.sendline()
127 self.session.expect(self.shell)
128
129 def reboot(self):
130 self.session.send('\f')
131 rc = self.session.expect([self.petitboot, self.shell], timeout=None)
132 if rc == 0:
133 self.session.sendline()
134 self.session.expect(self.shell)
135 self.session.sendline("reboot".encode())
136 self.session.expect("INIT: Waiting for kernel...".encode(), timeout=None)
137 self.session.expect("Petitboot".encode(), timeout=None)
138 self.session.sendline()
139 self.session.expect(self.shell)
140
141def rpp(machine):
142 bmc = Bmc(machine.bmc)
143 host = Host(machine.host, bmc)
144 host.poweron()
145 while True:
146 bmc.reboot()
147 host.connect()
148 host.reboot()
149
150def main():
151 bmccreds = Credentials("root", "0penBmc")
152 b = Entity(Target(bmccreds, Endpoint("serial.concentrator.somewhere.com", 1234)),
153 Target(bmccreds, Endpoint("bmc.somewhere.com", 22)))
154 h = Entity(Target(bmccreds, Endpoint("bmc.somewhere.com", 2200)),
155 Target(Credentials("user", "password"), Endpoint("host.somewhere.com", 22)))
156 m = Machine(b, h)
157 return rpp(m)
158
159if __name__ == "__main__":
160 main()