Bash Script for Executing Commands on Multiple Server

bash script for executing commands on multiple server

Parse your input parameters

# create an array of server:services
a=($(echo "$1" | gawk 'BEGIN { FS="[]],[[]" } ; { print $1, $2, $3 }' | tr -d '[]'))
# add a for loop here to iterate values in array with code below
for var in "${a[@]}" ; do
# get server name
server1=$(echo $var | cut -d ':' -f1)
# get your services as space separated
servs1="$(echo $var | cut -d ':' -f2 | tr ',' ' ')"
# loop your services
for s in $servs1; do
ssh $server1 "service $s restart"
done
done

If you like bash programming or have to learn it this is the 'bible' to me
Advanced Bash-Scripting Guide
An in-depth exploration of the art of shell scripting
Mendel Cooper
http://www.tldp.org/LDP/abs/html/

How to run remote script on multiple host simultaneously

The solution could be to deploy a monitoring software with custom checks.

For the parrallel ssh problem, without install any binaries you could use this script I wrote a while ago.
Put in a file mssh, run chmod u+x mssh and then :

./mssh -s SERVER1 -s SERVER2 -C script.sh

The mssh file :

#!/usr/bin/env bash

readonly prog_name="$(basename "$0")"
readonly date="$(date +%Y%m%d_%H%M%S)"

# print help
usage() {
cat <<- EOF
usage: $prog_name options

parallel ssh executions.

OPTIONS:
-c --cmd CMD execute command CMD
-s --host SRV execute cmd on server SRV
-C --cmd CMD_FILE execute command contained in CMD_FILE
-S --hosts-file SRV_FILE execute cmd on all servers contained in SRV_FILE
-h --help show this help

Examples:
Run CMD on SERVER1 and SERVER2:
./$prog_name -s SERVER1 -s SERVER2 -c "CMD"

EOF
}

# test if an element is in an array
is_element(){
local search=$1; shift;
for e in "$@"; do [[ "$e" == "$search" ]] && return 0; done
return 1
}

# parse arguments
for arg in "$@"; do
case "$arg" in
--help) args+=( -h );;
--host) args+=( -s );;
--hosts-file) args+=( -S );;
--cmd) args+=( -c );;
--cmd-file) args+=( -C );;
*) args+=("$arg");;
esac
done
set -- "${args[@]}"
while getopts "hs:S:c:C:" OPTION; do
case $OPTION in
h) usage; exit 0;;
s) servers_array+=("$OPTARG");;
S) while read -r L; do servers_array+=("$L"); done < <( grep -vE "^ *(#|$)" "$OPTARG");;
c) cmd="$OPTARG";;
C) cmd="$(< "$OPTARG")"; file=$OPTARG;;
*) :;;
esac
done
if [[ -z ${servers_array[0]} ]] || [[ -z $cmd ]]; then
usage; exit 1
fi

# clean up created files at exit
trap "rm -f /tmp/pssh*$date" EXIT

[[ -n $file ]] && echo "executing command file : $file" || echo "executing command : $cmd"
# run cmd on each server
for i in "${!servers_array[@]}"; do
# executing cmd in subshell
ssh -n "${servers_array[$i]}" "$cmd" > "/tmp/pssh_${i}_${servers_array[$i]}_${date}" 2>&1 &
pid=$!
pids_array+=("$pid")
echo "${servers_array[$i]} - $pid"
done

# for each pid, set state to running
ps_state_array=( $(for i in "${!servers_array[@]}"; do echo "running"; done) )

echo "waiting for results..."
echo

# begin finished verifications
continue=true; attempt=0
while $continue; do

# foreach ps
for i in "${!pids_array[@]}"; do

# if already finished skip
[[ ${ps_state_array[$i]} == "finished" ]] && continue

# else check if finished
ps -o pid "${pids_array[$i]}" > /dev/null 2>&1 && ps_finished=false || ps_finished=true
if $ps_finished; then
ps_state_array[$i]="finished"
echo -e "[ ${servers_array[$i]} @ $(date +%H:%M:%S) ]" | grep '.*' --color=always
cat "/tmp/pssh_${i}_${servers_array[$i]}_${date}"
rm -f "/tmp/pssh_${i}_${servers_array[$i]}_${date}"
echo
fi
done

is_element "running" "${ps_state_array[@]}" || continue=false
if $continue; then
(( attempt < 5 )) && attempt=$(( attempt + 1 ))
sleep $attempt
fi
done
exit 0

What is the cleanest way to ssh and run multiple commands in Bash?

How about a Bash Here Document:

ssh otherhost << EOF
ls some_folder;
./someaction.sh 'some params'
pwd
./some_other_action 'other params'
EOF

To avoid the problems mentioned by @Globalz in the comments, you may be able to (depending what you're doing on the remote site) get away with replacing the first line with

ssh otherhost /bin/bash << EOF

Note that you can do variable substitution in the Here document, but you may have to deal with quoting issues. For instance, if you quote the "limit string" (ie. EOF in the above), then you can't do variable substitutions. But without quoting the limit string, variables are substituted. For example, if you have defined $NAME above in your shell script, you could do

ssh otherhost /bin/bash << EOF
touch "/tmp/${NAME}"
EOF

and it would create a file on the destination otherhost with the name of whatever you'd assigned to $NAME. Other rules about shell script quoting also apply, but are too complicated to go into here.

shell script to run commands over SSH on multiple remote servers

Thanks to @GordonDavisson recommendation.

The mutt in the script is treating the remaining server details as an input list, hence the script is getting terminated after reading the first server values.

Replace mutt with another email program in your script.
However, users who wish to go with mutt, then it is recommended to add content to their email body or redirect the stdin from mutt to /dev/null

Below is the working solution:

#!bin/bash

while IFS="|" read -r userName hostIp Port Proxy proxyPort
do

STATUS=$(ssh -n -tt -o LogLevel=quiet ${userName}@${hostIp} -p${Port} 'timeout 4 /bin/bash -c' \'"</dev/tcp/${Proxy}/${proxyPort}"\'; echo $? < /dev/null | tr -d '\r')
if [ "$STATUS" -ne 0 ]
then
echo "Connection to $Proxy on port $proxyPort failed" | mutt -s "${hostIp}:Telnet connection to $Proxy on port $proxyPort failed" abc.def@xyz.com
else
echo "Connection to $Proxy on port $proxyPort succeeded" | mutt -s "${hostIp}:Telnet connection to $Proxy on port $proxyPort succeeded" abc.def@xyz.com
fi
done<.hostdetails

The trim command in the solution is to delete the carriage return(\r) I was getting in the variable(STATUS)

Run command multiple linux server

You can run ssh with the -t flag to open a ssh session, run a command and then close the session. But to get this fully automated you should automate the login process to every server so that you don't need to type the password for every server.

So to run df -hon a remote server and then close the session you would run ssh -t root@server.com "df -h". Then you can process that output however you want.

One way of automating this could be to write a bash script that runs this command for every server and process the output to check the health of the server.

For further information about the -t flag or how you can automate the login process for ssh.

https://www.novell.com/coolsolutions/tip/16747.html

https://serverfault.com/questions/241588/how-to-automate-ssh-login-with-password

Log in to another server and run commands - Using a script

Use a heredoc.

ssh username@server02.com << EOF
echo "In server02"
EOF


Related Topics



Leave a reply



Submit