xref: /openbmc/openbmc-test-automation/bin/websocket_monitor.py (revision 20f38712b324e61a94e174017c487a0af4b373e1)
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