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