gofer - execute multiple ssh sessions in parallel
# This expects a list of host connection definitions on STDIN, # then executes the command or command defined in the arguments # on each: echo =host1 =host2 | gofer [options] <commands>
This script will log in and execute commands on remote ssh servers.
It is WORK IN PROGRESS! Expect rough edges.
In simple terms, the format of the host connections on STDIN should be one or more terms like this:
='<connection>' 'login'='<name>' 'password'='<password>' 'port'='<port>' 'hostname'='<hostname>'
This is designed to be easy to parse using core Perl modules (specifically,
Text::ParseWords::parse_line(qr/\s*(=\s*|\s+)/, 0, $term)).
The first item must start with an equals character, and
<connection > indicates an (arbitrary) name for the connection. The other items can be omitted in certain circumstances. Only
connection is required in all circumstances. Other name-value parameters can be added (they will be ignored).
Multiple terms can be combined in one line, assuming the terms start with an equals character (i.e. no items contain unquoted spaces, such as
connection is used as the default hostname passed to ssh if no explicit
hostname parameter is given.
So if your .ssh/config defines connections to hosts with aliases
bar, you can use a concise form like this:
echo =foo =bar | gofer id
Instead of requiring the longer equivalents:
echo -e "=foo\n=bar\n" | gofer id echo -e "=foo 'hostname'='foo'\n=bar 'hostname'='bar'\n" | gofer id
Both examples would run
id on both
By default, you will be prompted for a password for each connection (whether or not you are sudoing or have ssh keys set up, etc.) There are some ways to make this easier.
First you can define keys and pass the
--p=sudoing option, which means you will only be prompted if the commands require a sudo.
Second, you can pass a
echo -e "=foo 'password'='offsite'\n=bar 'password'='offsite'\n" | gofer 'sudo id'
How this is interpreted can vary. By default the value is interpreted as a label for the password (not the password itself!). Then gofer will only prompt you to enter a password once for each label.
The point of this is to avoid explicit passwords on the command line, whilst also avoiding having to type any more passwords than necessary.
You can specify other interpretations for the
password parameter using the
--password-broker option. These allow you to specify the password literally on the command line (not recommended in general), or in an obfuscated form (better). The default is to prompt.
An example showing what you might get invoking:
echo =alpha password=xxx =beta password=xxx | gofer --file git-status.sh
~/.ssh/config defining key authenticated access for hosts with aliases
# bla de bla sudo cd /root/configuration; git status
Then you might get output like the following:
password for xxx: ----[ alpha ]----------------------------------------------------------- # bla de bla $ sudo "cd /root/configuration; git status" # On branch WORK_IN_PROGRESS nothing to commit (working directory clean) ----(4s elapsed) ----[ beta ]------------------------------------------------------------ # bla de bla $ sudo "cd /root/configuration; git status" # On branch BETA_LOCAL_MODS # Changed but not updated: # (use "git add <file>..." to update what will be committed) # # modified: foo/src/stuff.h # no changes added to commit (use "git add" and/or "git commit -a") ----(4s elapsed) done
Parses a sequence of lines of the following form:
Returns an array of
<($name = \%params)>> pairs, each defining a connection name and a parameter hash as accepted by
<Net::SSH::Mechanize::ConnectParams-new>>, which can be passed directly to