whoall 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  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. # siii, cioe', non avete proprio niente da fare, eh?
  93. #if fields[0] == "gian":
  94. # fields[0] = "gina"
  95. # fields[1] = "pts"
  96. # if fields[0] == "algebrato":
  97. # fields[0] = "stefanomandelli"
  98. # fields[1] = "pts"
  99. if "tty" in fields[1]:
  100. if fields[0] in gods:
  101. self.lgod.append(fields[0].lower())
  102. else:
  103. if fields[0] not in chucknorris:
  104. self.local.append(fields[0].lower())
  105. else:
  106. if fields[0] in gods:
  107. if fields[0] not in self.lgod:
  108. self.rgod.append(fields[0].lower())
  109. else:
  110. if fields[0] not in self.local:
  111. if fields[0] not in chucknorris:
  112. self.remote.append(fields[0].lower())
  113. #former admins
  114. if fields[0] in chucknorris:
  115. self.chuck.append(fields[0].lower())
  116. #run method
  117. #this is the part that every thread executes in parallel
  118. #if host is up -> open connection -> if connection -> read data
  119. def run(self):
  120. if self.isup():
  121. if self.connect():
  122. self.read()
  123. #is the host empty?
  124. def isempty(self):
  125. if (self.users > 0):
  126. return False
  127. else:
  128. return True
  129. #print output giorgio-style, host based (after threads have finished)
  130. def printlist(self):
  131. #uniq equivalent and string conversion
  132. strlocal = ""
  133. strremote = ""
  134. strlgod = ""
  135. strrgod = ""
  136. strchuck = ""
  137. if "-N" not in str(params[0]):
  138. #a set cannot have duplicate entries: uniq equivalent
  139. for item in set(self.local):
  140. strlocal += str(item) + ' '
  141. for item in set(self.remote):
  142. strremote += str(item) +' '
  143. for item in set(self.lgod):
  144. strlgod += str(item) +' '
  145. for item in set(self.rgod):
  146. strrgod += str(item) +' '
  147. for item in set(self.chuck):
  148. strchuck += str(item) +' '
  149. else:
  150. #print also how many times users are logged (added by jp)
  151. for item in set(self.local):
  152. strlocal += str(item) + '('+str(collections.Counter(self.local).values()[collections.Counter(self.local).keys().index(item)])+') '
  153. for item in set(self.remote):
  154. strremote += str(item) +'('+str(collections.Counter(self.remote).values()[collections.Counter(self.remote).keys().index(item)])+') '
  155. for item in set(self.lgod):
  156. strlgod += str(item) +'('+str(collections.Counter(self.lgod).values()[collections.Counter(self.lgod).keys().index(item)])+') '
  157. for item in set(self.rgod):
  158. strrgod += str(item) +'('+str(collections.Counter(self.rgod).values()[collections.Counter(self.rgod).keys().index(item)])+') '
  159. for item in set(self.chuck):
  160. strchuck += str(item) +'('+str(collections.Counter(self.chuck).values()[collections.Counter(self.chuck).keys().index(item)])+') '
  161. #routine that prints 64-bit nodes' names in yellow
  162. # if self.hostname in newcluster:
  163. # 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
  164. # else:
  165. #print a tag [C] aside CUDA hosts (jp)
  166. if self.hostname in cuda:
  167. self.hostname = self.hostname + ' '*(5-len(self.hostname))+'[C]'
  168. print ' ' + self.hostname + ' '*(15-len(self.hostname))+ red + strlgod + normal + pink + strrgod + normal + green + strlocal + normal + blue + strremote + normal+ turquoise+strchuck+normal
  169. ###################################################
  170. #main part
  171. ###################################################
  172. #get user groups
  173. groups = os.popen("groups").readlines()[0].split()
  174. #print usage info
  175. def Usage():
  176. print 'Usage: '+argv[0]+' [flags]'
  177. print ' -h\tthis help'
  178. print ' -f\tempty, unreachable and unavailable info'
  179. print ' -1\tonly LCM1 hosts'
  180. print ' -2\tonly LCM2 hosts'
  181. print ' -l\tonly LAUR hosts'
  182. print ' -C\tonly CUDA hosts'
  183. print ' -m\tonly mathematica hosts'
  184. print ' -c\tonly condor hosts'
  185. print ' -w\tonly hosts with cd burner'
  186. print ' -n\tnot display the progressbar and colors'
  187. print ' -N\talso display number of logs'
  188. exit(1)
  189. #getopt
  190. try: params = getopt.getopt(argv[1:],'12lcCmfhkFnwN')
  191. except getopt.GetoptError:
  192. print 'Wrong parameter'
  193. Usage()
  194. #help mode (-h)
  195. if "-h" in str(params[0]): Usage()
  196. #kurt mode
  197. port = 79
  198. if "-k" in str(params[0]): port = 799
  199. #default (no options given)
  200. 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')]
  201. progressbar = 1
  202. hosts = []
  203. #boring: define the various cases
  204. if "-1" in str(params[0]):
  205. hosts += lcm1
  206. if "-2" in str(params[0]):
  207. hosts += lcm2
  208. if "-l" in str(params[0]):
  209. hosts += laur
  210. if "-C" in str(params[0]):
  211. hosts += cuda
  212. if "-m" in str(params[0]):
  213. hosts += math
  214. #splitters = [('jake','LCM1'),('tilde','LCM2'),('wolfgang','LAUR')]
  215. if "-c" in str(params[0]):
  216. hosts = condor
  217. #splitters = [('jake','LCM1'),('gin','LCM2')]
  218. if "-w" in str(params[0]):
  219. hosts = masterizzatori
  220. #splitters = [('actarus','LCM1'),('z','LCM2')]
  221. if "-n" in str(params[0]):
  222. splitters = [('jake','LCM1'),('gin','LCM2'),('jacobi','CUDA'),('orion','LAUR')]
  223. progressbar = 0
  224. #commented lines: CUDA hosts are printed only once under section 'CUDA', not also under 'LCM1/2'
  225. #for i in cuda:
  226. # if i in lcm1:
  227. # lcm1=lcm1[:lcm1.index(i)]+lcm1[lcm1.index(i)+1:]
  228. # elif i in lcm2:
  229. # lcm2=lcm2[:lcm2.index(i)]+lcm2[lcm2.index(i)+1:]
  230. # elif i in laur:
  231. # laur=laur[:laur.index(i)]+laur[laur.index(i)+1:]
  232. #default behaviour (no options given)
  233. if (hosts == []):
  234. hosts = lcm1 + lcm2 + laur + cuda
  235. #setting colors
  236. if progressbar > 0:
  237. red = "\033[1;31m"
  238. normal = "\033[0m"
  239. blue = "\033[1;34m"
  240. pink = "\033[1;35m"
  241. green = "\033[1;32m"
  242. turquoise ="\033[1;36m"
  243. else:
  244. red = ""
  245. normal = ""
  246. blue = ""
  247. pink = ""
  248. green = ""
  249. turquoise =""
  250. #initialization of the four lists
  251. downlist = ""
  252. emptylist = ""
  253. unavlist = ""
  254. timeoutlist = ""
  255. #initialize the threadlist
  256. threadlist = []
  257. #number of hosts (for progressbar)
  258. num = len(hosts)
  259. #start the threads
  260. for item in hosts:
  261. m=Node(item,port)
  262. threadlist.append(m)
  263. m.start()
  264. #used for progressbar
  265. index = 0
  266. print ' Querying '+str(num)+' hosts...'
  267. #rejoin them when their work is done
  268. for thread in threadlist:
  269. thread.join()
  270. if progressbar > 0:
  271. #progessbar
  272. index += 1
  273. stdout.write('\r ['+'='*index+'>'*(1-int(index/num))+' '*(num-index-1)+']')
  274. stdout.flush()
  275. if progressbar > 0:
  276. #newline
  277. print '\n Done... ( %(t).3f s)' % {'t': (time() - start)}
  278. #and now print!
  279. for thread in threadlist:
  280. #lcm1-lcm2-laur splitters
  281. for pair in splitters:
  282. if thread.hostname in pair[0]: print '-' + pair[1] + normal +'----'
  283. #see what they are up to
  284. #and print accordingly
  285. if thread.hostname in cuda:
  286. thread.hostname +='[C]'
  287. if "-m" in str(params[0]):
  288. if thread.hostname in math4:
  289. thread.hostname +='[M4]'
  290. if thread.hostname in math5:
  291. thread.hostname +='[M5]'
  292. if not thread.up:
  293. #host down
  294. downlist += thread.hostname + ' '
  295. else:
  296. if not thread.aval:
  297. #host unavailable
  298. unavlist += thread.hostname + ' '
  299. continue
  300. if thread.timeout:
  301. #thread has timed out
  302. timeoutlist += thread.hostname + ' '
  303. continue
  304. if thread.isempty():
  305. #host is empty
  306. emptylist += thread.hostname + ' '
  307. else:
  308. thread.printlist()
  309. #some final output
  310. if progressbar > 0:
  311. print
  312. print 'Legenda: '+green + 'utente locale '+normal+blue+'utente remoto '+normal+red+'admin locale '+normal+pink+'admin remoto '+normal+turquoise+'nirvana'+normal
  313. print " I nodi contrassegnati con [C] sono i nodi CUDA."
  314. if "-m" in str(params[0]):
  315. print " I nodi contrassegnati con [M4] hanno Mathematica 4.0"
  316. print " I nodi contrassegnati con [M5] hanno Mathematica 5.2"
  317. # print " I nodi colorati in " + "\033[1;33mgiallo " + normal + "appartengono al cluster a 64bit"
  318. print
  319. #only in full mode
  320. if ("-f" in str(params[0])) or ("-F" in str(params[0])) or ("-m" in str(params[0])) or ("-C" in str(params[0])):
  321. print red+'Empty: '+normal+emptylist
  322. print red+'Timeout: '+normal+timeoutlist
  323. print red+'Unreachable: '+normal+downlist
  324. print red+'Unavailable: '+normal+unavlist
  325. #exit gracefully
  326. exit(0)