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 14import gen_cmd as gc 15 16PLUG_VAR_PREFIX = os.environ.get("PLUG_VAR_PREFIX", "AUTOBOOT") 17 18 19def get_plug_in_package_name(case=None): 20 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(): 40 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: 53 - Set a default value for environment variable 54 AUTOBOOT_OPENBMC_NICKNAME/AUTOIPL_FSP1_NICKNAME if it is not already set. 55 - Register PASSWORD variables to prevent their values from being printed. 56 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. 65 """ 66 67 plug_in_package_name = get_plug_in_package_name(case="upper") 68 regex = "^(" + PLUG_VAR_PREFIX + "|AUTOGUI|" + plug_in_package_name + ")_" 69 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 75 if os.environ.get("AUTOIPL_FSP1_NICKNAME", "") == "": 76 os.environ['AUTOIPL_FSP1_NICKNAME'] = \ 77 os.environ.get("AUTOIPL_FSP1_NAME", "").split(".")[0] 78 79 # 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: 105 # 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 111 112 plug_var_dict = \ 113 collections.OrderedDict(sorted({k: v for (k, v) in 114 os.environ.items() 115 if re.match(regex, k)}.items())) 116 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): 127 r""" 128 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.). 131 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(): 155 r""" 156 Get all plug-in variables and put them in corresponding global variables. 157 158 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). 161 162 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 165 AUTOBOOT_OPENBMC_HOST and global variable OPENBMC_HOST. 166 """ 167 168 module = sys.modules['__main__'] 169 plug_var_dict = return_plug_vars() 170 171 # Get all PLUG_VAR_PREFIX environment variables and put them into globals. 172 for key, value in plug_var_dict.items(): 173 setattr(module, key, value) 174 setattr(module, re.sub("^" + PLUG_VAR_PREFIX + "_", "", key), value) 175 176 177def get_plug_default(var_name, 178 default=None): 179 r""" 180 Derive and return a default value for the given parm variable. 181 182 Dependencies: 183 Global variable PLUG_VAR_PREFIX must be set. 184 185 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> 188 - <PLUG_VAR_PREFIX>_OVERRIDE_<var_name> 189 - <PLUG_VAR_PREFIX>_<var_name> 190 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 245 plug_var_name = PLUG_VAR_PREFIX + "_OVERRIDE_" + var_name 246 default_value = os.environ.get(plug_var_name, None) 247 if default_value is not None: 248 # A PLUG_VAR_PREFIX version of the variable was found so return its 249 # value. 250 return default_value 251 252 plug_var_name = PLUG_VAR_PREFIX + "_" + var_name 253 default_value = os.environ.get(plug_var_name, None) 254 if default_value is not None: 255 # A PLUG_VAR_PREFIX version of the variable was found so return its 256 # value. 257 return default_value 258 259 return default 260 261 262def srequired_plug_in(req_plug_in_names, 263 plug_in_dir_paths=None): 264 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 280 <PLUG_VAR_PREFIX>_PLUG_IN_DIR_PATHS 281 environment variable. 282 """ 283 284 # Calculate default value for plug_in_dir_paths. 285 if plug_in_dir_paths is None: 286 plug_in_dir_paths = os.environ.get(PLUG_VAR_PREFIX 287 + "_PLUG_IN_DIR_PATHS", "") 288 289 error_message = "" 290 291 # Convert plug_in_dir_paths to a list of base names. 292 plug_in_dir_paths = \ 293 filter(None, map(os.path.basename, plug_in_dir_paths.split(":"))) 294 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): 308 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 329def compose_plug_in_save_dir_path(): 330 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. 336 """ 337 338 BASE_TOOL_DIR_PATH = \ 339 gm.add_trailing_slash(os.environ.get(PLUG_VAR_PREFIX 340 + "BASE_TOOL_DIR_PATH", 341 "/fspmount/")) 342 NICKNAME = os.environ.get("AUTOBOOT_OPENBMC_NICKNAME", "") 343 if NICKNAME == "": 344 NICKNAME = os.environ["AUTOIPL_FSP1_NICKNAME"] 345 MASTER_PID = os.environ[PLUG_VAR_PREFIX + "_MASTER_PID"] 346 return BASE_TOOL_DIR_PATH + os.environ["USER"] + "/" + NICKNAME + "/" +\ 347 get_plug_in_package_name() + "/" + MASTER_PID + "/" 348 349 350def create_plug_in_save_dir(): 351 r""" 352 Create a directory suitable for saving plug-in processing data. See 353 compose_plug_in_save_dir_path for details. 354 """ 355 356 plug_in_save_dir_path = compose_plug_in_save_dir_path() 357 if os.path.isdir(plug_in_save_dir_path): 358 return plug_in_save_dir_path 359 gc.shell_cmd("mkdir -p " + plug_in_save_dir_path) 360 return plug_in_save_dir_path 361 362 363def delete_plug_in_save_dir(): 364 r""" 365 Delete the plug_in save directory. See compose_plug_in_save_dir_path for 366 details. 367 """ 368 369 gc.shell_cmd("rm -rf " + compose_plug_in_save_dir_path()) 370 371 372def save_plug_in_value(value): 373 r""" 374 Save a value in a plug-in save file. The value may be retrieved later via 375 a call to the restore_plug_in_value function. 376 377 This function will figure out the variable name of the value passed and 378 use that name in creating the plug-in save file. 379 380 Example call: 381 382 my_var1 = 5 383 save_plug_in_value(my_var1) 384 385 In this example, the value "5" would be saved to the "my_var1" file in the 386 plug-in save directory. 387 388 Description of argument(s): 389 value The value to be saved. 390 """ 391 392 # Get the name of the variable used as argument one to this function. 393 var_name = gp.get_arg_name(0, 1, stack_frame_ix=2) 394 plug_in_save_dir_path = create_plug_in_save_dir() 395 save_file_path = plug_in_save_dir_path + var_name 396 gp.qprint_timen("Saving \"" + var_name + "\" value.") 397 gc.shell_cmd("echo '" + str(value) + "' > " + save_file_path) 398 399 400def restore_plug_in_value(default=""): 401 r""" 402 Return a value from a plug-in save file. 403 404 The name of the value to be restored will be determined by this function 405 based on the lvalue being assigned. Consider the following example: 406 407 my_var1 = restore_plug_in_value(2) 408 409 In this example, this function would look for the "my_var1" file in the 410 plug-in save directory, read its value and return it. If no such file 411 exists, the default value of 2 would be returned. 412 413 Description of argument(s): 414 default The default value to be returned if there 415 is no plug-in save file for the value in 416 question. 417 """ 418 419 # Get the lvalue from the caller's invocation of this function. 420 lvalue = gp.get_arg_name(0, -1, stack_frame_ix=2) 421 plug_in_save_dir_path = create_plug_in_save_dir() 422 save_file_path = plug_in_save_dir_path + lvalue 423 if os.path.isfile(save_file_path): 424 gp.qprint_timen("Restoring " + lvalue + " value from " 425 + save_file_path + ".") 426 return gm.file_to_list(save_file_path, newlines=0, comments=0, 427 trim=1)[0] 428 else: 429 gp.qprint_timen("Save file " + save_file_path 430 + " does not exist so returning default value.") 431 return default 432 433 434# Create print wrapper functions for all sprint functions defined above. 435# func_names contains a list of all print functions which should be created 436# from their sprint counterparts. 437func_names = ['print_plug_vars'] 438 439# stderr_func_names is a list of functions whose output should go to stderr 440# rather than stdout. 441stderr_func_names = [] 442 443replace_dict = dict(gp.replace_dict) 444replace_dict['mod_qualifier'] = 'gp.' 445func_defs = gp.create_print_wrapper_funcs(func_names, stderr_func_names, 446 replace_dict) 447gp.gp_debug_print(func_defs) 448exec(func_defs) 449