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