blob: 0f0a5a4fcef30e0147a4d78972e004a1e51faf47 [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
George Keishinge635ddc2022-12-08 07:38:02 -06007import json
George Keishinge635ddc2022-12-08 07:38:02 -06008import ssl
Patrick Williams20f38712022-12-08 06:18:26 -06009import sys
10
George Keishinge635ddc2022-12-08 07:38:02 -060011import requests
Patrick Williams20f38712022-12-08 06:18:26 -060012import websocket
Steven Sombar3468df52019-06-29 11:01:47 -050013from retrying import retry
14
15save_path_0 = sys.path[0]
16del sys.path[0]
17
Patrick Williams20f38712022-12-08 06:18:26 -060018from gen_arg import * # NOQA
19from gen_print import * # NOQA
20from gen_valid import * # NOQA
George Keishing37c58c82022-12-08 07:42:54 -060021
Steven Sombar3468df52019-06-29 11:01:47 -050022# Restore sys.path[0].
23sys.path.insert(0, save_path_0)
24
25# Set exit_on_error for gen_valid functions.
26set_exit_on_error(True)
27
Steven Sombar3468df52019-06-29 11:01:47 -050028
29parser = argparse.ArgumentParser(
Patrick Williams20f38712022-12-08 06:18:26 -060030 usage="%(prog)s [OPTIONS]",
Steven Sombar3468df52019-06-29 11:01:47 -050031 description="%(prog)s will open a websocket session on a remote OpenBMC. "
Patrick Williams20f38712022-12-08 06:18:26 -060032 + "When an eSEL is created on that BMC, the monitor will receive "
33 + "notice over websocket that the eSEL was created "
34 + "and it will print a message.",
Steven Sombar3468df52019-06-29 11:01:47 -050035 formatter_class=argparse.ArgumentDefaultsHelpFormatter,
Patrick Williams20f38712022-12-08 06:18:26 -060036 prefix_chars="-+",
37)
Steven Sombar3468df52019-06-29 11:01:47 -050038parser.add_argument(
Patrick Williams20f38712022-12-08 06:18:26 -060039 "openbmc_host", default="", help="The BMC host name or IP address."
40)
Steven Sombar3468df52019-06-29 11:01:47 -050041parser.add_argument(
Patrick Williams20f38712022-12-08 06:18:26 -060042 "--openbmc_username",
43 default="root",
44 help="The userid for the open BMC system.",
45)
Steven Sombar3468df52019-06-29 11:01:47 -050046parser.add_argument(
Patrick Williams20f38712022-12-08 06:18:26 -060047 "--openbmc_password",
48 default="",
49 help="The password for the open BMC system.",
50)
Steven Sombaracdb3842019-10-21 14:12:35 -050051parser.add_argument(
Patrick Williams20f38712022-12-08 06:18:26 -060052 "--monitor_type",
53 choices=["logging", "dump"],
54 default="logging",
55 help="The type of notifications from websocket to monitor.",
56)
Steven Sombaracdb3842019-10-21 14:12:35 -050057
Steven Sombar3468df52019-06-29 11:01:47 -050058
59stock_list = [("test_mode", 0), ("quiet", 0), ("debug", 0)]
60
61
Patrick Williams20f38712022-12-08 06:18:26 -060062def exit_function(signal_number=0, frame=None):
Steven Sombar3468df52019-06-29 11:01:47 -050063 r"""
64 Execute whenever the program ends normally or with the signals that we
65 catch (i.e. TERM, INT).
66 """
67
68 qprint_dashes(width=160)
69 qprint_executing()
70 qprint_pgm_footer()
71
72
Patrick Williams20f38712022-12-08 06:18:26 -060073def signal_handler(signal_number, frame):
Steven Sombar3468df52019-06-29 11:01:47 -050074 r"""
75 Handle signals. Without a function to catch a SIGTERM or SIGINT, the
76 program would terminate immediately with return code 143 and without
77 calling the exit_function.
78 """
79
80 # Our convention is to set up exit_function with atexit.register() so
81 # there is no need to explicitly call exit_function from here.
82
83 dprint_executing()
84
Steven Sombaracdb3842019-10-21 14:12:35 -050085 # Calling exit prevents returning to the code that was running
Steven Sombar3468df52019-06-29 11:01:47 -050086 # when the signal was received.
87 exit(0)
88
89
90def validate_parms():
91 r"""
92 Validate program parameters, etc.
93 """
94
95 register_passwords(openbmc_password)
96 valid_value(openbmc_host)
97 valid_value(openbmc_username)
98 valid_value(openbmc_password)
Steven Sombaracdb3842019-10-21 14:12:35 -050099 global monitoring_uri
Patrick Williams20f38712022-12-08 06:18:26 -0600100 monitoring_uri = "/xyz/openbmc_project/" + monitor_type
Steven Sombar3468df52019-06-29 11:01:47 -0500101 gen_post_validation(exit_function, signal_handler)
102
103
104@retry(stop_max_attempt_number=3, wait_fixed=1000)
Patrick Williams20f38712022-12-08 06:18:26 -0600105def login(openbmc_host, openbmc_username, openbmc_password):
Steven Sombar3468df52019-06-29 11:01:47 -0500106 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
Patrick Williams20f38712022-12-08 06:18:26 -0600117 http_header = {"Content-Type": "application/json"}
Steven Sombar3468df52019-06-29 11:01:47 -0500118 session = requests.session()
Patrick Williams20f38712022-12-08 06:18:26 -0600119 response = session.post(
120 "https://" + openbmc_host + "/login",
121 headers=http_header,
122 json={"data": [openbmc_username, openbmc_password]},
123 verify=False,
124 timeout=30,
125 )
Steven Sombar3468df52019-06-29 11:01:47 -0500126 valid_value(response.status_code, valid_values=[200])
127 login_response = json.loads(response.text)
128 qprint_var(login_response)
Patrick Williams20f38712022-12-08 06:18:26 -0600129 valid_value(login_response["status"], valid_values=["ok"])
Steven Sombar3468df52019-06-29 11:01:47 -0500130
131 return session
132
133
134def on_message(websocket_obj, message):
135 """
136 Websocket message handler. Close the websocket if the
137 message is an eSEL message.
138
139 Description of argument(s):
140 websocket_obj The websocket established during opne_socket().
141 message The message sent from the websocket interface.
142 """
143
144 qprint_dashes(width=160)
145 qprint_executing()
146
147 # A typical message:
Steven Sombaracdb3842019-10-21 14:12:35 -0500148 # /xyz/openbmc_project/logging/entry/24","properties":{"Id":24}}
149 # or
150 # /xyz/openbmc_project/dump/entry/1","properties":{"Size":186180}}').
Steven Sombar3468df52019-06-29 11:01:47 -0500151
Patrick Williams20f38712022-12-08 06:18:26 -0600152 if monitoring_uri + "/entry" in message:
153 if "Id" in message:
154 qprint_timen("eSEL received over websocket interface.")
Steven Sombaracdb3842019-10-21 14:12:35 -0500155 websocket_obj.close()
Patrick Williams20f38712022-12-08 06:18:26 -0600156 elif "Size" in message:
157 qprint_timen(
158 "Dump notification received over websocket interface."
159 )
Steven Sombaracdb3842019-10-21 14:12:35 -0500160 websocket_obj.close()
Steven Sombar3468df52019-06-29 11:01:47 -0500161
162
163def on_error(websocket_obj, wserror):
164 """
165 Websocket error handler. This routine is called whenever the
166 websocket interfaces wishes to report an issue.
167
168 Description of argument(s):
169 websocket_obj The websocket established during opne_socket().
170 wserror The error message sent from the websocket interface.
171 """
172
173 # It is normal to receive this message when websocked closes:
174 # 'NoneType' object has no attribute 'connected'.
175
176 qprint_dashes(width=160)
177 qprint_executing()
178
179
180def on_close(websocket_obj):
181 """
182 Websocket close event handler.
183
184 Description of argument(s):
185 websocket_obj The websocket established during opne_socket().
186 """
187
188 qprint_dashes(width=160)
189 qprint_executing()
190
191
192def on_open(websocket_obj):
193 """
194 Send the filters needed to listen to the logging interface.
195
196 Description of argument(s):
197 websocket_obj The websocket established during opne_socket().
198 """
199
200 qprint_dashes(width=160)
201 qprint_executing()
Steven Sombaracdb3842019-10-21 14:12:35 -0500202 data = {"paths": [monitoring_uri]}
Steven Sombar3468df52019-06-29 11:01:47 -0500203 websocket_obj.send(json.dumps(data))
Steven Sombaracdb3842019-10-21 14:12:35 -0500204 qprint_timen("Registered for websocket monitoring: " + monitoring_uri)
Steven Sombar3468df52019-06-29 11:01:47 -0500205
206
207def open_socket(openbmc_host, openbmc_username, openbmc_password):
208 """
209 Open a long-running websocket to the BMC.
210 Description of argument(s):
211 openbmc_host The BMC host name or IP address.
212 openbmc_username The userid for the open BMC system.
213 openbmc_password The Password for the open BMC system.
214 """
215 websocket.enableTrace(False)
216 qprint_dashes(width=160)
217 qprint_executing()
218 session = login(openbmc_host, openbmc_username, openbmc_password)
219 qprint_timen("Registering websocket handlers.")
220 cookies = session.cookies.get_dict()
Patrick Williams20f38712022-12-08 06:18:26 -0600221 cookies = sprint_var(
222 cookies,
223 fmt=no_header() | strip_brackets(),
224 col1_width=0,
225 trailing_char="",
226 delim="=",
227 ).replace("\n", ";")
Steven Sombar3468df52019-06-29 11:01:47 -0500228 # Register the event handlers. When an ESEL is created by the system
229 # under test, the on_message() handler will be called.
Patrick Williams20f38712022-12-08 06:18:26 -0600230 websocket_obj = websocket.WebSocketApp(
231 "wss://" + openbmc_host + "/subscribe",
232 on_message=on_message,
233 on_error=on_error,
234 on_close=on_close,
235 on_open=on_open,
236 cookie=cookies,
237 )
Steven Sombar3468df52019-06-29 11:01:47 -0500238 qprint_timen("Completed registering of websocket handlers.")
239 websocket_obj.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
240
241
242def main():
243 gen_get_options(parser, stock_list)
244 validate_parms()
245 qprint_pgm_header()
Steven Sombaracdb3842019-10-21 14:12:35 -0500246 qprint_var(monitoring_uri)
Steven Sombar3468df52019-06-29 11:01:47 -0500247 open_socket(openbmc_host, openbmc_username, openbmc_password)
248
249
250main()