Browse Source

big commit: new way of printing and better handling of options

* la classe Node ora contiene tutte le informazioni relative a un nodo,
  e.g. versione di mathematica, se ha condor, ecc
* la classe Node sa anche stampare il proprio hostname con o senza
  qualifier ([M4], [M5]) a seconda delle opzioni passate a whoall
* le varie liste di host sono sostituite da un'unica lista di Node,
  che contiene anche le informazioni relative a mathematica, condor, ecc
* la lista di Node viene filtrata a seconda delle opzioni passate al
  parser (e.g. vengono tolti tutti i nodi che non hanno matematica per
  '-m'. In questo modo passando multiple opzioni (`whoall -m -1`) si
  ottiene l'intersezione dei risultati delle singole opzioni (solo i
  nodi di LCM1 che hanno mathematica)
* il modo in cui vengono separati i nodi di LCM1, LCM2, LAUR e CUDA è
  migliorato: ora non dipende piu' dall'ordine in cui i nodi sono
  inseriti nella hostlist, ma è fatto filtrando i nodi per location
* in linea teorica ora è facilissimo
* ho tolto (commentato) la stampa di '[C]' dopo i nodi cuda, visto che
  hanno una sezione riservata. Se siete d'accordo con questo
  cambiamento, cercate i FIXME e cancellate le righe commentate

Il funzionamento di whoall dovrebbe essere _identico_ a prima, anche in
termini di velocità di esecuzione. L'unica differenza di comportamento è
che adesso multiple opzioni del tipo '-1 -2 -m' restituiscono
l'intersezione delle condizioni (e.g. `whoall -1 -2` fa la query su ben
zero nodi).

In linea teorica, se mai ce ne fosse bisogno, ora è facilissimo creare
altri gruppi di nodi e generare un output corretto solo per quei nodi.

In tutto questo ho fatto un po' di refactoring del codice e ho
migliorato/aggiunto un po' di commenti qua e là, quindi forse
il diff è difficile da leggere, ma il codice dovrebbe essere mooolto
piu' leggibile rispetto a prima.
bluehood 8 years ago
parent
commit
6cfdea702d
1 changed files with 173 additions and 111 deletions
  1. 173 111
      whoall

+ 173 - 111
whoall

@@ -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"