|
@@ -17,32 +17,7 @@ import telnetlib
|
|
|
from collections import Counter
|
|
|
from threading import Thread
|
|
|
from socket import error
|
|
|
-from sys import argv,exit,stdout
|
|
|
-
|
|
|
-# Some list definitions
|
|
|
-lcm1 = ['abe','crash','duke','glados','lara','link','king','pang','pong',
|
|
|
- 'snake','sonic','spyro','yoshi']
|
|
|
-lcm2 = ['actarus','elwood','gex','gin','jake','kirk','martini','picard','q',
|
|
|
- 'raziel','sarek','spock','tron','worf','zombie']
|
|
|
-laur = ['eskimo','orion','tilde']
|
|
|
-
|
|
|
-math4 = ['sonic','crash','duke','raziel','actarus','gin','kirk','martini',
|
|
|
- 'picard','sarek','tron','worf','zombie','q','elwood','jake']
|
|
|
-math5 = ['abe','glados','link','king','pang','pong','snake','spyro','yoshi']
|
|
|
-math = math4 + math5
|
|
|
-
|
|
|
-cuda = ['jacobi','yukawa','tesla']
|
|
|
-
|
|
|
-
|
|
|
-# Important variables: gods, hosts and term colors
|
|
|
-gods = ['root','andreatsh','andreamalerba','lorenzouboldi',
|
|
|
- 'stefanobalzan','eugeniothieme']
|
|
|
-# Former admins: bother them at your own risk
|
|
|
-chucknorris = [ 'agalli', 'ikki', 'buddino', 'alex', 'ema', 'ktf',
|
|
|
- 'davideg', 'jacopogh', 'lampo', 'gian', 'rbondesan',
|
|
|
- 'scolari', 'emanueleb', 'giani_matteo','gabryv','fran',
|
|
|
- 'alqahirah','giorgio_ruffa','palazzi','algebrato','blanc',
|
|
|
- 'blue','silviacotroneo']
|
|
|
+from sys import exit,stdout
|
|
|
|
|
|
|
|
|
### ARGUMENT PARSING ###
|
|
@@ -72,49 +47,38 @@ parser.add_argument('-n', action='store_true', dest='n',
|
|
|
parser.add_argument('-N', action='store_true', dest='N',
|
|
|
help='also display number of logs')
|
|
|
parser.add_argument('-v', '--version', action='version',
|
|
|
- version='%(prog)s 2.0', help='Print program version')
|
|
|
-####
|
|
|
+ version='%(prog)s 2.1', help='Print program version')
|
|
|
|
|
|
+# Parse arguments
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
-hosts=[]
|
|
|
-
|
|
|
-if (( args.lcm1 and args.lcm2 ) or args.condor ) : hosts = lcm1 + lcm2
|
|
|
-elif args.lcm1: hosts += lcm1
|
|
|
-elif args.lcm2: hosts += lcm2
|
|
|
-elif args.laur: hosts += laur
|
|
|
-elif args.cuda: hosts += cuda
|
|
|
-elif args.math: hosts += math
|
|
|
-else: hosts = lcm1 + lcm2 + laur + cuda
|
|
|
-
|
|
|
-# FIXME it would be better not to rely on host names for splitting
|
|
|
-if args.n:
|
|
|
- splitters = [('jake','LCM1'),('gin','LCM2'),
|
|
|
- ('jacobi','CUDA'),('orion','LAUR')]
|
|
|
- progressbar = 0
|
|
|
-else:
|
|
|
- splitters = [('abe','\033[1;36mLCM1\033[0m'),
|
|
|
- ('actarus','\033[1;32mLCM2\033[0m'),
|
|
|
- ('jacobi','\033[1;35mCUDA\033[0m'),
|
|
|
- ('eskimo','\033[1;33mLAUR\033[0m')]
|
|
|
- progressbar = 1
|
|
|
-
|
|
|
-# Define port
|
|
|
-port = 79
|
|
|
+# Define port on which the lcm_w service is listening
|
|
|
+# NB at the time of writing lcm_w is managed by inetd
|
|
|
+PORT = 79
|
|
|
|
|
|
|
|
|
#############################################
|
|
|
# Node class
|
|
|
-# The bulk of the program is done here
|
|
|
+# Each node executes a `who` query in a separate thread
|
|
|
#############################################
|
|
|
|
|
|
class Node(Thread):
|
|
|
# Constructor
|
|
|
- def __init__(self,nome,port):
|
|
|
+ def __init__(self, name, location, math4=False, math5=False,
|
|
|
+ cuda=False, condor=False, port=PORT):
|
|
|
# Fork the thread first thing
|
|
|
Thread.__init__(self)
|
|
|
# Variables initialization
|
|
|
- self.hostname = nome
|
|
|
+ self.hostname = name
|
|
|
+ self.location = location
|
|
|
+ if math4:
|
|
|
+ self.math_version = 'M4'
|
|
|
+ elif math5:
|
|
|
+ self.math_version = 'M5'
|
|
|
+ else:
|
|
|
+ self.math_version = 'NA'
|
|
|
+ self.cuda = cuda
|
|
|
+ self.condor = condor
|
|
|
self.local = []
|
|
|
self.remote = []
|
|
|
self.lgod = []
|
|
@@ -202,6 +166,22 @@ class Node(Thread):
|
|
|
else:
|
|
|
return True
|
|
|
|
|
|
+ # Print hostname (plus qualifiers if needed)
|
|
|
+ def qualifiedname(self):
|
|
|
+ tmp = self.hostname
|
|
|
+
|
|
|
+ # Add math version to hostname if required
|
|
|
+ if args.math:
|
|
|
+ tmp += '[' + self.math_version + ']'
|
|
|
+
|
|
|
+ # Add cuda tag [C] to hostname for CUDA hosts (jp)
|
|
|
+ # FIXME I don't think we need this. Cuda nodes have their own section
|
|
|
+ # if self.cuda:
|
|
|
+ # self.hostname += ' '*(5-len(self.hostname))+'[C]'
|
|
|
+
|
|
|
+ return tmp
|
|
|
+
|
|
|
+
|
|
|
# Print output giorgio-style, host based (after threads have finished)
|
|
|
def printlist(self):
|
|
|
# Uniq equivalent and string conversion
|
|
@@ -242,17 +222,81 @@ class Node(Thread):
|
|
|
for user in ccounter:
|
|
|
strchuck += user + '(' + str(ccounter[user]) + ') '
|
|
|
|
|
|
- # Print a tag [C] alongside CUDA hosts (jp)
|
|
|
- if self.hostname in cuda:
|
|
|
- self.hostname = self.hostname + ' '*(5-len(self.hostname))+'[C]'
|
|
|
-
|
|
|
- print ' ' + self.hostname + ' '*(15-len(self.hostname)) \
|
|
|
+ # Print out hostname and connected users
|
|
|
+ print ' ' + self.qualifiedname() + ' '*(15-len(self.qualifiedname())) \
|
|
|
+ red + strlgod + normal + pink + strrgod + normal + green \
|
|
|
+ strlocal + normal + blue + strremote + normal \
|
|
|
+ turquoise + strchuck + normal
|
|
|
### end class Node
|
|
|
|
|
|
|
|
|
+### USER GROUPS ###
|
|
|
+# Current admins/150
|
|
|
+gods = ['root','andreatsh','andreamalerba','lorenzouboldi',
|
|
|
+ 'stefanobalzan','eugeniothieme']
|
|
|
+
|
|
|
+# Former admins: bother them at your own risk
|
|
|
+chucknorris = [ 'agalli', 'ikki', 'buddino', 'alex', 'ema', 'ktf',
|
|
|
+ 'davideg', 'jacopogh', 'lampo', 'gian', 'rbondesan',
|
|
|
+ 'scolari', 'emanueleb', 'giani_matteo','gabryv','fran',
|
|
|
+ 'alqahirah','giorgio_ruffa','palazzi','algebrato','blanc',
|
|
|
+ 'blue','silviacotroneo']
|
|
|
+
|
|
|
+
|
|
|
+### HOST LIST ###
|
|
|
+# Only edit here to add/remove/change hostlist
|
|
|
+
|
|
|
+nodes = [
|
|
|
+ Node('abe', 'LCM1', math5=True, condor=True),
|
|
|
+ Node('crash', 'LCM1', math4=True, condor=True),
|
|
|
+ Node('duke', 'LCM1', math4=True, condor=True),
|
|
|
+ Node('glados', 'LCM1', math5=True, condor=True),
|
|
|
+ Node('lara', 'LCM1', condor=True),
|
|
|
+ Node('link', 'LCM1', math5=True, condor=True),
|
|
|
+ Node('king', 'LCM1', math5=True, condor=True),
|
|
|
+ Node('pang', 'LCM1', math5=True, condor=True),
|
|
|
+ Node('pong', 'LCM1', math5=True, condor=True),
|
|
|
+ Node('snake', 'LCM1', math5=True, condor=True),
|
|
|
+ Node('sonic', 'LCM1', math4=True, condor=True),
|
|
|
+ Node('spyro', 'LCM1', math5=True, condor=True),
|
|
|
+ Node('yoshi', 'LCM1', math5=True, condor=True),
|
|
|
+ Node('actarus', 'LCM2', math4=True, condor=True),
|
|
|
+ Node('elwood', 'LCM2', math4=True, condor=True),
|
|
|
+ Node('gex', 'LCM2', condor=True),
|
|
|
+ Node('gin', 'LCM2', math4=True, condor=True),
|
|
|
+ Node('jake', 'LCM2', math4=True, condor=True),
|
|
|
+ Node('kirk', 'LCM2', math4=True, condor=True),
|
|
|
+ Node('martini', 'LCM2', math4=True, condor=True),
|
|
|
+ Node('picard', 'LCM2', math4=True, condor=True),
|
|
|
+ Node('q', 'LCM2', math4=True, condor=True),
|
|
|
+ Node('raziel', 'LCM2', math4=True, condor=True),
|
|
|
+ Node('sarek', 'LCM2', math4=True, condor=True),
|
|
|
+ Node('spock', 'LCM2', condor=True),
|
|
|
+ Node('tron', 'LCM2', math4=True, condor=True),
|
|
|
+ Node('worf', 'LCM2', math4=True, condor=True),
|
|
|
+ Node('zombie', 'LCM2', math4=True, condor=True),
|
|
|
+ Node('eskimo', 'LAUR'),
|
|
|
+ Node('orion', 'LAUR'),
|
|
|
+ Node('tilde', 'LAUR'),
|
|
|
+ Node('jacobi', 'CUDA', cuda=True),
|
|
|
+ Node('yukawa', 'CUDA', cuda=True),
|
|
|
+ Node('tesla', 'CUDA', cuda=True),
|
|
|
+]
|
|
|
+
|
|
|
+
|
|
|
+### SECTION SPLITTERS ###
|
|
|
+if args.n:
|
|
|
+ splitters = { 'LCM1': '-LCM1----',
|
|
|
+ 'LCM2': '-LCM2----',
|
|
|
+ 'CUDA': '-CUDA----',
|
|
|
+ 'LAUR': '-LAUR----' }
|
|
|
+else:
|
|
|
+ splitters = { 'LCM1': '-\033[1;36mLCM1\033[0m----',
|
|
|
+ 'LCM2': '-\033[1;32mLCM2\033[0m----',
|
|
|
+ 'CUDA': '-\033[1;35mCUDA\033[0m----',
|
|
|
+ 'LAUR': '-\033[1;33mLAUR\033[0m----' }
|
|
|
+
|
|
|
+
|
|
|
###################################################
|
|
|
# Main
|
|
|
###################################################
|
|
@@ -277,33 +321,37 @@ else:
|
|
|
green = ""
|
|
|
turquoise =""
|
|
|
|
|
|
-
|
|
|
-# Initialization of the four lists
|
|
|
-downlist = ""
|
|
|
-emptylist = ""
|
|
|
-unavlist = ""
|
|
|
-timeoutlist = ""
|
|
|
-
|
|
|
-# Initialize the threadlist
|
|
|
-threadlist = []
|
|
|
+# Check whether we want a progressbar displayed
|
|
|
+progressbar = not args.n
|
|
|
+
|
|
|
+# Filter hostlist according to arguments
|
|
|
+if args.lcm1:
|
|
|
+ nodes = [ node for node in nodes if node.location == 'LCM1' ]
|
|
|
+if args.lcm2:
|
|
|
+ nodes = [ node for node in nodes if node.location == 'LCM2' ]
|
|
|
+if args.laur:
|
|
|
+ nodes = [ node for node in nodes if node.location == 'LAUR' ]
|
|
|
+if args.cuda:
|
|
|
+ nodes = [ node for node in nodes if node.location == 'CUDA' ]
|
|
|
+if args.math:
|
|
|
+ nodes = [ node for node in nodes if node.math_version != 'NA' ]
|
|
|
|
|
|
# Number of hosts (for progressbar)
|
|
|
-num = len(hosts)
|
|
|
+num = len(nodes)
|
|
|
|
|
|
# Start the threads
|
|
|
-for item in hosts:
|
|
|
- m=Node(item,port)
|
|
|
- threadlist.append(m)
|
|
|
- m.start()
|
|
|
+for node in nodes:
|
|
|
+ node.start()
|
|
|
|
|
|
# Used for progressbar
|
|
|
index = 0
|
|
|
print ' Querying '+str(num)+' hosts...'
|
|
|
|
|
|
# Rejoin them when their work is done
|
|
|
-for thread in threadlist:
|
|
|
- thread.join()
|
|
|
- if progressbar > 0:
|
|
|
+# NB a progress bar does not make much sense if join is not asynchronous (blue)
|
|
|
+for node in nodes:
|
|
|
+ node.join()
|
|
|
+ if progressbar:
|
|
|
# Progessbar
|
|
|
index += 1
|
|
|
stdout.write('\r ['
|
|
@@ -312,49 +360,63 @@ for thread in threadlist:
|
|
|
+ ' '*(num-index-1) + ']')
|
|
|
stdout.flush()
|
|
|
|
|
|
-if progressbar > 0:
|
|
|
+if progressbar:
|
|
|
# Newline
|
|
|
print '\n Done... ( %(t).3f s)' % {'t': (time() - start)}
|
|
|
|
|
|
-# And now print!
|
|
|
-for thread in threadlist:
|
|
|
- # lcm1-lcm2-laur splitters
|
|
|
- for pair in splitters:
|
|
|
- if thread.hostname in pair[0]: print '-' + pair[1] + normal +'----'
|
|
|
-
|
|
|
- # See what they are up to and print accordingly
|
|
|
- if thread.hostname in cuda:
|
|
|
- thread.hostname +='[C]'
|
|
|
- if args.math :
|
|
|
- if thread.hostname in math4:
|
|
|
- thread.hostname +='[M4]'
|
|
|
- if thread.hostname in math5:
|
|
|
- thread.hostname +='[M5]'
|
|
|
- if not thread.up:
|
|
|
- # Host down
|
|
|
- downlist += thread.hostname + ' '
|
|
|
- else:
|
|
|
- if not thread.aval:
|
|
|
- # Host unavailable
|
|
|
- unavlist += thread.hostname + ' '
|
|
|
- continue
|
|
|
- if thread.timeout:
|
|
|
- # Thread has timed out
|
|
|
- timeoutlist += thread.hostname + ' '
|
|
|
- continue
|
|
|
- if thread.isempty():
|
|
|
- # Host is empty
|
|
|
- emptylist += thread.hostname + ' '
|
|
|
- else:
|
|
|
- thread.printlist()
|
|
|
-
|
|
|
+if args.full or args.math or args.cuda:
|
|
|
+# Save down/unreachable/unavailable nodes to separate lists
|
|
|
+ downlist = ''
|
|
|
+ timeoutlist = ''
|
|
|
+ unavlist = ''
|
|
|
+ emptylist = ''
|
|
|
+ for node in nodes:
|
|
|
+ if not node.up:
|
|
|
+ downlist += node.qualifiedname() + ' '
|
|
|
+ elif node.timeout:
|
|
|
+ timeoutlist += node.qualifiedname() + ' '
|
|
|
+ elif not node.avail:
|
|
|
+ unavlist += node.qualifiedname() + ' '
|
|
|
+ elif node.isempty():
|
|
|
+ emptylist += node.qualifiedname() + ' '
|
|
|
+
|
|
|
+nodes = [ node for node in nodes if node.up
|
|
|
+ and not node.timeout
|
|
|
+ and node.avail
|
|
|
+ and not node.isempty() ]
|
|
|
+
|
|
|
+# Split notes by location
|
|
|
+lcm1nodes = [ node for node in nodes if node.location == 'LCM1' ]
|
|
|
+lcm2nodes = [ node for node in nodes if node.location == 'LCM2' ]
|
|
|
+laurnodes = [ node for node in nodes if node.location == 'LAUR' ]
|
|
|
+cudanodes = [ node for node in nodes if node.location == 'CUDA' ]
|
|
|
+
|
|
|
+# Print out
|
|
|
+if len(lcm1nodes):
|
|
|
+ print splitters['LCM1']
|
|
|
+ for node in lcm1nodes:
|
|
|
+ node.printlist()
|
|
|
+if len(lcm2nodes):
|
|
|
+ print splitters['LCM2']
|
|
|
+ for node in lcm2nodes:
|
|
|
+ node.printlist()
|
|
|
+if len(laurnodes):
|
|
|
+ print splitters['LAUR']
|
|
|
+ for node in laurnodes:
|
|
|
+ node.printlist()
|
|
|
+if len(cudanodes):
|
|
|
+ print splitters['CUDA']
|
|
|
+ for node in cudanodes:
|
|
|
+ node.printlist()
|
|
|
+
|
|
|
# Some final output
|
|
|
if progressbar > 0:
|
|
|
print
|
|
|
print 'Legenda: ' + green + 'utente locale '+ normal \
|
|
|
+ blue + 'utente remoto ' + normal + red + 'admin locale ' + normal \
|
|
|
+ pink + 'admin remoto ' + normal + turquoise + 'nirvana' + normal
|
|
|
- print " I nodi contrassegnati con [C] sono i nodi CUDA."
|
|
|
+ # FIXME I don't think we need this. Cuda nodes have their own section
|
|
|
+ # print " I nodi contrassegnati con [C] sono i nodi CUDA."
|
|
|
if args.math:
|
|
|
print " I nodi contrassegnati con [M4] hanno Mathematica 4.0"
|
|
|
print " I nodi contrassegnati con [M5] hanno Mathematica 5.2"
|