17423c01aSMichael Walsh#!/usr/bin/env python 27423c01aSMichael Walsh 37423c01aSMichael Walshimport sys 47423c01aSMichael Walshimport __builtin__ 57423c01aSMichael Walshimport subprocess 67423c01aSMichael Walshimport os 77423c01aSMichael Walshimport argparse 87423c01aSMichael Walsh 97423c01aSMichael Walsh# python puts the program's directory path in sys.path[0]. In other words, 107423c01aSMichael Walsh# the user ordinarily has no way to override python's choice of a module from 117423c01aSMichael Walsh# its own dir. We want to have that ability in our environment. However, we 127423c01aSMichael Walsh# don't want to break any established python modules that depend on this 137423c01aSMichael Walsh# behavior. So, we'll save the value from sys.path[0], delete it, import our 147423c01aSMichael Walsh# modules and then restore sys.path to its original value. 157423c01aSMichael Walsh 167423c01aSMichael Walshsave_path_0 = sys.path[0] 177423c01aSMichael Walshdel sys.path[0] 187423c01aSMichael Walsh 197423c01aSMichael Walshfrom gen_print import * 207423c01aSMichael Walshfrom gen_valid import * 217423c01aSMichael Walshfrom gen_arg import * 227423c01aSMichael Walshfrom gen_plug_in import * 237423c01aSMichael Walsh 247423c01aSMichael Walsh# Restore sys.path[0]. 257423c01aSMichael Walshsys.path.insert(0, save_path_0) 267423c01aSMichael Walsh# I use this variable in calls to print_var. 277423c01aSMichael Walshhex = 1 287423c01aSMichael Walsh 297423c01aSMichael Walsh############################################################################### 307423c01aSMichael Walsh# Create parser object to process command line parameters and args. 317423c01aSMichael Walsh 327423c01aSMichael Walsh# Create parser object. 337423c01aSMichael Walshparser = argparse.ArgumentParser( 347423c01aSMichael Walsh usage='%(prog)s [OPTIONS]', 357423c01aSMichael Walsh description="%(prog)s will process the plug-in packages passed to it." + 367423c01aSMichael Walsh " A plug-in package is essentially a directory containing" + 377423c01aSMichael Walsh " one or more call point programs. Each of these call point" + 387423c01aSMichael Walsh " programs must have a prefix of \"cp_\". When calling" + 397423c01aSMichael Walsh " %(prog)s, a user must provide a call_point parameter" + 407423c01aSMichael Walsh " (described below). For each plug-in package passed," + 417423c01aSMichael Walsh " %(prog)s will check for the presence of the specified call" + 427423c01aSMichael Walsh " point program in the plug-in directory. If it is found," + 437423c01aSMichael Walsh " %(prog)s will run it. It is the responsibility of the" + 447423c01aSMichael Walsh " caller to set any environment variables needed by the call" + 457423c01aSMichael Walsh " point programs.\n\nAfter each call point program" + 467423c01aSMichael Walsh " has been run, %(prog)s will print the following values in" + 477423c01aSMichael Walsh " the following formats for use by the calling program:\n" + 487423c01aSMichael Walsh " failed_plug_in_name: <failed plug-in value," + 497423c01aSMichael Walsh " if any>\n shell_rc: " + 507423c01aSMichael Walsh "<shell return code value of last call point program - this" + 517423c01aSMichael Walsh " will be printed in hexadecimal format. Also, be aware" + 527423c01aSMichael Walsh " that if a call point program returns a value it will be" + 537423c01aSMichael Walsh " shifted left 2 bytes (e.g. rc of 2 will be printed as" + 547423c01aSMichael Walsh " 0x00000200). That is because the rightmost byte is" + 557423c01aSMichael Walsh " reserverd for errors in calling the call point program" + 567423c01aSMichael Walsh " rather than errors generated by the call point program.>", 577423c01aSMichael Walsh formatter_class=argparse.RawTextHelpFormatter, 587423c01aSMichael Walsh prefix_chars='-+' 597423c01aSMichael Walsh ) 607423c01aSMichael Walsh 617423c01aSMichael Walsh# Create arguments. 627423c01aSMichael Walshparser.add_argument( 637423c01aSMichael Walsh 'plug_in_dir_paths', 647423c01aSMichael Walsh nargs='?', 657423c01aSMichael Walsh default="", 667423c01aSMichael Walsh help=plug_in_dir_paths_help_text + default_string 677423c01aSMichael Walsh ) 687423c01aSMichael Walsh 697423c01aSMichael Walshparser.add_argument( 707423c01aSMichael Walsh '--call_point', 717423c01aSMichael Walsh default="setup", 727423c01aSMichael Walsh required=True, 737423c01aSMichael Walsh help='The call point program name. This value must not include the' + 747423c01aSMichael Walsh ' "cp_" prefix. For each plug-in package passed to this program,' + 757423c01aSMichael Walsh ' the specified call_point program will be called if it exists in' + 767423c01aSMichael Walsh ' the plug-in directory.' + default_string 777423c01aSMichael Walsh ) 787423c01aSMichael Walsh 797423c01aSMichael Walshparser.add_argument( 807423c01aSMichael Walsh '--shell_rc', 817423c01aSMichael Walsh default="0x00000000", 827423c01aSMichael Walsh help='The user may supply a value other than zero to indicate an' + 837423c01aSMichael Walsh ' acceptable non-zero return code. For example, if this value' + 847423c01aSMichael Walsh ' equals 0x00000200, it means that for each plug-in call point that' + 857423c01aSMichael Walsh ' runs, a 0x00000200 will not be counted as a failure. See note' + 867423c01aSMichael Walsh ' above regarding left-shifting of return codes.' + default_string 877423c01aSMichael Walsh ) 887423c01aSMichael Walsh 897423c01aSMichael Walshparser.add_argument( 907423c01aSMichael Walsh '--stop_on_plug_in_failure', 917423c01aSMichael Walsh default=1, 927423c01aSMichael Walsh type=int, 937423c01aSMichael Walsh choices=[1, 0], 947423c01aSMichael Walsh help='If this parameter is set to 1, this program will stop and return ' + 957423c01aSMichael Walsh 'non-zero if the call point program from any plug-in directory ' + 967423c01aSMichael Walsh 'fails. Conversely, if it is set to false, this program will run ' + 977423c01aSMichael Walsh 'the call point program from each and every plug-in directory ' + 987423c01aSMichael Walsh 'regardless of their return values. Typical example cases where ' + 997423c01aSMichael Walsh 'you\'d want to run all plug-in call points regardless of success ' + 1007423c01aSMichael Walsh 'or failure would be "cleanup" or "ffdc" call points.' 1017423c01aSMichael Walsh ) 1027423c01aSMichael Walsh 1037423c01aSMichael Walshparser.add_argument( 1047423c01aSMichael Walsh '--stop_on_non_zero_rc', 1057423c01aSMichael Walsh default=0, 1067423c01aSMichael Walsh type=int, 1077423c01aSMichael Walsh choices=[1, 0], 1087423c01aSMichael Walsh help='If this parm is set to 1 and a plug-in call point program returns ' + 1097423c01aSMichael Walsh 'a valid non-zero return code (see "shell_rc" parm above), this' + 1107423c01aSMichael Walsh ' program will stop processing and return 0 (success). Since this' + 1117423c01aSMichael Walsh ' constitutes a successful exit, this would normally be used where' + 1127423c01aSMichael Walsh ' the caller wishes to stop processing if one of the plug-in' + 1137423c01aSMichael Walsh ' directory call point programs returns a special value indicating' + 1147423c01aSMichael Walsh ' that some special case has been found. An example might be in' + 1157423c01aSMichael Walsh ' calling some kind of "check_errl" call point program. Such a' + 1167423c01aSMichael Walsh ' call point program might return a 2 (i.e. 0x00000200) to indicate' + 1177423c01aSMichael Walsh ' that a given error log entry was found in an "ignore" list and is' + 1187423c01aSMichael Walsh ' therefore to be ignored. That being the case, no other' + 1197423c01aSMichael Walsh ' "check_errl" call point program would need to be called.' + 1207423c01aSMichael Walsh default_string 1217423c01aSMichael Walsh ) 1227423c01aSMichael Walsh 1237423c01aSMichael Walshparser.add_argument( 1247423c01aSMichael Walsh '--mch_class', 1257423c01aSMichael Walsh default="obmc", 1267423c01aSMichael Walsh help=mch_class_help_text + default_string 1277423c01aSMichael Walsh ) 1287423c01aSMichael Walsh 1297423c01aSMichael Walsh# The stock_list will be passed to gen_get_options. We populate it with the 1307423c01aSMichael Walsh# names of stock parm options we want. These stock parms are pre-defined by 1317423c01aSMichael Walsh# gen_get_options. 1327423c01aSMichael Walshstock_list = [("test_mode", 0), ("quiet", 1), ("debug", 0)] 1337423c01aSMichael Walsh############################################################################### 1347423c01aSMichael Walsh 1357423c01aSMichael Walsh 1367423c01aSMichael Walsh############################################################################### 1377423c01aSMichael Walshdef exit_function(signal_number=0, 1387423c01aSMichael Walsh frame=None): 1397423c01aSMichael Walsh 1407423c01aSMichael Walsh r""" 1417423c01aSMichael Walsh Execute whenever the program ends normally or with the signals that we 1427423c01aSMichael Walsh catch (i.e. TERM, INT). 1437423c01aSMichael Walsh """ 1447423c01aSMichael Walsh 1457423c01aSMichael Walsh dprint_executing() 1467423c01aSMichael Walsh dprint_var(signal_number) 1477423c01aSMichael Walsh 1487423c01aSMichael Walsh qprint_pgm_footer() 1497423c01aSMichael Walsh 1507423c01aSMichael Walsh############################################################################### 1517423c01aSMichael Walsh 1527423c01aSMichael Walsh 1537423c01aSMichael Walsh############################################################################### 1547423c01aSMichael Walshdef signal_handler(signal_number, frame): 1557423c01aSMichael Walsh 1567423c01aSMichael Walsh r""" 1577423c01aSMichael Walsh Handle signals. Without a function to catch a SIGTERM or SIGINT, our 1587423c01aSMichael Walsh program would terminate immediately with return code 143 and without 1597423c01aSMichael Walsh calling our exit_function. 1607423c01aSMichael Walsh """ 1617423c01aSMichael Walsh 1627423c01aSMichael Walsh # Our convention is to set up exit_function with atexit.registr() so 1637423c01aSMichael Walsh # there is no need to explicitly call exit_function from here. 1647423c01aSMichael Walsh 1657423c01aSMichael Walsh dprint_executing() 1667423c01aSMichael Walsh 1677423c01aSMichael Walsh # Calling exit prevents us from returning to the code that was running 1687423c01aSMichael Walsh # when we received the signal. 1697423c01aSMichael Walsh exit(0) 1707423c01aSMichael Walsh 1717423c01aSMichael Walsh############################################################################### 1727423c01aSMichael Walsh 1737423c01aSMichael Walsh 1747423c01aSMichael Walsh############################################################################### 1757423c01aSMichael Walshdef validate_parms(): 1767423c01aSMichael Walsh 1777423c01aSMichael Walsh r""" 1787423c01aSMichael Walsh Validate program parameters, etc. Return True or False accordingly. 1797423c01aSMichael Walsh """ 1807423c01aSMichael Walsh 1817423c01aSMichael Walsh if not valid_value(call_point): 1827423c01aSMichael Walsh return False 1837423c01aSMichael Walsh 1847423c01aSMichael Walsh gen_post_validation(exit_function, signal_handler) 1857423c01aSMichael Walsh 1867423c01aSMichael Walsh return True 1877423c01aSMichael Walsh 1887423c01aSMichael Walsh############################################################################### 1897423c01aSMichael Walsh 1907423c01aSMichael Walsh 1917423c01aSMichael Walsh############################################################################### 1927423c01aSMichael Walshdef run_pgm(plug_in_dir_path, 1937423c01aSMichael Walsh call_point, 1947423c01aSMichael Walsh caller_shell_rc): 1957423c01aSMichael Walsh 1967423c01aSMichael Walsh r""" 1977423c01aSMichael Walsh Run the call point program in the given plug_in_dir_path. Return the 1987423c01aSMichael Walsh following: 1997423c01aSMichael Walsh rc The return code - 0 = PASS, 1 = FAIL. 2007423c01aSMichael Walsh shell_rc The shell return code returned by 2017423c01aSMichael Walsh process_plug_in_packages.py. 2027423c01aSMichael Walsh failed_plug_in_name The failed plug in name (if any). 2037423c01aSMichael Walsh 2047423c01aSMichael Walsh Description of arguments: 2057423c01aSMichael Walsh plug_in_dir_path The directory path where the call_point 2067423c01aSMichael Walsh program may be located. 2077423c01aSMichael Walsh call_point The call point (e.g. "setup"). This 2087423c01aSMichael Walsh program will look for a program named 2097423c01aSMichael Walsh "cp_" + call_point in the 2107423c01aSMichael Walsh plug_in_dir_path. If no such call point 2117423c01aSMichael Walsh program is found, this function returns an 2127423c01aSMichael Walsh rc of 0 (i.e. success). 2137423c01aSMichael Walsh caller_shell_rc The user may supply a value other than 2147423c01aSMichael Walsh zero to indicate an acceptable non-zero 2157423c01aSMichael Walsh return code. For example, if this value 2167423c01aSMichael Walsh equals 0x00000200, it means that for each 2177423c01aSMichael Walsh plug-in call point that runs, a 0x00000200 2187423c01aSMichael Walsh will not be counted as a failure. See 2197423c01aSMichael Walsh note above regarding left-shifting of 2207423c01aSMichael Walsh return codes. 2217423c01aSMichael Walsh """ 2227423c01aSMichael Walsh 2237423c01aSMichael Walsh rc = 0 2247423c01aSMichael Walsh failed_plug_in_name = "" 2257423c01aSMichael Walsh shell_rc = 0x00000000 2267423c01aSMichael Walsh 2277423c01aSMichael Walsh cp_prefix = "cp_" 2287423c01aSMichael Walsh plug_in_pgm_path = plug_in_dir_path + cp_prefix + call_point 2297423c01aSMichael Walsh if not os.path.exists(plug_in_pgm_path): 2307423c01aSMichael Walsh # No such call point in this plug in dir path. This is legal so we 2317423c01aSMichael Walsh # return 0, etc. 2327423c01aSMichael Walsh return rc, shell_rc, failed_plug_in_name 2337423c01aSMichael Walsh 2347423c01aSMichael Walsh # Get some stats on the file. 2357423c01aSMichael Walsh cmd_buf = "stat -c '%n %s %z' " + plug_in_pgm_path 236a6723f27SMichael Walsh dpissuing(cmd_buf) 2377423c01aSMichael Walsh sub_proc = subprocess.Popen(cmd_buf, shell=True, stdout=subprocess.PIPE, 2387423c01aSMichael Walsh stderr=subprocess.STDOUT) 2397423c01aSMichael Walsh out_buf, err_buf = sub_proc.communicate() 2407423c01aSMichael Walsh shell_rc = sub_proc.returncode 2417423c01aSMichael Walsh if shell_rc != 0: 2427423c01aSMichael Walsh rc = 1 2437423c01aSMichael Walsh print_var(shell_rc, hex) 2447423c01aSMichael Walsh failed_plug_in_name = \ 2457423c01aSMichael Walsh os.path.basename(os.path.normpath(plug_in_dir_path)) 2467423c01aSMichael Walsh print(out_buf) 2477423c01aSMichael Walsh return rc, shell_rc, failed_plug_in_name 2487423c01aSMichael Walsh 249a6723f27SMichael Walsh print("------------------------------------------------- Starting plug-" + 250a6723f27SMichael Walsh "in -----------------------------------------------") 2517423c01aSMichael Walsh print(out_buf) 2527423c01aSMichael Walsh cmd_buf = "PATH=" + plug_in_dir_path + ":${PATH} ; " + cp_prefix +\ 2537423c01aSMichael Walsh call_point 254a6723f27SMichael Walsh pissuing(cmd_buf) 2557423c01aSMichael Walsh 256*be6153b8SMichael Walsh sub_proc = subprocess.Popen(cmd_buf, shell=True) 257*be6153b8SMichael Walsh sub_proc.communicate() 2587423c01aSMichael Walsh shell_rc = sub_proc.returncode 2597423c01aSMichael Walsh if shell_rc != 0 and shell_rc != int(caller_shell_rc, 16): 2607423c01aSMichael Walsh rc = 1 2617423c01aSMichael Walsh failed_plug_in_name = \ 2627423c01aSMichael Walsh os.path.basename(os.path.normpath(plug_in_dir_path)) 2637423c01aSMichael Walsh 2647423c01aSMichael Walsh print("------------------------------------------------- Ending plug-in" + 2657423c01aSMichael Walsh " -------------------------------------------------") 2667423c01aSMichael Walsh 2677423c01aSMichael Walsh return rc, shell_rc, failed_plug_in_name 2687423c01aSMichael Walsh 2697423c01aSMichael Walsh############################################################################### 2707423c01aSMichael Walsh 2717423c01aSMichael Walsh 2727423c01aSMichael Walsh############################################################################### 2737423c01aSMichael Walshdef main(): 2747423c01aSMichael Walsh 2757423c01aSMichael Walsh r""" 2767423c01aSMichael Walsh This is the "main" function. The advantage of having this function vs 2777423c01aSMichael Walsh just doing this in the true mainline is that you can: 2787423c01aSMichael Walsh - Declare local variables 2797423c01aSMichael Walsh - Use "return" instead of "exit". 2807423c01aSMichael Walsh - Indent 4 chars like you would in any function. 2817423c01aSMichael Walsh This makes coding more consistent, i.e. it's easy to move code from here 2827423c01aSMichael Walsh into a function and vice versa. 2837423c01aSMichael Walsh """ 2847423c01aSMichael Walsh 2857423c01aSMichael Walsh if not gen_get_options(parser, stock_list): 2867423c01aSMichael Walsh return False 2877423c01aSMichael Walsh 2887423c01aSMichael Walsh if not validate_parms(): 2897423c01aSMichael Walsh return False 2907423c01aSMichael Walsh 2917423c01aSMichael Walsh qprint_pgm_header() 2927423c01aSMichael Walsh 2937423c01aSMichael Walsh # Access program parameter globals. 2947423c01aSMichael Walsh global plug_in_dir_paths 2957423c01aSMichael Walsh global mch_class 2967423c01aSMichael Walsh global shell_rc 2977423c01aSMichael Walsh global stop_on_plug_in_failure 2987423c01aSMichael Walsh global stop_on_non_zero_rc 2997423c01aSMichael Walsh 3007423c01aSMichael Walsh plug_in_packages_list = return_plug_in_packages_list(plug_in_dir_paths, 3017423c01aSMichael Walsh mch_class) 3027423c01aSMichael Walsh 3037423c01aSMichael Walsh qpvar(plug_in_packages_list) 3047423c01aSMichael Walsh qprint("\n") 3057423c01aSMichael Walsh 3067423c01aSMichael Walsh caller_shell_rc = shell_rc 307a6723f27SMichael Walsh shell_rc = 0 3087423c01aSMichael Walsh failed_plug_in_name = "" 3097423c01aSMichael Walsh 3107423c01aSMichael Walsh ret_code = 0 3117423c01aSMichael Walsh for plug_in_dir_path in plug_in_packages_list: 3127423c01aSMichael Walsh rc, shell_rc, failed_plug_in_name = \ 3137423c01aSMichael Walsh run_pgm(plug_in_dir_path, call_point, caller_shell_rc) 3147423c01aSMichael Walsh print_var(failed_plug_in_name) 3157423c01aSMichael Walsh print_var(shell_rc, hex) 3167423c01aSMichael Walsh if rc != 0: 3177423c01aSMichael Walsh ret_code = 1 3187423c01aSMichael Walsh if stop_on_plug_in_failure: 3197423c01aSMichael Walsh break 3207423c01aSMichael Walsh if shell_rc != 0 and stop_on_non_zero_rc: 3217423c01aSMichael Walsh qprint_time("Stopping on non-zero shell return code as requested" + 3227423c01aSMichael Walsh " by caller.\n") 3237423c01aSMichael Walsh break 3247423c01aSMichael Walsh 3257423c01aSMichael Walsh if ret_code == 0: 3267423c01aSMichael Walsh return True 3277423c01aSMichael Walsh else: 3287423c01aSMichael Walsh if not stop_on_plug_in_failure: 3297423c01aSMichael Walsh # We print a summary error message to make the failure more 3307423c01aSMichael Walsh # obvious. 3317423c01aSMichael Walsh print_error_report("At least one plug-in failed.\n") 3327423c01aSMichael Walsh return False 3337423c01aSMichael Walsh 3347423c01aSMichael Walsh############################################################################### 3357423c01aSMichael Walsh 3367423c01aSMichael Walsh 3377423c01aSMichael Walsh############################################################################### 3387423c01aSMichael Walsh# Main 3397423c01aSMichael Walsh 3407423c01aSMichael Walshif not main(): 3417423c01aSMichael Walsh exit(1) 3427423c01aSMichael Walsh 3437423c01aSMichael Walsh############################################################################### 344