whoall 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. #!/usr/bin/python
  2. #
  3. # Python whoall: parallel, multi-threaded version
  4. # First author: jacopogh - nov 2006
  5. # Modified and updated by admins & 150 over time
  6. #
  7. # Requires python version 2.7 or above
  8. # Please read the wiki before editing this file
  9. from time import time
  10. start = time()
  11. # Import needed modules
  12. import argparse
  13. import collections
  14. import os
  15. import telnetlib
  16. import textwrap
  17. from threading import Thread
  18. from socket import error
  19. from sys import argv,exit,stdout
  20. # Some array definitions
  21. lcm1 = ['abe','crash','duke','glados','lara','link','king','pang','pong','snake','sonic','spyro','yoshi']
  22. lcm2 = ['actarus','elwood','gex','gin','jake','kirk','martini','picard','q','raziel','sarek','spock','tron','worf','zombie']
  23. laur = ['eskimo','orion','tilde']
  24. math4 = ['sonic','crash','duke','raziel','actarus','gin','kirk','martini','picard','sarek','tron','worf','zombie','q','elwood','jake']
  25. math5 = ['abe','glados','link','king','pang','pong','snake','spyro','yoshi']
  26. math = math4 + math5
  27. cuda = ['jacobi','yukawa','tesla']
  28. # Important variables: gods, hosts and term colors
  29. gods = ['root','andreatsh','andreamalerba','lorenzouboldi','stefanobalzan','eugeniothieme']
  30. # Former admins: bother them at your own risk
  31. 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']
  32. parser = argparse.ArgumentParser( epilog='Please, report bugs or unwanted behavior to: working@lcm.mi.infn.it' )
  33. ## Optional arguments
  34. parser.add_argument( '-1', '--lcm1', action='store_true', default=False, dest='lcm1', help='LCM1 hosts ' )
  35. parser.add_argument( '-2', '--lcm2', action='store_true', default=False, dest='lcm2', help='LCM2 hosts ' )
  36. parser.add_argument( '-l', '--laur', action='store_true', default=False, dest='laur', help='only LAUR hosts ' )
  37. parser.add_argument( '-c', '--condor', action='store_true', default=False, dest='condor', help='condor nodes ' )
  38. parser.add_argument( '-C', '--cuda', action='store_true', default=False, dest='cuda', help='only CUDA hosts ' )
  39. parser.add_argument( '-f', '--full', action='store_true', default=False, dest='full', help='empty, unreachable and unavailable info' )
  40. parser.add_argument( '-m', '--math', action='store_true', default=False, dest='math', help='only Mathematica hosts ' )
  41. parser.add_argument( '-n', action='store_true', default=False, dest='n', help='not display the progressbar and colors' )
  42. parser.add_argument( '-N', action='store_true', default=False, dest='N', help='also display number of logs' )
  43. parser.add_argument( '-v', '--version', action='version', version='%(prog)s 2.0', help='Print program version' )
  44. ####
  45. args = parser.parse_args()
  46. hosts=[]
  47. if (( args.lcm1 and args.lcm2 ) or args.condor ) : hosts = lcm1 + lcm2
  48. elif args.lcm1: hosts += lcm1
  49. elif args.lcm2: hosts += lcm2
  50. elif args.laur: hosts += laur
  51. elif args.cuda: hosts += cuda
  52. elif args.math: hosts += math
  53. else: hosts = lcm1 + lcm2 + laur + cuda
  54. if args.n:
  55. splitters = [('jake','LCM1'),('gin','LCM2'),('jacobi','CUDA'),('orion','LAUR')]
  56. progressbar = 0
  57. else:
  58. 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')]
  59. progressbar = 1
  60. # Define port
  61. port = 79
  62. #############################################
  63. # Node class
  64. # The bulk of the program is done here
  65. #############################################
  66. class Node(Thread):
  67. # Constructor
  68. def __init__(self,nome,port):
  69. # Fork the thread first thing
  70. Thread.__init__(self)
  71. # Variables initialization
  72. self.hostname = nome
  73. self.local = []
  74. self.remote = []
  75. self.lgod = []
  76. self.rgod = []
  77. # Former admins
  78. self.chuck = []
  79. # Node status
  80. self.up = True
  81. self.aval = True
  82. self.port = port
  83. self.timeout = False
  84. # Ping the host to see if it's up
  85. def isup(self):
  86. # Is the host up?
  87. ping = os.popen("ping -w1 -c1 "+self.hostname,"r")
  88. if "0 received" in ping.read():
  89. self.up = False
  90. return False
  91. else:
  92. return True
  93. # Open telnet connection
  94. def connect(self):
  95. # Try to connect first
  96. try:
  97. self.conn = telnetlib.Telnet(self.hostname,self.port)
  98. # Inetd is down!
  99. except error, msg:
  100. self.aval = False
  101. return False
  102. return True
  103. # Read lcm_w ouput and fill accordingly the users-gods lists
  104. def read(self):
  105. # Read data
  106. lista=''
  107. reachable=0
  108. try: lista = self.conn.read_until("EOF",1)
  109. except EOFError: reachable=1
  110. del self.conn
  111. if lista=='':
  112. if reachable == 0:
  113. self.timeout=True
  114. # Split lines and fields
  115. righe = lista.splitlines()
  116. # Needed later for isempty
  117. self.users = len(righe)
  118. # Local-remote-god user check
  119. for x in righe:
  120. fields = x.split()
  121. if "tty" in fields[1]:
  122. if fields[0] in gods:
  123. self.lgod.append(fields[0].lower())
  124. else:
  125. if fields[0] not in chucknorris:
  126. self.local.append(fields[0].lower())
  127. else:
  128. if fields[0] in gods:
  129. if fields[0] not in self.lgod:
  130. self.rgod.append(fields[0].lower())
  131. else:
  132. if fields[0] not in self.local:
  133. if fields[0] not in chucknorris:
  134. self.remote.append(fields[0].lower())
  135. # Former admins
  136. if fields[0] in chucknorris:
  137. self.chuck.append(fields[0].lower())
  138. # Run method
  139. # This is the part that every thread executes in parallel
  140. # If host is up -> open connection -> if connection -> read data
  141. def run(self):
  142. if self.isup():
  143. if self.connect():
  144. self.read()
  145. # Is the host empty?
  146. def isempty(self):
  147. if (self.users > 0):
  148. return False
  149. else:
  150. return True
  151. # Print output giorgio-style, host based (after threads have finished)
  152. def printlist(self):
  153. # Uniq equivalent and string conversion
  154. strlocal = ""
  155. strremote = ""
  156. strlgod = ""
  157. strrgod = ""
  158. strchuck = ""
  159. if not args.N:
  160. # A set cannot have duplicate entries: uniq equivalent
  161. for item in set(self.local):
  162. strlocal += str(item) + ' '
  163. for item in set(self.remote):
  164. strremote += str(item) +' '
  165. for item in set(self.lgod):
  166. strlgod += str(item) +' '
  167. for item in set(self.rgod):
  168. strrgod += str(item) +' '
  169. for item in set(self.chuck):
  170. strchuck += str(item) +' '
  171. else:
  172. # Print also how many times users are logged (added by jp)
  173. for item in set(self.local):
  174. strlocal += str(item) + '('+str(collections.Counter(self.local).values()[collections.Counter(self.local).keys().index(item)])+') '
  175. for item in set(self.remote):
  176. strremote += str(item) +'('+str(collections.Counter(self.remote).values()[collections.Counter(self.remote).keys().index(item)])+') '
  177. for item in set(self.lgod):
  178. strlgod += str(item) +'('+str(collections.Counter(self.lgod).values()[collections.Counter(self.lgod).keys().index(item)])+') '
  179. for item in set(self.rgod):
  180. strrgod += str(item) +'('+str(collections.Counter(self.rgod).values()[collections.Counter(self.rgod).keys().index(item)])+') '
  181. for item in set(self.chuck):
  182. strchuck += str(item) +'('+str(collections.Counter(self.chuck).values()[collections.Counter(self.chuck).keys().index(item)])+') '
  183. # Print a tag [C] aside CUDA hosts (jp)
  184. if self.hostname in cuda:
  185. self.hostname = self.hostname + ' '*(5-len(self.hostname))+'[C]'
  186. print ' ' + self.hostname + ' '*(15-len(self.hostname))+ red + strlgod + normal + pink + strrgod + normal + green + strlocal + normal + blue + strremote + normal+ turquoise+strchuck+normal
  187. ###################################################
  188. # Main
  189. ###################################################
  190. # Get user groups
  191. groups = os.popen("groups").readlines()[0].split()
  192. # Setting colors
  193. if progressbar > 0:
  194. red = "\033[1;31m"
  195. normal = "\033[0m"
  196. blue = "\033[1;34m"
  197. pink = "\033[1;35m"
  198. green = "\033[1;32m"
  199. turquoise ="\033[1;36m"
  200. else:
  201. red = ""
  202. normal = ""
  203. blue = ""
  204. pink = ""
  205. green = ""
  206. turquoise =""
  207. # Initialization of the four lists
  208. downlist = ""
  209. emptylist = ""
  210. unavlist = ""
  211. timeoutlist = ""
  212. # Initialize the threadlist
  213. threadlist = []
  214. # Number of hosts (for progressbar)
  215. num = len(hosts)
  216. # Start the threads
  217. for item in hosts:
  218. m=Node(item,port)
  219. threadlist.append(m)
  220. m.start()
  221. # Used for progressbar
  222. index = 0
  223. print ' Querying '+str(num)+' hosts...'
  224. # Rejoin them when their work is done
  225. for thread in threadlist:
  226. thread.join()
  227. if progressbar > 0:
  228. # Progessbar
  229. index += 1
  230. stdout.write('\r ['+'='*index+'>'*(1-int(index/num))+' '*(num-index-1)+']')
  231. stdout.flush()
  232. if progressbar > 0:
  233. # Newline
  234. print '\n Done... ( %(t).3f s)' % {'t': (time() - start)}
  235. # And now print!
  236. for thread in threadlist:
  237. # lcm1-lcm2-laur splitters
  238. for pair in splitters:
  239. if thread.hostname in pair[0]: print '-' + pair[1] + normal +'----'
  240. # See what they are up to and print accordingly
  241. if thread.hostname in cuda:
  242. thread.hostname +='[C]'
  243. if args.math :
  244. if thread.hostname in math4:
  245. thread.hostname +='[M4]'
  246. if thread.hostname in math5:
  247. thread.hostname +='[M5]'
  248. if not thread.up:
  249. # Host down
  250. downlist += thread.hostname + ' '
  251. else:
  252. if not thread.aval:
  253. # Host unavailable
  254. unavlist += thread.hostname + ' '
  255. continue
  256. if thread.timeout:
  257. # Thread has timed out
  258. timeoutlist += thread.hostname + ' '
  259. continue
  260. if thread.isempty():
  261. # Host is empty
  262. emptylist += thread.hostname + ' '
  263. else:
  264. thread.printlist()
  265. # Some final output
  266. if progressbar > 0:
  267. print
  268. print 'Legenda: '+green + 'utente locale '+normal+blue+'utente remoto '+normal+red+'admin locale '+normal+pink+'admin remoto '+normal+turquoise+'nirvana'+normal
  269. print " I nodi contrassegnati con [C] sono i nodi CUDA."
  270. if args.math:
  271. print " I nodi contrassegnati con [M4] hanno Mathematica 4.0"
  272. print " I nodi contrassegnati con [M5] hanno Mathematica 5.2"
  273. print
  274. # Only in full mode
  275. #if ("-f" in str(params[0])) or ("-F" in str(params[0])) or ("-m" in str(params[0])) or ("-C" in str(params[0])):
  276. if args.full or args.math or args.cuda:
  277. print red+'Empty: '+normal+emptylist
  278. print red+'Timeout: '+normal+timeoutlist
  279. print red+'Unreachable: '+normal+downlist
  280. print red+'Unavailable: '+normal+unavlist
  281. # Exit gracefully
  282. exit(0)