diff --git a/ChangeLog.txt b/ChangeLog.txt index 66a63ae6..ef8374f2 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,5 +1,8 @@ ** Release Notes +1.5.48 + * pbook in batch mode + 1.5.47 * utilities for ID tokens diff --git a/pandaclient/PBookCore.py b/pandaclient/PBookCore.py index 375d74cc..e1c06969 100644 --- a/pandaclient/PBookCore.py +++ b/pandaclient/PBookCore.py @@ -65,8 +65,6 @@ def wrapper(self, *args, **kwargs): tmpLog = PLogger.getPandaLogger() # initialize ret = None - # check proxy - PsubUtils.check_proxy(self.verbose, None) # check task owner try: taskid = None @@ -111,15 +109,21 @@ class PBookCore(object): def __init__(self, verbose=False): # verbose self.verbose = verbose + self.username = None + + # init + def init(self, sanity_check=True): # check proxy - PsubUtils.check_proxy(self.verbose, None) + if sanity_check: + PsubUtils.check_proxy(self.verbose, None) # user name username_from_proxy = PsubUtils.extract_voms_proxy_username() if username_from_proxy: self.username = username_from_proxy sys.stdout.write('PBook user: {0} \n'.format(self.username)) else: - sys.stderr.write('ERROR : Cannot get user name from proxy. Exit... \n') + sys.stderr.write('ERROR : Cannot get user name from proxy or token. ' + 'Please generate a new one using "generate_credential"\n') sys.exit(1) # kill @@ -172,8 +176,6 @@ def finish(self, taskID, soft=False): def debug(self, pandaID, modeOn): # get logger tmpLog = PLogger.getPandaLogger() - # check proxy - PsubUtils.check_proxy(self.verbose, None) # set status,output = Client.setDebugMode(pandaID,modeOn,self.verbose) if status != 0: @@ -485,3 +487,7 @@ def resume(self, task_id): # done tmpLog.info('Done') return True + + # generate_credential + def generate_credential(self): + return PsubUtils.check_proxy(self.verbose, None, generate_new=True) diff --git a/pandaclient/PBookScript.py b/pandaclient/PBookScript.py index 438fa5e6..a8f7ce65 100644 --- a/pandaclient/PBookScript.py +++ b/pandaclient/PBookScript.py @@ -30,6 +30,7 @@ def list_parallel_exec(func, array): import argparse import readline +import pydoc from pandaclient import Client from pandaclient import PandaToolsPkgInfo @@ -88,11 +89,9 @@ def _onExit(dirName,hFile): from pandaclient import PBookCore # noqa: E402 -orig_help = help - # main for interactive session -def intmain(pbookCore,comString): +def intmain(pbookCore, comString, args_list): # help def help(*arg): @@ -105,7 +104,7 @@ def help(*arg): func = main_locals[arg[0]] else: func = arg[0] - orig_help(func) + print(pydoc.plain(pydoc.render_doc(func))) return except Exception: print("Unknown command : {0}".format(str(arg[0]))) @@ -132,8 +131,9 @@ def help(*arg): list_secrets delete_secret delete_all_secrets + generate_credential -For more info, do help(show) for example +For more info of each command, e.g. do "help(show)" in interactive mode or "help show" in batch mode. """ print(tmp_str) @@ -418,16 +418,72 @@ def list_secrets(full=False): """ pbookCore.list_secrets(full) + # generate credential + def generate_credential(): + """ + Generate a new proxy or token + + """ + pbookCore.generate_credential() + + main_locals = locals() + # execute command in the batch mode if comString != '': + pbookCore.init() exec(comString) in globals(), locals() # exit if PBookCore.func_return_value: sys.exit(0) else: sys.exit(1) - main_locals = locals() + + # execute with args in the batch mode + if args_list: + func_name = args_list.pop(0) + if func_name not in locals(): + print("ERROR : function {0} is undefined".format(func_name)) + sys.exit(1) + + # convert arg string + def _conv_str(some_string): + if ',' in some_string: + try: + return [int(s) for s in some_string.split(',')] + except Exception: + return some_string.split(',') + else: + if some_string == 'True': + return True + elif some_string == 'False': + return False + try: + return int(some_string) + except Exception: + return some_string + + # separate args and kwargs + args = [] + kwargs = {} + for arg in args_list: + if '=' in arg: + k, v = arg.split('=') + kwargs[k] = _conv_str(v) + else: + args.append(_conv_str(arg)) + # execute + if func_name not in ['help', 'generate_credential']: + pbookCore.init(sanity_check=False) + locals()[func_name](*args, **kwargs) + + # exit + if PBookCore.func_return_value: + sys.exit(0) + else: + sys.exit(1) + # go to interactive prompt + pbookCore.init() code.interact(banner="\nStart pBook %s" % PandaToolsPkgInfo.release_version, local=locals()) @@ -443,11 +499,54 @@ def catch_sig(sig, frame): # overall main def main(): # parse option - parser = argparse.ArgumentParser(conflict_handler="resolve") + usage = """ + $ pbook [options] # interactive mode + $ pbook [options] command [args] [kwargs] # batch mode + + The same command can be executed in interactive mode: + + $ pbook + >>> command(*args, **kwargs) + + or in batch mode: + + $ pbook command arg1 arg2 ... argN kwarg1=value1 kwarg2=value2 ... kwargN=valueN + + E.g. + + $ pbook + >>> show(123, format='long', sync=True) + + is equivalent to + + $ pbook show 123 format='long' sync=True + + If arg or value is a list in interactive mode, it is represented as a comma-separate list in batch mode. E.g. + to kill three tasks in interactive mode: + + $ pbook + >>> kill([123, 456, 789]) + + or in batch mode: + + $ pbook kill 123,456,789 + + To see the list of commands and help of each command, + + $ pbook + >>> help() + >>> help(command_name) + + or + + $ pbook help + $ pbook help command_name + """ + parser = argparse.ArgumentParser(conflict_handler="resolve", usage=usage) parser.add_argument("-v",action="store_true",dest="verbose",default=False, help="Verbose") parser.add_argument('-c',action='store',dest='comString',default='',type=str, - help='Execute a command in the batch mode') + help='Execute a python code snippet') parser.add_argument("-3", action="store_true", dest="python3", default=False, help="Use python3") parser.add_argument('--version',action='store_const',const=True,dest='version',default=False, @@ -460,7 +559,7 @@ def main(): parser.add_argument('--prompt_with_newline', action='store_const', const=True, dest='prompt_with_newline', default=False, help=argparse.SUPPRESS) - options,args = parser.parse_known_args() + options, args = parser.parse_known_args() # display version if options.version: @@ -483,15 +582,14 @@ def main(): sys.exit(1) if fork_child_pid == 0: # main - # instantiate core if options.verbose: print(options) if options.prompt_with_newline: sys.ps1 = ">>> \n" + # instantiate core pbookCore = PBookCore.PBookCore(verbose=options.verbose) - - # CUI - intmain(pbookCore,options.comString) + # execute + intmain(pbookCore, options.comString, args) else: # set handler signal.signal(signal.SIGINT, catch_sig) diff --git a/pandaclient/PandaToolsPkgInfo.py b/pandaclient/PandaToolsPkgInfo.py index 88df5a7c..b67a861c 100644 --- a/pandaclient/PandaToolsPkgInfo.py +++ b/pandaclient/PandaToolsPkgInfo.py @@ -1 +1 @@ -release_version = "1.5.47" +release_version = "1.5.48" diff --git a/pandaclient/PsubUtils.py b/pandaclient/PsubUtils.py index 174af453..906b5a79 100644 --- a/pandaclient/PsubUtils.py +++ b/pandaclient/PsubUtils.py @@ -128,6 +128,8 @@ def check_proxy(verbose, voms_role, refresh_info=False, generate_new=True): tmpLog.error(output) tmpLog.error("Could not generate a grid proxy") sys.exit(EC_Config) + else: + tmpLog.info("Succeeded") return check_proxy(verbose, voms_role, refresh_info=True, generate_new=False) @@ -863,6 +865,8 @@ def extract_voms_proxy_username(): status, output = get_proxy_info(False, False) if Client.use_oidc(): return output[0] + if status != 0: + return None for line in output.split('\n'): if line.startswith('subject'): subj = line.split(':', 1)[-1].lstrip()