1e7e9171eSGeorge Keishing#!/usr/bin/env python3 23468df56SSteven Sombar 33468df56SSteven Sombarr""" 43468df56SSteven SombarSee help text for details. 53468df56SSteven Sombar""" 63468df56SSteven Sombar 7e635ddc0SGeorge Keishingimport json 8e635ddc0SGeorge Keishingimport ssl 9*20f38712SPatrick Williamsimport sys 10*20f38712SPatrick Williams 11e635ddc0SGeorge Keishingimport requests 12*20f38712SPatrick Williamsimport websocket 133468df56SSteven Sombarfrom retrying import retry 143468df56SSteven Sombar 153468df56SSteven Sombarsave_path_0 = sys.path[0] 163468df56SSteven Sombardel sys.path[0] 173468df56SSteven Sombar 1809679890SGeorge Keishingfrom gen_arg import * # NOQA 19*20f38712SPatrick Williamsfrom gen_print import * # NOQA 2009679890SGeorge Keishingfrom gen_valid import * # NOQA 2137c58c8cSGeorge Keishing 223468df56SSteven Sombar# Restore sys.path[0]. 233468df56SSteven Sombarsys.path.insert(0, save_path_0) 243468df56SSteven Sombar 253468df56SSteven Sombar# Set exit_on_error for gen_valid functions. 263468df56SSteven Sombarset_exit_on_error(True) 273468df56SSteven Sombar 283468df56SSteven Sombar 293468df56SSteven Sombarparser = argparse.ArgumentParser( 30*20f38712SPatrick Williams usage="%(prog)s [OPTIONS]", 313468df56SSteven Sombar description="%(prog)s will open a websocket session on a remote OpenBMC. " 323468df56SSteven Sombar + "When an eSEL is created on that BMC, the monitor will receive " 333468df56SSteven Sombar + "notice over websocket that the eSEL was created " 343468df56SSteven Sombar + "and it will print a message.", 353468df56SSteven Sombar formatter_class=argparse.ArgumentDefaultsHelpFormatter, 36*20f38712SPatrick Williams prefix_chars="-+", 37*20f38712SPatrick Williams) 383468df56SSteven Sombarparser.add_argument( 39*20f38712SPatrick Williams "openbmc_host", default="", help="The BMC host name or IP address." 40*20f38712SPatrick Williams) 413468df56SSteven Sombarparser.add_argument( 42*20f38712SPatrick Williams "--openbmc_username", 43*20f38712SPatrick Williams default="root", 44*20f38712SPatrick Williams help="The userid for the open BMC system.", 45*20f38712SPatrick Williams) 463468df56SSteven Sombarparser.add_argument( 47*20f38712SPatrick Williams "--openbmc_password", 48*20f38712SPatrick Williams default="", 49*20f38712SPatrick Williams help="The password for the open BMC system.", 50*20f38712SPatrick Williams) 51acdb3842SSteven Sombarparser.add_argument( 52*20f38712SPatrick Williams "--monitor_type", 53*20f38712SPatrick Williams choices=["logging", "dump"], 54*20f38712SPatrick Williams default="logging", 55*20f38712SPatrick Williams help="The type of notifications from websocket to monitor.", 56*20f38712SPatrick Williams) 57acdb3842SSteven Sombar 583468df56SSteven Sombar 593468df56SSteven Sombarstock_list = [("test_mode", 0), ("quiet", 0), ("debug", 0)] 603468df56SSteven Sombar 613468df56SSteven Sombar 62*20f38712SPatrick Williamsdef exit_function(signal_number=0, frame=None): 633468df56SSteven Sombar r""" 643468df56SSteven Sombar Execute whenever the program ends normally or with the signals that we 653468df56SSteven Sombar catch (i.e. TERM, INT). 663468df56SSteven Sombar """ 673468df56SSteven Sombar 683468df56SSteven Sombar qprint_dashes(width=160) 693468df56SSteven Sombar qprint_executing() 703468df56SSteven Sombar qprint_pgm_footer() 713468df56SSteven Sombar 723468df56SSteven Sombar 73*20f38712SPatrick Williamsdef signal_handler(signal_number, frame): 743468df56SSteven Sombar r""" 753468df56SSteven Sombar Handle signals. Without a function to catch a SIGTERM or SIGINT, the 763468df56SSteven Sombar program would terminate immediately with return code 143 and without 773468df56SSteven Sombar calling the exit_function. 783468df56SSteven Sombar """ 793468df56SSteven Sombar 803468df56SSteven Sombar # Our convention is to set up exit_function with atexit.register() so 813468df56SSteven Sombar # there is no need to explicitly call exit_function from here. 823468df56SSteven Sombar 833468df56SSteven Sombar dprint_executing() 843468df56SSteven Sombar 85acdb3842SSteven Sombar # Calling exit prevents returning to the code that was running 863468df56SSteven Sombar # when the signal was received. 873468df56SSteven Sombar exit(0) 883468df56SSteven Sombar 893468df56SSteven Sombar 903468df56SSteven Sombardef validate_parms(): 913468df56SSteven Sombar r""" 923468df56SSteven Sombar Validate program parameters, etc. 933468df56SSteven Sombar """ 943468df56SSteven Sombar 953468df56SSteven Sombar register_passwords(openbmc_password) 963468df56SSteven Sombar valid_value(openbmc_host) 973468df56SSteven Sombar valid_value(openbmc_username) 983468df56SSteven Sombar valid_value(openbmc_password) 99acdb3842SSteven Sombar global monitoring_uri 100*20f38712SPatrick Williams monitoring_uri = "/xyz/openbmc_project/" + monitor_type 1013468df56SSteven Sombar gen_post_validation(exit_function, signal_handler) 1023468df56SSteven Sombar 1033468df56SSteven Sombar 1043468df56SSteven Sombar@retry(stop_max_attempt_number=3, wait_fixed=1000) 105*20f38712SPatrick Williamsdef login(openbmc_host, openbmc_username, openbmc_password): 1063468df56SSteven Sombar r""" 1073468df56SSteven Sombar Log into the BMC and return the session object. 1083468df56SSteven Sombar 1093468df56SSteven Sombar Description of argument(s): 1103468df56SSteven Sombar openbmc_host The BMC host name or IP address. 1113468df56SSteven Sombar openbmc_username The userid for the open BMC system. 1123468df56SSteven Sombar openbmc_password The password for the open BMC system. 1133468df56SSteven Sombar """ 1143468df56SSteven Sombar 1153468df56SSteven Sombar qprint_executing() 1163468df56SSteven Sombar 117*20f38712SPatrick Williams http_header = {"Content-Type": "application/json"} 1183468df56SSteven Sombar session = requests.session() 119*20f38712SPatrick Williams response = session.post( 120*20f38712SPatrick Williams "https://" + openbmc_host + "/login", 121*20f38712SPatrick Williams headers=http_header, 1223468df56SSteven Sombar json={"data": [openbmc_username, openbmc_password]}, 123*20f38712SPatrick Williams verify=False, 124*20f38712SPatrick Williams timeout=30, 125*20f38712SPatrick Williams ) 1263468df56SSteven Sombar valid_value(response.status_code, valid_values=[200]) 1273468df56SSteven Sombar login_response = json.loads(response.text) 1283468df56SSteven Sombar qprint_var(login_response) 129*20f38712SPatrick Williams valid_value(login_response["status"], valid_values=["ok"]) 1303468df56SSteven Sombar 1313468df56SSteven Sombar return session 1323468df56SSteven Sombar 1333468df56SSteven Sombar 1343468df56SSteven Sombardef on_message(websocket_obj, message): 1353468df56SSteven Sombar """ 1363468df56SSteven Sombar Websocket message handler. Close the websocket if the 1373468df56SSteven Sombar message is an eSEL message. 1383468df56SSteven Sombar 1393468df56SSteven Sombar Description of argument(s): 1403468df56SSteven Sombar websocket_obj The websocket established during opne_socket(). 1413468df56SSteven Sombar message The message sent from the websocket interface. 1423468df56SSteven Sombar """ 1433468df56SSteven Sombar 1443468df56SSteven Sombar qprint_dashes(width=160) 1453468df56SSteven Sombar qprint_executing() 1463468df56SSteven Sombar 1473468df56SSteven Sombar # A typical message: 148acdb3842SSteven Sombar # /xyz/openbmc_project/logging/entry/24","properties":{"Id":24}} 149acdb3842SSteven Sombar # or 150acdb3842SSteven Sombar # /xyz/openbmc_project/dump/entry/1","properties":{"Size":186180}}'). 1513468df56SSteven Sombar 152*20f38712SPatrick Williams if monitoring_uri + "/entry" in message: 153*20f38712SPatrick Williams if "Id" in message: 154*20f38712SPatrick Williams qprint_timen("eSEL received over websocket interface.") 155acdb3842SSteven Sombar websocket_obj.close() 156*20f38712SPatrick Williams elif "Size" in message: 157*20f38712SPatrick Williams qprint_timen( 158*20f38712SPatrick Williams "Dump notification received over websocket interface." 159*20f38712SPatrick Williams ) 1603468df56SSteven Sombar websocket_obj.close() 1613468df56SSteven Sombar 1623468df56SSteven Sombar 1633468df56SSteven Sombardef on_error(websocket_obj, wserror): 1643468df56SSteven Sombar """ 1653468df56SSteven Sombar Websocket error handler. This routine is called whenever the 1663468df56SSteven Sombar websocket interfaces wishes to report an issue. 1673468df56SSteven Sombar 1683468df56SSteven Sombar Description of argument(s): 1693468df56SSteven Sombar websocket_obj The websocket established during opne_socket(). 1703468df56SSteven Sombar wserror The error message sent from the websocket interface. 1713468df56SSteven Sombar """ 1723468df56SSteven Sombar 1733468df56SSteven Sombar # It is normal to receive this message when websocked closes: 1743468df56SSteven Sombar # 'NoneType' object has no attribute 'connected'. 1753468df56SSteven Sombar 1763468df56SSteven Sombar qprint_dashes(width=160) 1773468df56SSteven Sombar qprint_executing() 1783468df56SSteven Sombar 1793468df56SSteven Sombar 1803468df56SSteven Sombardef on_close(websocket_obj): 1813468df56SSteven Sombar """ 1823468df56SSteven Sombar Websocket close event handler. 1833468df56SSteven Sombar 1843468df56SSteven Sombar Description of argument(s): 1853468df56SSteven Sombar websocket_obj The websocket established during opne_socket(). 1863468df56SSteven Sombar """ 1873468df56SSteven Sombar 1883468df56SSteven Sombar qprint_dashes(width=160) 1893468df56SSteven Sombar qprint_executing() 1903468df56SSteven Sombar 1913468df56SSteven Sombar 1923468df56SSteven Sombardef on_open(websocket_obj): 1933468df56SSteven Sombar """ 1943468df56SSteven Sombar Send the filters needed to listen to the logging interface. 1953468df56SSteven Sombar 1963468df56SSteven Sombar Description of argument(s): 1973468df56SSteven Sombar websocket_obj The websocket established during opne_socket(). 1983468df56SSteven Sombar """ 1993468df56SSteven Sombar 2003468df56SSteven Sombar qprint_dashes(width=160) 2013468df56SSteven Sombar qprint_executing() 202acdb3842SSteven Sombar data = {"paths": [monitoring_uri]} 2033468df56SSteven Sombar websocket_obj.send(json.dumps(data)) 204acdb3842SSteven Sombar qprint_timen("Registered for websocket monitoring: " + monitoring_uri) 2053468df56SSteven Sombar 2063468df56SSteven Sombar 2073468df56SSteven Sombardef open_socket(openbmc_host, openbmc_username, openbmc_password): 2083468df56SSteven Sombar """ 2093468df56SSteven Sombar Open a long-running websocket to the BMC. 2103468df56SSteven Sombar Description of argument(s): 2113468df56SSteven Sombar openbmc_host The BMC host name or IP address. 2123468df56SSteven Sombar openbmc_username The userid for the open BMC system. 2133468df56SSteven Sombar openbmc_password The Password for the open BMC system. 2143468df56SSteven Sombar """ 2153468df56SSteven Sombar websocket.enableTrace(False) 2163468df56SSteven Sombar qprint_dashes(width=160) 2173468df56SSteven Sombar qprint_executing() 2183468df56SSteven Sombar session = login(openbmc_host, openbmc_username, openbmc_password) 2193468df56SSteven Sombar qprint_timen("Registering websocket handlers.") 2203468df56SSteven Sombar cookies = session.cookies.get_dict() 221*20f38712SPatrick Williams cookies = sprint_var( 222*20f38712SPatrick Williams cookies, 223*20f38712SPatrick Williams fmt=no_header() | strip_brackets(), 224*20f38712SPatrick Williams col1_width=0, 225*20f38712SPatrick Williams trailing_char="", 226*20f38712SPatrick Williams delim="=", 227*20f38712SPatrick Williams ).replace("\n", ";") 2283468df56SSteven Sombar # Register the event handlers. When an ESEL is created by the system 2293468df56SSteven Sombar # under test, the on_message() handler will be called. 230*20f38712SPatrick Williams websocket_obj = websocket.WebSocketApp( 231*20f38712SPatrick Williams "wss://" + openbmc_host + "/subscribe", 2323468df56SSteven Sombar on_message=on_message, 2333468df56SSteven Sombar on_error=on_error, 2343468df56SSteven Sombar on_close=on_close, 2353468df56SSteven Sombar on_open=on_open, 236*20f38712SPatrick Williams cookie=cookies, 237*20f38712SPatrick Williams ) 2383468df56SSteven Sombar qprint_timen("Completed registering of websocket handlers.") 2393468df56SSteven Sombar websocket_obj.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE}) 2403468df56SSteven Sombar 2413468df56SSteven Sombar 2423468df56SSteven Sombardef main(): 2433468df56SSteven Sombar gen_get_options(parser, stock_list) 2443468df56SSteven Sombar validate_parms() 2453468df56SSteven Sombar qprint_pgm_header() 246acdb3842SSteven Sombar qprint_var(monitoring_uri) 2473468df56SSteven Sombar open_socket(openbmc_host, openbmc_username, openbmc_password) 2483468df56SSteven Sombar 2493468df56SSteven Sombar 2503468df56SSteven Sombarmain() 251