blob: d0ae84407c2279222848dfd73736988f45a864b7 [file] [log] [blame]
Steven Sombar3468df52019-06-29 11:01:47 -05001#!/usr/bin/env python
2
3r"""
4See help text for details.
5"""
6
7import json
8import sys
9import websocket
10import ssl
11import requests
12from retrying import retry
13
14save_path_0 = sys.path[0]
15del sys.path[0]
16
17from gen_print import *
18from gen_arg import *
19from gen_valid import *
20
21# Restore sys.path[0].
22sys.path.insert(0, save_path_0)
23
24# Set exit_on_error for gen_valid functions.
25set_exit_on_error(True)
26
27# URI of the logging interface. This should end with the word "logging" and
28# have no / character at the end.
29logging_uri = '/xyz/openbmc_project/logging'
30
31
32parser = argparse.ArgumentParser(
33 usage='%(prog)s [OPTIONS]',
34 description="%(prog)s will open a websocket session on a remote OpenBMC. "
35 + "When an eSEL is created on that BMC, the monitor will receive "
36 + "notice over websocket that the eSEL was created "
37 + "and it will print a message.",
38 formatter_class=argparse.ArgumentDefaultsHelpFormatter,
39 prefix_chars='-+')
40parser.add_argument(
41 'openbmc_host',
42 default='',
43 help='The BMC host name or IP address.')
44parser.add_argument(
45 '--openbmc_username',
46 default='root',
47 help='The userid for the open BMC system.')
48parser.add_argument(
49 '--openbmc_password',
50 default='',
51 help='The password for the open BMC system.')
52
53stock_list = [("test_mode", 0), ("quiet", 0), ("debug", 0)]
54
55
56def exit_function(signal_number=0,
57 frame=None):
58 r"""
59 Execute whenever the program ends normally or with the signals that we
60 catch (i.e. TERM, INT).
61 """
62
63 qprint_dashes(width=160)
64 qprint_executing()
65 qprint_pgm_footer()
66
67
68def signal_handler(signal_number,
69 frame):
70 r"""
71 Handle signals. Without a function to catch a SIGTERM or SIGINT, the
72 program would terminate immediately with return code 143 and without
73 calling the exit_function.
74 """
75
76 # Our convention is to set up exit_function with atexit.register() so
77 # there is no need to explicitly call exit_function from here.
78
79 dprint_executing()
80
81 # Calling exit prevents us from returning to the code that was running
82 # when the signal was received.
83 exit(0)
84
85
86def validate_parms():
87 r"""
88 Validate program parameters, etc.
89 """
90
91 register_passwords(openbmc_password)
92 valid_value(openbmc_host)
93 valid_value(openbmc_username)
94 valid_value(openbmc_password)
95 gen_post_validation(exit_function, signal_handler)
96
97
98@retry(stop_max_attempt_number=3, wait_fixed=1000)
99def login(openbmc_host,
100 openbmc_username,
101 openbmc_password):
102 r"""
103 Log into the BMC and return the session object.
104
105 Description of argument(s):
106 openbmc_host The BMC host name or IP address.
107 openbmc_username The userid for the open BMC system.
108 openbmc_password The password for the open BMC system.
109 """
110
111 qprint_executing()
112
113 http_header = {'Content-Type': 'application/json'}
114 session = requests.session()
115 response = session.post('https://' + openbmc_host + '/login', headers=http_header,
116 json={"data": [openbmc_username, openbmc_password]},
117 verify=False, timeout=30)
118 valid_value(response.status_code, valid_values=[200])
119 login_response = json.loads(response.text)
120 qprint_var(login_response)
121 valid_value(login_response['status'], valid_values=['ok'])
122
123 return session
124
125
126def on_message(websocket_obj, message):
127 """
128 Websocket message handler. Close the websocket if the
129 message is an eSEL message.
130
131 Description of argument(s):
132 websocket_obj The websocket established during opne_socket().
133 message The message sent from the websocket interface.
134 """
135
136 qprint_dashes(width=160)
137 qprint_executing()
138
139 # A typical message:
140 # {"event":"PropertiesChanged","interface":"xyz.openbmc_
141 # project.Logging.Entry","path":"/xyz/openbmc_project/lo
142 # gging/entry/24","properties":{"Id":24}}
143
144 if logging_uri + '/entry' in message and 'Id' in message:
145 qprint_timen('eSEL received over websocket interface.')
146 qprint_timen("Closing websocket. Expect to receive 'NoneType' object has no attribute 'connected'.")
147 websocket_obj.close()
148
149
150def on_error(websocket_obj, wserror):
151 """
152 Websocket error handler. This routine is called whenever the
153 websocket interfaces wishes to report an issue.
154
155 Description of argument(s):
156 websocket_obj The websocket established during opne_socket().
157 wserror The error message sent from the websocket interface.
158 """
159
160 # It is normal to receive this message when websocked closes:
161 # 'NoneType' object has no attribute 'connected'.
162
163 qprint_dashes(width=160)
164 qprint_executing()
165
166
167def on_close(websocket_obj):
168 """
169 Websocket close event handler.
170
171 Description of argument(s):
172 websocket_obj The websocket established during opne_socket().
173 """
174
175 qprint_dashes(width=160)
176 qprint_executing()
177
178
179def on_open(websocket_obj):
180 """
181 Send the filters needed to listen to the logging interface.
182
183 Description of argument(s):
184 websocket_obj The websocket established during opne_socket().
185 """
186
187 qprint_dashes(width=160)
188 qprint_executing()
189 data = {"paths": [logging_uri]}
190 websocket_obj.send(json.dumps(data))
191 qprint_timen("Registered for websocket monitoring: " + logging_uri)
192
193
194def open_socket(openbmc_host, openbmc_username, openbmc_password):
195 """
196 Open a long-running websocket to the BMC.
197 Description of argument(s):
198 openbmc_host The BMC host name or IP address.
199 openbmc_username The userid for the open BMC system.
200 openbmc_password The Password for the open BMC system.
201 """
202 websocket.enableTrace(False)
203 qprint_dashes(width=160)
204 qprint_executing()
205 session = login(openbmc_host, openbmc_username, openbmc_password)
206 qprint_timen("Registering websocket handlers.")
207 cookies = session.cookies.get_dict()
208 cookies = sprint_var(cookies, fmt=no_header() | strip_brackets(),
209 col1_width=0, trailing_char="",
210 delim="=").replace("\n", ";")
211 # Register the event handlers. When an ESEL is created by the system
212 # under test, the on_message() handler will be called.
213 websocket_obj = websocket.WebSocketApp("wss://" + openbmc_host + "/subscribe",
214 on_message=on_message,
215 on_error=on_error,
216 on_close=on_close,
217 on_open=on_open,
218 cookie=cookies)
219 qprint_timen("Completed registering of websocket handlers.")
220 websocket_obj.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
221
222
223def main():
224 gen_get_options(parser, stock_list)
225 validate_parms()
226 qprint_pgm_header()
227 open_socket(openbmc_host, openbmc_username, openbmc_password)
228
229
230main()