diff --git a/TODO b/TODO index f82ab29..91f433f 100644 --- a/TODO +++ b/TODO @@ -19,7 +19,7 @@ Gets done before Puts Gets prepend hostname to saved file -- Option to read from stdin +- Option to read commands from file via -f - EOL command added to end - Cosmetic changes in reporting output diff --git a/tsshbatch.py b/tsshbatch.py index abd208b..c193920 100755 --- a/tsshbatch.py +++ b/tsshbatch.py @@ -17,7 +17,7 @@ PROGNAME = "tsshbatch.py" BASENAME = PROGNAME.split(".py")[0] PROGENV = BASENAME.upper() -CVSID = "$Id: tsshbatch.py,v 1.154 2013/10/23 18:10:33 tundra Exp $" +CVSID = "$Id: tsshbatch.py,v 1.155 2013/10/23 19:17:37 tundra Exp $" VERSION = CVSID.split()[2] CPRT = "(c)" @@ -64,7 +64,7 @@ FAILURE = "FAILURE: %s" HOSTSEP = ":" INDENTWIDTH = 8 -OPTIONSLIST = "G:H:NP:Sehkn:p:v" +OPTIONSLIST = "G:H:NP:Sef:hkn:p:v" PADWIDTH = 12 PATHSEP = os.sep SEPARATOR = " ---> " @@ -77,7 +77,7 @@ USAGE = \ PROGVER + "\n" +\ HOMEPAGE + "\n\n" +\ - "Usage: tsshbatch.py [-NSehkv] [-n name] [-p pw] -G 'file dest' -P 'file dest' [-H 'host ..' | serverlistfile] [command arg ... | - ]\n" +\ + "Usage: tsshbatch.py [-NSehkv -G 'file dest' -P 'file dest' -f file -n name -p pw ] -H 'host ..' | serverlistfile [command arg ... ]\n" +\ " where,\n" +\ "\n" +\ " -G 'file dest' GET file on host and write local dest directory\n" +\ @@ -86,12 +86,14 @@ " -P 'file dest' PUT local file to host dest directory\n" +\ " -S Force prompting for sudo password\n" +\ " -e Don't report remote host stderr output\n" +\ + " -f file Read commands from file\n" +\ " -h Display help\n" +\ " -k Use key exchange-based authentication\n" +\ " -n name Specify login name\n" +\ " -p pw Specify login password\n" +\ " -v Display extended program version information\n" + ##### # Error Messages ##### @@ -123,6 +125,18 @@ ##### +# Functions +##### + +# Gets rid of comments and strips leading/trailing whitespace + +def ConditionLine(line): + return line.split(COMMENT)[0].strip() + +# End of 'ConditionLine()' + + +##### # Print Message(s) To stderr ##### @@ -349,7 +363,6 @@ Put_Transfer_List = {} Get_Transfer_List = {} - # Handle any options set in the environment OPTIONS = sys.argv[1:] @@ -363,8 +376,10 @@ try: opts, args = getopt.getopt(OPTIONS, OPTIONSLIST) + except getopt.GetoptError, (errmsg, badarg): ErrorExit(eBADARG % errmsg) + for opt, val in opts: if opt == "-G": @@ -385,6 +400,17 @@ if opt == "-e": REPORTERR = False + if opt == "-f": + try: + f = open(val) + for line in f.readlines(): + line = ConditionLine(line) + if line: + Commands.append(line) + f.close() + except: + ErrorExit(eBADFILE % val) + if opt == "-h": PrintStdout(USAGE) sys.exit() @@ -403,38 +429,9 @@ sys.exit() ##### -# Go Do The Requested Work +# Host & Command Line Command Definition Processing ##### -# Precedence of authentication credential sources: -# -# 1) Key exchange -# 2) Forced prompting for name via -N -# 3) Command Line/$TSSHBATCH env variable sets name -# 4) Name picked up from $USER (Default behavior) - -if not KEYEXCHANGE: - - # Preset commandline and/or program option variable username takes precedence - - if not UNAME: - UNAME = os.getenv("USER") - - # By default, use the above as the login name and don't prompt for it - # unless overriden on the command line with -N - if PROMPTUSERNAME: - current_user = UNAME - UNAME = raw_input(pUSER %current_user) - if not UNAME: # User just hit return - wants default - UNAME = current_user - - # Preset commandline and/or program option variable password takes precedence - if not PWORD: - PWORD = getpass.getpass(pPASS) - - -# Host list and command parsing - # Get the list of hosts if not specified on command line. # The assumption is that the first argument is the file # containing the list of targeted hosts and the remaining @@ -465,22 +462,51 @@ else: command = " ".join(args[0:]) -# Cleanup the command and check to see if the user really wants to use -# stdin instead of explicit command line spefication of the desired -# remote command. # Put it in a list data structure because this is what the # HostCommands() function expects. This is necessary to handle multi -# command input from stdin. +# command input from from a file. -command = command.strip() -if (command == STDIN): - for command in sys.stdin.readlines(): - Commands.append(command.strip()) +command = ConditionLine(command) +if command: + Commands.append(command) -elif command: - Commands = [command,] +##### +# Authentication Credential Processing +##### +# Precedence of authentication credential sources: +# +# 1) Key exchange +# 2) Forced prompting for name via -N +# 3) Command Line/$TSSHBATCH env variable sets name +# 4) Name picked up from $USER (Default behavior) + +if not KEYEXCHANGE: + + # Preset commandline and/or program option variable username takes precedence + + if not UNAME: + UNAME = os.getenv("USER") + + # By default, use the above as the login name and don't prompt for it + # unless overriden on the command line with -N + + if PROMPTUSERNAME: + + current_user = UNAME + UNAME = raw_input(pUSER %current_user) + if not UNAME: # User just hit return - wants default + UNAME = current_user + + # Preset commandline and/or program option variable password takes precedence + + if not PWORD: + PWORD = getpass.getpass(pPASS) + +##### +# If Needed, Get sudo Password +#### # The need to prompt for a sudo password depends on a number of # conditions: @@ -523,12 +549,16 @@ if PWORD and not SUDOPW: SUDOPW = PWORD +##### +# Do The Requested Work +##### + # Iterate over the list of hosts, executing any file transfers and # commands. Accomodate commenting out hosts in a list. for host in HOSTS: - host = host.split(COMMENT)[0].strip() + host = ConditionLine(host) if host: if Get_Transfer_List: diff --git a/tsshbatch.rst b/tsshbatch.rst index b4554fb..2cc407d 100644 --- a/tsshbatch.rst +++ b/tsshbatch.rst @@ -8,7 +8,7 @@ SYNOPSIS -------- -tsshbatch.py [-NSehksv] [-n name] [-p pw] [-H 'h1 h2 ...' | hostlistfile] [command arg ... | -] +tsshbatch.py [-NSehkv -G 'file dest' -P 'file dest' -f file -n name -p pw ] -H 'host ..' | serverlistfile [command arg ... ] DESCRIPTION @@ -77,6 +77,10 @@ -e Don't report remote host stderr output + -f file Read commands from a file. File contents can be + commented freely with the ``#`` character. Leading- and + trailing whitespace on a line are ignored. + -h Print help information -k Use ssh keys instead of name/password credentials @@ -87,10 +91,9 @@ -v Print detailed program version information and exit -The last option on the command line is either an explicit command -string or the ``-`` character. If you provide an explicit command, +The last option on the command line is an (optional) command to run. ``tsshbatch`` will attempt to execute it on every host you've -specified either via ``-H`` or a ``hostlistfile``:: +specified either via ``-H`` or a ``hostfile``:: tsshbatch.py -Hmyhost ls -al /etc @@ -101,16 +104,10 @@ your local shell will interfere with them being properly conveyed to the remote machine. -If ``tsshbatch`` sees a ``-`` character, it will read commands to -execute from stdin. This is the preferred way of doing multiple -commands in a single run of ``tsshbatch``:: - - tsshbatch.py .....