whoall 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. #!/usr/bin/env python2.7
  2. #python whoall
  3. #parallel, multi-threaded version
  4. #jacopogh - nov 2006
  5. #updated by various lcm admins & 150ers up to Nov 2015
  6. #requires python version 2.7 or above
  7. #please read the wiki before editing this file
  8. #take the starting time
  9. from time import time
  10. start = time()
  11. #import needed modules
  12. import telnetlib
  13. from sys import argv,exit,stdout
  14. import getopt
  15. import os
  16. from threading import Thread
  17. from socket import error
  18. import collections
  19. #important variables: gods, hosts and term colors
  20. gods = ['root','andreatsh','andreamalerba','lorenzouboldi','stefanobalzan','eugeniothieme']
  21. #former admins: bother them at your own risk
  22. 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']
  23. #riordinati in ordine alfabetico - jp
  24. lcm1 = ['abe','crash','duke','glados','lara','link','king','pang','pong','snake','sonic','spyro','yoshi']
  25. lcm2 = ['actarus','elwood','gex','gin','jake','kirk','martini','picard','q','raziel','sarek','spock','tron','worf','zombie']
  26. laur = ['eskimo','orion','tilde']
  27. cuda = ['jacobi','yukawa','tesla']
  28. math5 = ['abe','glados','link','king','pang','pong','snake','spyro','yoshi']
  29. math4 = ['sonic','crash','duke','raziel','actarus','gin','kirk','martini','picard','sarek','tron','worf','zombie','q','elwood','jake']
  30. math = math5 + math4
  31. condor = lcm1 + lcm2
  32. masterizzatori = ['crash','duke','spyro']
  33. #############################################
  34. #Node class
  35. #the bulk of the program is done here
  36. #############################################
  37. class Node(Thread):
  38. #constructor
  39. def __init__(self,nome,port):
  40. #fork the thread first thing
  41. Thread.__init__(self)
  42. #variable initialization
  43. self.hostname = nome
  44. self.local = []
  45. self.remote = []
  46. self.lgod = []
  47. self.rgod = []
  48. #former admins
  49. self.chuck = []
  50. #node status
  51. self.up = True
  52. self.aval = True
  53. self.port = port
  54. self.timeout = False
  55. #ping the host to see if it's up
  56. def isup(self):
  57. #is the host up?
  58. ping = os.popen("ping -w1 -c1 "+self.hostname,"r")
  59. if "0 received" in ping.read():
  60. self.up = False
  61. return False
  62. else:
  63. return True
  64. #open telnet connection
  65. def connect(self):
  66. #try to connect first
  67. try:
  68. self.conn = telnetlib.Telnet(self.hostname,self.port)
  69. #inetd is down!
  70. except error, msg:
  71. self.aval = False
  72. return False
  73. return True
  74. #read lcm_w ouput and fill accordingly the users-gods lists
  75. def read(self):
  76. #read data
  77. lista=''
  78. reachable=0
  79. try: lista = self.conn.read_until("EOF",1)
  80. except EOFError: reachable=1
  81. del self.conn
  82. if lista=='':
  83. if reachable == 0:
  84. self.timeout=True
  85. #split lines and fields
  86. righe = lista.splitlines()
  87. #needed later for isempty
  88. self.users = len(righe)
  89. #local-remote-god user check
  90. for x in righe:
  91. fields = x.split()
  92. if "tty" in fields[1]:
  93. if fields[0] in gods:
  94. self.lgod.append(fields[0].lower())
  95. else:
  96. if fields[0] not in chucknorris:
  97. self.local.append(fields[0].lower())
  98. else:
  99. if fields[0] in gods:
  100. if fields[0] not in self.lgod:
  101. self.rgod.append(fields[0].lower())
  102. else:
  103. if fields[0] not in self.local:
  104. if fields[0] not in chucknorris:
  105. self.remote.append(fields[0].lower())
  106. #former admins
  107. if fields[0] in chucknorris:
  108. self.chuck.append(fields[0].lower())
  109. #run method
  110. #this is the part that every thread executes in parallel
  111. #if host is up -> open connection -> if connection -> read data
  112. def run(self):
  113. if self.isup():
  114. if self.connect():
  115. self.read()
  116. #is the host empty?
  117. def isempty(self):
  118. if (self.users > 0):
  119. return False
  120. else:
  121. return True
  122. #print output giorgio-style, host based (after threads have finished)
  123. def printlist(self):
  124. #uniq equivalent and string conversion
  125. strlocal = ""
  126. strremote = ""
  127. strlgod = ""
  128. strrgod = ""
  129. strchuck = ""
  130. if "-N" not in str(params[0]):
  131. #a set cannot have duplicate entries: uniq equivalent
  132. for item in set(self.local):
  133. strlocal += str(item) + ' '
  134. for item in set(self.remote):
  135. strremote += str(item) +' '
  136. for item in set(self.lgod):
  137. strlgod += str(item) +' '
  138. for item in set(self.rgod):
  139. strrgod += str(item) +' '
  140. for item in set(self.chuck):
  141. strchuck += str(item) +' '
  142. else:
  143. #print also how many times users are logged (added by jp)
  144. for item in set(self.local):
  145. strlocal += str(item) + '('+str(collections.Counter(self.local).values()[collections.Counter(self.local).keys().index(item)])+') '
  146. for item in set(self.remote):
  147. strremote += str(item) +'('+str(collections.Counter(self.remote).values()[collections.Counter(self.remote).keys().index(item)])+') '
  148. for item in set(self.lgod):
  149. strlgod += str(item) +'('+str(collections.Counter(self.lgod).values()[collections.Counter(self.lgod).keys().index(item)])+') '
  150. for item in set(self.rgod):
  151. strrgod += str(item) +'('+str(collections.Counter(self.rgod).values()[collections.Counter(self.rgod).keys().index(item)])+') '
  152. for item in set(self.chuck):
  153. strchuck += str(item) +'('+str(collections.Counter(self.chuck).values()[collections.Counter(self.chuck).keys().index(item)])+') '
  154. #routine that prints 64-bit nodes' names in yellow
  155. # if self.hostname in newcluster:
  156. # print ' ' + "\033[1;33m" + self.hostname + ' '*(15-len(self.hostname))+ red + strlgod + normal + pink + strrgod + normal + green + strlocal + normal + blue + strremote + normal+ turquoise+strchuck+normal
  157. # else:
  158. #print a tag [C] aside CUDA hosts (jp)
  159. if self.hostname in cuda:
  160. self.hostname = self.hostname + ' '*(5-len(self.hostname))+'[C]'
  161. print ' ' + self.hostname + ' '*(15-len(self.hostname))+ red + strlgod + normal + pink + strrgod + normal + green + strlocal + normal + blue + strremote + normal+ turquoise+strchuck+normal
  162. ###################################################
  163. #main part
  164. ###################################################
  165. #get user groups
  166. groups = os.popen("groups").readlines()[0].split()
  167. #print usage info
  168. def Usage():
  169. print 'Usage: '+argv[0]+' [flags]'
  170. print ' -h\tthis help'
  171. print ' -f\tempty, unreachable and unavailable info'
  172. print ' -1\tonly LCM1 hosts'
  173. print ' -2\tonly LCM2 hosts'
  174. print ' -l\tonly LAUR hosts'
  175. print ' -C\tonly CUDA hosts'
  176. print ' -m\tonly mathematica hosts'
  177. print ' -c\tonly condor hosts'
  178. print ' -w\tonly hosts with cd burner'
  179. print ' -n\tnot display the progressbar and colors'
  180. print ' -N\talso display number of logs'
  181. exit(1)
  182. #getopt
  183. try: params = getopt.getopt(argv[1:],'12lcCmfhkFnwN')
  184. except getopt.GetoptError:
  185. print 'Wrong parameter'
  186. Usage()
  187. #help mode (-h)
  188. if "-h" in str(params[0]): Usage()
  189. #kurt mode
  190. port = 79
  191. if "-k" in str(params[0]): port = 799
  192. #default (no options given)
  193. 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')]
  194. progressbar = 1
  195. hosts = []
  196. #boring: define the various cases
  197. if "-1" in str(params[0]):
  198. hosts += lcm1
  199. if "-2" in str(params[0]):
  200. hosts += lcm2
  201. if "-l" in str(params[0]):
  202. hosts += laur
  203. if "-C" in str(params[0]):
  204. hosts += cuda
  205. if "-m" in str(params[0]):
  206. hosts += math
  207. #splitters = [('jake','LCM1'),('tilde','LCM2'),('wolfgang','LAUR')]
  208. if "-c" in str(params[0]):
  209. hosts = condor
  210. #splitters = [('jake','LCM1'),('gin','LCM2')]
  211. if "-w" in str(params[0]):
  212. hosts = masterizzatori
  213. #splitters = [('actarus','LCM1'),('z','LCM2')]
  214. if "-n" in str(params[0]):
  215. splitters = [('jake','LCM1'),('gin','LCM2'),('jacobi','CUDA'),('orion','LAUR')]
  216. progressbar = 0
  217. #commented lines: CUDA hosts are printed only once under section 'CUDA', not also under 'LCM1/2'
  218. #for i in cuda:
  219. # if i in lcm1:
  220. # lcm1=lcm1[:lcm1.index(i)]+lcm1[lcm1.index(i)+1:]
  221. # elif i in lcm2:
  222. # lcm2=lcm2[:lcm2.index(i)]+lcm2[lcm2.index(i)+1:]
  223. # elif i in laur:
  224. # laur=laur[:laur.index(i)]+laur[laur.index(i)+1:]
  225. #default behaviour (no options given)
  226. if (hosts == []):
  227. hosts = lcm1 + lcm2 + laur + cuda
  228. #setting colors
  229. if progressbar > 0:
  230. red = "\033[1;31m"
  231. normal = "\033[0m"
  232. blue = "\033[1;34m"
  233. pink = "\033[1;35m"
  234. green = "\033[1;32m"
  235. turquoise ="\033[1;36m"
  236. else:
  237. red = ""
  238. normal = ""
  239. blue = ""
  240. pink = ""
  241. green = ""
  242. turquoise =""
  243. #initialization of the four lists
  244. downlist = ""
  245. emptylist = ""
  246. unavlist = ""
  247. timeoutlist = ""
  248. #initialize the threadlist
  249. threadlist = []
  250. #number of hosts (for progressbar)
  251. num = len(hosts)
  252. #start the threads
  253. for item in hosts:
  254. m=Node(item,port)
  255. threadlist.append(m)
  256. m.start()
  257. #used for progressbar
  258. index = 0
  259. print ' Querying '+str(num)+' hosts...'
  260. #rejoin them when their work is done
  261. for thread in threadlist:
  262. thread.join()
  263. if progressbar > 0:
  264. #progessbar
  265. index += 1
  266. stdout.write('\r ['+'='*index+'>'*(1-int(index/num))+' '*(num-index-1)+']')
  267. stdout.flush()
  268. if progressbar > 0:
  269. #newline
  270. print '\n Done... ( %(t).3f s)' % {'t': (time() - start)}
  271. #and now print!
  272. for thread in threadlist:
  273. #lcm1-lcm2-laur splitters
  274. for pair in splitters:
  275. if thread.hostname in pair[0]: print '-' + pair[1] + normal +'----'
  276. #see what they are up to
  277. #and print accordingly
  278. if thread.hostname in cuda:
  279. thread.hostname +='[C]'
  280. if "-m" in str(params[0]):
  281. if thread.hostname in math4:
  282. thread.hostname +='[M4]'
  283. if thread.hostname in math5:
  284. thread.hostname +='[M5]'
  285. if not thread.up:
  286. #host down
  287. downlist += thread.hostname + ' '
  288. else:
  289. if not thread.aval:
  290. #host unavailable
  291. unavlist += thread.hostname + ' '
  292. continue
  293. if thread.timeout:
  294. #thread has timed out
  295. timeoutlist += thread.hostname + ' '
  296. continue
  297. if thread.isempty():
  298. #host is empty
  299. emptylist += thread.hostname + ' '
  300. else:
  301. thread.printlist()
  302. #some final output
  303. if progressbar > 0:
  304. print
  305. print 'Legenda: '+green + 'utente locale '+normal+blue+'utente remoto '+normal+red+'admin locale '+normal+pink+'admin remoto '+normal+turquoise+'nirvana'+normal
  306. print " I nodi contrassegnati con [C] sono i nodi CUDA."
  307. if "-m" in str(params[0]):
  308. print " I nodi contrassegnati con [M4] hanno Mathematica 4.0"
  309. print " I nodi contrassegnati con [M5] hanno Mathematica 5.2"
  310. # print " I nodi colorati in " + "\033[1;33mgiallo " + normal + "appartengono al cluster a 64bit"
  311. print
  312. #only in full mode
  313. if ("-f" in str(params[0])) or ("-F" in str(params[0])) or ("-m" in str(params[0])) or ("-C" in str(params[0])):
  314. print red+'Empty: '+normal+emptylist
  315. print red+'Timeout: '+normal+timeoutlist
  316. print red+'Unreachable: '+normal+downlist
  317. print red+'Unavailable: '+normal+unavlist
  318. #exit gracefully
  319. exit(0)