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 gen_arg import * 14from gen_print import * 15from gen_valid import * 16from retrying import retry 17 18save_path_0 = sys.path[0] 19del sys.path[0] 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 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="-+", 36) 37parser.add_argument( 38 "openbmc_host", default="", help="The BMC host name or IP address." 39) 40parser.add_argument( 41 "--openbmc_username", 42 default="root", 43 help="The userid for the open BMC system.", 44) 45parser.add_argument( 46 "--openbmc_password", 47 default="", 48 help="The password for the open BMC system.", 49) 50parser.add_argument( 51 "--monitor_type", 52 choices=["logging", "dump"], 53 default="logging", 54 help="The type of notifications from websocket to monitor.", 55) 56 57 58stock_list = [("test_mode", 0), ("quiet", 0), ("debug", 0)] 59 60 61def exit_function(signal_number=0, frame=None): 62 r""" 63 Execute whenever the program ends normally or with the signals that we 64 catch (i.e. TERM, INT). 65 """ 66 67 qprint_dashes(width=160) 68 qprint_executing() 69 qprint_pgm_footer() 70 71 72def signal_handler(signal_number, frame): 73 r""" 74 Handle signals. Without a function to catch a SIGTERM or SIGINT, the 75 program would terminate immediately with return code 143 and without 76 calling the exit_function. 77 """ 78 79 # Our convention is to set up exit_function with atexit.register() so 80 # there is no need to explicitly call exit_function from here. 81 82 dprint_executing() 83 84 # Calling exit prevents returning to the code that was running 85 # when the signal was received. 86 exit(0) 87 88 89def validate_parms(): 90 r""" 91 Validate program parameters, etc. 92 """ 93 94 register_passwords(openbmc_password) 95 valid_value(openbmc_host) 96 valid_value(openbmc_username) 97 valid_value(openbmc_password) 98 global monitoring_uri 99 monitoring_uri = "/xyz/openbmc_project/" + monitor_type 100 gen_post_validation(exit_function, signal_handler) 101 102 103@retry(stop_max_attempt_number=3, wait_fixed=1000) 104def login(openbmc_host, openbmc_username, openbmc_password): 105 r""" 106 Log into the BMC and return the session object. 107 108 Description of argument(s): 109 openbmc_host The BMC host name or IP address. 110 openbmc_username The userid for the open BMC system. 111 openbmc_password The password for the open BMC system. 112 """ 113 114 qprint_executing() 115 116 http_header = {"Content-Type": "application/json"} 117 session = requests.session() 118 response = session.post( 119 "https://" + openbmc_host + "/login", 120 headers=http_header, 121 json={"data": [openbmc_username, openbmc_password]}, 122 verify=False, 123 timeout=30, 124 ) 125 valid_value(response.status_code, valid_values=[200]) 126 login_response = json.loads(response.text) 127 qprint_var(login_response) 128 valid_value(login_response["status"], valid_values=["ok"]) 129 130 return session 131 132 133def on_message(websocket_obj, message): 134 """ 135 Websocket message handler. Close the websocket if the 136 message is an eSEL message. 137 138 Description of argument(s): 139 websocket_obj The websocket established during opne_socket(). 140 message The message sent from the websocket interface. 141 """ 142 143 qprint_dashes(width=160) 144 qprint_executing() 145 146 # A typical message: 147 # /xyz/openbmc_project/logging/entry/24","properties":{"Id":24}} 148 # or 149 # /xyz/openbmc_project/dump/entry/1","properties":{"Size":186180}}'). 150 151 if monitoring_uri + "/entry" in message: 152 if "Id" in message: 153 qprint_timen("eSEL received over websocket interface.") 154 websocket_obj.close() 155 elif "Size" in message: 156 qprint_timen( 157 "Dump notification received over websocket interface." 158 ) 159 websocket_obj.close() 160 161 162def on_error(websocket_obj, wserror): 163 """ 164 Websocket error handler. This routine is called whenever the 165 websocket interfaces wishes to report an issue. 166 167 Description of argument(s): 168 websocket_obj The websocket established during opne_socket(). 169 wserror The error message sent from the websocket interface. 170 """ 171 172 # It is normal to receive this message when websocked closes: 173 # 'NoneType' object has no attribute 'connected'. 174 175 qprint_dashes(width=160) 176 qprint_executing() 177 178 179def on_close(websocket_obj): 180 """ 181 Websocket close event handler. 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 190 191def on_open(websocket_obj): 192 """ 193 Send the filters needed to listen to the logging interface. 194 195 Description of argument(s): 196 websocket_obj The websocket established during opne_socket(). 197 """ 198 199 qprint_dashes(width=160) 200 qprint_executing() 201 data = {"paths": [monitoring_uri]} 202 websocket_obj.send(json.dumps(data)) 203 qprint_timen("Registered for websocket monitoring: " + monitoring_uri) 204 205 206def open_socket(openbmc_host, openbmc_username, openbmc_password): 207 """ 208 Open a long-running websocket to the BMC. 209 Description of argument(s): 210 openbmc_host The BMC host name or IP address. 211 openbmc_username The userid for the open BMC system. 212 openbmc_password The Password for the open BMC system. 213 """ 214 websocket.enableTrace(False) 215 qprint_dashes(width=160) 216 qprint_executing() 217 session = login(openbmc_host, openbmc_username, openbmc_password) 218 qprint_timen("Registering websocket handlers.") 219 cookies = session.cookies.get_dict() 220 cookies = sprint_var( 221 cookies, 222 fmt=no_header() | strip_brackets(), 223 col1_width=0, 224 trailing_char="", 225 delim="=", 226 ).replace("\n", ";") 227 # Register the event handlers. When an ESEL is created by the system 228 # under test, the on_message() handler will be called. 229 websocket_obj = websocket.WebSocketApp( 230 "wss://" + openbmc_host + "/subscribe", 231 on_message=on_message, 232 on_error=on_error, 233 on_close=on_close, 234 on_open=on_open, 235 cookie=cookies, 236 ) 237 qprint_timen("Completed registering of websocket handlers.") 238 websocket_obj.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE}) 239 240 241def main(): 242 gen_get_options(parser, stock_list) 243 validate_parms() 244 qprint_pgm_header() 245 qprint_var(monitoring_uri) 246 open_socket(openbmc_host, openbmc_username, openbmc_password) 247 248 249main() 250