pax_global_header00006660000000000000000000000064131560001070014503gustar00rootroot0000000000000052 comment=a60c83fafb85dc9e657e1d05c02187b562668504 runoverssh-2.2/000077500000000000000000000000001315600010700135645ustar00rootroot00000000000000runoverssh-2.2/CHANGELOG000066400000000000000000000003461315600010700150010ustar00rootroot000000000000002.2: - added option to pass arguments to the script file (ex: --script "test.sh" --args "arg1 arg2") 2.1: - now checks for sshpass only when '-n' option is not set - improved error messages - added default Bash flags in README runoverssh-2.2/README.md000066400000000000000000000046231315600010700150500ustar00rootroot00000000000000## Run Over SSH This program runs a Bash command/script over ssh in one or more hosts. #### Usage: ``` $ runoverssh [OPTIONS] USERNAME COMMAND HOSTS... ``` #### Default behavior: * Ask each `username@host` password at the start * SSH flags `-o ConnectTimeout=5 -o StrictHostKeyChecking=no` * Bash flags `-l` * Prints all SSH output in the screen #### Options: ``` -g, --globalpw ask one global password for all connections -s, --script [file] read commands from a script file instead -r, --hostsfile [file] use the list of hosts from a file (one host per line) -n, --nopw no password (use ssh directly instead of sshpass) -a, --args specify the arguments to be passed to the script file -l, --log save ssh output (default: runoverssh.log) (append) -q, --quiet disable ssh screen output --bashflags [flags] set custom bash flags default: '-l' --sshflags [flags] set custom ssh flags default: '-o ConnectTimeout=5 -o StrictHostKeyChecking=no' --logfile [file] save ssh output to a custom file (append) ``` #### Examples ``` $ runoverssh root "systemctl restart apache2" webserver webserver2 Please set root's password for each host: root@webserver password: root@webserver2 password: Connecting as root@webserver... Connecting as root@webserver2... ``` ``` $ runoverssh --log --quiet --globalpw root "reboot" host1 host2 host3 root's password (used for all connections): Connecting as root@host1... Connecting as root@host2... Connecting as root@host3... ``` ``` $ runoverssh -q -l -g -r puppet-nodes root "puppet agent -t" root's password (used for all connections): Connecting as root@node1... Connecting as root@node2... Connecting as root@node3... ``` ``` $ runoverssh remoteuser "cd git-project && git status" devmachine Please set remoteuser's password for each host: remoteuser@devmachine password: Connecting as remoteuser@devmachine... On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working directory clean ``` ``` $ runoverssh -g --script backup.sh --hostsfile hostlist remoteuser remoteuser's password (used for all connections): Connecting as remoteuser@host1... Backup successful Connecting as remoteuser@host2... Backup successful Connecting as remoteuser@host3... Backup successful ``` runoverssh-2.2/runoverssh000077500000000000000000000242111315600010700157300ustar00rootroot00000000000000#!/usr/bin/env bash # This program runs a BASH command/script over SSH in a remote host or list of hosts # Copyright (C) 2017 Yuri Escalianti (https://github.com/yuriescl/runoverssh) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Script name script_name=`basename "$0"` script_alias=`basename -s .sh "$0"` # Print help function print_help { echo "Usage: ${script_name} [OPTIONS] USERNAME COMMAND HOSTS..." echo "Runs a Bash command/script over ssh in one or more hosts." echo "Options:" echo "" echo " -g, --globalpw ask one global password for all connections" echo " -s, --script [file] read commands from a script file instead" echo " -r, --hostsfile [file] use the list of hosts from a file (one host per line)" echo "" echo " -n, --nopw no password (use ssh directly instead of sshpass)" echo " -a, --args specify the arguments to be passed to the script file" echo " -l, --log save ssh output (default: ${script_alias}.log) (append)" echo " -q, --quiet disable ssh screen output" echo "" echo " --bashflags [flags] set custom bash flags" echo " default: '-l'" echo " --sshflags [flags] set custom ssh flags" echo " default: '-o ConnectTimeout=5 -o StrictHostKeyChecking=no'" echo " --logfile [file] save ssh output to a custom file (append)" echo "" echo "Examples:" echo "" echo " runoverssh root 'systemctl restart apache2' server1 server2" echo "" echo " runoverssh --log --quiet --globalpw root 'reboot' host1 host2 host3" echo "" echo " runoverssh remoteuser 'cd git-project && git status' devmachine" echo "" echo " runoverssh --script myscript.sh --hostsfile hostlist remoteuser" echo "" echo " runoverssh --script myscript.sh --args '-q -s -t' --hostsfile hostlist remoteuser" echo "" echo "Bugs or Requests: https://github.com/yuriescl/runoverssh/issues" } # Standard parameters username="" remote_command="" hosts=() # Optional parameters read_commands_from_file="" # -s , --script script_arguments="" # -a , --args read_hosts_from_file="" # -r , --hostsfile log_enabled="" # -l , --log log_file="${script_alias}.log" # --logfile global_pw="" # -g, --globalpw passwords=() no_pw="" # -n, --nopw ssh_flags="-o ConnectTimeout=5 -o StrictHostKeyChecking=no" # --sshflags bash_flags="-l" # --bashflags quiet_enabled="" # -q , --quiet if [[ "$1" == "--help" ]]; then print_help exit 0 else # Check parameter count if [[ $# -lt 3 ]]; then echo "Usage: ${script_name} [OPTIONS] USERNAME COMMAND HOSTS..." echo "Use '${script_name} --help' for command help and examples." exit 1 fi fi # Read parameters is_first="" waiting_option="" for parameter do if [ -n "${is_first}" ] && [ -n "${waiting_option}" ]; then # Assign the option case "${waiting_option}" in "-s" | "--script") read_commands_from_file="${parameter}" ;; "-a" | "--args") script_arguments="${parameter}" ;; "-r" | "--hostsfile") read_hosts_from_file="${parameter}" ;; "--logfile") log_enabled="true" log_file="${parameter}" ;; "--sshflags") ssh_flags="${parameter}" ;; "--bashflags") bash_flags="${parameter}" ;; esac waiting_option="" else # first or not waiting option is_first="no" case "${parameter}" in "-s" | "--script" | "-a" | "--args" | "-r" | "--hostsfile" | "--logfile" | "--sshflags" | "--bashflags") waiting_option="${parameter}" ;; "-g" | "--globalpw") global_pw="true" ;; "-n" | "--nopw") no_pw="true" ;; "-l" | "--log") log_enabled="true" ;; "-q" | "--quiet") quiet_enabled="true" ;; *) if [[ "${parameter}" == "--"* ]] || [[ "${parameter}" == "-"* ]]; then echo "Error: invalid option '${parameter}'. Exiting." exit 1 fi # Read the end arguments if [ -z "${username}" ]; then username=${parameter} else if [ -z "${read_commands_from_file}" ] && [ -z "${remote_command}" ]; then remote_command="${parameter}" else if [ -z "${read_hosts_from_file}" ]; then hosts+=("${parameter}") fi # host fi #command fi #username waiting_option="" esac fi # ! is_first and is waiting done # Check parameter and argument consistency if [ -n "${waiting_option}" ]; then echo "Error: missing value for '${waiting_option}' parameter. Exiting." exit 1 fi if [ -z "${username}" ]; then echo "Error: please specify the username to be used in SSH. Exiting." exit 1 fi if [ -z "${read_commands_from_file}" ] && [ -z "${remote_command}" ] ; then echo "Error: please specify the command or script file ('-s') to be executed over SSH. Exiting." exit 1 fi if [ -n "${read_commands_from_file}" ] && [ -n "${remote_command}" ] ; then echo "Error: parameter conflict: do not put a command as argument when also specifying a script as parameter. Exiting." exit 1 fi if [ -n "${script_arguments}" ] && [ -z "${read_commands_from_file}" ]; then echo "Error: arguments specified but no script file provided. Exiting." exit 1 fi if [ -z "${read_hosts_from_file}" ] && [ ${#hosts[@]} -eq 0 ]; then echo "Error: please specify at least one target host or use the '--hostsfile' option. Exiting." exit 1 fi if [ -n "${read_hosts_from_file}" ] && [ ${#hosts[@]} -gt 0 ]; then echo "Error: parameter conflict: do not list hosts as arguments when also specifying a hostsfile as parameter. Exiting." exit 1 fi if [ -n "${global_pw}" ] && [ -n "${no_pw}" ]; then echo "Error: parameter conflict: do not set the 'no password' option when also specifying a global password. Exiting."; exit 1 fi # Check file readability (if specified to read from a file) if [ -n "${read_hosts_from_file}" ] && [ ! -r "${read_hosts_from_file}" ]; then echo "Error: can't read the hosts file '${read_hosts_from_file}'. Exiting." exit 1 fi if [ -n "${read_commands_from_file}" ] && [ ! -r "${read_commands_from_file}" ]; then echo "Error: can't read the script file '${read_commands_from_file}'. Exiting." exit 1 fi # Check log file if [ -d "${log_file}" ]; then echo "Error: log file '${log_file}' is a directory. Exiting." exit 1 fi # In case the hostsfile was used, fill the hosts array with them if [ -n "${read_hosts_from_file}" ]; then hosts=() while read host; do if [ -n "${host}" ]; then hosts+=("${host}") fi done<"${read_hosts_from_file}" fi # Check dependencies command -v "ssh" >/dev/null 2>&1 || { echo >&2 "Error: program 'ssh' not found. Exiting."; exit 1; } # Check for sshpass if the option '-n' is not set if [ -z "${no_pw}" ]; then command -v "sshpass" >/dev/null 2>&1 || { echo >&2 "Error: program 'sshpass' not found (use the '-n' option to use 'ssh' instead). Exiting."; exit 1; } fi # Get the SSH passwords (unless 'no password' is set) if [ -z "${no_pw}" ]; then if [ -n "${global_pw}" ]; then printf "${username}\'s password (used for all connections): " read -s gpassword echo "" # Fill the passwords array with the global password for host in "${hosts[@]}" do passwords+=("${gpassword}") done else # Ask each password echo "Please set ${username}'s password for each host:" echo "" for host in "${hosts[@]}" do printf "${username}@${host} password: " read -s host_pw passwords+=("${host_pw}") echo "" done fi fi echo "" # Set variables for easy pipes if [ -z "${log_enabled}" ]; then log_file="/dev/null" fi if [ -f "${log_file}" ]; then rm "${log_file}" fi # Connect to each host and execute the command/script if [ -n "${no_pw}" ]; then for host in "${hosts[@]}" do echo "Connecting as ${username}@${host}..." if [ -n "${read_commands_from_file}" ]; then if [ -n "${quiet_enabled}" ]; then ssh ${ssh_flags} ${username}@${host} "bash ${bash_flags} -s" < "${read_commands_from_file}" "${script_arguments}" >> "${log_file}" else ssh ${ssh_flags} ${username}@${host} "bash ${bash_flags} -s" < "${read_commands_from_file}" "${script_arguments}" | tee -a "${log_file}" fi else if [ -n "${quiet_enabled}" ]; then ssh ${ssh_flags} ${username}@${host} "bash ${bash_flags} -c \"${remote_command}\"" >> "${log_file}" else ssh ${ssh_flags} ${username}@${host} "bash ${bash_flags} -c \"${remote_command}\"" | tee -a "${log_file}" fi fi done else i=0 for host in "${hosts[@]}" do echo "Connecting as ${username}@${host}..." if [ -n "${read_commands_from_file}" ]; then if [ -n "${quiet_enabled}" ]; then sshpass -p "${passwords[$i]}" ssh ${ssh_flags} ${username}@${host} "bash ${bash_flags} -s" < "${read_commands_from_file}" "${script_arguments}" >> "${log_file}" else sshpass -p "${passwords[$i]}" ssh ${ssh_flags} ${username}@${host} "bash ${bash_flags} -s" < "${read_commands_from_file}" "${script_arguments}" | tee -a "${log_file}" fi else if [ -n "${quiet_enabled}" ]; then sshpass -p "${passwords[$i]}" ssh ${ssh_flags} ${username}@${host} "bash ${bash_flags} -c \"${remote_command}\"" >> "${log_file}" else sshpass -p "${passwords[$i]}" ssh ${ssh_flags} ${username}@${host} "bash ${bash_flags} -c \"${remote_command}\"" | tee -a "${log_file}" fi fi i=$((i + 1)) done fi exit 0 # end.