source: trunk/tssh/tssh @ 221

Last change on this file since 221 was 197, checked in by g7moreau, 6 years ago
  • Add some doc !
File size: 9.2 KB
Line 
1#!/bin/bash
2#
3# 2014/03/26 Gabriel Moreau <Gabriel Moreau(A)univ-grenoble-alpes.fr> - Initial release
4#
5# From http://hd-recording.at/dokuwiki/doku.php?id=linux:tmux#tssh
6
7# Clean when Ctrl^C
8trap '[ -n "${base_path}" -a -d "/tmp/${base_path}" ] && rm -rf "/tmp/${base_path}"; exit 4;' QUIT INT TERM
9
10export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin
11export LANG=C
12
13
14function usage() {
15   cat <<END_USAGE
16NAME
17   $(basename $0) - tmux cluster ssh
18
19SYNOPSIS
20   $0 [-w number] [-f] [-v] [-c remote_cmd] <host1> <host2> <clusterssh class>... <hostM>- <hostN>+
21
22OPTIONS
23   -w             windows to open (integer, default 16)
24   -f             fast, no nmap scan to eliminate sleeping computer
25   -v             verbose
26   -c remote_cmd  launch the remote command on hosts and exit
27   -h             help
28
29DESCRIPTION
30   tssh can be use to launch terminal on many computer in parallel with tmux
31   multiplexer and ssh.
32   The tmux windows is splitted automatically.
33   If you need more computers on the same windows, you can zoom in and out
34   under gnome terminal with Ctrl- or Ctrl+.
35   This must be done before launching tssh.
36   
37   On the command line, you can put host, login@host, clusterssh class.
38   A host or a class can be remove from the list with a dash append
39   and force to be in this one with a plus append.
40   Example with the cluster ssh config below:
41   
42    tssh all team- node005 laptop04+
43
44   Is equivalent to:
45 
46    tssh srv-mail srv-dns srv-imap srv-web srv-proxy \\
47      node001 node002 node003 node004 \\
48      node101 node102 node103 node104 \\
49      node005 laptop04
50
51   The control command for tmux is Ctrl^b.
52   You can switch from broadcast to a local machine with Ctrl^b Ctrl^b
53   and move between machine with Ctrl^b ArrowKey.
54
55DEPENDS
56   On Debian, you need the package
57
58    apt-get install tmux ncurses-bin wamerican nmap
59
60   wamerican (or wfrench...) is used to choose a random word in the file /usr/share/dict/words
61   for each new tmux session.
62
63   ncurses-bin is required for the tput command
64   to automatically split your terminal into several small panels.
65   nmap is only used for dynamic DNS domain and dynamic scan.
66   This is not mandatory for general use.
67
68   By default, tssh use tput to know the number of columns and lines of your terminal.
69   It takes 10 lines and 40 columns for each windows by default.
70   If tput is not installed, the default is 16 windows...
71
72CONFIGURATION
73   The clusterssh config file ~/.csshrc is a key values file.
74   The "clusters" is mandatory for clusterssh (not tssh) and define the other keys.
75   Values could be computer list or other key...
76   
77    clusters = all server s1 s2 s3 node n1 n2 team switch
78    all = server node team
79    server = s1 s2
80    node = n1 n2
81    s1 = srv-mail srv-dns srv-imap
82    s2 = srv-web srv-proxy
83    n1 = node001 node002 node003 node004
84    n2 = node101 node102 node103 node104
85    team = pc01 pc06 laptop04 laptop05 laptop09
86    switch = root@switch01 root@switch05 root@switch17
87
88   The tssh config file (~/.tsshrc) can be use change the default parameters.
89   
90    #export split_number=16
91    export dyn_domain='mycompagny.local'
92    #export fast='yes'
93    #export verbose='yes'
94
95AUTHOR
96   Gabriel Moreau
97
98COPYRIGHT
99   Copyright (C) 2014-2018, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France
100   Licence : GNU GPL version 2 or later
101END_USAGE
102   }
103
104export remote_command=''
105export split_number=16
106if which tput > /dev/null
107then
108   export split_number=$(( ($(tput  lines)/ 10) * ($(tput  cols)/ 40) ))
109fi
110
111export dyn_domain=''
112if [ -e "${HOME}/.tsshrc" ]
113then
114   . "${HOME}/.tsshrc"
115fi
116
117# get options
118if [ $# -eq 0 ]; then usage; exit 1; fi 
119while getopts "w:c:fvh" options
120do
121   case ${options} in
122      w)
123         if echo ${OPTARG} | egrep -q '^[[:digit:]]+$' && [ ${OPTARG} -gt 0 ]
124         then
125            export split_number=${OPTARG}
126         else
127            usage
128            exit 2
129         fi
130         ;;
131      c)
132         if echo ${OPTARG} | egrep -q '[[:alpha:]]'
133         then
134            export remote_command=${OPTARG}
135         else
136            usage
137            exit 2
138         fi
139         ;;
140      f)
141         export fast='yes'
142         ;;
143      v)
144         export verbose='yes'
145         ;;
146      h|*)
147         usage
148         exit 3
149         ;;
150   esac
151done
152shift $((OPTIND - 1))
153[[ $1 = "--" ]] && shift
154
155cd /tmp/
156export base_path=$(mktemp -d tssh.XXXXXX)
157touch "/tmp/${base_path}/master"
158touch "/tmp/${base_path}/master-"
159touch "/tmp/${base_path}/master+"
160touch "/tmp/${base_path}/master--"
161touch "/tmp/${base_path}/master++"
162
163get_host_list () {
164   local cluster
165   local default_mode=''
166
167   # set local mode
168   if echo $1 | grep -- ^--mode=
169   then
170      default_mode=$(echo $1 | grep -- ^--mode= | cut -f 2 -d '=')
171      shift
172   fi
173
174   for host in $*
175   do
176      local mode=${default_mode}
177      local last_char="${host: -1}"
178      if [ "${last_char}" == "-" -o "${last_char}" == "+" ]
179      then
180         mode="${last_char}"
181         host="${host:0:${#host}-1}"
182      fi
183
184      # short host without login part if any
185      local justhost=${host#*@}
186     
187      cluster=$(grep "^${justhost}\b" ${HOME}/.csshrc | cut -f 2 -d '=' | sed -e 's/^[[:space:]]*//;')
188      if [ "${cluster}" == "" ]
189      then
190         # just a host to scan and add
191         if [ "${fast}" != 'yes' -a "${mode}" != '-' ]
192         then
193            # test if exists host
194            if host ${justhost} | grep -q 'not found'
195            then
196               [ "${verbose}" == 'yes' ] && echo "Warning: ${justhost} does not exists"
197               continue
198            fi
199            if ! nmap -p 22 -sT -PN ${justhost} | grep -q '\bopen\b'
200            then
201               if host ${justhost}.${dyn_domain} | grep -q 'not found' || ! nmap -p 22 -sT -PN ${justhost}.${dyn_domain} | grep -q '\bopen\b'
202               then
203                  [ "${verbose}" == 'yes' ] && echo "Warning: ${justhost} is down"
204                  continue
205               else
206                  [ "${verbose}" == 'yes' ] && echo "Warning: remove ssh key of ${justhost}.${dyn_domain}"
207                  host=${justhost}.${dyn_domain}
208                  ssh-keygen -q -R $(LANG=C host ${justhost} | awk '{print $4}')
209               fi
210            fi
211         fi
212         [ "${verbose}" == 'yes' ] && echo "Warning: add ${host} on list with mode ${mode}"
213         echo "${host}" >> "/tmp/${base_path}/master${mode}"
214      else
215         # cluster, jump in a recursive mode
216         [ "${verbose}" == 'yes' ] && echo "Warning: recursive call for cluster ${justhost} (${cluster}), with mode ${mode}"
217         cluster=$(get_host_list --mode=${mode} "${cluster}")
218      fi
219   done
220   }
221declare -fx get_host_list
222
223get_host_list $@
224cat "/tmp/${base_path}/master+" >> "/tmp/${base_path}/master"
225for f in $(grep . "/tmp/${base_path}/master-")
226do
227   egrep "^${f}$" "/tmp/${base_path}/master+" && continue
228   echo "${f}" >> "/tmp/${base_path}/master--"
229done
230for f in $(grep . "/tmp/${base_path}/master")
231do
232   egrep "^${f}$" "/tmp/${base_path}/master--" && continue
233   echo "${f}" >> "/tmp/${base_path}/master++"
234done
235
236# split master list in paquet of split_number computer
237sort -u "/tmp/${base_path}/master++" | split -l ${split_number} - /tmp/${base_path}/__splitted_
238
239# wait is needed by time tmux session open and ssh time connection
240tempo=0.8
241first_tempo=0
242other_tempo=0
243if [ -n "${remote_command}" ]
244then
245   # add tempo after remote command
246   other_tempo=${tempo}
247   first_tempo="${tempo} ${other_tempo}"
248fi
249
250# loop on each split windows
251for f in $(ls -1 /tmp/${base_path}/ | grep ^__splitted_)
252do
253   if [ "${verbose}" == 'yes' ]
254   then
255      echo "Info: next hosts to be splitted"
256      cat "/tmp/${base_path}/${f}" | sed -e 's/^/  /;'
257      sleep 5
258   fi
259
260   session=$(shuf -n 1 /usr/share/dict/words | tr -cd "[:alpha:]")
261
262   IFS=$'\n' host=($(cat "/tmp/${base_path}/${f}"))
263
264   tmux -2 new-session -d -s $session "ssh ${host[0]} ${remote_command}; sleep ${first_tempo}"
265   # wait ${tempo} second to let new session start...
266   sleep ${tempo}
267
268   for (( i=1 ; i < ${#host[@]} ; i++))
269   do
270      # wait ${tempo} needed in case of ${remote_command}
271      tmux splitw -t $session "ssh ${host[$i]} ${remote_command}; sleep ${other_tempo}"
272      tmux select-layout tiled
273   done
274
275   tmux set-window-option synchronize-panes on  > /dev/null
276   tmux set-window-option -g utf8 on            > /dev/null
277   tmux set -g default-terminal screen-256color > /dev/null
278   #tmux set-option -g set-clipboard on
279 
280   # Sane scrolling
281   #tmux set -g mode-mouse on
282   #tmux set -g mouse-resize-pane on
283   #tmux set -g mouse-select-pane on
284   #tmux set -g mouse-select-window on
285 
286   #set -g terminal-overrides 'xterm*:smcup@:rmcup@'
287 
288   # toggle mouse mode to allow mouse copy/paste
289   # set mouse on with prefix m
290   tmux bind m \
291      set -g mode-mouse on \; \
292      set -g mouse-select-pane on \; \
293      display 'Mouse: ON' > /dev/null
294      # set -g mouse-resize-pane on \; \
295      #set -g mouse-select-window on \; \
296   # set mouse off with prefix M
297   tmux bind M \
298      set -g mode-mouse off \; \
299      set -g mouse-select-pane off \; \
300      display 'Mouse: OFF' > /dev/null
301      #set -g mouse-resize-pane off \; \
302      #set -g mouse-select-window off \; \
303   # toggle Broadcast
304   tmux bind b set-window-option synchronize-panes
305
306   tmux attach -t $session
307done
308
309# Clean temporary folder
310[ -d "/tmp/${base_path}" ] && rm -rf "/tmp/${base_path}"
Note: See TracBrowser for help on using the repository browser.