diff options
| -rw-r--r-- | pars.sh | 213 | 
1 files changed, 117 insertions, 96 deletions
| @@ -15,12 +15,121 @@  #   You should have received a copy of the GNU General Public License  #   along with this program.  If not, see <http://www.gnu.org/licenses/>. +# help function +_parssh.usage () { +    printf '  %s\n'\ +        "parssh: Parallel SSH orchestration in a Bash session."\ +        ""\ +        "SYNOPSIS"\ +        "parssh [-NUM] [-r|--rinput FILE] [-s|--servers FILE] [-b|--bare] [-c|--config]"\ +        "  [COMMANDS] [< SERVERS]"\ +        ""\ +        "DESCRIPTION"\ +        "  -NUM  (default: 4)"\ +        "     Number of concurrent ssh connections to maintain.  E.g. '-40'."\ +        ""\ +        "  -r FILE, --rinput FILE  (default: unset/inactive)"\ +        "     File to send as STDIN redirection on remote servers."\ +        "     (Can be used as replacement for or in conjunction with COMMANDS)."\ +        ""\ +        "  -s FILE, --servers FILE  (default: unset/inactive)"\ +        "     File to use as list of servers to run COMMANDS on."\ +        "     (Cannot be used in conjunction with a server list on STDIN)."\ +        ""\ +        "  -b, --bare  (default: unset/inactive)"\ +        "     Disable prepending of hostname to each output line returned by COMMANDS on SERVERS."\ +        ""\ +	"  -C, --savecmd  (default: unset/inactive)"\ +	"     Save the remote command line and local meta data as a header on the output."\ +	""\ +        "  -c SSH_OPTIONS, --config SSH_OPTIONS  (default: unset/inactive)"\ +        "     Comma separated list of configuration parameters to be passed to SSH via '-o' flag."\ +        ""\ +        "  -o PREFIX, --out PREFIX  (default: unset/inactive)"\ +        "     Redirect STDOUT / STDERR to PREFIX.out / PREFIX.err, respectively."\ +        ""\ +        "  -t PREFIX, --tee PREFIX  (default: unset/inactive)"\ +        "     Copy STDOUT / STDERR to PREFIX.out / PREFIX.err, respectively."\ +        ""\ +        "  COMMANDS"\ +        "     The list of commands to be executed remotely by SSH on each SERVER."\ +        ""\ +        "  < SERVERS"\ +        "     Unless '-s' flag is used, STDIN will be used as list of remote servers."\ +        "     (Deliniated by newlines)."\ +        ""\ +        "NOTES"\ +        "  Given the nature of entering passwords manually, this function will likely not be"\ +        "     very useful without properly authorized SSH keys on all SERVERS." +    return 1 +} + +# text processing functions +_parssh.host_prepend () +    while read -r; do +        printf "${_parssh_prepend_host+$host: }%s\n" "$REPLY" +    done + +_parssh.out () { +    local _parssh_out_stream="$1" + +    while read -r; do +        [[ "${_parssh_out_stdout}" == "true" ]] && \ +            printf "%s\n" "$REPLY" +        [[ "${_parssh_out_file}" == "true" ]] && \ +            printf "%s\n" "$REPLY" >> "${_parssh_out_prefix}.${_parssh_out_stream}" +    done +} + +_parssh.savecmd () { +    CMDLINE=$(fc -ln -0) +    CMDLINE="${CMDLINE#[[:space:]][[:space:]]}" +    printf "### ###\n" +    printf "### %s: %s\n"\ +        date "$(date +%F@%R%z)"\ +        user "$USER($UID)"\ +	pwd "$PWD"\ +	cmdline "$CMDLINE" +    printf "### BEGIN parssh remote commands ###\n" +    printf "%s\n### END parssh remote commands ###\n### ###\n"\ +        "$@" +} + +# fd handlers +_parssh.serverlist_fd () { +    [[ -z "$_parssh_servers" ]] && { +        [[ -t 0 ]] && { +            echo "No list of servers provided." +            return 79 +        } +        exec 9<&0 +    } || { +        exec 9< <(printf "%s\n" "$_parssh_servers") +    } +} + +_parssh.serverlist_fd_close () { +    exec 9>&- +} + +# ssh workers +_parssh.ssh () { +    ssh -n ${_parssh_ssh_config+-o} ${_parssh_ssh_config//,/ -o } $host -- "$@" +} + +_parssh.ssh_rinput () { +    ssh -T ${_parssh_ssh_config+-o} ${_parssh_ssh_config//,/ -o } $host -- "$@"\ +        < "$_parssh_rinput" +} + +# main  parssh () {      (( $# )) || {          _parssh.usage          return $?      } +    # preserve current bash options and ensure monitor (job control) is set      local _parssh_origopts=$-      set -m @@ -95,30 +204,12 @@ parssh () {          shift      done -    [[ -z "$_parssh_servers" ]] && { -        [[ -t 0 ]] && { -            echo "No list of servers provided." -            return 79 -        } -        exec 9<&0 -    } || { -        exec 9<"$_parssh_servers" -    } +    # load list of servers on fd 9 +    _parssh.serverlist_fd +    # run main command loop / capture outputs      { -        [[ "$_parssh_savecmd" == "true" ]] && { -	    CMDLINE=$(fc -ln -0) -	    CMDLINE="${CMDLINE#[[:space:]][[:space:]]}" -            printf "### ###\n" -	    printf "### %s: %s\n"\ -	        date "$(date +%F@%R%z)"\ -                user "$USER($UID)"\ -		pwd "$PWD"\ -		cmdline "$CMDLINE" -	    printf "### BEGIN parssh remote commands ###\n" -	    printf "%s\n### END parssh remote commands ###\n### ###\n"\ -	        "$@" -        } +        [[ "$_parssh_savecmd" == "true" ]] && _parssh.savecmd          while read host; do              while (( $(jobs -pr | wc -l) >= ${_parssh_concurrency:-4} )); do                  sleep 1 @@ -130,79 +221,9 @@ parssh () {      wait -    exec 9>&- -    [[ "${_parssh_origopts//[^m]/}" == "m" ]] || set +m -} +    # close serverlist fd +    _parssh.serverlist_fd close -_parssh.ssh () { -    ssh -n ${_parssh_ssh_config+-o} ${_parssh_ssh_config//,/ -o } $host -- "$@" -} - -_parssh.ssh_rinput () { -    ssh -T ${_parssh_ssh_config+-o} ${_parssh_ssh_config//,/ -o } $host -- "$@"\ -        < "$_parssh_rinput" -} - -_parssh.host_prepend () -    while read -r; do -        printf "${_parssh_prepend_host+$host: }%s\n" "$REPLY" -    done - -_parssh.out () { -    local _parssh_out_stream="$1" - -    while read -r; do -        [[ "${_parssh_out_stdout}" == "true" ]] && \ -            printf "%s\n" "$REPLY" -        [[ "${_parssh_out_file}" == "true" ]] && \ -            printf "%s\n" "$REPLY" >> "${_parssh_out_prefix}.${_parssh_out_stream}" -    done -} - -_parssh.usage () { -    printf '  %s\n'\ -        "parssh: Parallel SSH orchestration in a Bash session."\ -        ""\ -        "SYNOPSIS"\ -        "parssh [-NUM] [-r|--rinput FILE] [-s|--servers FILE] [-b|--bare] [-c|--config]"\ -        "  [COMMANDS] [< SERVERS]"\ -        ""\ -        "DESCRIPTION"\ -        "  -NUM  (default: 4)"\ -        "     Number of concurrent ssh connections to maintain.  E.g. '-40'."\ -        ""\ -        "  -r FILE, --rinput FILE  (default: unset/inactive)"\ -        "     File to send as STDIN redirection on remote servers."\ -        "     (Can be used as replacement for or in conjunction with COMMANDS)."\ -        ""\ -        "  -s FILE, --servers FILE  (default: unset/inactive)"\ -        "     File to use as list of servers to run COMMANDS on."\ -        "     (Cannot be used in conjunction with a server list on STDIN)."\ -        ""\ -        "  -b, --bare  (default: unset/inactive)"\ -        "     Disable prepending of hostname to each output line returned by COMMANDS on SERVERS."\ -        ""\ -	"  -C, --savecmd  (default: unset/inactive)"\ -	"     Save the remote command line and local meta data as a header on the output."\ -	""\ -        "  -c SSH_OPTIONS, --config SSH_OPTIONS  (default: unset/inactive)"\ -        "     Comma separated list of configuration parameters to be passed to SSH via '-o' flag."\ -        ""\ -        "  -o PREFIX, --out PREFIX  (default: unset/inactive)"\ -        "     Redirect STDOUT / STDERR to PREFIX.out / PREFIX.err, respectively."\ -        ""\ -        "  -t PREFIX, --tee PREFIX  (default: unset/inactive)"\ -        "     Copy STDOUT / STDERR to PREFIX.out / PREFIX.err, respectively."\ -        ""\ -        "  COMMANDS"\ -        "     The list of commands to be executed remotely by SSH on each SERVER."\ -        ""\ -        "  < SERVERS"\ -        "     Unless '-s' flag is used, STDIN will be used as list of remote servers."\ -        "     (Deliniated by newlines)."\ -        ""\ -        "NOTES"\ -        "  Given the nature of entering passwords manually, this function will likely not be"\ -        "     very useful without properly authorized SSH keys on all SERVERS." -    return 1 +    # restore bash options if modified +    [[ "${_parssh_origopts//[^m]/}" == "m" ]] || set +m  } | 
