NAME
dish - tool for parallel sysadmin of multiple hosts
SYNOPSIS
dish [option]... -e command {-g hosts_file | host_1 host_2 ...}
dicp {-g hosts_file | -g "user@host_1 ..."} local_file :remote_file
dicp {-g hosts_file | -g "user@host_1 ..."} :remote_file local_file
DESCRIPTION
dish - the diligence shell executes commands on several hosts via
ssh/rsh/telnet, and also makes easy the distribution of files by
scp/rcp, a remote password change, etc. It can process hosts in
parallel mode.
OPTIONS
-h Print help message describing shortly all command-line options
-H, --help
Comprehensive help including examples
--version
Print program version and copyright message, then exit
-V Display the version number and exit
-C <dir>
Configuration directory (default is $HOME/.dish) where the
config files - ’hosts’, ’rests’, ’pass’, and ’options’ - are
located. When used, this option must be the first argument in
the command line string, or the second if ‘-D’ chosen!
Alternatively, one can specify the configuration directory by
defining the environment variable DISH_CONF.
-CC <dir>
Same as ‘-C’ with fallback to default if local config not found;
that is, in case the files ’pass’, ’options’ or ’rests’ are
absent in the given directory, however such files exist in
$HOME/.dish, the latter will be considered. The only exception
is ’$HOME/.dish/hosts’ which will be ignored. Using this option
is equivalent to changing directory to the opted one and then
executing ‘dish’.
-c <name>
Program (alias "connector") and its options used for connect;
for example ‘rsh’, whereas the spawned process will be "rsh
$host <cmd>". Your default connector is ‘ssh’. Furthermore, by
using a relevant text-based client as connector, one can access
various kinds of hosts - switches, databases, and so on.
-e <cmd>
Command to execute
-E <cmd>
Execute command where also the connection part is specified e.g.
"-E ’ssh $host date’" which is equal to "-e date". This option
is incompatible with ‘-c’ and ‘-e’.
-t Force pseudo-tty allocation in ssh; this happens automatically
in case of password change.
-T <time>
Time out for command execution - default are 30 sec.
-x <regex>
Regular expression for the shell prompt; After login into a
system by telnet, mysql, sqlplus, or other interactive
command-line clients, this value specifies which prompt is to be
expected in the program’s shell. It is relevant only when
ssh/rsh, or scp/rcp are not used as connectors (see ‘-c’). The
default value is ‘(%|\$|#|\>) ?$’.
-X <regex>
Regular expression for the password prompt; It is
case-insensitive with default value ‘Password:’.
-g <file>
File with list of hosts/ip’s/accounts to target; the command
will be executed on those. The default host file is
’$HOME/.dish/hosts’ - normally per line one account of the form
"user@host" if ssh is your choice for connector. In order to
join lists use the option repeatedly. Alternatively, the
environment variable DISH_HOSTS could be defined to specify the
target hosts separated by blanks. By using this option within
combination of ‘-r’ or ‘-i’ you can define various subsets of
targeted hosts/accounts.
-r <file>
File with list of resting hosts/accounts to exclude; the default
one is ’$HOME/.dish/rests’. A "resting host" means one which
will be excluded from the targets. The list of resting hosts or
the file name could be specified also by the environment
variable DISH_RESTS.
-i <file>
File with list of hosts/accounts to overlap with targeted hosts;
there is no default file. Only overlapping hosts, such included
in this list and at the same time defined as targets, will be
processed.
-u <name>
User name - default is your local user name; it can be defined
also by the external variable DISH_USER. Internally the value
is accessible by the variable $user (see examples). Further, it
is irrelevant in case that accounts of the form "user@host" are
processed since they include already the user name.
-p <passwd>
Login password (-p ’’ = -pp = -a0); alias "login authentic" or
"a0". If no authentication for login is required (no user and no
password prompt appear), then use ‘/dev/null’ as password. If
the user name is requested, yet the password is an empty string,
then ‘/dev/empty’ has to be given as password. The value of this
option could be also a password file (see ‘-P’). Eventually, one
can define the password by setting an environment variable:
export DISH_PASS=<password>
-p0 Login without authentication: the same as ‘-p /dev/null’
-P <file>
File with password(s); The default password file is
’$HOME/.dish/pass’. It must be readable only for the user (file
mode 600 or 700), otherwise the program exits with error status,
but see also next option. Every line in the file can hold a
password of the form "password[:username[:host]]". One can
specify a list of hosts separated by the ‘,’ or ‘;’ characters.
Regular expressions for host names are also allowed (see the
example configuration files in the distribution).
-m Ignore the access permissions of the password file
-a <passwd>
Additional password for authentication (-a ’’ = -aa = -a1);
alias "first authentic" or "a1". Inside the spawn process, if a
program like smbmount, su, ssh, etc. asks for authentication,
the a1-password is passed to it. In case that ‘-a’ and ‘-n’ are
not involved options, and the login password a0 is not an empty
one, then the a1-password is equal to it (see example c) below).
-A <passwd>
One more password for authentication (-A ’’ = -AA = -a2); alias
"second authentic" or "a2". When a spawned process, after one
authentication by the a1-password, asks again for a password,
then a2 is sent.
-n <passwd>
New password in case of password change (-n ’’ = -nn = -ne)
-s [<time>]
Sequential processing of hosts (default mode) If a time interval
in seconds is specified then processing of next host, after
current host is finished, is delayed by this amount of time.
-F Spawn processes in background - fork and disconnect; this way
all hosts are processed essentially in parallel! It’s a very
powerful option - depending on you RAM size and memory
utilization, it shouldn’t be a problem to process a few hundreds
of hosts in parallel. Anyway, be careful if you have too many
hosts on the list - your could put your system under load. The
stdout’s of the background processes are redirected to
’/dev/null’, however you can use ‘-l’ or ‘-L’ to write the
output to files. See also ’bugs and known problems’ in the man
page.
-f Spawn processes in background without disconnecting from tty;
it’s the same as ‘-F’ whereas the stdout’s of the spawned
processes are sent to the terminal. Also the parent process
waits for his children to finish. See also ’bugs and known
problems’ in the man page.
-q Be quiet - skip output from spawn and login; when working with
the secure shell, it is also convenient to use ssh with the ‘-q’
option.
-Q Be QUIET - skip any output
-v Be verbose (default) - overrides ‘-q’ and ‘-Q’
-l <file>
Log command output to file; the output of the spawned processes
is appended to the file.
-L <name>
Write a separate log for every host where <name> denotes the
base name of the log file. The full name of a log file is
defined as "<name>_<user@host>.log"
-j Record the invoked command into a journal file with the name
’$HOME/.dish/journal’. It keeps the history of the executed
commands and their time of execution. An unique identifier is
associated with every command.
-J Record the invoked command and the spawned processes as well;
write into the journal file the executed command as well as the
single processes spawned and their time of execution.
-o <file>
File with command line options passed to the program; the
options must be one per line, whereas the default option file is
’$HOME/.dish/options’. By means of this file one can modify the
standard configuration - set up fork mode as default, change the
default connector, and so forth. When working in "copy mode",
i.e. by invoking the program as ’dicp’,
’$HOME/.dish/options.dicp’ is considered as default options
file.
-d enable expect’s diagnostic output (look at ‘man expect’)
-D Debug mode (dry-run); print out environment variables, config
file names, and commands to execute, then exit. This option
should be used as first in the command line.
EXAMPLES
You should consider that the variables $host and $user are evaluated.
Thus $host changes dynamically its value to the actual host/account
name before a new process is spawned. The same is true for $user.
a) Check the date and uptime on hosts 192.168.0.1 and 192.168.0.2
dish -e ’date \; uptime’ root@192.168.0.1 root@192.168.0.2
b) Distribute ’.profile’ and ’.bashrc’ to guest accounts on ’host1’ and
’host2’
dish -E "scp $HOME/.profile $HOME/.bashrc guest@\$host:" host1
host2
or
dicp -e "$HOME/.profile $HOME/.bashrc guest@:" host1 host2
or
dicp -g "host1 host2" $HOME/.profile $HOME/.bashrc guest@:
or
dicp -g "guest@host1 guest@host2" $HOME/.profile $HOME/.bashrc :
c) Copy remote ’.profile’ files into the local directory on localhost
dicp -g "guest@host1 guest@host2 admin@host2" :.profile
.profile.\$host
Here, the name of the target file include the account name in
order that the emerging local files have unique names.
d) Use ssh to login on ’host1’ and copy from there ’.profile’ to
’host2’
Since the list of hosts can not be empty, a dummy host is used
to initiate the process. The ‘-t’ option for ssh is necessary to
force pseudo-tty allocation in ‘ssh’, otherwise ‘ssh’ will fail
with error on login. A second password (a1-password) is required
for scp-authentication on ’host2’:
dish -a ’’ -E ’ssh -t user1@host1 scp .profile user2@host2:’
dummy_host
In case the password of ’user1’ and ’user2’ is the same, you
will be asked only once for a login password for user1@host1:
dish -E ’ssh -t user1@host1 scp .profile user2@host2:’
dummy_host
Or equivalently, and more simple:
dish -e ’scp .profile user2@host2:’ user1@host1
e) Substitute lines with ‘START_XNTPD=’ by ‘START_XNTPD="yes"’ in
/etc/rc.config
This command is executed as root user on every host listed in
’Hosts.root’:
dish -u root -E ’ssh $user@$host "perl -pi -e
\"s/^START_XNTPD=.*\$/START_XNTPD=\\\"yes\\\"/g;\"
/etc/rc.config"’ -g Hosts.root
f) Freeze accounts of users on a termination list
By using a script called ‘FreezeUser.sh’, all accounts of users
found on ’Terminate.User.lst’ will be frozen today at 24:00
o’clock on both server groups as defined in files ’Hosts.1’ and
’Hosts.2’:
dish -E ’ssh root@$host "cat Terminate.User.lst | while read UN;
do echo \"su - admin -c \\\$HOME/bin/FreezeUser.sh \$UN\" | at
24:00 ; done"’ -g Hosts.1 -g Hosts.2
g) Print out remote configuration file of an automounter
Login as admin user on host 192.168.0.1, switch to root, then
cat the file ’/etc/auto.net’ and print out the date. The ‘-a’
option causes the program to ask you for the root password on
remote host:
dish -u admin -a ’’ -E ’rsh -l $user $host su - root -c \"cat
/etc/auto.net\; date\"’ 192.168.0.1
h) Install a package on Debian GNU/Linux hosts
After mounting a fileserver over samba, install from there a
debian dish-package on all Debian running servers, yet skip
hosts on maintenance. Three different passwords are needed for
authentication - one for login, next for su-root, and the last
for mounting the fileserver:
dish -a0 -a1 -a2 -g Debian.up -r Debian.maint -e ’su - -c
\"mount -t smbfs //FILESERVER/Packages.Dir /mnt/smb ; dpkg -i
/mnt/smb/dish_1.17.1_all.deb\"’
i) Check for system load >2 using default ’hosts’ and ’pass’ config
files
dish ’(uptime |egrep \" (\[2-9\]|1\[0-9\])\\.\" && hostname)
|paste - -’
j) Query a MySQL database on remote host 10.0.0.1
dish -pp -c ’mysql -p -u $user -h’ -e ’use mysql; show tables;
describe user;’ -u root 10.0.0.1
k) Change password concurrently on all hosts/accounts
We assume that the list of user accounts is contained in file
’Accounts.lst’, whereas an entry in the list is of the form
"user@hostname". After command execution, you will be asked one
time for a login password, and one more for the a1-password
(which, in this case, must be the same as the login password).
Then you have to type the new password, and finally retype it
correctly:
dish -p ’’ -a ’’ -n ’’ -e passwd -g Accounts.lst
Or, alternatively, without retyping the login password,
processing concurrently and quietly all hosts:
dish -g Accounts.lst -f -Q -pp -nn -e passwd
l) Change root password (don’t use the ‘-a0’ option)
If you are going to change the root password on remotehost, then
try:
dish -nn -e passwd root@remotehost
The same as previous, but login as user admin (login password),
then switch to root (a1-password), and finally update the root
password:
dish -a1 -nn -e ’su -c passwd’ admin@remotehost
Changing the password for admin on localhost, after login as
root via telnet, is done by:
dish -nn -c telnet -u root -e ’passwd admin’ localhost
Note that for password change, when ‘-p ""’ (or equivalently ‘-a0’ or
‘-pp’) is not explicitly used, the assumption is made that ‘passwd’
will not ask for the old password, as in case of a password change by
root. This example is valid also if you can login into account without
typing a password, but then ‘passwd’ prompts you to type the current
one - such situation occurs when using a ssh-key for login
authentication. Alternatively, the options ‘-p0 -aa -nn’ would yield
the same result.
In case of properly prepared configuration files in ’$HOME/.dish’, one
can use dish as a distributed shell for a virtual cluster of hosts, and
run it without specifying any program parameters but merely issuing a
command, as for instance ‘dish df -k /’ or ‘dicp .profile :’.
As a very last note, one should be aware, that dish’s automated login
process is based on the premise that in case a program is asking for
password, the prompt send to the terminal will include the
case-insensitive string ‘Password:’. Otherwise the authentication
procedure will fail. You can change this, in fact regular expression,
by using the option ‘-X’.
BUGS AND KNOWN PROBLEMS
If Tcl is compiled with thread support, the program hangs when executed
in parallel mode (options ‘-f’ or ‘-F’) - it seems to be a Tcl problem.
Generally, at present Debian GNU/Linux (and other debian-based Linux
distros as Ubuntu, Knoppix, etc.) pre-package Tcl with multi-thread
support enabled. Therefore, on such systems dish fails to process
hosts in parallel. In this case you can download the debian source
package of Tcl, remove the option "--enable-threads" in ´debian/rules´,
rebuild the package with ‘dpkg-buildpackage -rfakeroot’, and eventually
install it. It could be a good idea to put the freshly installed
package on hold. Otherwise, you should recompile it on every tcl
upgrade.
REPORTING BUGS
Report bugs to <gnu@mirendom.net>
COPYRIGHT
Copyright © 2003-2009 Dimitar Ivanov
License: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
SEE ALSO
expect(1), tcl(3), ssh(1), rsh(1), telnet(1)