xref: /openbmc/openbmc-test-automation/lib/gen_plug_in_utils.py (revision bfa16ee4f68964bd5dd20618cb3b293584b78c69)
1#!/usr/bin/env python
2
3r"""
4This module provides functions which are useful to plug-in call point programs.
5"""
6
7import sys
8import os
9import re
10import collections
11
12import gen_print as gp
13
14
15def get_plug_in_package_name(case=None):
16
17    r"""
18    Return the plug-in package name (e.g. "OS_Console", "DB_Logging").
19
20    Description of argument(s):
21    case                            Indicates whether the value returned
22                                    should be converted to upper or lower
23                                    case.  Valid values are "upper", "lower"
24                                    or None.
25    """
26
27    plug_in_package_name = os.path.basename(gp.pgm_dir_path[:-1])
28    if case == "upper":
29        return plug_in_package_name.upper()
30    elif case == "lower":
31        return plug_in_package_name.lower()
32    else:
33        return plug_in_package_name
34
35
36def return_plug_vars():
37
38    r"""
39    Return an OrderedDict which is sorted by key and which contains all of the
40    plug-in environment variables.
41
42    Example excerpt of resulting dictionary:
43
44    plug_var_dict:
45      [AUTOBOOT_BASE_TOOL_DIR_PATH]:  /fspmount/
46      [AUTOBOOT_BB_LEVEL]:            <blank>
47      [AUTOBOOT_BOOT_FAIL]:           0
48      ...
49
50    This function also does the following:
51    - Set a default value for environment variable AUTOBOOT_OPENBMC_NICKNAME
52    if it is not already set.
53    - Register PASSWORD variables to prevent their values from being printed.
54    """
55
56    plug_in_package_name = get_plug_in_package_name(case="upper")
57    regex = "^(AUTOBOOT|" + plug_in_package_name + ")_"
58
59    # Set a default for nickname.
60    if os.environ.get("AUTOBOOT_OPENBMC_NICKNAME", "") == "":
61        os.environ['AUTOBOOT_OPENBMC_NICKNAME'] = \
62            os.environ.get("AUTOBOOT_OPENBMC_HOST", "")
63
64    plug_var_dict = \
65        collections.OrderedDict(sorted({k: v for (k, v) in
66                                       os.environ.items()
67                                       if re.match(regex, k)}.items()))
68
69    # Register password values to prevent printing them out.  Any plug var
70    # whose name ends in PASSWORD will be registered.
71    password_vals = {k: v for (k, v) in plug_var_dict.items()
72                     if re.match(r".*_PASSWORD$", k)}.values()
73    map(gp.register_passwords, password_vals)
74
75    return plug_var_dict
76
77
78def sprint_plug_vars(headers=1):
79
80    r"""
81    Sprint the plug-in environment variables (i.e. those that begin with
82    AUTOBOOT_ those that begin with <plug-in package_name>_ in upper case
83    letters.).
84
85    Example excerpt of output:
86    AUTOBOOT_BASE_TOOL_DIR_PATH=/fspmount/
87    AUTOBOOT_BB_LEVEL=
88    AUTOBOOT_BOOT_FAIL=0
89    AUTOBOOT_BOOT_FAIL_THRESHOLD=1000000
90
91    Description of argument(s):
92    headers                         Print a header and a footer.
93    """
94
95    plug_var_dict = return_plug_vars()
96    buffer = ""
97    if headers:
98        buffer += "\n" + gp.sprint_dashes()
99    for key, value in plug_var_dict.items():
100        buffer += key + "=" + value + "\n"
101    if headers:
102        buffer += gp.sprint_dashes() + "\n"
103
104    return buffer
105
106
107def get_plug_vars():
108
109    r"""
110    Get all plug-in variables and put them in corresponding global variables.
111
112    This would include all environment variables beginning with either
113    "AUTOBOOT_" or with the upper case version of the plug-in package name +
114    underscore (e.g. OP_SAMPLE_VAR1 for plug-in OP_Sample).
115
116    The global variables to be set will be both with and without the
117    "AUTOBOOT_" prefix.  For example, if the environment variable in question
118    is AUTOBOOT_OPENBMC_HOST, this function will set global variable
119    AUTOBOOT_OPENBMC_HOST and global variable OPENBMC_HOST.
120    """
121
122    module = sys.modules['__main__']
123    plug_var_dict = return_plug_vars()
124
125    # Get all "AUTOBOOT_" environment variables and put them into globals.
126    for key, value in plug_var_dict.items():
127        setattr(module, key, value)
128        setattr(module, re.sub("^AUTOBOOT_", "", key), value)
129
130
131def get_plug_default(var_name,
132                     default=None):
133
134    r"""
135    Derive and return a default value for the given parm variable.
136
137    This function will assign a default by checking the following environment
138    variables in the order shown.  The first one that has a value will be used.
139    - <upper case package_name>_<var_name>
140    - AUTOBOOT_OVERRIDE_<var_name>
141    - AUTOBOOT_<var_name>
142
143    If none of these are found, this function will return the value passed by
144    the caller in the "default" parm.
145
146    Example:
147
148    Let's say your plug-in is named "OS_Console" and you call this function as
149    follows:
150
151    get_plug_default("quiet", 0)
152
153    The first of these environment variables that is found to be set will be
154    used to provide the default value.
155    - OS_CONSOLE_QUIET
156    - AUTOBOOT_OVERRIDE_QUIET
157    - AUTOBOOT_QUIET
158
159    If none of those has a value, 0 (as specified by the caller in this
160    example) is returned.
161
162    Let's say the master driver program is named obmc_boot.  obmc_boot program
163    is responsible for calling plug-ins.  Let's further suppose that the user
164    wishes to run the master program with --debug=0 but wishes to have all
165    plug-ins run with --debug=1.  This could be accomplished with the
166    following call:
167    export AUTOBOOT_OVERRIDE_DEBUG=1 ; obmc_boot --debug=0
168    --plug_in_dir_paths=<list of plug ins>
169
170    As another example, let's suppose that the user wishes to have just the
171    OS_Console plug-in run with debug and everything else to default to
172    debug=0.  This could be accomplished as follows:
173    export OS_CONSOLE_DEBUG=1 ; obmc_boot --debug=0 --plug_in_dir_paths=<list
174    of plug ins>
175
176    And as one more example, let's say the user wishes to have obmc_boot and
177    OS_Console run without debug but have all other plug-ins run with debug:
178    export AUTOBOOT_OVERRIDE_DEBUG=1 ; export OS_CONSOLE_DEBUG=0 ; obmc_boot
179    --debug=0 --plug_in_dir_paths=<list of plug ins>
180
181    Description of argument(s):
182    var_name                        The name of the variable for which a
183                                    default value is to be calculated.
184    default                         The default value if one cannot be
185                                    determined.
186    """
187
188    var_name = var_name.upper()
189    plug_in_package_name = get_plug_in_package_name(case="upper")
190
191    package_var_name = plug_in_package_name + "_" + var_name
192    default_value = os.environ.get(package_var_name, None)
193    if default_value is not None:
194        # A package-name version of the variable was found so return its value.
195        return(default_value)
196
197    autoboot_var_name = "AUTOBOOT_OVERRIDE_" + var_name
198    default_value = os.environ.get(autoboot_var_name, None)
199    if default_value is not None:
200        # An AUTOBOOT_ version of the variable was found so return its value.
201        return default_value
202
203    autoboot_var_name = "AUTOBOOT_" + var_name
204    default_value = os.environ.get(autoboot_var_name, None)
205    if default_value is not None:
206        # An AUTOBOOT_ version of the variable was found so return its value.
207        return default_value
208
209    return default
210
211
212def srequired_plug_in(req_plug_in_names,
213                      plug_in_dir_paths=None):
214
215    r"""
216    Return an empty string if the required plug-ins are found in
217    plug_in_dir_paths.  Otherwise, return an error string.
218
219    Example call:
220    error_message = srequired_plug_in(req_plug_in_names, plug_in_dir_paths)
221
222    Description of argument(s):
223    req_plug_in_names               A list of plug_in names that the caller
224                                    requires (e.g. ['OS_Console']).
225    plug_in_dir_paths               A string which is a colon-delimited list
226                                    of plug-ins specified by the user (e.g.
227                                    DB_Logging:FFDC:OS_Console:Perf).  Path
228                                    values (e.g. "/home/robot/dir1") will be
229                                    stripped from this list to do the
230                                    analysis.  Default value is the
231                                    AUTOBOOT_PLUG_IN_DIR_PATHS environment
232                                    variable.
233    """
234
235    # Calculate default value for plug_in_dir_paths.
236    if plug_in_dir_paths is None:
237        plug_in_dir_paths = os.environ.get("AUTOBOOT_PLUG_IN_DIR_PATHS", "")
238
239    error_message = ""
240
241    # Convert plug_in_dir_paths to a list of base names.
242    plug_in_dir_paths = \
243        filter(None, map(os.path.basename, plug_in_dir_paths.split(":")))
244
245    # Check for each of the user's required plug-ins.
246    for plug_in_name in req_plug_in_names:
247        if plug_in_name not in plug_in_dir_paths:
248            error_message = "The \"" + get_plug_in_package_name() +\
249                "\" plug-in cannot run unless the user also selects the \"" +\
250                plug_in_name + "\" plug in:\n" +\
251                gp.sprint_var(plug_in_dir_paths)
252
253    return error_message
254
255
256def required_plug_in(req_plug_in_names,
257                     plug_in_dir_paths=None):
258
259    r"""
260    Return True if each of the plug-ins in req_plug_in_names can be found in
261    plug_in_dir_paths  Otherwise, return False and print an error message to
262    stderr.
263
264    Example call:
265    if not required_plug_in(['OS_Console'], AUTOBOOT_PLUG_IN_DIR_PATHS):
266        return False
267
268    Description of argument(s):
269    (See Description of arguments for srequired_plug_in (above)).
270    """
271
272    error_message = srequired_plug_in(req_plug_in_names, plug_in_dir_paths)
273    if not error_message == "":
274        gp.print_error_report(error_message)
275        return False
276
277    return True
278
279
280# Create print wrapper functions for all sprint functions defined above.
281# func_names contains a list of all print functions which should be created
282# from their sprint counterparts.
283func_names = ['print_plug_vars']
284
285# stderr_func_names is a list of functions whose output should go to stderr
286# rather than stdout.
287stderr_func_names = []
288
289replace_dict = dict(gp.replace_dict)
290replace_dict['mod_qualifier'] = 'gp.'
291func_defs = gp.create_print_wrapper_funcs(func_names, stderr_func_names,
292                                          replace_dict)
293gp.gp_debug_print(func_defs)
294exec(func_defs)
295