1#!/usr/bin/env python3 2 3r""" 4See help text for details. 5""" 6 7import json 8import ssl 9import sys 10 11import requests 12import websocket 13from retrying import retry 14 15save_path_0 = sys.path[0] 16del sys.path[0] 17 18from gen_arg import * # NOQA 19from gen_print import * # NOQA 20from gen_valid import * # NOQA 21 22# 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 28 29parser = argparse.ArgumentParser( 30 usage="%(prog)s [OPTIONS]", 31 description="%(prog)s will open a websocket session on a remote OpenBMC. " 32 + "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.", 35 formatter_class=argparse.ArgumentDefaultsHelpFormatter, 36 prefix_chars="-+", 37) 38parser.add_argument( 39 "openbmc_host", default="", help="The BMC host name or IP address." 40) 41parser.add_argument( 42 "--openbmc_username", 43 default="root", 44 help="The userid for the open BMC system.", 45) 46parser.add_argument( 47 "--openbmc_password", 48 default="", 49 help="The password for the open BMC system.", 50) 51parser.add_argument( 52 "--monitor_type", 53 choices=["logging", "dump"], 54 default="logging", 55 help="The type of notifications from websocket to monitor.", 56) 57 58 59stock_list = [("test_mode", 0), ("quiet", 0), ("debug", 0)] 60 61 62def exit_function(signal_number=0, frame=None): 63 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 73def signal_handler(signal_number, frame): 74 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 85 # Calling exit prevents returning to the code that was running 86 # 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) 99 global monitoring_uri 100 monitoring_uri = "/xyz/openbmc_project/" + monitor_type 101 gen_post_validation(exit_function, signal_handler) 102 103 104@retry(stop_max_attempt_number=3, wait_fixed=1000) 105def login(openbmc_host, openbmc_username, 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( 120 "https://" + openbmc_host + "/login", 121 headers=http_header, 122 json={"data": [openbmc_username, openbmc_password]}, 123 verify=False, 124 timeout=30, 125 ) 126 valid_value(response.status_code, valid_values=[200]) 127 login_response = json.loads(response.text) 128 qprint_var(login_response) 129 valid_value(login_response["status"], valid_values=["ok"]) 130 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: 148 # /xyz/openbmc_project/logging/entry/24","properties":{"Id":24}} 149 # or 150 # /xyz/openbmc_project/dump/entry/1","properties":{"Size":186180}}'). 151 152 if monitoring_uri + "/entry" in message: 153 if "Id" in message: 154 qprint_timen("eSEL received over websocket interface.") 155 websocket_obj.close() 156 elif "Size" in message: 157 qprint_timen( 158 "Dump notification received over websocket interface." 159 ) 160 websocket_obj.close() 161 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() 202 data = {"paths": [monitoring_uri]} 203 websocket_obj.send(json.dumps(data)) 204 qprint_timen("Registered for websocket monitoring: " + monitoring_uri) 205 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() 221 cookies = sprint_var( 222 cookies, 223 fmt=no_header() | strip_brackets(), 224 col1_width=0, 225 trailing_char="", 226 delim="=", 227 ).replace("\n", ";") 228 # Register the event handlers. When an ESEL is created by the system 229 # under test, the on_message() handler will be called. 230 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 ) 238 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() 246 qprint_var(monitoring_uri) 247 open_socket(openbmc_host, openbmc_username, openbmc_password) 248 249 250main() 251