blob: f5f96d608a7a22fe737ad22fe713691d9e13b001 [file] [log] [blame]
Michael Walshf4c62a22017-11-13 15:40:57 -06001#!/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
Michael Walsh3ba8ecd2018-04-24 11:33:25 -050013import gen_misc as gm
Michael Walsha6b46ed2018-06-01 14:31:23 -050014import gen_cmd as gc
15
16PLUG_VAR_PREFIX = os.environ.get("PLUG_VAR_PREFIX", "AUTOBOOT")
Michael Walshf4c62a22017-11-13 15:40:57 -060017
18
19def get_plug_in_package_name(case=None):
Michael Walshf4c62a22017-11-13 15:40:57 -060020 r"""
21 Return the plug-in package name (e.g. "OS_Console", "DB_Logging").
22
23 Description of argument(s):
24 case Indicates whether the value returned
25 should be converted to upper or lower
26 case. Valid values are "upper", "lower"
27 or None.
28 """
29
30 plug_in_package_name = os.path.basename(gp.pgm_dir_path[:-1])
31 if case == "upper":
32 return plug_in_package_name.upper()
33 elif case == "lower":
34 return plug_in_package_name.lower()
35 else:
36 return plug_in_package_name
37
38
39def return_plug_vars():
Michael Walshf4c62a22017-11-13 15:40:57 -060040 r"""
41 Return an OrderedDict which is sorted by key and which contains all of the
42 plug-in environment variables.
43
44 Example excerpt of resulting dictionary:
45
46 plug_var_dict:
47 [AUTOBOOT_BASE_TOOL_DIR_PATH]: /fspmount/
48 [AUTOBOOT_BB_LEVEL]: <blank>
49 [AUTOBOOT_BOOT_FAIL]: 0
50 ...
51
52 This function also does the following:
Michael Walsha6b46ed2018-06-01 14:31:23 -050053 - Set a default value for environment variable
Michael Walshfaafa9c2018-06-27 16:39:31 -050054 AUTOBOOT_OPENBMC_NICKNAME/AUTOIPL_FSP1_NICKNAME if it is not already set.
Michael Walshf4c62a22017-11-13 15:40:57 -060055 - Register PASSWORD variables to prevent their values from being printed.
Michael Walsha6b46ed2018-06-01 14:31:23 -050056
57 Note: The programmer may set a default for any given environment variable
58 by declaring a global variable of the same name and setting its value.
59 For example, let's say the calling program has this global declaration:
60
61 PERF_EXERCISERS_TOTAL_TIMEOUT = '180'
62
63 If environment variable PERF_EXERCISERS_TOTAL_TIMEOUT is blank or not set,
64 this function will set it to 180.
Michael Walshf4c62a22017-11-13 15:40:57 -060065 """
66
67 plug_in_package_name = get_plug_in_package_name(case="upper")
Michael Walsha6b46ed2018-06-01 14:31:23 -050068 regex = "^(" + PLUG_VAR_PREFIX + "|AUTOGUI|" + plug_in_package_name + ")_"
Michael Walshf4c62a22017-11-13 15:40:57 -060069
70 # Set a default for nickname.
71 if os.environ.get("AUTOBOOT_OPENBMC_NICKNAME", "") == "":
72 os.environ['AUTOBOOT_OPENBMC_NICKNAME'] = \
73 os.environ.get("AUTOBOOT_OPENBMC_HOST", "")
74
Michael Walsha6b46ed2018-06-01 14:31:23 -050075 if os.environ.get("AUTOIPL_FSP1_NICKNAME", "") == "":
76 os.environ['AUTOIPL_FSP1_NICKNAME'] = \
77 os.environ.get("AUTOIPL_FSP1_NAME", "").split(".")[0]
78
Michael Walsh3ba8ecd2018-04-24 11:33:25 -050079 # For all variables specified in the parm_def file, we want them to
80 # default to "" rather than being unset.
81 # Process the parm_def file if it exists.
82 parm_def_file_path = gp.pgm_dir_path + "parm_def"
83 if os.path.exists(parm_def_file_path):
84 parm_defs = gm.my_parm_file(parm_def_file_path)
85 else:
86 parm_defs = collections.OrderedDict()
87 # Example parm_defs:
88 # parm_defs:
89 # parm_defs[rest_fail]: boolean
90 # parm_defs[command]: string
91 # parm_defs[esel_stop_file_path]: string
92
93 # Create a list of plug-in environment variables by pre-pending <all caps
94 # plug-in package name>_<all caps var name>
95 plug_in_parm_names = [plug_in_package_name + "_" + x for x in
96 map(str.upper, parm_defs.keys())]
97 # Example plug_in_parm_names:
98 # plug_in_parm_names:
99 # plug_in_parm_names[0]: STOP_REST_FAIL
100 # plug_in_parm_names[1]: STOP_COMMAND
101 # plug_in_parm_names[2]: STOP_ESEL_STOP_FILE_PATH
102
103 # Initialize unset plug-in vars.
104 for var_name in plug_in_parm_names:
Michael Walsha6b46ed2018-06-01 14:31:23 -0500105 # If there is a global variable with the same name as the environment
106 # variable, use its value as a default.
107 default_value = gm.get_mod_global(var_name, "")
108 os.environ[var_name] = os.environ.get(var_name, default_value)
109 if os.environ[var_name] == "":
110 os.environ[var_name] = default_value
Michael Walsh3ba8ecd2018-04-24 11:33:25 -0500111
Michael Walshf4c62a22017-11-13 15:40:57 -0600112 plug_var_dict = \
113 collections.OrderedDict(sorted({k: v for (k, v) in
Gunnar Mills096cd562018-03-26 10:19:12 -0500114 os.environ.items()
115 if re.match(regex, k)}.items()))
Michael Walshf4c62a22017-11-13 15:40:57 -0600116
117 # Register password values to prevent printing them out. Any plug var
118 # whose name ends in PASSWORD will be registered.
119 password_vals = {k: v for (k, v) in plug_var_dict.items()
120 if re.match(r".*_PASSWORD$", k)}.values()
121 map(gp.register_passwords, password_vals)
122
123 return plug_var_dict
124
125
126def sprint_plug_vars(headers=1):
Michael Walshf4c62a22017-11-13 15:40:57 -0600127 r"""
Michael Walsha6b46ed2018-06-01 14:31:23 -0500128 Sprint the plug-in environment variables (i.e. those that begin with the
129 global PLUG_VAR_PREFIX value or those that begin with <plug-in
130 package_name>_ in upper case letters.).
Michael Walshf4c62a22017-11-13 15:40:57 -0600131
132 Example excerpt of output:
133 AUTOBOOT_BASE_TOOL_DIR_PATH=/fspmount/
134 AUTOBOOT_BB_LEVEL=
135 AUTOBOOT_BOOT_FAIL=0
136 AUTOBOOT_BOOT_FAIL_THRESHOLD=1000000
137
138 Description of argument(s):
139 headers Print a header and a footer.
140 """
141
142 plug_var_dict = return_plug_vars()
143 buffer = ""
144 if headers:
145 buffer += "\n" + gp.sprint_dashes()
146 for key, value in plug_var_dict.items():
147 buffer += key + "=" + value + "\n"
148 if headers:
149 buffer += gp.sprint_dashes() + "\n"
150
151 return buffer
152
153
154def get_plug_vars():
Michael Walshf4c62a22017-11-13 15:40:57 -0600155 r"""
156 Get all plug-in variables and put them in corresponding global variables.
157
Michael Walsha6b46ed2018-06-01 14:31:23 -0500158 This would include all environment variables beginning with either the
159 global PLUG_VAR_PREFIX value or with the upper case version of the plug-in
160 package name + underscore (e.g. OP_SAMPLE_VAR1 for plug-in OP_Sample).
Michael Walshf4c62a22017-11-13 15:40:57 -0600161
Michael Walsha6b46ed2018-06-01 14:31:23 -0500162 The global variables to be set will be both with and without the global
163 PLUG_VAR_PREFIX value prefix. For example, if the environment variable in
164 question is AUTOBOOT_OPENBMC_HOST, this function will set global variable
Michael Walshf4c62a22017-11-13 15:40:57 -0600165 AUTOBOOT_OPENBMC_HOST and global variable OPENBMC_HOST.
166 """
167
168 module = sys.modules['__main__']
169 plug_var_dict = return_plug_vars()
170
Michael Walsha6b46ed2018-06-01 14:31:23 -0500171 # Get all PLUG_VAR_PREFIX environment variables and put them into globals.
Michael Walshf4c62a22017-11-13 15:40:57 -0600172 for key, value in plug_var_dict.items():
173 setattr(module, key, value)
Michael Walsha6b46ed2018-06-01 14:31:23 -0500174 setattr(module, re.sub("^" + PLUG_VAR_PREFIX + "_", "", key), value)
Michael Walshf4c62a22017-11-13 15:40:57 -0600175
176
177def get_plug_default(var_name,
178 default=None):
Michael Walshf4c62a22017-11-13 15:40:57 -0600179 r"""
180 Derive and return a default value for the given parm variable.
181
Michael Walsha6b46ed2018-06-01 14:31:23 -0500182 Dependencies:
183 Global variable PLUG_VAR_PREFIX must be set.
184
Michael Walshf4c62a22017-11-13 15:40:57 -0600185 This function will assign a default by checking the following environment
186 variables in the order shown. The first one that has a value will be used.
187 - <upper case package_name>_<var_name>
Michael Walsha6b46ed2018-06-01 14:31:23 -0500188 - <PLUG_VAR_PREFIX>_OVERRIDE_<var_name>
189 - <PLUG_VAR_PREFIX>_<var_name>
Michael Walshf4c62a22017-11-13 15:40:57 -0600190
191 If none of these are found, this function will return the value passed by
192 the caller in the "default" parm.
193
194 Example:
195
196 Let's say your plug-in is named "OS_Console" and you call this function as
197 follows:
198
199 get_plug_default("quiet", 0)
200
201 The first of these environment variables that is found to be set will be
202 used to provide the default value.
203 - OS_CONSOLE_QUIET
204 - AUTOBOOT_OVERRIDE_QUIET
205 - AUTOBOOT_QUIET
206
207 If none of those has a value, 0 (as specified by the caller in this
208 example) is returned.
209
210 Let's say the master driver program is named obmc_boot. obmc_boot program
211 is responsible for calling plug-ins. Let's further suppose that the user
212 wishes to run the master program with --debug=0 but wishes to have all
213 plug-ins run with --debug=1. This could be accomplished with the
214 following call:
215 export AUTOBOOT_OVERRIDE_DEBUG=1 ; obmc_boot --debug=0
216 --plug_in_dir_paths=<list of plug ins>
217
218 As another example, let's suppose that the user wishes to have just the
219 OS_Console plug-in run with debug and everything else to default to
220 debug=0. This could be accomplished as follows:
221 export OS_CONSOLE_DEBUG=1 ; obmc_boot --debug=0 --plug_in_dir_paths=<list
222 of plug ins>
223
224 And as one more example, let's say the user wishes to have obmc_boot and
225 OS_Console run without debug but have all other plug-ins run with debug:
226 export AUTOBOOT_OVERRIDE_DEBUG=1 ; export OS_CONSOLE_DEBUG=0 ; obmc_boot
227 --debug=0 --plug_in_dir_paths=<list of plug ins>
228
229 Description of argument(s):
230 var_name The name of the variable for which a
231 default value is to be calculated.
232 default The default value if one cannot be
233 determined.
234 """
235
236 var_name = var_name.upper()
237 plug_in_package_name = get_plug_in_package_name(case="upper")
238
239 package_var_name = plug_in_package_name + "_" + var_name
240 default_value = os.environ.get(package_var_name, None)
241 if default_value is not None:
242 # A package-name version of the variable was found so return its value.
243 return(default_value)
244
Michael Walsha6b46ed2018-06-01 14:31:23 -0500245 plug_var_name = PLUG_VAR_PREFIX + "_OVERRIDE_" + var_name
246 default_value = os.environ.get(plug_var_name, None)
Michael Walshf4c62a22017-11-13 15:40:57 -0600247 if default_value is not None:
Michael Walsha6b46ed2018-06-01 14:31:23 -0500248 # A PLUG_VAR_PREFIX version of the variable was found so return its
249 # value.
Michael Walshf4c62a22017-11-13 15:40:57 -0600250 return default_value
251
Michael Walsha6b46ed2018-06-01 14:31:23 -0500252 plug_var_name = PLUG_VAR_PREFIX + "_" + var_name
253 default_value = os.environ.get(plug_var_name, None)
Michael Walshf4c62a22017-11-13 15:40:57 -0600254 if default_value is not None:
Michael Walsha6b46ed2018-06-01 14:31:23 -0500255 # A PLUG_VAR_PREFIX version of the variable was found so return its
256 # value.
Michael Walshf4c62a22017-11-13 15:40:57 -0600257 return default_value
258
259 return default
260
261
262def srequired_plug_in(req_plug_in_names,
263 plug_in_dir_paths=None):
Michael Walshf4c62a22017-11-13 15:40:57 -0600264 r"""
265 Return an empty string if the required plug-ins are found in
266 plug_in_dir_paths. Otherwise, return an error string.
267
268 Example call:
269 error_message = srequired_plug_in(req_plug_in_names, plug_in_dir_paths)
270
271 Description of argument(s):
272 req_plug_in_names A list of plug_in names that the caller
273 requires (e.g. ['OS_Console']).
274 plug_in_dir_paths A string which is a colon-delimited list
275 of plug-ins specified by the user (e.g.
276 DB_Logging:FFDC:OS_Console:Perf). Path
277 values (e.g. "/home/robot/dir1") will be
278 stripped from this list to do the
279 analysis. Default value is the
Michael Walsha6b46ed2018-06-01 14:31:23 -0500280 <PLUG_VAR_PREFIX>_PLUG_IN_DIR_PATHS
281 environment variable.
Michael Walshf4c62a22017-11-13 15:40:57 -0600282 """
283
284 # Calculate default value for plug_in_dir_paths.
285 if plug_in_dir_paths is None:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500286 plug_in_dir_paths = os.environ.get(PLUG_VAR_PREFIX
287 + "_PLUG_IN_DIR_PATHS", "")
Michael Walshf4c62a22017-11-13 15:40:57 -0600288
289 error_message = ""
290
291 # Convert plug_in_dir_paths to a list of base names.
292 plug_in_dir_paths = \
Michael Walsh6aa5a9e2018-08-07 15:04:56 -0500293 list(filter(None, map(os.path.basename, plug_in_dir_paths.split(":"))))
Michael Walshf4c62a22017-11-13 15:40:57 -0600294
295 # Check for each of the user's required plug-ins.
296 for plug_in_name in req_plug_in_names:
297 if plug_in_name not in plug_in_dir_paths:
298 error_message = "The \"" + get_plug_in_package_name() +\
299 "\" plug-in cannot run unless the user also selects the \"" +\
300 plug_in_name + "\" plug in:\n" +\
301 gp.sprint_var(plug_in_dir_paths)
302
303 return error_message
304
305
306def required_plug_in(req_plug_in_names,
307 plug_in_dir_paths=None):
Michael Walshf4c62a22017-11-13 15:40:57 -0600308 r"""
309 Return True if each of the plug-ins in req_plug_in_names can be found in
310 plug_in_dir_paths Otherwise, return False and print an error message to
311 stderr.
312
313 Example call:
314 if not required_plug_in(['OS_Console'], AUTOBOOT_PLUG_IN_DIR_PATHS):
315 return False
316
317 Description of argument(s):
318 (See Description of arguments for srequired_plug_in (above)).
319 """
320
321 error_message = srequired_plug_in(req_plug_in_names, plug_in_dir_paths)
322 if not error_message == "":
323 gp.print_error_report(error_message)
324 return False
325
326 return True
327
328
Michael Walsh96ffeb72018-08-23 11:37:22 -0500329def compose_plug_in_save_dir_path(plug_in_package_name=None):
Michael Walsha6b46ed2018-06-01 14:31:23 -0500330 r"""
331 Create and return a directory path name that is suitable for saving
332 plug-in data.
333
334 The name will be comprised of things such as plug_in package name, pid,
335 etc. in order to guarantee that it is unique for a given test run.
Michael Walsh96ffeb72018-08-23 11:37:22 -0500336
337 Description of argument(s):
338 plug_in_package_name The plug-in package name. This defaults
339 to the name of the caller's plug-in
340 package. However, the caller can specify
341 another value in order to retrieve data
342 saved by another plug-in package.
Michael Walsha6b46ed2018-06-01 14:31:23 -0500343 """
344
Michael Walsh96ffeb72018-08-23 11:37:22 -0500345 plug_in_package_name = gm.dft(plug_in_package_name,
346 get_plug_in_package_name())
347
Michael Walsha6b46ed2018-06-01 14:31:23 -0500348 BASE_TOOL_DIR_PATH = \
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500349 gm.add_trailing_slash(os.environ.get(PLUG_VAR_PREFIX
350 + "BASE_TOOL_DIR_PATH",
Michael Walsha6b46ed2018-06-01 14:31:23 -0500351 "/fspmount/"))
352 NICKNAME = os.environ.get("AUTOBOOT_OPENBMC_NICKNAME", "")
353 if NICKNAME == "":
354 NICKNAME = os.environ["AUTOIPL_FSP1_NICKNAME"]
355 MASTER_PID = os.environ[PLUG_VAR_PREFIX + "_MASTER_PID"]
356 return BASE_TOOL_DIR_PATH + os.environ["USER"] + "/" + NICKNAME + "/" +\
Michael Walsh96ffeb72018-08-23 11:37:22 -0500357 plug_in_package_name + "/" + MASTER_PID + "/"
Michael Walsha6b46ed2018-06-01 14:31:23 -0500358
359
Michael Walsh96ffeb72018-08-23 11:37:22 -0500360def create_plug_in_save_dir(plug_in_package_name=None):
Michael Walsha6b46ed2018-06-01 14:31:23 -0500361 r"""
362 Create a directory suitable for saving plug-in processing data. See
363 compose_plug_in_save_dir_path for details.
Michael Walsh96ffeb72018-08-23 11:37:22 -0500364
365 Description of argument(s):
366 plug_in_package_name See compose_plug_in_save_dir_path for
367 details.
Michael Walsha6b46ed2018-06-01 14:31:23 -0500368 """
369
Michael Walsh96ffeb72018-08-23 11:37:22 -0500370 plug_in_save_dir_path = compose_plug_in_save_dir_path(plug_in_package_name)
Michael Walsha6b46ed2018-06-01 14:31:23 -0500371 if os.path.isdir(plug_in_save_dir_path):
372 return plug_in_save_dir_path
373 gc.shell_cmd("mkdir -p " + plug_in_save_dir_path)
374 return plug_in_save_dir_path
375
376
Michael Walsh96ffeb72018-08-23 11:37:22 -0500377def delete_plug_in_save_dir(plug_in_package_name=None):
Michael Walsha6b46ed2018-06-01 14:31:23 -0500378 r"""
379 Delete the plug_in save directory. See compose_plug_in_save_dir_path for
380 details.
Michael Walsh96ffeb72018-08-23 11:37:22 -0500381
382 Description of argument(s):
383 plug_in_package_name See compose_plug_in_save_dir_path for
384 details.
Michael Walsha6b46ed2018-06-01 14:31:23 -0500385 """
386
Michael Walsh96ffeb72018-08-23 11:37:22 -0500387 gc.shell_cmd("rm -rf "
388 + compose_plug_in_save_dir_path(plug_in_package_name))
Michael Walsha6b46ed2018-06-01 14:31:23 -0500389
390
Michael Walsh96ffeb72018-08-23 11:37:22 -0500391def save_plug_in_value(value, plug_in_package_name=None):
Michael Walsha6b46ed2018-06-01 14:31:23 -0500392 r"""
393 Save a value in a plug-in save file. The value may be retrieved later via
394 a call to the restore_plug_in_value function.
395
396 This function will figure out the variable name of the value passed and
397 use that name in creating the plug-in save file.
398
399 Example call:
400
401 my_var1 = 5
402 save_plug_in_value(my_var1)
403
404 In this example, the value "5" would be saved to the "my_var1" file in the
405 plug-in save directory.
406
407 Description of argument(s):
408 value The value to be saved.
Michael Walsh96ffeb72018-08-23 11:37:22 -0500409 plug_in_package_name See compose_plug_in_save_dir_path for
410 details.
Michael Walsha6b46ed2018-06-01 14:31:23 -0500411 """
412
413 # Get the name of the variable used as argument one to this function.
414 var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
Michael Walsh96ffeb72018-08-23 11:37:22 -0500415 plug_in_save_dir_path = create_plug_in_save_dir(plug_in_package_name)
Michael Walsha6b46ed2018-06-01 14:31:23 -0500416 save_file_path = plug_in_save_dir_path + var_name
417 gp.qprint_timen("Saving \"" + var_name + "\" value.")
418 gc.shell_cmd("echo '" + str(value) + "' > " + save_file_path)
419
420
Michael Walsh96ffeb72018-08-23 11:37:22 -0500421def restore_plug_in_value(default="", plug_in_package_name=None):
Michael Walsha6b46ed2018-06-01 14:31:23 -0500422 r"""
423 Return a value from a plug-in save file.
424
425 The name of the value to be restored will be determined by this function
426 based on the lvalue being assigned. Consider the following example:
427
428 my_var1 = restore_plug_in_value(2)
429
430 In this example, this function would look for the "my_var1" file in the
431 plug-in save directory, read its value and return it. If no such file
432 exists, the default value of 2 would be returned.
433
434 Description of argument(s):
435 default The default value to be returned if there
436 is no plug-in save file for the value in
437 question.
Michael Walsh96ffeb72018-08-23 11:37:22 -0500438 plug_in_package_name See compose_plug_in_save_dir_path for
439 details.
Michael Walsha6b46ed2018-06-01 14:31:23 -0500440 """
441
442 # Get the lvalue from the caller's invocation of this function.
443 lvalue = gp.get_arg_name(0, -1, stack_frame_ix=2)
Michael Walsh96ffeb72018-08-23 11:37:22 -0500444 plug_in_save_dir_path = create_plug_in_save_dir(plug_in_package_name)
Michael Walsha6b46ed2018-06-01 14:31:23 -0500445 save_file_path = plug_in_save_dir_path + lvalue
446 if os.path.isfile(save_file_path):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500447 gp.qprint_timen("Restoring " + lvalue + " value from "
448 + save_file_path + ".")
Michael Walsh25f0f162018-09-10 13:57:11 -0500449 value = gm.file_to_list(save_file_path, newlines=0, comments=0,
450 trim=1)[0]
451 if type(default) is bool:
452 # Convert from string to bool.
453 value = (value == 'True')
454 if type(default) is int:
455 # Convert from string to int.
456 value = int(value)
457 gp.qprint_varx(lvalue, value)
458 return value
Michael Walsha6b46ed2018-06-01 14:31:23 -0500459 else:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500460 gp.qprint_timen("Save file " + save_file_path
461 + " does not exist so returning default value.")
Michael Walsh25f0f162018-09-10 13:57:11 -0500462 gp.qprint_var(default)
Michael Walsha6b46ed2018-06-01 14:31:23 -0500463 return default
464
465
Michael Walshf4c62a22017-11-13 15:40:57 -0600466# Create print wrapper functions for all sprint functions defined above.
467# func_names contains a list of all print functions which should be created
468# from their sprint counterparts.
469func_names = ['print_plug_vars']
470
471# stderr_func_names is a list of functions whose output should go to stderr
472# rather than stdout.
473stderr_func_names = []
474
475replace_dict = dict(gp.replace_dict)
Michael Walsh81c02342018-01-05 15:43:28 -0600476replace_dict['mod_qualifier'] = 'gp.'
Michael Walshf4c62a22017-11-13 15:40:57 -0600477func_defs = gp.create_print_wrapper_funcs(func_names, stderr_func_names,
478 replace_dict)
479gp.gp_debug_print(func_defs)
480exec(func_defs)