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