0

How can I execute scripts from arguments on multiple servers?

I'm trying to build a command list, and then execute commands on each server. I'm unable to generate the command list in a way that can be eval'd correctly on each server.

Here's my entire script so far. Essentially I'd like to log into each server in the $server_array and execute either all of the commands in $script_arr or just the selected command.

#!/bin/bash

# run-commands.sh [optional script name]
# ex. run-commands.sh
# ex. run-commands.sh date_script
# ex. run-commands.sh hostname_script

# declare -a server_arr=("a.local" "b.local")
declare -a server_arr=("localhost")

if [ $# -eq 0 ]
  then
    # Default Processes
    declare -a script_arr=("date_script" "hostname_script")
else
    declare -a script_arr=($1)
fi

build_cmds()
{

    script_arr=("${@}")
    declare -a cmds

    for script_name in "${script_arr[@]}"
    do

        case "$script_name" in
            "date_script")
                cmds+='printf "executing date command\n; "'
                cmds+='date'
                cmds+='printf "date command executed\n; "'
            ;;
            "hostname_script")
                cmds+='printf "executing date command\n; "'
                cmds+='date'
                cmds+='printf "date command executed\n; "'
            ;;
        esac

    done

}

build_cmds "${script_arr[@]}"

for cmd in "${cmds[@]}"
do
    ssh user@$server_name -T 'eval "$cmd"'
done

echo "Completed executing all commands"
Ryan
  • 420
  • 2
  • 8
  • 16

4 Answers4

2

capistrano, mssh, and clusterssh are all tools that claim to issue commands to multiple servers at once. It's a complex enough task, as you found, that it's probably better not to reinvent the wheel.

Andrew Schulman
  • 8,811
  • 21
  • 32
  • 47
1

I would do this with Puppet Bolt.. it allows advocacy commands to be run remotely with ease. Just download Puppet Bolt (FREE) and use that to issue the command on a provided list of hosts.

Puppet Bolt Info/Download

Just install bolt and make sure you have ssh keys set up on all hosts

CrispyDuck
  • 215
  • 2
  • 5
0

1). Write server side script with all necessary commands and output redirection to log. For example, "server-side.sh", which display server name and how much free space on this server:

#! /bin/bash
cat /etc/hostname > log.txt
date > log.txt
df -h > log.txt

2). Write the second script, which You will be run on the local workstation. For example, "run-server-side.sh", which send a script to the server, run and return result log:

#! /bin/bash
SERVERS="server_1 server_2"

for ONE_SERVER in SERVERS
do
  scp server-side.sh $ONE_SERVER:path
  ssh $ONE_SERVER path/server-side.sh
  scp $ONE_SERVER:path/log.txt
  mv log.txt "log-$ONE_SERVER.txt"
done

Notes: Servers must be configured in .ssh/config, authorization by key. For example:

Host server_1
HostName address_1
User user_name_1

Host server_2
HostName address_2
User user_name_2

Benefits.

  • Just "native" and "built-in" bash - without any additional software.
  • Every remote server always will have the newest version of the script.
  • You may write and edit a rather complex script at the local workstation in Your favorite editor.

Places for evolution.

Sergey Serov
  • 407
  • 3
  • 8
  • 14
0

There are a few things you can do.

I don't know if you prefer that the commands will run in parallel or serial.

If you prefer running in serial then you can do something like:

  1. Make a list of all servers you want the commands to run on.
  2. run:
for server in $(cat server.list); do "command1 ; command2 ; command3..."; done

If you want the commands to be run in parallel, you can use the parallel-ssh tool which can be installed in both CentOS/Ubuntu flavor OS's.

If you want, I wrote a shell script which wraps the parallel-ssh command and allows the user to supply a servers list and commands and the script will issue the commands on all the servers in parallel.

The script can be found in my Github.

One last thing I can offer, is to use Ansible with inventory.

Itai Ganot
  • 10,644
  • 29
  • 93
  • 146