blob: 846ccd5ff04f7051b8c25476f248da031d8c58ba [file] [log] [blame]
George Keishinge7e91712021-09-03 11:28:44 -05001#!/usr/bin/env python3
Steven Sombar3468df52019-06-29 11:01:47 -05002
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
Steven Sombar3468df52019-06-29 11:01:47 -050027
28parser = argparse.ArgumentParser(
29 usage='%(prog)s [OPTIONS]',
30 description="%(prog)s will open a websocket session on a remote OpenBMC. "
31 + "When an eSEL is created on that BMC, the monitor will receive "
32 + "notice over websocket that the eSEL was created "
33 + "and it will print a message.",
34 formatter_class=argparse.ArgumentDefaultsHelpFormatter,
35 prefix_chars='-+')
36parser.add_argument(
37 'openbmc_host',
38 default='',
39 help='The BMC host name or IP address.')
40parser.add_argument(
41 '--openbmc_username',
42 default='root',
43 help='The userid for the open BMC system.')
44parser.add_argument(
45 '--openbmc_password',
46 default='',
47 help='The password for the open BMC system.')
Steven Sombaracdb3842019-10-21 14:12:35 -050048parser.add_argument(
49 '--monitor_type',
50 choices=['logging', 'dump'],
51 default='logging',
52 help='The type of notifications from websocket to monitor.')
53
Steven Sombar3468df52019-06-29 11:01:47 -050054
55stock_list = [("test_mode", 0), ("quiet", 0), ("debug", 0)]
56
57
58def exit_function(signal_number=0,
59 frame=None):
60 r"""
61 Execute whenever the program ends normally or with the signals that we
62 catch (i.e. TERM, INT).
63 """
64
65 qprint_dashes(width=160)
66 qprint_executing()
67 qprint_pgm_footer()
68
69
70def signal_handler(signal_number,
71 frame):
72 r"""
73 Handle signals. Without a function to catch a SIGTERM or SIGINT, the
74 program would terminate immediately with return code 143 and without
75 calling the exit_function.
76 """
77
78 # Our convention is to set up exit_function with atexit.register() so
79 # there is no need to explicitly call exit_function from here.
80
81 dprint_executing()
82
Steven Sombaracdb3842019-10-21 14:12:35 -050083 # Calling exit prevents returning to the code that was running
Steven Sombar3468df52019-06-29 11:01:47 -050084 # when the signal was received.
85 exit(0)
86
87
88def validate_parms():
89 r"""
90 Validate program parameters, etc.
91 """
92
93 register_passwords(openbmc_password)
94 valid_value(openbmc_host)
95 valid_value(openbmc_username)
96 valid_value(openbmc_password)
Steven Sombaracdb3842019-10-21 14:12:35 -050097 global monitoring_uri
98 monitoring_uri = '/xyz/openbmc_project/' + monitor_type
Steven Sombar3468df52019-06-29 11:01:47 -050099 gen_post_validation(exit_function, signal_handler)
100
101
102@retry(stop_max_attempt_number=3, wait_fixed=1000)
103def login(openbmc_host,
104 openbmc_username,
105 openbmc_password):
106 r"""
107 Log into the BMC and return the session object.
108
109 Description of argument(s):
110 openbmc_host The BMC host name or IP address.
111 openbmc_username The userid for the open BMC system.
112 openbmc_password The password for the open BMC system.
113 """
114
115 qprint_executing()
116
117 http_header = {'Content-Type': 'application/json'}
118 session = requests.session()
119 response = session.post('https://' + openbmc_host + '/login', headers=http_header,
120 json={"data": [openbmc_username, openbmc_password]},
121 verify=False, timeout=30)
122 valid_value(response.status_code, valid_values=[200])
123 login_response = json.loads(response.text)
124 qprint_var(login_response)
125 valid_value(login_response['status'], valid_values=['ok'])
126
127 return session
128
129
130def on_message(websocket_obj, message):
131 """
132 Websocket message handler. Close the websocket if the
133 message is an eSEL message.
134
135 Description of argument(s):
136 websocket_obj The websocket established during opne_socket().
137 message The message sent from the websocket interface.
138 """
139
140 qprint_dashes(width=160)
141 qprint_executing()
142
143 # A typical message:
Steven Sombaracdb3842019-10-21 14:12:35 -0500144 # /xyz/openbmc_project/logging/entry/24","properties":{"Id":24}}
145 # or
146 # /xyz/openbmc_project/dump/entry/1","properties":{"Size":186180}}').
Steven Sombar3468df52019-06-29 11:01:47 -0500147
Steven Sombaracdb3842019-10-21 14:12:35 -0500148 if monitoring_uri + '/entry' in message:
149 if 'Id' in message:
150 qprint_timen('eSEL received over websocket interface.')
151 websocket_obj.close()
152 elif 'Size' in message:
153 qprint_timen('Dump notification received over websocket interface.')
154 websocket_obj.close()
Steven Sombar3468df52019-06-29 11:01:47 -0500155
156
157def on_error(websocket_obj, wserror):
158 """
159 Websocket error handler. This routine is called whenever the
160 websocket interfaces wishes to report an issue.
161
162 Description of argument(s):
163 websocket_obj The websocket established during opne_socket().
164 wserror The error message sent from the websocket interface.
165 """
166
167 # It is normal to receive this message when websocked closes:
168 # 'NoneType' object has no attribute 'connected'.
169
170 qprint_dashes(width=160)
171 qprint_executing()
172
173
174def on_close(websocket_obj):
175 """
176 Websocket close event handler.
177
178 Description of argument(s):
179 websocket_obj The websocket established during opne_socket().
180 """
181
182 qprint_dashes(width=160)
183 qprint_executing()
184
185
186def on_open(websocket_obj):
187 """
188 Send the filters needed to listen to the logging interface.
189
190 Description of argument(s):
191 websocket_obj The websocket established during opne_socket().
192 """
193
194 qprint_dashes(width=160)
195 qprint_executing()
Steven Sombaracdb3842019-10-21 14:12:35 -0500196 data = {"paths": [monitoring_uri]}
Steven Sombar3468df52019-06-29 11:01:47 -0500197 websocket_obj.send(json.dumps(data))
Steven Sombaracdb3842019-10-21 14:12:35 -0500198 qprint_timen("Registered for websocket monitoring: " + monitoring_uri)
Steven Sombar3468df52019-06-29 11:01:47 -0500199
200
201def open_socket(openbmc_host, openbmc_username, openbmc_password):
202 """
203 Open a long-running websocket to the BMC.
204 Description of argument(s):
205 openbmc_host The BMC host name or IP address.
206 openbmc_username The userid for the open BMC system.
207 openbmc_password The Password for the open BMC system.
208 """
209 websocket.enableTrace(False)
210 qprint_dashes(width=160)
211 qprint_executing()
212 session = login(openbmc_host, openbmc_username, openbmc_password)
213 qprint_timen("Registering websocket handlers.")
214 cookies = session.cookies.get_dict()
215 cookies = sprint_var(cookies, fmt=no_header() | strip_brackets(),
216 col1_width=0, trailing_char="",
217 delim="=").replace("\n", ";")
218 # Register the event handlers. When an ESEL is created by the system
219 # under test, the on_message() handler will be called.
220 websocket_obj = websocket.WebSocketApp("wss://" + openbmc_host + "/subscribe",
221 on_message=on_message,
222 on_error=on_error,
223 on_close=on_close,
224 on_open=on_open,
225 cookie=cookies)
226 qprint_timen("Completed registering of websocket handlers.")
227 websocket_obj.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
228
229
230def main():
231 gen_get_options(parser, stock_list)
232 validate_parms()
233 qprint_pgm_header()
Steven Sombaracdb3842019-10-21 14:12:35 -0500234 qprint_var(monitoring_uri)
Steven Sombar3468df52019-06-29 11:01:47 -0500235 open_socket(openbmc_host, openbmc_username, openbmc_password)
236
237
238main()