xref: /openbmc/openbmc-test-automation/lib/state.py (revision 139f1da69baea53bab830baafcbc75d59f51459b)
1e7e9171eSGeorge Keishing#!/usr/bin/env python3
270369fdcSMichael Walsh
370369fdcSMichael Walshr"""
470369fdcSMichael WalshThis module contains functions having to do with machine state: get_state,
570369fdcSMichael Walshcheck_state, wait_state, etc.
670369fdcSMichael Walsh
770369fdcSMichael WalshThe 'State' is a composite of many pieces of data.  Therefore, the functions
870369fdcSMichael Walshin this module define state as an ordered dictionary.  Here is an example of
970369fdcSMichael Walshsome test output showing machine state:
1070369fdcSMichael Walsh
11341c21ebSMichael Walshdefault_state:
1265b12540SMichael Walsh  default_state[chassis]:                         On
1301975fa8SMichael Walsh  default_state[boot_progress]:                   OSStart
145674922eSMichael Walsh  default_state[operating_system]:                BootComplete
1565b12540SMichael Walsh  default_state[host]:                            Running
16341c21ebSMichael Walsh  default_state[os_ping]:                         1
17341c21ebSMichael Walsh  default_state[os_login]:                        1
18341c21ebSMichael Walsh  default_state[os_run_cmd]:                      1
1970369fdcSMichael Walsh
2070369fdcSMichael WalshDifferent users may very well have different needs when inquiring about
218fae6eaeSMichael Walshstate.  Support for new pieces of state information may be added to this
228fae6eaeSMichael Walshmodule as needed.
2370369fdcSMichael Walsh
2470369fdcSMichael WalshBy using the wait_state function, a caller can start a boot and then wait for
2570369fdcSMichael Walsha precisely defined state to indicate that the boot has succeeded.  If
2670369fdcSMichael Walshthe boot fails, they can see exactly why by looking at the current state as
2770369fdcSMichael Walshcompared with the expected state.
2870369fdcSMichael Walsh"""
2970369fdcSMichael Walsh
30*139f1da6SBrian Maimport importlib.util
3120f38712SPatrick Williamsimport os
3220f38712SPatrick Williamsimport re
3320f38712SPatrick Williamsimport sys
34e635ddc0SGeorge Keishing
3520f38712SPatrick Williamsimport bmc_ssh_utils as bsu
3620f38712SPatrick Williamsimport gen_cmd as gc
3720f38712SPatrick Williamsimport gen_print as gp
3820f38712SPatrick Williamsimport gen_robot_utils as gru
3920f38712SPatrick Williamsimport gen_valid as gv
4070369fdcSMichael Walshfrom robot.libraries.BuiltIn import BuiltIn
41341c21ebSMichael Walshfrom robot.utils import DotDict
4270369fdcSMichael Walsh
435a5868aaSMichael Walsh# NOTE: Avoid importing utils.robot because utils.robot imports state.py
445a5868aaSMichael Walsh# (indirectly) which will cause failures.
455a5868aaSMichael Walshgru.my_import_resource("rest_client.robot")
4670369fdcSMichael Walsh
4720f38712SPatrick Williamsbase_path = (
48*139f1da6SBrian Ma    os.path.dirname(
49*139f1da6SBrian Ma        os.path.dirname(importlib.util.find_spec("gen_robot_print").origin)
50*139f1da6SBrian Ma    )
5120f38712SPatrick Williams    + os.sep
5220f38712SPatrick Williams)
535674922eSMichael Walshsys.path.append(base_path + "data/")
545674922eSMichael Walsh
55940d6914SMichael Walsh# Previously, I had this coded:
56940d6914SMichael Walsh# import variables as var
57940d6914SMichael Walsh# However, we ran into a problem where a robot program did this...
58940d6914SMichael Walsh# Variables           ../../lib/ras/variables.py
59940d6914SMichael Walsh# Prior to doing this...
60940d6914SMichael Walsh# Library            ../lib/state.py
61940d6914SMichael Walsh
62940d6914SMichael Walsh# This caused the wrong variables.py file to be selected.  Attempts to fix this
63940d6914SMichael Walsh# have failed so far.  For the moment, we will hard-code the value we need from
64940d6914SMichael Walsh# the file.
65940d6914SMichael Walsh
66940d6914SMichael WalshSYSTEM_STATE_URI = "/xyz/openbmc_project/state/"
675674922eSMichael Walsh
688fae6eaeSMichael Walsh# The BMC code has recently been changed as far as what states are defined and
698fae6eaeSMichael Walsh# what the state values can be.  This module now has a means of processing both
708fae6eaeSMichael Walsh# the old style state (i.e. OBMC_STATES_VERSION = 0) and the new style (i.e.
7116cbb7f7SMichael Walsh# OBMC_STATES_VERSION = 1).
72341c21ebSMichael Walsh# The caller can set environment variable OBMC_STATES_VERSION to dictate
73341c21ebSMichael Walsh# whether we're processing old or new style states.  If OBMC_STATES_VERSION is
748fae6eaeSMichael Walsh# not set it will default to 1.
75341c21ebSMichael Walsh
76619aa332SMichael Walsh# As of the present moment, OBMC_STATES_VERSION of 0 is for cold that is so old
77619aa332SMichael Walsh# that it is no longer worthwhile to maintain.  The OBMC_STATES_VERSION 0 code
78619aa332SMichael Walsh# is being removed but the OBMC_STATES_VERSION value will stay for now in the
79619aa332SMichael Walsh# event that it is needed in the future.
80619aa332SMichael Walsh
8120f38712SPatrick WilliamsOBMC_STATES_VERSION = int(os.environ.get("OBMC_STATES_VERSION", 1))
82341c21ebSMichael Walsh
8320f38712SPatrick Williamsredfish_support_trans_state = int(
8420f38712SPatrick Williams    os.environ.get("REDFISH_SUPPORT_TRANS_STATE", 0)
8520f38712SPatrick Williams) or int(
8620f38712SPatrick Williams    BuiltIn().get_variable_value("${REDFISH_SUPPORT_TRANS_STATE}", default=0)
8720f38712SPatrick Williams)
88da40c1d2SMichael Shepos
8920f38712SPatrick Williamsplatform_arch_type = os.environ.get(
9020f38712SPatrick Williams    "PLATFORM_ARCH_TYPE", ""
9120f38712SPatrick Williams) or BuiltIn().get_variable_value("${PLATFORM_ARCH_TYPE}", default="power")
921e2fbee9SGeorge Keishing
93bdd1dceaSMichael Shepos# valid_os_req_states and default_os_req_states are used by the os_get_state
94bdd1dceaSMichael Shepos# function.
95bdd1dceaSMichael Shepos# valid_os_req_states is a list of state information supported by the
96bdd1dceaSMichael Shepos# get_os_state function.
9720f38712SPatrick Williamsvalid_os_req_states = ["os_ping", "os_login", "os_run_cmd"]
98bdd1dceaSMichael Shepos
99bdd1dceaSMichael Shepos# When a user calls get_os_state w/o specifying req_states,
100bdd1dceaSMichael Shepos# default_os_req_states is used as its value.
10120f38712SPatrick Williamsdefault_os_req_states = ["os_ping", "os_login", "os_run_cmd"]
102bdd1dceaSMichael Shepos
103bdd1dceaSMichael Shepos# Presently, some BMCs appear to not keep time very well.  This environment
104bdd1dceaSMichael Shepos# variable directs the get_state function to use either the BMC's epoch time
105bdd1dceaSMichael Shepos# or the local epoch time.
10620f38712SPatrick WilliamsUSE_BMC_EPOCH_TIME = int(os.environ.get("USE_BMC_EPOCH_TIME", 0))
107bdd1dceaSMichael Shepos
108bdd1dceaSMichael Shepos# Useful state constant definition(s).
109bdd1dceaSMichael Sheposif not redfish_support_trans_state:
1108fae6eaeSMichael Walsh    # When a user calls get_state w/o specifying req_states, default_req_states
1118fae6eaeSMichael Walsh    # is used as its value.
11220f38712SPatrick Williams    default_req_states = [
11320f38712SPatrick Williams        "rest",
11420f38712SPatrick Williams        "chassis",
11520f38712SPatrick Williams        "bmc",
11620f38712SPatrick Williams        "boot_progress",
11720f38712SPatrick Williams        "operating_system",
11820f38712SPatrick Williams        "host",
11920f38712SPatrick Williams        "os_ping",
12020f38712SPatrick Williams        "os_login",
12120f38712SPatrick Williams        "os_run_cmd",
12220f38712SPatrick Williams    ]
1238fae6eaeSMichael Walsh
124619aa332SMichael Walsh    # valid_req_states is a list of sub states supported by the get_state function.
125619aa332SMichael Walsh    # valid_req_states, default_req_states and master_os_up_match are used by the
1268fae6eaeSMichael Walsh    # get_state function.
127da40c1d2SMichael Shepos
12820f38712SPatrick Williams    valid_req_states = [
12920f38712SPatrick Williams        "ping",
13020f38712SPatrick Williams        "packet_loss",
13120f38712SPatrick Williams        "uptime",
13220f38712SPatrick Williams        "epoch_seconds",
13320f38712SPatrick Williams        "elapsed_boot_time",
13420f38712SPatrick Williams        "rest",
13520f38712SPatrick Williams        "chassis",
13620f38712SPatrick Williams        "requested_chassis",
13720f38712SPatrick Williams        "bmc",
13820f38712SPatrick Williams        "requested_bmc",
13920f38712SPatrick Williams        "boot_progress",
14020f38712SPatrick Williams        "operating_system",
14120f38712SPatrick Williams        "host",
14220f38712SPatrick Williams        "requested_host",
14320f38712SPatrick Williams        "attempts_left",
14420f38712SPatrick Williams        "os_ping",
14520f38712SPatrick Williams        "os_login",
14620f38712SPatrick Williams        "os_run_cmd",
14720f38712SPatrick Williams    ]
1488fae6eaeSMichael Walsh
149619aa332SMichael Walsh    # default_state is an initial value which may be of use to callers.
15020f38712SPatrick Williams    default_state = DotDict(
15120f38712SPatrick Williams        [
15220f38712SPatrick Williams            ("rest", "1"),
15320f38712SPatrick Williams            ("chassis", "On"),
15420f38712SPatrick Williams            ("bmc", "Ready"),
15520f38712SPatrick Williams            ("boot_progress", "OSStart"),
15620f38712SPatrick Williams            ("operating_system", "BootComplete"),
15720f38712SPatrick Williams            ("host", "Running"),
15820f38712SPatrick Williams            ("os_ping", "1"),
15920f38712SPatrick Williams            ("os_login", "1"),
16020f38712SPatrick Williams            ("os_run_cmd", "1"),
16120f38712SPatrick Williams        ]
16220f38712SPatrick Williams    )
163619aa332SMichael Walsh
1647dc885b6SMichael Walsh    # A match state for checking that the system is at "standby".
16520f38712SPatrick Williams    standby_match_state = DotDict(
16620f38712SPatrick Williams        [
16720f38712SPatrick Williams            ("rest", "^1$"),
16820f38712SPatrick Williams            ("chassis", "^Off$"),
16920f38712SPatrick Williams            ("bmc", "^Ready$"),
17020f38712SPatrick Williams            ("boot_progress", "^Off|Unspecified$"),
17120f38712SPatrick Williams            ("operating_system", "^Inactive$"),
17220f38712SPatrick Williams            ("host", "^Off$"),
17320f38712SPatrick Williams        ]
17420f38712SPatrick Williams    )
1757dc885b6SMichael Walsh
1767dc885b6SMichael Walsh    # A match state for checking that the system is at "os running".
17720f38712SPatrick Williams    os_running_match_state = DotDict(
17820f38712SPatrick Williams        [
17920f38712SPatrick Williams            ("chassis", "^On$"),
18020f38712SPatrick Williams            ("bmc", "^Ready$"),
18120f38712SPatrick Williams            ("boot_progress", "FW Progress, Starting OS|OSStart"),
18220f38712SPatrick Williams            ("operating_system", "BootComplete"),
18320f38712SPatrick Williams            ("host", "^Running$"),
18420f38712SPatrick Williams            ("os_ping", "^1$"),
18520f38712SPatrick Williams            ("os_login", "^1$"),
18620f38712SPatrick Williams            ("os_run_cmd", "^1$"),
18720f38712SPatrick Williams        ]
18820f38712SPatrick Williams    )
1897dc885b6SMichael Walsh
190619aa332SMichael Walsh    # A master dictionary to determine whether the os may be up.
19120f38712SPatrick Williams    master_os_up_match = DotDict(
19220f38712SPatrick Williams        [
19320f38712SPatrick Williams            ("chassis", "^On$"),
19420f38712SPatrick Williams            ("bmc", "^Ready$"),
19520f38712SPatrick Williams            ("boot_progress", "FW Progress, Starting OS|OSStart"),
19620f38712SPatrick Williams            ("operating_system", "BootComplete"),
19720f38712SPatrick Williams            ("host", "^Running|Quiesced$"),
19820f38712SPatrick Williams        ]
19920f38712SPatrick Williams    )
200619aa332SMichael Walsh
20120f38712SPatrick Williams    invalid_state_match = DotDict(
20220f38712SPatrick Williams        [
20320f38712SPatrick Williams            ("rest", "^$"),
20420f38712SPatrick Williams            ("chassis", "^$"),
20520f38712SPatrick Williams            ("bmc", "^$"),
20620f38712SPatrick Williams            ("boot_progress", "^$"),
20720f38712SPatrick Williams            ("operating_system", "^$"),
20820f38712SPatrick Williams            ("host", "^$"),
20920f38712SPatrick Williams        ]
21020f38712SPatrick Williams    )
211da40c1d2SMichael Sheposelse:
212bdd1dceaSMichael Shepos    # When a user calls get_state w/o specifying req_states, default_req_states
213bdd1dceaSMichael Shepos    # is used as its value.
21420f38712SPatrick Williams    default_req_states = [
21520f38712SPatrick Williams        "redfish",
21620f38712SPatrick Williams        "chassis",
21720f38712SPatrick Williams        "bmc",
21820f38712SPatrick Williams        "boot_progress",
21920f38712SPatrick Williams        "host",
22020f38712SPatrick Williams        "os_ping",
22120f38712SPatrick Williams        "os_login",
22220f38712SPatrick Williams        "os_run_cmd",
22320f38712SPatrick Williams    ]
224bdd1dceaSMichael Shepos
225bdd1dceaSMichael Shepos    # valid_req_states is a list of sub states supported by the get_state function.
226bdd1dceaSMichael Shepos    # valid_req_states, default_req_states and master_os_up_match are used by the
227bdd1dceaSMichael Shepos    # get_state function.
228bdd1dceaSMichael Shepos
22920f38712SPatrick Williams    valid_req_states = [
23020f38712SPatrick Williams        "ping",
23120f38712SPatrick Williams        "packet_loss",
23220f38712SPatrick Williams        "uptime",
23320f38712SPatrick Williams        "epoch_seconds",
23420f38712SPatrick Williams        "elapsed_boot_time",
23520f38712SPatrick Williams        "redfish",
23620f38712SPatrick Williams        "chassis",
23720f38712SPatrick Williams        "requested_chassis",
23820f38712SPatrick Williams        "bmc",
23920f38712SPatrick Williams        "requested_bmc",
24020f38712SPatrick Williams        "boot_progress",
24120f38712SPatrick Williams        "host",
24220f38712SPatrick Williams        "requested_host",
24320f38712SPatrick Williams        "attempts_left",
24420f38712SPatrick Williams        "os_ping",
24520f38712SPatrick Williams        "os_login",
24620f38712SPatrick Williams        "os_run_cmd",
24720f38712SPatrick Williams    ]
248bdd1dceaSMichael Shepos
249da40c1d2SMichael Shepos    # default_state is an initial value which may be of use to callers.
25020f38712SPatrick Williams    default_state = DotDict(
25120f38712SPatrick Williams        [
25220f38712SPatrick Williams            ("redfish", "1"),
25320f38712SPatrick Williams            ("chassis", "On"),
25420f38712SPatrick Williams            ("bmc", "Enabled"),
25520f38712SPatrick Williams            (
25620f38712SPatrick Williams                "boot_progress",
25720f38712SPatrick Williams                "SystemHardwareInitializationComplete|OSBootStarted|OSRunning",
25820f38712SPatrick Williams            ),
25920f38712SPatrick Williams            ("host", "Enabled"),
26020f38712SPatrick Williams            ("os_ping", "1"),
26120f38712SPatrick Williams            ("os_login", "1"),
26220f38712SPatrick Williams            ("os_run_cmd", "1"),
26320f38712SPatrick Williams        ]
26420f38712SPatrick Williams    )
265da40c1d2SMichael Shepos
266da40c1d2SMichael Shepos    # A match state for checking that the system is at "standby".
26720f38712SPatrick Williams    standby_match_state = DotDict(
26820f38712SPatrick Williams        [
26920f38712SPatrick Williams            ("redfish", "^1$"),
27020f38712SPatrick Williams            ("chassis", "^Off$"),
27120f38712SPatrick Williams            ("bmc", "^Enabled$"),
27220f38712SPatrick Williams            ("boot_progress", "^None$"),
27320f38712SPatrick Williams            ("host", "^Disabled$"),
27420f38712SPatrick Williams        ]
27520f38712SPatrick Williams    )
276da40c1d2SMichael Shepos
277da40c1d2SMichael Shepos    # A match state for checking that the system is at "os running".
27820f38712SPatrick Williams    os_running_match_state = DotDict(
27920f38712SPatrick Williams        [
28020f38712SPatrick Williams            ("chassis", "^On$"),
28120f38712SPatrick Williams            ("bmc", "^Enabled$"),
28220f38712SPatrick Williams            (
28320f38712SPatrick Williams                "boot_progress",
28420f38712SPatrick Williams                "SystemHardwareInitializationComplete|OSBootStarted|OSRunning",
28520f38712SPatrick Williams            ),
28620f38712SPatrick Williams            ("host", "^Enabled$"),
28720f38712SPatrick Williams            ("os_ping", "^1$"),
28820f38712SPatrick Williams            ("os_login", "^1$"),
28920f38712SPatrick Williams            ("os_run_cmd", "^1$"),
29020f38712SPatrick Williams        ]
29120f38712SPatrick Williams    )
292da40c1d2SMichael Shepos
293da40c1d2SMichael Shepos    # A master dictionary to determine whether the os may be up.
29420f38712SPatrick Williams    master_os_up_match = DotDict(
29520f38712SPatrick Williams        [
29620f38712SPatrick Williams            ("chassis", "^On$"),
29720f38712SPatrick Williams            ("bmc", "^Enabled$"),
29820f38712SPatrick Williams            (
29920f38712SPatrick Williams                "boot_progress",
30020f38712SPatrick Williams                "SystemHardwareInitializationComplete|OSBootStarted|OSRunning",
30120f38712SPatrick Williams            ),
30220f38712SPatrick Williams            ("host", "^Enabled$"),
30320f38712SPatrick Williams        ]
30420f38712SPatrick Williams    )
305da40c1d2SMichael Shepos
30620f38712SPatrick Williams    invalid_state_match = DotDict(
30720f38712SPatrick Williams        [
30820f38712SPatrick Williams            ("redfish", "^$"),
30920f38712SPatrick Williams            ("chassis", "^$"),
31020f38712SPatrick Williams            ("bmc", "^$"),
31120f38712SPatrick Williams            ("boot_progress", "^$"),
31220f38712SPatrick Williams            ("host", "^$"),
31320f38712SPatrick Williams        ]
31420f38712SPatrick Williams    )
31545ca6e4cSMichael Walsh
3161e2fbee9SGeorge Keishing# Filter the states based on platform type.
3171e2fbee9SGeorge Keishingif platform_arch_type == "x86":
318b51d1505SGeorge Keishing    if not redfish_support_trans_state:
3191e2fbee9SGeorge Keishing        default_req_states.remove("operating_system")
3201e2fbee9SGeorge Keishing        valid_req_states.remove("operating_system")
3211e2fbee9SGeorge Keishing        del default_state["operating_system"]
3221e2fbee9SGeorge Keishing        del standby_match_state["operating_system"]
3231e2fbee9SGeorge Keishing        del os_running_match_state["operating_system"]
3241e2fbee9SGeorge Keishing        del master_os_up_match["operating_system"]
3251e2fbee9SGeorge Keishing        del invalid_state_match["operating_system"]
326b51d1505SGeorge Keishing
327b51d1505SGeorge Keishing    default_req_states.remove("boot_progress")
328b51d1505SGeorge Keishing    valid_req_states.remove("boot_progress")
329b51d1505SGeorge Keishing    del default_state["boot_progress"]
330b51d1505SGeorge Keishing    del standby_match_state["boot_progress"]
331b51d1505SGeorge Keishing    del os_running_match_state["boot_progress"]
332b51d1505SGeorge Keishing    del master_os_up_match["boot_progress"]
3331e2fbee9SGeorge Keishing    del invalid_state_match["boot_progress"]
3341e2fbee9SGeorge Keishing
335341c21ebSMichael Walsh
33620f38712SPatrick Williamsdef return_state_constant(state_name="default_state"):
337619aa332SMichael Walsh    r"""
3387dc885b6SMichael Walsh    Return the named state dictionary constant.
339619aa332SMichael Walsh    """
340619aa332SMichael Walsh
34136efbc04SGeorge Keishing    return eval(state_name)
342619aa332SMichael Walsh
343619aa332SMichael Walsh
34470369fdcSMichael Walshdef anchor_state(state):
34570369fdcSMichael Walsh    r"""
34670369fdcSMichael Walsh    Add regular expression anchors ("^" and "$") to the beginning and end of
34770369fdcSMichael Walsh    each item in the state dictionary passed in.  Return the resulting
34870369fdcSMichael Walsh    dictionary.
34970369fdcSMichael Walsh
3502a0df683SMichael Walsh    Description of argument(s):
35170369fdcSMichael Walsh    state    A dictionary such as the one returned by the get_state()
35270369fdcSMichael Walsh             function.
35370369fdcSMichael Walsh    """
35470369fdcSMichael Walsh
3552ce067aeSMichael Walsh    anchored_state = state.copy()
3562a0df683SMichael Walsh    for key in anchored_state.keys():
35770369fdcSMichael Walsh        anchored_state[key] = "^" + str(anchored_state[key]) + "$"
35870369fdcSMichael Walsh
35970369fdcSMichael Walsh    return anchored_state
36070369fdcSMichael Walsh
36170369fdcSMichael Walsh
3628fae6eaeSMichael Walshdef strip_anchor_state(state):
3638fae6eaeSMichael Walsh    r"""
3648fae6eaeSMichael Walsh    Strip regular expression anchors ("^" and "$") from the beginning and end
3658fae6eaeSMichael Walsh    of each item in the state dictionary passed in.  Return the resulting
3668fae6eaeSMichael Walsh    dictionary.
3678fae6eaeSMichael Walsh
3682a0df683SMichael Walsh    Description of argument(s):
3698fae6eaeSMichael Walsh    state    A dictionary such as the one returned by the get_state()
3708fae6eaeSMichael Walsh             function.
3718fae6eaeSMichael Walsh    """
3728fae6eaeSMichael Walsh
3732ce067aeSMichael Walsh    stripped_state = state.copy()
3742a0df683SMichael Walsh    for key in stripped_state.keys():
3758fae6eaeSMichael Walsh        stripped_state[key] = stripped_state[key].strip("^$")
3768fae6eaeSMichael Walsh
3778fae6eaeSMichael Walsh    return stripped_state
3788fae6eaeSMichael Walsh
3798fae6eaeSMichael Walsh
3802a0df683SMichael Walshdef expressions_key():
3812a0df683SMichael Walsh    r"""
3822a0df683SMichael Walsh    Return expressions key constant.
3832a0df683SMichael Walsh    """
38420f38712SPatrick Williams    return "<expressions>"
3852a0df683SMichael Walsh
3862a0df683SMichael Walsh
38720f38712SPatrick Williamsdef compare_states(state, match_state, match_type="and"):
38870369fdcSMichael Walsh    r"""
3898fae6eaeSMichael Walsh    Compare 2 state dictionaries.  Return True if they match and False if they
39070369fdcSMichael Walsh    don't.  Note that the match_state dictionary does not need to have an entry
39170369fdcSMichael Walsh    corresponding to each entry in the state dictionary.  But for each entry
39270369fdcSMichael Walsh    that it does have, the corresponding state entry will be checked for a
39370369fdcSMichael Walsh    match.
39470369fdcSMichael Walsh
3952a0df683SMichael Walsh    Description of argument(s):
39670369fdcSMichael Walsh    state           A state dictionary such as the one returned by the
39770369fdcSMichael Walsh                    get_state function.
39870369fdcSMichael Walsh    match_state     A dictionary whose key/value pairs are "state field"/
39970369fdcSMichael Walsh                    "state value".  The state value is interpreted as a
40070369fdcSMichael Walsh                    regular expression.  Every value in this dictionary is
40145ca6e4cSMichael Walsh                    considered.  When match_type is 'and', if each and every
40245ca6e4cSMichael Walsh                    comparison matches, the two dictionaries are considered to
40345ca6e4cSMichael Walsh                    be matching.  If match_type is 'or', if any two of the
40445ca6e4cSMichael Walsh                    elements compared match, the two dictionaries are
40545ca6e4cSMichael Walsh                    considered to be matching.
4062a0df683SMichael Walsh
4077dc885b6SMichael Walsh                    This value may also be any string accepted by
4082a0df683SMichael Walsh                    return_state_constant (e.g. "standby_match_state").  In
4092a0df683SMichael Walsh                    such a case this function will call return_state_constant
4102a0df683SMichael Walsh                    to convert it to a proper dictionary as described above.
4112a0df683SMichael Walsh
4122a0df683SMichael Walsh                    Finally, one special value is accepted for the key field:
4132a0df683SMichael Walsh                    expression_key().  If such an entry exists, its value is
4142a0df683SMichael Walsh                    taken to be a list of expressions to be evaluated.  These
4152a0df683SMichael Walsh                    expressions may reference state dictionary entries by
4162a0df683SMichael Walsh                    simply coding them in standard python syntax (e.g.
4172a0df683SMichael Walsh                    state['key1']).  What follows is an example expression:
4182a0df683SMichael Walsh
4192a0df683SMichael Walsh                    "int(float(state['uptime'])) < int(state['elapsed_boot_time'])"
4202a0df683SMichael Walsh
4212a0df683SMichael Walsh                    In this example, if the state dictionary's 'uptime' entry
4222a0df683SMichael Walsh                    is less than its 'elapsed_boot_time' entry, it would
4232a0df683SMichael Walsh                    qualify as a match.
42445ca6e4cSMichael Walsh    match_type      This may be 'and' or 'or'.
42570369fdcSMichael Walsh    """
42670369fdcSMichael Walsh
42720f38712SPatrick Williams    error_message = gv.valid_value(match_type, valid_values=["and", "or"])
42845ca6e4cSMichael Walsh    if error_message != "":
42945ca6e4cSMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
43045ca6e4cSMichael Walsh
43136efbc04SGeorge Keishing    try:
4327dc885b6SMichael Walsh        match_state = return_state_constant(match_state)
43336efbc04SGeorge Keishing    except TypeError:
43436efbc04SGeorge Keishing        pass
4357dc885b6SMichael Walsh
43620f38712SPatrick Williams    default_match = match_type == "and"
43770369fdcSMichael Walsh    for key, match_state_value in match_state.items():
43897df71ceSMichael Walsh        # Blank match_state_value means "don't care".
43997df71ceSMichael Walsh        if match_state_value == "":
44097df71ceSMichael Walsh            continue
4412a0df683SMichael Walsh        if key == expressions_key():
4422a0df683SMichael Walsh            for expr in match_state_value:
4432a0df683SMichael Walsh                # Use python interpreter to evaluate the expression.
4442a0df683SMichael Walsh                match = eval(expr)
4452a0df683SMichael Walsh                if match != default_match:
4462a0df683SMichael Walsh                    return match
4472a0df683SMichael Walsh        else:
44870369fdcSMichael Walsh            try:
44920f38712SPatrick Williams                match = (
45020f38712SPatrick Williams                    re.match(match_state_value, str(state[key])) is not None
45120f38712SPatrick Williams                )
45270369fdcSMichael Walsh            except KeyError:
45370369fdcSMichael Walsh                match = False
45445ca6e4cSMichael Walsh            if match != default_match:
45570369fdcSMichael Walsh                return match
45670369fdcSMichael Walsh
45745ca6e4cSMichael Walsh    return default_match
45845ca6e4cSMichael Walsh
45970369fdcSMichael Walsh
46020f38712SPatrick Williamsdef get_os_state(
46120f38712SPatrick Williams    os_host="",
46270369fdcSMichael Walsh    os_username="",
46370369fdcSMichael Walsh    os_password="",
4648fae6eaeSMichael Walsh    req_states=default_os_req_states,
4658fae6eaeSMichael Walsh    os_up=True,
46620f38712SPatrick Williams    quiet=None,
46720f38712SPatrick Williams):
46870369fdcSMichael Walsh    r"""
46970369fdcSMichael Walsh    Get component states for the operating system such as ping, login,
47070369fdcSMichael Walsh    etc, put them into a dictionary and return them to the caller.
47170369fdcSMichael Walsh
4728fae6eaeSMichael Walsh    Note that all substate values are strings.
4738fae6eaeSMichael Walsh
4742a0df683SMichael Walsh    Description of argument(s):
47570369fdcSMichael Walsh    os_host      The DNS name or IP address of the operating system.
47670369fdcSMichael Walsh                 This defaults to global ${OS_HOST}.
47770369fdcSMichael Walsh    os_username  The username to be used to login to the OS.
47870369fdcSMichael Walsh                 This defaults to global ${OS_USERNAME}.
47970369fdcSMichael Walsh    os_password  The password to be used to login to the OS.
48070369fdcSMichael Walsh                 This defaults to global ${OS_PASSWORD}.
4818fae6eaeSMichael Walsh    req_states   This is a list of states whose values are being requested by
4828fae6eaeSMichael Walsh                 the caller.
4838fae6eaeSMichael Walsh    os_up        If the caller knows that the os can't possibly be up, it can
4848fae6eaeSMichael Walsh                 improve performance by passing os_up=False.  This function
4858fae6eaeSMichael Walsh                 will then simply return default values for all requested os
4868fae6eaeSMichael Walsh                 sub states.
48770369fdcSMichael Walsh    quiet        Indicates whether status details (e.g. curl commands) should
48870369fdcSMichael Walsh                 be written to the console.
48970369fdcSMichael Walsh                 Defaults to either global value of ${QUIET} or to 1.
49070369fdcSMichael Walsh    """
49170369fdcSMichael Walsh
492619aa332SMichael Walsh    quiet = int(gp.get_var_value(quiet, 0))
49370369fdcSMichael Walsh
49470369fdcSMichael Walsh    # Set parm defaults where necessary and validate all parms.
49570369fdcSMichael Walsh    if os_host == "":
49670369fdcSMichael Walsh        os_host = BuiltIn().get_variable_value("${OS_HOST}")
4972a0df683SMichael Walsh    error_message = gv.valid_value(os_host, invalid_values=[None, ""])
49870369fdcSMichael Walsh    if error_message != "":
49970369fdcSMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
50070369fdcSMichael Walsh
50170369fdcSMichael Walsh    if os_username == "":
50270369fdcSMichael Walsh        os_username = BuiltIn().get_variable_value("${OS_USERNAME}")
5032a0df683SMichael Walsh    error_message = gv.valid_value(os_username, invalid_values=[None, ""])
50470369fdcSMichael Walsh    if error_message != "":
50570369fdcSMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
50670369fdcSMichael Walsh
50770369fdcSMichael Walsh    if os_password == "":
50870369fdcSMichael Walsh        os_password = BuiltIn().get_variable_value("${OS_PASSWORD}")
5092a0df683SMichael Walsh    error_message = gv.valid_value(os_password, invalid_values=[None, ""])
51070369fdcSMichael Walsh    if error_message != "":
51170369fdcSMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
51270369fdcSMichael Walsh
51320f38712SPatrick Williams    invalid_req_states = [
51420f38712SPatrick Williams        sub_state
51520f38712SPatrick Williams        for sub_state in req_states
51620f38712SPatrick Williams        if sub_state not in valid_os_req_states
51720f38712SPatrick Williams    ]
5188fae6eaeSMichael Walsh    if len(invalid_req_states) > 0:
51920f38712SPatrick Williams        error_message = (
52020f38712SPatrick Williams            "The following req_states are not supported:\n"
52120f38712SPatrick Williams            + gp.sprint_var(invalid_req_states)
52220f38712SPatrick Williams        )
5238fae6eaeSMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
5248fae6eaeSMichael Walsh
5258fae6eaeSMichael Walsh    # Initialize all substate values supported by this function.
5268fae6eaeSMichael Walsh    os_ping = 0
5278fae6eaeSMichael Walsh    os_login = 0
5288fae6eaeSMichael Walsh    os_run_cmd = 0
5298fae6eaeSMichael Walsh
5308fae6eaeSMichael Walsh    if os_up:
53120f38712SPatrick Williams        if "os_ping" in req_states:
53270369fdcSMichael Walsh            # See if the OS pings.
53320f38712SPatrick Williams            rc, out_buf = gc.shell_cmd(
53420f38712SPatrick Williams                "ping -c 1 -w 2 " + os_host,
53520f38712SPatrick Williams                print_output=0,
53620f38712SPatrick Williams                show_err=0,
53720f38712SPatrick Williams                ignore_err=1,
53820f38712SPatrick Williams            )
53970369fdcSMichael Walsh            if rc == 0:
5408fae6eaeSMichael Walsh                os_ping = 1
54170369fdcSMichael Walsh
5428fae6eaeSMichael Walsh        # Programming note: All attributes which do not require an ssh login
5438fae6eaeSMichael Walsh        # should have been processed by this point.
54420f38712SPatrick Williams        master_req_login = ["os_login", "os_run_cmd"]
54520f38712SPatrick Williams        req_login = [
54620f38712SPatrick Williams            sub_state
54720f38712SPatrick Williams            for sub_state in req_states
54820f38712SPatrick Williams            if sub_state in master_req_login
54920f38712SPatrick Williams        ]
55020f38712SPatrick Williams        must_login = len(req_login) > 0
5518fae6eaeSMichael Walsh
5528fae6eaeSMichael Walsh        if must_login:
55320f38712SPatrick Williams            output, stderr, rc = bsu.os_execute_command(
55420f38712SPatrick Williams                "uptime",
55520f38712SPatrick Williams                quiet=quiet,
5567fc3397aSMichael Walsh                ignore_err=1,
5573390c85eSMichael Shepos                time_out=20,
5583390c85eSMichael Shepos                os_host=os_host,
5593390c85eSMichael Shepos                os_username=os_username,
56020f38712SPatrick Williams                os_password=os_password,
56120f38712SPatrick Williams            )
5626a9bd143SMichael Walsh            if rc == 0:
5638fae6eaeSMichael Walsh                os_login = 1
5648fae6eaeSMichael Walsh                os_run_cmd = 1
5653eb50027SMichael Walsh            else:
5666a9bd143SMichael Walsh                gp.dprint_vars(output, stderr)
5676a9bd143SMichael Walsh                gp.dprint_vars(rc, 1)
56870369fdcSMichael Walsh
5698fae6eaeSMichael Walsh    os_state = DotDict()
5708fae6eaeSMichael Walsh    for sub_state in req_states:
5718fae6eaeSMichael Walsh        cmd_buf = "os_state['" + sub_state + "'] = str(" + sub_state + ")"
5728fae6eaeSMichael Walsh        exec(cmd_buf)
57370369fdcSMichael Walsh
57470369fdcSMichael Walsh    return os_state
57570369fdcSMichael Walsh
57670369fdcSMichael Walsh
57720f38712SPatrick Williamsdef get_state(
57820f38712SPatrick Williams    openbmc_host="",
57970369fdcSMichael Walsh    openbmc_username="",
58070369fdcSMichael Walsh    openbmc_password="",
58170369fdcSMichael Walsh    os_host="",
58270369fdcSMichael Walsh    os_username="",
58370369fdcSMichael Walsh    os_password="",
5848fae6eaeSMichael Walsh    req_states=default_req_states,
58520f38712SPatrick Williams    quiet=None,
58620f38712SPatrick Williams):
58770369fdcSMichael Walsh    r"""
588619aa332SMichael Walsh    Get component states such as chassis state, bmc state, etc, put them into a
58970369fdcSMichael Walsh    dictionary and return them to the caller.
59070369fdcSMichael Walsh
5918fae6eaeSMichael Walsh    Note that all substate values are strings.
5928fae6eaeSMichael Walsh
5932a0df683SMichael Walsh    Note: If elapsed_boot_time is included in req_states, it is the caller's
5942a0df683SMichael Walsh    duty to call set_start_boot_seconds() in order to set global
5952a0df683SMichael Walsh    start_boot_seconds.  elapsed_boot_time is the current time minus
5962a0df683SMichael Walsh    start_boot_seconds.
5972a0df683SMichael Walsh
5982a0df683SMichael Walsh    Description of argument(s):
59970369fdcSMichael Walsh    openbmc_host      The DNS name or IP address of the BMC.
60070369fdcSMichael Walsh                      This defaults to global ${OPENBMC_HOST}.
60170369fdcSMichael Walsh    openbmc_username  The username to be used to login to the BMC.
60270369fdcSMichael Walsh                      This defaults to global ${OPENBMC_USERNAME}.
60370369fdcSMichael Walsh    openbmc_password  The password to be used to login to the BMC.
60470369fdcSMichael Walsh                      This defaults to global ${OPENBMC_PASSWORD}.
60570369fdcSMichael Walsh    os_host           The DNS name or IP address of the operating system.
60670369fdcSMichael Walsh                      This defaults to global ${OS_HOST}.
60770369fdcSMichael Walsh    os_username       The username to be used to login to the OS.
60870369fdcSMichael Walsh                      This defaults to global ${OS_USERNAME}.
60970369fdcSMichael Walsh    os_password       The password to be used to login to the OS.
61070369fdcSMichael Walsh                      This defaults to global ${OS_PASSWORD}.
6118fae6eaeSMichael Walsh    req_states        This is a list of states whose values are being requested
6128fae6eaeSMichael Walsh                      by the caller.
61370369fdcSMichael Walsh    quiet             Indicates whether status details (e.g. curl commands)
61470369fdcSMichael Walsh                      should be written to the console.
61570369fdcSMichael Walsh                      Defaults to either global value of ${QUIET} or to 1.
61670369fdcSMichael Walsh    """
61770369fdcSMichael Walsh
618619aa332SMichael Walsh    quiet = int(gp.get_var_value(quiet, 0))
61970369fdcSMichael Walsh
62070369fdcSMichael Walsh    # Set parm defaults where necessary and validate all parms.
62170369fdcSMichael Walsh    if openbmc_host == "":
62270369fdcSMichael Walsh        openbmc_host = BuiltIn().get_variable_value("${OPENBMC_HOST}")
6232a0df683SMichael Walsh    error_message = gv.valid_value(openbmc_host, invalid_values=[None, ""])
62470369fdcSMichael Walsh    if error_message != "":
62570369fdcSMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
62670369fdcSMichael Walsh
62770369fdcSMichael Walsh    if openbmc_username == "":
62870369fdcSMichael Walsh        openbmc_username = BuiltIn().get_variable_value("${OPENBMC_USERNAME}")
6292a0df683SMichael Walsh    error_message = gv.valid_value(openbmc_username, invalid_values=[None, ""])
63070369fdcSMichael Walsh    if error_message != "":
63170369fdcSMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
63270369fdcSMichael Walsh
63370369fdcSMichael Walsh    if openbmc_password == "":
63470369fdcSMichael Walsh        openbmc_password = BuiltIn().get_variable_value("${OPENBMC_PASSWORD}")
6352a0df683SMichael Walsh    error_message = gv.valid_value(openbmc_password, invalid_values=[None, ""])
63670369fdcSMichael Walsh    if error_message != "":
63770369fdcSMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
63870369fdcSMichael Walsh
6398fae6eaeSMichael Walsh    # NOTE: OS parms are optional.
64070369fdcSMichael Walsh    if os_host == "":
64170369fdcSMichael Walsh        os_host = BuiltIn().get_variable_value("${OS_HOST}")
64270369fdcSMichael Walsh        if os_host is None:
64370369fdcSMichael Walsh            os_host = ""
64470369fdcSMichael Walsh
645e7e9171eSGeorge Keishing    if os_username == "":
64670369fdcSMichael Walsh        os_username = BuiltIn().get_variable_value("${OS_USERNAME}")
64770369fdcSMichael Walsh        if os_username is None:
64870369fdcSMichael Walsh            os_username = ""
64970369fdcSMichael Walsh
650e7e9171eSGeorge Keishing    if os_password == "":
65170369fdcSMichael Walsh        os_password = BuiltIn().get_variable_value("${OS_PASSWORD}")
65270369fdcSMichael Walsh        if os_password is None:
65370369fdcSMichael Walsh            os_password = ""
65470369fdcSMichael Walsh
65520f38712SPatrick Williams    invalid_req_states = [
65620f38712SPatrick Williams        sub_state
65720f38712SPatrick Williams        for sub_state in req_states
65820f38712SPatrick Williams        if sub_state not in valid_req_states
65920f38712SPatrick Williams    ]
6608fae6eaeSMichael Walsh    if len(invalid_req_states) > 0:
66120f38712SPatrick Williams        error_message = (
66220f38712SPatrick Williams            "The following req_states are not supported:\n"
66320f38712SPatrick Williams            + gp.sprint_var(invalid_req_states)
66420f38712SPatrick Williams        )
6658fae6eaeSMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
6668fae6eaeSMichael Walsh
6678fae6eaeSMichael Walsh    # Initialize all substate values supported by this function.
6688fae6eaeSMichael Walsh    ping = 0
66920f38712SPatrick Williams    packet_loss = ""
67020f38712SPatrick Williams    uptime = ""
67120f38712SPatrick Williams    epoch_seconds = ""
67220f38712SPatrick Williams    elapsed_boot_time = ""
67320f38712SPatrick Williams    rest = ""
67420f38712SPatrick Williams    redfish = ""
67520f38712SPatrick Williams    chassis = ""
67620f38712SPatrick Williams    requested_chassis = ""
67720f38712SPatrick Williams    bmc = ""
67820f38712SPatrick Williams    requested_bmc = ""
67918f15dd7SGeorge Keishing    # BootProgress state will get populated when state logic enumerates the
68018f15dd7SGeorge Keishing    # state URI. This is to prevent state dictionary  boot_progress value
68118f15dd7SGeorge Keishing    # getting empty when the BootProgress is NOT found, making it optional.
68220f38712SPatrick Williams    boot_progress = "NA"
68320f38712SPatrick Williams    operating_system = ""
68420f38712SPatrick Williams    host = ""
68520f38712SPatrick Williams    requested_host = ""
68620f38712SPatrick Williams    attempts_left = ""
6878fae6eaeSMichael Walsh
68870369fdcSMichael Walsh    # Get the component states.
68920f38712SPatrick Williams    if "ping" in req_states:
6908fae6eaeSMichael Walsh        # See if the OS pings.
69120f38712SPatrick Williams        rc, out_buf = gc.shell_cmd(
69220f38712SPatrick Williams            "ping -c 1 -w 2 " + openbmc_host,
69320f38712SPatrick Williams            print_output=0,
69420f38712SPatrick Williams            show_err=0,
69520f38712SPatrick Williams            ignore_err=1,
69620f38712SPatrick Williams        )
6978fae6eaeSMichael Walsh        if rc == 0:
6988fae6eaeSMichael Walsh            ping = 1
6998fae6eaeSMichael Walsh
70020f38712SPatrick Williams    if "packet_loss" in req_states:
7018fae6eaeSMichael Walsh        # See if the OS pings.
70220f38712SPatrick Williams        cmd_buf = (
70320f38712SPatrick Williams            "ping -c 5 -w 5 "
70420f38712SPatrick Williams            + openbmc_host
70520f38712SPatrick Williams            + " | egrep 'packet loss' | sed -re 's/.* ([0-9]+)%.*/\\1/g'"
70620f38712SPatrick Williams        )
70720f38712SPatrick Williams        rc, out_buf = gc.shell_cmd(
70820f38712SPatrick Williams            cmd_buf, print_output=0, show_err=0, ignore_err=1
70920f38712SPatrick Williams        )
7108fae6eaeSMichael Walsh        if rc == 0:
7118fae6eaeSMichael Walsh            packet_loss = out_buf.rstrip("\n")
7128fae6eaeSMichael Walsh
71320f38712SPatrick Williams    if "uptime" in req_states:
714fa76593aSMichael Walsh        # Sometimes reading uptime results in a blank value. Call with
715fa76593aSMichael Walsh        # wait_until_keyword_succeeds to ensure a non-blank value is obtained.
71620f38712SPatrick Williams        remote_cmd_buf = (
71720f38712SPatrick Williams            "bash -c 'read uptime filler 2>/dev/null < /proc/uptime"
71820f38712SPatrick Williams            + ' && [ ! -z "${uptime}" ] && echo ${uptime}\''
71920f38712SPatrick Williams        )
72020f38712SPatrick Williams        cmd_buf = [
72120f38712SPatrick Williams            "BMC Execute Command",
72220f38712SPatrick Williams            re.sub("\\$", "\\$", remote_cmd_buf),
72320f38712SPatrick Williams            "quiet=1",
72420f38712SPatrick Williams            "test_mode=0",
72520f38712SPatrick Williams            "time_out=5",
72620f38712SPatrick Williams        ]
7272a0df683SMichael Walsh        gp.qprint_issuing(cmd_buf, 0)
7282a0df683SMichael Walsh        gp.qprint_issuing(remote_cmd_buf, 0)
729fa76593aSMichael Walsh        try:
73020f38712SPatrick Williams            stdout, stderr, rc = BuiltIn().wait_until_keyword_succeeds(
73120f38712SPatrick Williams                "10 sec", "5 sec", *cmd_buf
73220f38712SPatrick Williams            )
7333eb50027SMichael Walsh            if rc == 0 and stderr == "":
7343eb50027SMichael Walsh                uptime = stdout
735fa76593aSMichael Walsh        except AssertionError as my_assertion_error:
736fa76593aSMichael Walsh            pass
7378fae6eaeSMichael Walsh
73820f38712SPatrick Williams    if "epoch_seconds" in req_states or "elapsed_boot_time" in req_states:
7398fae6eaeSMichael Walsh        date_cmd_buf = "date -u +%s"
7408fae6eaeSMichael Walsh        if USE_BMC_EPOCH_TIME:
74120f38712SPatrick Williams            cmd_buf = ["BMC Execute Command", date_cmd_buf, "quiet=${1}"]
7428fae6eaeSMichael Walsh            if not quiet:
743edb5c949SMichael Walsh                gp.print_issuing(cmd_buf)
74420f38712SPatrick Williams            status, ret_values = BuiltIn().run_keyword_and_ignore_error(
74520f38712SPatrick Williams                *cmd_buf
74620f38712SPatrick Williams            )
74797df71ceSMichael Walsh            if status == "PASS":
74897df71ceSMichael Walsh                stdout, stderr, rc = ret_values
7493eb50027SMichael Walsh                if rc == 0 and stderr == "":
7503eb50027SMichael Walsh                    epoch_seconds = stdout.rstrip("\n")
7518fae6eaeSMichael Walsh        else:
75220f38712SPatrick Williams            shell_rc, out_buf = gc.cmd_fnc_u(
75320f38712SPatrick Williams                date_cmd_buf, quiet=quiet, print_output=0
75420f38712SPatrick Williams            )
7558fae6eaeSMichael Walsh            if shell_rc == 0:
7568fae6eaeSMichael Walsh                epoch_seconds = out_buf.rstrip("\n")
7578fae6eaeSMichael Walsh
75820f38712SPatrick Williams    if "elapsed_boot_time" in req_states:
7592a0df683SMichael Walsh        global start_boot_seconds
7602a0df683SMichael Walsh        elapsed_boot_time = int(epoch_seconds) - start_boot_seconds
7612a0df683SMichael Walsh
762bdd1dceaSMichael Shepos    if not redfish_support_trans_state:
76320f38712SPatrick Williams        master_req_rest = [
76420f38712SPatrick Williams            "rest",
76520f38712SPatrick Williams            "host",
76620f38712SPatrick Williams            "requested_host",
76720f38712SPatrick Williams            "operating_system",
76820f38712SPatrick Williams            "attempts_left",
76920f38712SPatrick Williams            "boot_progress",
77020f38712SPatrick Williams            "chassis",
77120f38712SPatrick Williams            "requested_chassisbmcrequested_bmc",
77220f38712SPatrick Williams        ]
7735674922eSMichael Walsh
77420f38712SPatrick Williams        req_rest = [
77520f38712SPatrick Williams            sub_state
77620f38712SPatrick Williams            for sub_state in req_states
77720f38712SPatrick Williams            if sub_state in master_req_rest
77820f38712SPatrick Williams        ]
77920f38712SPatrick Williams        need_rest = len(req_rest) > 0
7805674922eSMichael Walsh        state = DotDict()
7815674922eSMichael Walsh        if need_rest:
78220f38712SPatrick Williams            cmd_buf = [
78320f38712SPatrick Williams                "Read Properties",
78420f38712SPatrick Williams                SYSTEM_STATE_URI + "enumerate",
78520f38712SPatrick Williams                "quiet=${" + str(quiet) + "}",
78620f38712SPatrick Williams                "timeout=30",
78720f38712SPatrick Williams            ]
788edb5c949SMichael Walsh            gp.dprint_issuing(cmd_buf)
78920f38712SPatrick Williams            status, ret_values = BuiltIn().run_keyword_and_ignore_error(
79020f38712SPatrick Williams                *cmd_buf
79120f38712SPatrick Williams            )
79297df71ceSMichael Walsh            if status == "PASS":
79320f38712SPatrick Williams                state["rest"] = "1"
7945674922eSMichael Walsh            else:
79520f38712SPatrick Williams                state["rest"] = "0"
79670369fdcSMichael Walsh
79720f38712SPatrick Williams            if int(state["rest"]):
7985674922eSMichael Walsh                for url_path in ret_values:
7993adda95eSGeorge Keishing                    # Skip conflicting "CurrentHostState" URL from the enum
8003adda95eSGeorge Keishing                    # /xyz/openbmc_project/state/hypervisor0
8013adda95eSGeorge Keishing                    if "hypervisor0" in url_path:
8023adda95eSGeorge Keishing                        continue
8033adda95eSGeorge Keishing
8048c9cf9c8SKonstantin Aladyshev                    if platform_arch_type == "x86":
8058c9cf9c8SKonstantin Aladyshev                        # Skip conflicting "CurrentPowerState" URL from the enum
8068c9cf9c8SKonstantin Aladyshev                        # /xyz/openbmc_project/state/chassis_system0
8078c9cf9c8SKonstantin Aladyshev                        if "chassis_system0" in url_path:
8088c9cf9c8SKonstantin Aladyshev                            continue
8098c9cf9c8SKonstantin Aladyshev
8105674922eSMichael Walsh                    for attr_name in ret_values[url_path]:
8115674922eSMichael Walsh                        # Create a state key value based on the attr_name.
81236efbc04SGeorge Keishing                        try:
81320f38712SPatrick Williams                            ret_values[url_path][attr_name] = re.sub(
81420f38712SPatrick Williams                                r".*\.", "", ret_values[url_path][attr_name]
81520f38712SPatrick Williams                            )
81636efbc04SGeorge Keishing                        except TypeError:
81736efbc04SGeorge Keishing                            pass
8185674922eSMichael Walsh                        # Do some key name manipulations.
81920f38712SPatrick Williams                        new_attr_name = re.sub(
82020f38712SPatrick Williams                            r"^Current|(State|Transition)$", "", attr_name
82120f38712SPatrick Williams                        )
82220f38712SPatrick Williams                        new_attr_name = re.sub(r"BMC", r"Bmc", new_attr_name)
82320f38712SPatrick Williams                        new_attr_name = re.sub(
82420f38712SPatrick Williams                            r"([A-Z][a-z])", r"_\1", new_attr_name
82520f38712SPatrick Williams                        )
8265674922eSMichael Walsh                        new_attr_name = new_attr_name.lower().lstrip("_")
82720f38712SPatrick Williams                        new_attr_name = re.sub(
82820f38712SPatrick Williams                            r"power", r"chassis", new_attr_name
82920f38712SPatrick Williams                        )
8305674922eSMichael Walsh                        if new_attr_name in req_states:
83120f38712SPatrick Williams                            state[new_attr_name] = ret_values[url_path][
83220f38712SPatrick Williams                                attr_name
83320f38712SPatrick Williams                            ]
834bdd1dceaSMichael Shepos    else:
83520f38712SPatrick Williams        master_req_rf = [
83620f38712SPatrick Williams            "redfish",
83720f38712SPatrick Williams            "host",
83820f38712SPatrick Williams            "requested_host",
83920f38712SPatrick Williams            "attempts_left",
84020f38712SPatrick Williams            "boot_progress",
84120f38712SPatrick Williams            "chassis",
84220f38712SPatrick Williams            "requested_chassisbmcrequested_bmc",
84320f38712SPatrick Williams        ]
844bdd1dceaSMichael Shepos
84520f38712SPatrick Williams        req_rf = [
84620f38712SPatrick Williams            sub_state for sub_state in req_states if sub_state in master_req_rf
84720f38712SPatrick Williams        ]
84820f38712SPatrick Williams        need_rf = len(req_rf) > 0
849bdd1dceaSMichael Shepos        state = DotDict()
850bdd1dceaSMichael Shepos        if need_rf:
851bdd1dceaSMichael Shepos            cmd_buf = ["Redfish Get States"]
852bdd1dceaSMichael Shepos            gp.dprint_issuing(cmd_buf)
85321e28b47SGeorge Keishing            try:
85420f38712SPatrick Williams                status, ret_values = BuiltIn().run_keyword_and_ignore_error(
85520f38712SPatrick Williams                    *cmd_buf
85620f38712SPatrick Williams                )
85721e28b47SGeorge Keishing            except Exception as ex:
85821e28b47SGeorge Keishing                # Robot raised UserKeywordExecutionFailed error exception.
85921e28b47SGeorge Keishing                gp.dprint_issuing("Retrying Redfish Get States")
86020f38712SPatrick Williams                status, ret_values = BuiltIn().run_keyword_and_ignore_error(
86120f38712SPatrick Williams                    *cmd_buf
86220f38712SPatrick Williams                )
86321e28b47SGeorge Keishing
864bdd1dceaSMichael Shepos            gp.dprint_vars(status, ret_values)
865bdd1dceaSMichael Shepos            if status == "PASS":
86620f38712SPatrick Williams                state["redfish"] = "1"
867bdd1dceaSMichael Shepos            else:
86820f38712SPatrick Williams                state["redfish"] = "0"
869bdd1dceaSMichael Shepos
87020f38712SPatrick Williams            if int(state["redfish"]):
87120f38712SPatrick Williams                state["chassis"] = ret_values["chassis"]
87220f38712SPatrick Williams                state["host"] = ret_values["host"]
87320f38712SPatrick Williams                state["bmc"] = ret_values["bmc"]
874b51d1505SGeorge Keishing                if platform_arch_type != "x86":
87520f38712SPatrick Williams                    state["boot_progress"] = ret_values["boot_progress"]
87670369fdcSMichael Walsh
8778fae6eaeSMichael Walsh    for sub_state in req_states:
8785674922eSMichael Walsh        if sub_state in state:
8795674922eSMichael Walsh            continue
8808fae6eaeSMichael Walsh        if sub_state.startswith("os_"):
8818fae6eaeSMichael Walsh            # We pass "os_" requests on to get_os_state.
8828fae6eaeSMichael Walsh            continue
8838fae6eaeSMichael Walsh        cmd_buf = "state['" + sub_state + "'] = str(" + sub_state + ")"
8848fae6eaeSMichael Walsh        exec(cmd_buf)
885341c21ebSMichael Walsh
8868fae6eaeSMichael Walsh    if os_host == "":
8878fae6eaeSMichael Walsh        # The caller has not specified an os_host so as far as we're concerned,
8888fae6eaeSMichael Walsh        # it doesn't exist.
8898fae6eaeSMichael Walsh        return state
89070369fdcSMichael Walsh
89120f38712SPatrick Williams    os_req_states = [
89220f38712SPatrick Williams        sub_state for sub_state in req_states if sub_state.startswith("os_")
89320f38712SPatrick Williams    ]
8948fae6eaeSMichael Walsh
8958fae6eaeSMichael Walsh    if len(os_req_states) > 0:
8968fae6eaeSMichael Walsh        # The caller has specified an os_host and they have requested
8978fae6eaeSMichael Walsh        # information on os substates.
8988fae6eaeSMichael Walsh
8998fae6eaeSMichael Walsh        # Based on the information gathered on bmc, we'll try to make a
9008fae6eaeSMichael Walsh        # determination of whether the os is even up.  We'll pass the result
9018fae6eaeSMichael Walsh        # of that assessment to get_os_state to enhance performance.
9028fae6eaeSMichael Walsh        os_up_match = DotDict()
9038fae6eaeSMichael Walsh        for sub_state in master_os_up_match:
9048fae6eaeSMichael Walsh            if sub_state in req_states:
9058fae6eaeSMichael Walsh                os_up_match[sub_state] = master_os_up_match[sub_state]
90670369fdcSMichael Walsh        os_up = compare_states(state, os_up_match)
90720f38712SPatrick Williams        os_state = get_os_state(
90820f38712SPatrick Williams            os_host=os_host,
90970369fdcSMichael Walsh            os_username=os_username,
91070369fdcSMichael Walsh            os_password=os_password,
9118fae6eaeSMichael Walsh            req_states=os_req_states,
9128fae6eaeSMichael Walsh            os_up=os_up,
91320f38712SPatrick Williams            quiet=quiet,
91420f38712SPatrick Williams        )
9158fae6eaeSMichael Walsh        # Append os_state dictionary to ours.
9168fae6eaeSMichael Walsh        state.update(os_state)
91770369fdcSMichael Walsh
91870369fdcSMichael Walsh    return state
91970369fdcSMichael Walsh
92070369fdcSMichael Walsh
921fd5a868dSMichael Walshexit_wait_early_message = ""
922fd5a868dSMichael Walsh
923fd5a868dSMichael Walsh
924fd5a868dSMichael Walshdef set_exit_wait_early_message(value):
925fd5a868dSMichael Walsh    r"""
926fd5a868dSMichael Walsh    Set global exit_wait_early_message to the indicated value.
927fd5a868dSMichael Walsh
928fd5a868dSMichael Walsh    This is a mechanism by which the programmer can do an early exit from
929fd5a868dSMichael Walsh    wait_until_keyword_succeeds() based on some special condition.
930fd5a868dSMichael Walsh
931fd5a868dSMichael Walsh    Description of argument(s):
932fd5a868dSMichael Walsh    value                           The value to assign to the global
933fd5a868dSMichael Walsh                                    exit_wait_early_message.
934fd5a868dSMichael Walsh    """
935fd5a868dSMichael Walsh
936fd5a868dSMichael Walsh    global exit_wait_early_message
937fd5a868dSMichael Walsh    exit_wait_early_message = value
938fd5a868dSMichael Walsh
939fd5a868dSMichael Walsh
94020f38712SPatrick Williamsdef check_state(
94120f38712SPatrick Williams    match_state,
94270369fdcSMichael Walsh    invert=0,
94370369fdcSMichael Walsh    print_string="",
94470369fdcSMichael Walsh    openbmc_host="",
94570369fdcSMichael Walsh    openbmc_username="",
94670369fdcSMichael Walsh    openbmc_password="",
94770369fdcSMichael Walsh    os_host="",
94870369fdcSMichael Walsh    os_username="",
94970369fdcSMichael Walsh    os_password="",
95020f38712SPatrick Williams    quiet=None,
95120f38712SPatrick Williams):
95270369fdcSMichael Walsh    r"""
95370369fdcSMichael Walsh    Check that the Open BMC machine's composite state matches the specified
95470369fdcSMichael Walsh    state.  On success, this keyword returns the machine's composite state as a
95570369fdcSMichael Walsh    dictionary.
95670369fdcSMichael Walsh
9572a0df683SMichael Walsh    Description of argument(s):
95870369fdcSMichael Walsh    match_state       A dictionary whose key/value pairs are "state field"/
95970369fdcSMichael Walsh                      "state value".  The state value is interpreted as a
96070369fdcSMichael Walsh                      regular expression.  Example call from robot:
961341c21ebSMichael Walsh                      ${match_state}=  Create Dictionary  chassis=^On$
962341c21ebSMichael Walsh                      ...  bmc=^Ready$
96301975fa8SMichael Walsh                      ...  boot_progress=^OSStart$
96470369fdcSMichael Walsh                      ${state}=  Check State  &{match_state}
96570369fdcSMichael Walsh    invert            If this flag is set, this function will succeed if the
96670369fdcSMichael Walsh                      states do NOT match.
96770369fdcSMichael Walsh    print_string      This function will print this string to the console prior
96870369fdcSMichael Walsh                      to getting the state.
96970369fdcSMichael Walsh    openbmc_host      The DNS name or IP address of the BMC.
97070369fdcSMichael Walsh                      This defaults to global ${OPENBMC_HOST}.
97170369fdcSMichael Walsh    openbmc_username  The username to be used to login to the BMC.
97270369fdcSMichael Walsh                      This defaults to global ${OPENBMC_USERNAME}.
97370369fdcSMichael Walsh    openbmc_password  The password to be used to login to the BMC.
97470369fdcSMichael Walsh                      This defaults to global ${OPENBMC_PASSWORD}.
97570369fdcSMichael Walsh    os_host           The DNS name or IP address of the operating system.
97670369fdcSMichael Walsh                      This defaults to global ${OS_HOST}.
97770369fdcSMichael Walsh    os_username       The username to be used to login to the OS.
97870369fdcSMichael Walsh                      This defaults to global ${OS_USERNAME}.
97970369fdcSMichael Walsh    os_password       The password to be used to login to the OS.
98070369fdcSMichael Walsh                      This defaults to global ${OS_PASSWORD}.
98170369fdcSMichael Walsh    quiet             Indicates whether status details should be written to the
98270369fdcSMichael Walsh                      console.  Defaults to either global value of ${QUIET} or
98370369fdcSMichael Walsh                      to 1.
98470369fdcSMichael Walsh    """
98570369fdcSMichael Walsh
986619aa332SMichael Walsh    quiet = int(gp.get_var_value(quiet, 0))
98770369fdcSMichael Walsh
988edb5c949SMichael Walsh    gp.gp_print(print_string)
989edb5c949SMichael Walsh
990edb5c949SMichael Walsh    try:
991edb5c949SMichael Walsh        match_state = return_state_constant(match_state)
992edb5c949SMichael Walsh    except TypeError:
993edb5c949SMichael Walsh        pass
99470369fdcSMichael Walsh
9952a0df683SMichael Walsh    req_states = list(match_state.keys())
9962a0df683SMichael Walsh    # Remove special-case match key from req_states.
9972a0df683SMichael Walsh    if expressions_key() in req_states:
9982a0df683SMichael Walsh        req_states.remove(expressions_key())
99970369fdcSMichael Walsh    # Initialize state.
100020f38712SPatrick Williams    state = get_state(
100120f38712SPatrick Williams        openbmc_host=openbmc_host,
100270369fdcSMichael Walsh        openbmc_username=openbmc_username,
100370369fdcSMichael Walsh        openbmc_password=openbmc_password,
100470369fdcSMichael Walsh        os_host=os_host,
100570369fdcSMichael Walsh        os_username=os_username,
100670369fdcSMichael Walsh        os_password=os_password,
10078fae6eaeSMichael Walsh        req_states=req_states,
100820f38712SPatrick Williams        quiet=quiet,
100920f38712SPatrick Williams    )
101070369fdcSMichael Walsh    if not quiet:
10113eb50027SMichael Walsh        gp.print_var(state)
101270369fdcSMichael Walsh
1013fd5a868dSMichael Walsh    if exit_wait_early_message != "":
1014fd5a868dSMichael Walsh        # The exit_wait_early_message has been set by a signal handler so we
1015fd5a868dSMichael Walsh        # will exit "successfully".  It is incumbent upon the calling function
1016fd5a868dSMichael Walsh        # (e.g. wait_state) to check/clear this variable and to fail
1017fd5a868dSMichael Walsh        # appropriately.
1018fd5a868dSMichael Walsh        return state
1019fd5a868dSMichael Walsh
102070369fdcSMichael Walsh    match = compare_states(state, match_state)
102170369fdcSMichael Walsh
102270369fdcSMichael Walsh    if invert and match:
102320f38712SPatrick Williams        fail_msg = (
102420f38712SPatrick Williams            "The current state of the machine matches the match"
102520f38712SPatrick Williams            + " state:\n"
102620f38712SPatrick Williams            + gp.sprint_varx("state", state)
102720f38712SPatrick Williams        )
102870369fdcSMichael Walsh        BuiltIn().fail("\n" + gp.sprint_error(fail_msg))
102970369fdcSMichael Walsh    elif not invert and not match:
103020f38712SPatrick Williams        fail_msg = (
103120f38712SPatrick Williams            "The current state of the machine does NOT match the"
103220f38712SPatrick Williams            + " match state:\n"
103320f38712SPatrick Williams            + gp.sprint_varx("state", state)
103420f38712SPatrick Williams        )
103570369fdcSMichael Walsh        BuiltIn().fail("\n" + gp.sprint_error(fail_msg))
103670369fdcSMichael Walsh
103770369fdcSMichael Walsh    return state
103870369fdcSMichael Walsh
103970369fdcSMichael Walsh
104020f38712SPatrick Williamsdef wait_state(
104120f38712SPatrick Williams    match_state=(),
104270369fdcSMichael Walsh    wait_time="1 min",
104370369fdcSMichael Walsh    interval="1 second",
104470369fdcSMichael Walsh    invert=0,
104570369fdcSMichael Walsh    openbmc_host="",
104670369fdcSMichael Walsh    openbmc_username="",
104770369fdcSMichael Walsh    openbmc_password="",
104870369fdcSMichael Walsh    os_host="",
104970369fdcSMichael Walsh    os_username="",
105070369fdcSMichael Walsh    os_password="",
105120f38712SPatrick Williams    quiet=None,
105220f38712SPatrick Williams):
105370369fdcSMichael Walsh    r"""
105470369fdcSMichael Walsh    Wait for the Open BMC machine's composite state to match the specified
105570369fdcSMichael Walsh    state.  On success, this keyword returns the machine's composite state as
105670369fdcSMichael Walsh    a dictionary.
105770369fdcSMichael Walsh
10582a0df683SMichael Walsh    Description of argument(s):
105970369fdcSMichael Walsh    match_state       A dictionary whose key/value pairs are "state field"/
106070369fdcSMichael Walsh                      "state value".  See check_state (above) for details.
1061619aa332SMichael Walsh                      This value may also be any string accepted by
1062619aa332SMichael Walsh                      return_state_constant (e.g. "standby_match_state").
1063619aa332SMichael Walsh                      In such a case this function will call
1064619aa332SMichael Walsh                      return_state_constant to convert it to a proper
1065619aa332SMichael Walsh                      dictionary as described above.
106670369fdcSMichael Walsh    wait_time         The total amount of time to wait for the desired state.
106770369fdcSMichael Walsh                      This value may be expressed in Robot Framework's time
106870369fdcSMichael Walsh                      format (e.g. 1 minute, 2 min 3 s, 4.5).
106970369fdcSMichael Walsh    interval          The amount of time between state checks.
107070369fdcSMichael Walsh                      This value may be expressed in Robot Framework's time
107170369fdcSMichael Walsh                      format (e.g. 1 minute, 2 min 3 s, 4.5).
107270369fdcSMichael Walsh    invert            If this flag is set, this function will for the state of
107370369fdcSMichael Walsh                      the machine to cease to match the match state.
107470369fdcSMichael Walsh    openbmc_host      The DNS name or IP address of the BMC.
107570369fdcSMichael Walsh                      This defaults to global ${OPENBMC_HOST}.
107670369fdcSMichael Walsh    openbmc_username  The username to be used to login to the BMC.
107770369fdcSMichael Walsh                      This defaults to global ${OPENBMC_USERNAME}.
107870369fdcSMichael Walsh    openbmc_password  The password to be used to login to the BMC.
107970369fdcSMichael Walsh                      This defaults to global ${OPENBMC_PASSWORD}.
108070369fdcSMichael Walsh    os_host           The DNS name or IP address of the operating system.
108170369fdcSMichael Walsh                      This defaults to global ${OS_HOST}.
108270369fdcSMichael Walsh    os_username       The username to be used to login to the OS.
108370369fdcSMichael Walsh                      This defaults to global ${OS_USERNAME}.
108470369fdcSMichael Walsh    os_password       The password to be used to login to the OS.
108570369fdcSMichael Walsh                      This defaults to global ${OS_PASSWORD}.
108670369fdcSMichael Walsh    quiet             Indicates whether status details should be written to the
108770369fdcSMichael Walsh                      console.  Defaults to either global value of ${QUIET} or
108870369fdcSMichael Walsh                      to 1.
108970369fdcSMichael Walsh    """
109070369fdcSMichael Walsh
1091619aa332SMichael Walsh    quiet = int(gp.get_var_value(quiet, 0))
1092619aa332SMichael Walsh
109336efbc04SGeorge Keishing    try:
1094619aa332SMichael Walsh        match_state = return_state_constant(match_state)
109536efbc04SGeorge Keishing    except TypeError:
109636efbc04SGeorge Keishing        pass
109770369fdcSMichael Walsh
109870369fdcSMichael Walsh    if not quiet:
109970369fdcSMichael Walsh        if invert:
110070369fdcSMichael Walsh            alt_text = "cease to "
110170369fdcSMichael Walsh        else:
110270369fdcSMichael Walsh            alt_text = ""
110320f38712SPatrick Williams        gp.print_timen(
110420f38712SPatrick Williams            "Checking every "
110520f38712SPatrick Williams            + str(interval)
110620f38712SPatrick Williams            + " for up to "
110720f38712SPatrick Williams            + str(wait_time)
110820f38712SPatrick Williams            + " for the state of the machine to "
110920f38712SPatrick Williams            + alt_text
111020f38712SPatrick Williams            + "match the state shown below."
111120f38712SPatrick Williams        )
11123eb50027SMichael Walsh        gp.print_var(match_state)
111370369fdcSMichael Walsh
1114f893ba09SMichael Walsh    if quiet:
1115f893ba09SMichael Walsh        print_string = ""
1116f893ba09SMichael Walsh    else:
1117f893ba09SMichael Walsh        print_string = "#"
11188fae6eaeSMichael Walsh
11198fae6eaeSMichael Walsh    debug = int(BuiltIn().get_variable_value("${debug}", "0"))
11208fae6eaeSMichael Walsh    if debug:
11218fae6eaeSMichael Walsh        # In debug we print state so no need to print the "#".
11228fae6eaeSMichael Walsh        print_string = ""
11238fae6eaeSMichael Walsh    check_state_quiet = 1 - debug
112420f38712SPatrick Williams    cmd_buf = [
112520f38712SPatrick Williams        "Check State",
112620f38712SPatrick Williams        match_state,
112720f38712SPatrick Williams        "invert=${" + str(invert) + "}",
112820f38712SPatrick Williams        "print_string=" + print_string,
112920f38712SPatrick Williams        "openbmc_host=" + openbmc_host,
113070369fdcSMichael Walsh        "openbmc_username=" + openbmc_username,
113120f38712SPatrick Williams        "openbmc_password=" + openbmc_password,
113220f38712SPatrick Williams        "os_host=" + os_host,
113320f38712SPatrick Williams        "os_username=" + os_username,
113420f38712SPatrick Williams        "os_password=" + os_password,
113520f38712SPatrick Williams        "quiet=${" + str(check_state_quiet) + "}",
113620f38712SPatrick Williams    ]
1137edb5c949SMichael Walsh    gp.dprint_issuing(cmd_buf)
1138619aa332SMichael Walsh    try:
113920f38712SPatrick Williams        state = BuiltIn().wait_until_keyword_succeeds(
114020f38712SPatrick Williams            wait_time, interval, *cmd_buf
114120f38712SPatrick Williams        )
1142619aa332SMichael Walsh    except AssertionError as my_assertion_error:
1143619aa332SMichael Walsh        gp.printn()
1144619aa332SMichael Walsh        message = my_assertion_error.args[0]
1145619aa332SMichael Walsh        BuiltIn().fail(message)
1146619aa332SMichael Walsh
1147fd5a868dSMichael Walsh    if exit_wait_early_message:
1148fd5a868dSMichael Walsh        # The global exit_wait_early_message was set by a signal handler
1149fd5a868dSMichael Walsh        # indicating that we should fail.
1150fd5a868dSMichael Walsh        message = exit_wait_early_message
1151fd5a868dSMichael Walsh        # Clear the exit_wait_early_message variable for future use.
1152fd5a868dSMichael Walsh        set_exit_wait_early_message("")
1153fd5a868dSMichael Walsh        BuiltIn().fail(gp.sprint_error(message))
1154fd5a868dSMichael Walsh
115570369fdcSMichael Walsh    if not quiet:
11563eb50027SMichael Walsh        gp.printn()
115770369fdcSMichael Walsh        if invert:
11583eb50027SMichael Walsh            gp.print_timen("The states no longer match:")
115970369fdcSMichael Walsh        else:
11603eb50027SMichael Walsh            gp.print_timen("The states match:")
11613eb50027SMichael Walsh        gp.print_var(state)
116270369fdcSMichael Walsh
116370369fdcSMichael Walsh    return state
116470369fdcSMichael Walsh
11658fae6eaeSMichael Walsh
11662a0df683SMichael Walshdef set_start_boot_seconds(value=0):
11672a0df683SMichael Walsh    global start_boot_seconds
11682a0df683SMichael Walsh    start_boot_seconds = int(value)
11692a0df683SMichael Walsh
11702a0df683SMichael Walsh
11712a0df683SMichael Walshset_start_boot_seconds(0)
11722a0df683SMichael Walsh
11732a0df683SMichael Walsh
117420f38712SPatrick Williamsdef wait_for_comm_cycle(start_boot_seconds, quiet=None):
11758fae6eaeSMichael Walsh    r"""
11762a0df683SMichael Walsh    Wait for the BMC uptime to be less than elapsed_boot_time.
11778fae6eaeSMichael Walsh
11782a0df683SMichael Walsh    This function will tolerate an expected loss of communication to the BMC.
11792a0df683SMichael Walsh    This function is useful when some kind of reboot has been initiated by the
11802a0df683SMichael Walsh    caller.
11812a0df683SMichael Walsh
11822a0df683SMichael Walsh    Description of argument(s):
11838fae6eaeSMichael Walsh    start_boot_seconds  The time that the boot test started.  The format is the
11848fae6eaeSMichael Walsh                        epoch time in seconds, i.e. the number of seconds since
11858fae6eaeSMichael Walsh                        1970-01-01 00:00:00 UTC.  This value should be obtained
11868fae6eaeSMichael Walsh                        from the BMC so that it is not dependent on any kind of
11878fae6eaeSMichael Walsh                        synchronization between this machine and the target BMC
11888fae6eaeSMichael Walsh                        This will allow this program to work correctly even in
11898fae6eaeSMichael Walsh                        a simulated environment.  This value should be obtained
11908fae6eaeSMichael Walsh                        by the caller prior to initiating a reboot.  It can be
11918fae6eaeSMichael Walsh                        obtained as follows:
11928fae6eaeSMichael Walsh                        state = st.get_state(req_states=['epoch_seconds'])
11938fae6eaeSMichael Walsh    """
11948fae6eaeSMichael Walsh
1195619aa332SMichael Walsh    quiet = int(gp.get_var_value(quiet, 0))
1196619aa332SMichael Walsh
11978fae6eaeSMichael Walsh    # Validate parms.
11982a0df683SMichael Walsh    error_message = gv.valid_integer(start_boot_seconds)
11992a0df683SMichael Walsh    if error_message:
12008fae6eaeSMichael Walsh        BuiltIn().fail(gp.sprint_error(error_message))
12018fae6eaeSMichael Walsh
12022a0df683SMichael Walsh    # Wait for uptime to be less than elapsed_boot_time.
12032a0df683SMichael Walsh    set_start_boot_seconds(start_boot_seconds)
120420f38712SPatrick Williams    expr = "int(float(state['uptime'])) < int(state['elapsed_boot_time'])"
120520f38712SPatrick Williams    match_state = DotDict(
120620f38712SPatrick Williams        [
120720f38712SPatrick Williams            ("uptime", "^[0-9\\.]+$"),
120820f38712SPatrick Williams            ("elapsed_boot_time", "^[0-9]+$"),
120920f38712SPatrick Williams            (expressions_key(), [expr]),
121020f38712SPatrick Williams        ]
121120f38712SPatrick Williams    )
1212e9192561SDavid Shaw    wait_state(match_state, wait_time="12 mins", interval="5 seconds")
12138fae6eaeSMichael Walsh
1214bdd1dceaSMichael Shepos    gp.qprint_timen("Verifying that REST/Redfish API interface is working.")
1215bdd1dceaSMichael Shepos    if not redfish_support_trans_state:
121620f38712SPatrick Williams        match_state = DotDict([("rest", "^1$")])
1217bdd1dceaSMichael Shepos    else:
121820f38712SPatrick Williams        match_state = DotDict([("redfish", "^1$")])
12198fae6eaeSMichael Walsh    state = wait_state(match_state, wait_time="5 mins", interval="2 seconds")
1220