AM nagios/plc2nagios.py
[monitor.git] / reboot.py
1 #!/usr/bin/python
2 #
3 # Reboot specified nodes
4 #
5
6 import getpass, getopt
7 import os, sys
8 import xml, xmlrpclib
9 import errno, time, traceback
10 import urllib2
11 import urllib
12 import threading, popen2
13 import array, struct
14 #from socket import *
15 import socket
16 import plc
17 import base64
18 from subprocess import PIPE, Popen
19 import ssh.pxssh as pxssh
20 import ssh.pexpect as pexpect
21 import socket
22
23 # Use our versions of telnetlib and pyssh
24 sys.path.insert(0, os.path.dirname(sys.argv[0]))
25 import telnetlib
26 sys.path.insert(0, os.path.dirname(sys.argv[0]) + "/pyssh")    
27 import pyssh
28
29 # Timeouts in seconds
30 TELNET_TIMEOUT = 45
31
32 # Event class ID from pcu events
33 #NODE_POWER_CONTROL = 3
34
35 # Monitor user ID
36 #MONITOR_USER_ID = 11142
37
38 import logging
39 logger = logging.getLogger("monitor")
40 verbose = 1
41 #dryrun = 0;
42
43 class ExceptionNoTransport(Exception): pass
44 class ExceptionNotFound(Exception): pass
45 class ExceptionPassword(Exception): pass
46 class ExceptionTimeout(Exception): pass
47 class ExceptionPrompt(Exception): pass
48 class ExceptionSequence(Exception): pass
49 class ExceptionReset(Exception): pass
50 class ExceptionPort(Exception): pass
51 class ExceptionUsername(Exception): pass
52
53 def telnet_answer(telnet, expected, buffer):
54         global verbose
55
56         output = telnet.read_until(expected, TELNET_TIMEOUT)
57         #if verbose:
58         #       logger.debug(output)
59         if output.find(expected) == -1:
60                 raise ExceptionNotFound, "'%s' not found" % expected
61         else:
62                 telnet.write(buffer + "\r\n")
63
64
65 # PCU has model, host, preferred-port, user, passwd, 
66
67 # This is an object derived directly form the PLCAPI DB fields
68 class PCU(object):
69         def __init__(self, plc_pcu_dict):
70                 for field in ['username', 'password', 'site_id', 
71                                                 'hostname', 'ip', 
72                                                 'pcu_id', 'model', 
73                                                 'node_ids', 'ports', ]:
74                         if field in plc_pcu_dict:
75                                 self.__setattr__(field, plc_pcu_dict[field])
76                         else:
77                                 raise Exception("No such field %s in PCU object" % field)
78
79 # These are the convenience functions build around the PCU object.
80 class PCUModel(PCU):
81         def __init__(self, plc_pcu_dict):
82                 PCU.__init__(self, plc_pcu_dict)
83                 self.host = self.pcu_name()
84
85         def pcu_name(self):
86                 if self.hostname is not None and self.hostname is not "":
87                         return self.hostname
88                 elif self.ip is not None and self.ip is not "":
89                         return self.ip
90                 else:
91                         return None
92
93         def nodeidToPort(self, node_id):
94                 if node_id in self.node_ids:
95                         for i in range(0, len(self.node_ids)):
96                                 if node_id == self.node_ids[i]:
97                                         return self.ports[i]
98
99                 raise Exception("No such Node ID: %d" % node_id)
100
101 # This class captures the observed pcu records from FindBadPCUs.py
102 class PCURecord:
103         def __init__(self, pcu_record_dict):
104                 for field in ['nodenames', 'portstatus', 
105                                                 'dnsmatch', 
106                                                 'complete_entry', ]:
107                         if field in pcu_record_dict:
108                                 if field == "reboot":
109                                         self.__setattr__("reboot_str", pcu_record_dict[field])
110                                 else:
111                                         self.__setattr__(field, pcu_record_dict[field])
112                         else:
113                                 raise Exception("No such field %s in pcu record dict" % field)
114
115 class Transport:
116         TELNET = 1
117         SSH    = 2
118         HTTP   = 3
119         IPAL   = 4
120
121         TELNET_TIMEOUT = 60
122
123         def __init__(self, type, verbose):
124                 self.type = type
125                 self.verbose = verbose
126                 self.transport = None
127
128         def open(self, host, username=None, password=None, prompt="User Name"):
129                 transport = None
130
131                 if self.type == self.TELNET:
132                         transport = telnetlib.Telnet(host, timeout=self.TELNET_TIMEOUT)
133                         transport.set_debuglevel(self.verbose)
134                         if username is not None:
135                                 self.transport = transport
136                                 self.ifThenSend(prompt, username, ExceptionUsername)
137
138                 elif self.type == self.SSH:
139                         if username is not None:
140                                 transport = pyssh.Ssh(username, host)
141                                 transport.set_debuglevel(self.verbose)
142                                 transport.open()
143                                 # TODO: have an ssh set_debuglevel() also...
144                         else:
145                                 raise Exception("Username cannot be None for ssh transport.")
146                 elif self.type == self.HTTP:
147                         self.url = "http://%s:%d/" % (host,80)
148                         uri = "%s:%d" % (host,80)
149
150                         # create authinfo
151                         authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm()
152                         authinfo.add_password (None, uri, username, password)
153                         authhandler = urllib2.HTTPBasicAuthHandler( authinfo )
154
155                         transport = urllib2.build_opener(authhandler)
156
157                 else:
158                         raise Exception("Unknown transport type: %s" % self.type)
159
160                 self.transport = transport
161                 return True
162
163         def close(self):
164                 if self.type == self.TELNET:
165                         self.transport.close() 
166                 elif self.type == self.SSH:
167                         self.transport.close() 
168                 elif self.type == self.HTTP:
169                         pass
170                 else:
171                         raise Exception("Unknown transport type %s" % self.type)
172                 self.transport = None
173
174         def sendHTTP(self, resource, data):
175                 if self.verbose:
176                         print "POSTing '%s' to %s" % (data,self.url + resource)
177
178                 try:
179                         f = self.transport.open(self.url + resource ,data)
180                         r = f.read()
181                         if self.verbose:
182                                 print r
183
184                 except urllib2.URLError,err:
185                         logger.info('Could not open http connection', err)
186                         return "http transport error"
187
188                 return 0
189
190         def sendPassword(self, password, prompt=None):
191                 if self.type == self.TELNET:
192                         if prompt == None:
193                                 self.ifThenSend("Password", password, ExceptionPassword)
194                         else:
195                                 self.ifThenSend(prompt, password, ExceptionPassword)
196                 elif self.type == self.SSH:
197                         self.ifThenSend("password:", password, ExceptionPassword)
198                 elif self.type == self.HTTP:
199                         pass
200                 else:
201                         raise Exception("Unknown transport type: %s" % self.type)
202
203         def ifThenSend(self, expected, buffer, ErrorClass=ExceptionPrompt):
204
205                 if self.transport != None:
206                         output = self.transport.read_until(expected, self.TELNET_TIMEOUT)
207                         if output.find(expected) == -1:
208                                 raise ErrorClass, "'%s' not found" % expected
209                         else:
210                                 self.transport.write(buffer + "\r\n")
211                 else:
212                         raise ExceptionNoTransport("transport object is type None")
213
214         def ifElse(self, expected, ErrorClass):
215                 try:
216                         self.transport.read_until(expected, self.TELNET_TIMEOUT)
217                 except:
218                         raise ErrorClass("Could not find '%s' within timeout" % expected)
219                         
220
221 class PCUControl(Transport,PCUModel,PCURecord):
222         def __init__(self, plc_pcu_record, verbose, supported_ports=[]):
223                 PCUModel.__init__(self, plc_pcu_record)
224                 PCURecord.__init__(self, plc_pcu_record)
225                 type = None
226                 if self.portstatus:
227                         if '22' in supported_ports and self.portstatus['22'] == "open":
228                                 type = Transport.SSH
229                         elif '23' in supported_ports and self.portstatus['23'] == "open":
230                                 type = Transport.TELNET
231                         elif '80' in supported_ports and self.portstatus['80'] == "open":
232                                 type = Transport.HTTP
233                         elif '443' in supported_ports and self.portstatus['443'] == "open":
234                                 type = Transport.HTTP
235                         elif '5869' in supported_ports and self.portstatus['5869'] == "open":
236                                 # For DRAC cards. Racadm opens this port.
237                                 type = Transport.HTTP
238                         elif '9100' in supported_ports and self.portstatus['9100'] == "open":
239                                 type = Transport.IPAL
240                         elif '16992' in supported_ports and self.portstatus['16992'] == "open":
241                                 type = Transport.HTTP
242                         else:
243                                 raise ExceptionPort("Unsupported Port: No transport from open ports")
244                 else:
245                         raise Exception("No Portstatus: No transport because no open ports")
246                 Transport.__init__(self, type, verbose)
247
248         def run(self, node_port, dryrun):
249                 """ This function is to be defined by the specific PCU instance.  """
250                 pass
251                 
252         def reboot(self, node_port, dryrun):
253                 try:
254                         return self.run(node_port, dryrun)
255                 except ExceptionNotFound, err:
256                         return "error: " + str(err)
257                 except ExceptionPassword, err:
258                         return "password exception: " + str(err)
259                 except ExceptionTimeout, err:
260                         return "timeout exception: " + str(err)
261                 except ExceptionUsername, err:
262                         return "exception: no username prompt: " + str(err)
263                 except ExceptionSequence, err:
264                         return "sequence error: " + str(err)
265                 except ExceptionPrompt, err:
266                         return "prompt exception: " + str(err)
267                 except ExceptionPort, err:
268                         return "no ports exception: " + str(err)
269                 except socket.error, err:
270                         return "socket error: timeout: " + str(err)
271                 except EOFError, err:
272                         if self.verbose:
273                                 logger.debug("reboot: EOF")
274                                 logger.debug(err)
275                         self.transport.close()
276                         import traceback
277                         traceback.print_exc()
278                         return "EOF connection reset" + str(err)
279                 
280 class IPAL(PCUControl):
281         """ 
282                 This now uses a proprietary format for communicating with the PCU.  I
283                 prefer it to Telnet, and Web access, since it's much lighter weight
284                 and, more importantly, IT WORKS!! HHAHHHAHAHAHAHAHA!
285         """
286
287         def format_msg(self, data, cmd):
288                 esc = chr(int('1b',16))
289                 return "%c%s%c%s%c" % (esc, self.password, esc, data, cmd) # esc, 'q', chr(4))
290         
291         def recv_noblock(self, s, count):
292                 import errno
293
294                 try:
295                         # TODO: make sleep backoff, before stopping.
296                         time.sleep(4)
297                         ret = s.recv(count, socket.MSG_DONTWAIT)
298                 except socket.error, e:
299                         if e[0] == errno.EAGAIN:
300                                 raise Exception(e[1])
301                         else:
302                                 # TODO: not other exceptions.
303                                 raise Exception(e)
304                 return ret
305
306         def run(self, node_port, dryrun):
307                 import errno
308
309                 power_on = False
310
311                 print "open socket"
312                 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
313                 try:
314                         print "connect"
315                         s.connect((self.host, 9100))
316                 except socket.error, e:
317                         s.close()
318                         if e[0] == errno.ECONNREFUSED:
319                                 # cannot connect to remote host
320                                 raise Exception(e[1])
321                         else:
322                                 # TODO: what other conditions are there?
323                                 raise Exception(e)
324                                 
325                 # get current status
326                 print "Checking status"
327                 s.send(self.format_msg("", 'O'))
328                 ret = self.recv_noblock(s, 8)
329                 print "Current status is '%s'" % ret
330
331                 if ret == '':
332                         raise Exception("Status returned 'another session already open' %s : %s" % (node_port, ret))
333                         
334                                 
335                 if node_port < len(ret):
336                         status = ret[node_port]
337                         if status == '1':
338                                 # up
339                                 power_on = True
340                         elif status == '0':
341                                 # down
342                                 power_on = False
343                         else:
344                                 raise Exception("Unknown status for PCU socket %s : %s" % (node_port, ret))
345                 else:
346                         raise Exception("Mismatch between configured port and PCU status: %s %s" % (node_port, ret))
347                         
348
349                 if not dryrun:
350                         if power_on:
351                                 print "Pulsing %s" % node_port
352                                 s.send(self.format_msg("%s" % node_port, 'P'))
353                         else:
354                                 # NOTE: turn power on ; do not pulse the port.
355                                 print "Power was off, so turning on ..."
356                                 s.send(self.format_msg("%s" % node_port, 'E'))
357                                 #s.send(self.format_msg("%s" % node_port, 'P'))
358
359                         print "Receiving response."
360                         ret = self.recv_noblock(s, 8)
361                         print "Current status is '%s'" % ret
362
363                         if node_port < len(ret):
364                                 status = ret[node_port]
365                                 if status == '1':
366                                         # up
367                                         power_on = True
368                                 elif status == '0':
369                                         # down
370                                         power_on = False
371                                 else:
372                                         raise Exception("Unknown status for PCU socket %s : %s" % (node_port, ret))
373                         else:
374                                 raise Exception("Mismatch between configured port and PCU status: %s %s" % (node_port, ret))
375
376                         if power_on:
377                                 return 0
378                         else:
379                                 return "Failed Power On"
380
381                 s.close()
382                 return 0
383
384 # TELNET version of protocol...
385 #               #self.open(self.host)
386 #               ## XXX Some iPals require you to hit Enter a few times first
387 #               #self.ifThenSend("Password >", "\r\n\r\n", ExceptionNotFound)
388 #               # Login
389 #               self.ifThenSend("Password >", self.password, ExceptionPassword)
390 #               self.transport.write("\r\n\r\n")
391 #               if not dryrun: # P# - Pulse relay
392 #                       print "node_port %s" % node_port
393 #                       self.ifThenSend("Enter >", 
394 #                                                       "P7", # % node_port, 
395 #                                                       ExceptionNotFound)
396 #                       print "send newlines"
397 #                       self.transport.write("\r\n\r\n")
398 #                       print "after new lines"
399 #               # Get the next prompt
400 #               print "wait for enter"
401 #               self.ifElse("Enter >", ExceptionTimeout)
402 #               print "closing "
403 #               self.close()
404 #               return 0
405
406 class APCEurope(PCUControl):
407         def run(self, node_port, dryrun):
408                 self.open(self.host, self.username)
409                 self.sendPassword(self.password)
410
411                 self.ifThenSend("\r\n> ", "1", ExceptionPassword)
412                 self.ifThenSend("\r\n> ", "2")
413                 self.ifThenSend("\r\n> ", str(node_port))
414                 # 3- Immediate Reboot             
415                 self.ifThenSend("\r\n> ", "3")
416
417                 if not dryrun:
418                         self.ifThenSend("Enter 'YES' to continue or <ENTER> to cancel", 
419                                                         "YES\r\n",
420                                                         ExceptionSequence)
421                 else:
422                         self.ifThenSend("Enter 'YES' to continue or <ENTER> to cancel", 
423                                                         "", ExceptionSequence)
424                 self.ifThenSend("Press <ENTER> to continue...", "", ExceptionSequence)
425
426                 self.close()
427                 return 0
428
429 class APCBrazil(PCUControl):
430         def run(self, node_port, dryrun):
431                 self.open(self.host, self.username)
432                 self.sendPassword(self.password)
433
434                 self.ifThenSend("\r\n> ", "1", ExceptionPassword)
435                 self.ifThenSend("\r\n> ", str(node_port))
436                 # 4- Immediate Reboot             
437                 self.ifThenSend("\r\n> ", "4")
438
439                 if not dryrun:
440                         self.ifThenSend("Enter 'YES' to continue or <ENTER> to cancel", 
441                                                         "YES\r\n",
442                                                         ExceptionSequence)
443                 else:
444                         self.ifThenSend("Enter 'YES' to continue or <ENTER> to cancel", 
445                                                         "", ExceptionSequence)
446                 self.ifThenSend("Press <ENTER> to continue...", "", ExceptionSequence)
447
448                 self.close()
449                 return 0
450
451 class APCBerlin(PCUControl):
452         def run(self, node_port, dryrun):
453                 self.open(self.host, self.username)
454                 self.sendPassword(self.password)
455
456                 self.ifThenSend("\r\n> ", "1", ExceptionPassword)
457                 self.ifThenSend("\r\n> ", "2")
458                 self.ifThenSend("\r\n> ", "1")
459                 self.ifThenSend("\r\n> ", str(node_port))
460                 # 3- Immediate Reboot             
461                 self.ifThenSend("\r\n> ", "3")
462
463                 if not dryrun:
464                         self.ifThenSend("Enter 'YES' to continue or <ENTER> to cancel", 
465                                                         "YES\r\n",
466                                                         ExceptionSequence)
467                 else:
468                         self.ifThenSend("Enter 'YES' to continue or <ENTER> to cancel", 
469                                                         "", ExceptionSequence)
470                 self.ifThenSend("Press <ENTER> to continue...", "", ExceptionSequence)
471
472                 self.close()
473                 return 0
474
475 class APCFolsom(PCUControl):
476         def run(self, node_port, dryrun):
477                 self.open(self.host, self.username)
478                 self.sendPassword(self.password)
479
480                 self.ifThenSend("\r\n> ", "1", ExceptionPassword)
481                 self.ifThenSend("\r\n> ", "2")
482                 self.ifThenSend("\r\n> ", "1")
483                 self.ifThenSend("\r\n> ", str(node_port))
484                 self.ifThenSend("\r\n> ", "1")
485
486                 # 3- Immediate Reboot             
487                 self.ifThenSend("\r\n> ", "3")
488
489                 if not dryrun:
490                         self.ifThenSend("Enter 'YES' to continue or <ENTER> to cancel", 
491                                                         "YES\r\n",
492                                                         ExceptionSequence)
493                 else:
494                         self.ifThenSend("Enter 'YES' to continue or <ENTER> to cancel", 
495                                                         "", ExceptionSequence)
496                 self.ifThenSend("Press <ENTER> to continue...", "", ExceptionSequence)
497
498                 self.close()
499                 return 0
500
501 class APCMaster(PCUControl):
502         def run(self, node_port, dryrun):
503                 print "Rebooting %s" % self.host
504                 self.open(self.host, self.username)
505                 self.sendPassword(self.password)
506
507                 # 1- Device Manager
508                 self.ifThenSend("\r\n> ", "1", ExceptionPassword)
509                 # 3- Outlet Control/Config
510                 self.ifThenSend("\r\n> ", "3")
511                 # n- Outlet n
512                 self.ifThenSend("\r\n> ", str(node_port))
513                 # 1- Control Outlet
514                 self.ifThenSend("\r\n> ", "1")
515                 # 3- Immediate Reboot             
516                 self.ifThenSend("\r\n> ", "3")
517
518                 if not dryrun:
519                         self.ifThenSend("Enter 'YES' to continue or <ENTER> to cancel", 
520                                                         "YES\r\n",
521                                                         ExceptionSequence)
522                 else:
523                         self.ifThenSend("Enter 'YES' to continue or <ENTER> to cancel", 
524                                                         "", ExceptionSequence)
525                 self.ifThenSend("Press <ENTER> to continue...", "", ExceptionSequence)
526
527                 self.close()
528                 return 0
529
530 class APC(PCUControl):
531         def __init__(self, plc_pcu_record, verbose):
532                 PCUControl.__init__(self, plc_pcu_record, verbose)
533
534                 self.master = APCMaster(plc_pcu_record, verbose)
535                 self.folsom = APCFolsom(plc_pcu_record, verbose)
536                 self.europe = APCEurope(plc_pcu_record, verbose)
537
538         def run(self, node_port, dryrun):
539                 try_again = True
540                 sleep_time = 1
541
542                 for pcu in [self.master, self.europe, self.folsom]:
543                         if try_again:
544                                 try:
545                                         print "-*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*"
546                                         try_again = False
547                                         print "sleeping 5"
548                                         time.sleep(sleep_time)
549                                         ret = pcu.reboot(node_port, dryrun)
550                                 except ExceptionSequence, err:
551                                         del pcu
552                                         sleep_time = 130
553                                         try_again = True
554
555                 if try_again:
556                         return "Unknown reboot sequence for APC PCU"
557                 else:
558                         return ret
559
560 class IntelAMT(PCUControl):
561         def run(self, node_port, dryrun):
562                 import soltesz
563
564                 cmd = soltesz.CMD()
565                 #[cmd_str = "IntelAMTSDK/Samples/RemoteControl/remoteControl"
566                 cmd_str = "cmdamt/remoteControl"
567
568                 if dryrun:
569                         # NOTE: -p checks the power state of the host.
570                         # TODO: parse the output to find out if it's ok or not.
571                         cmd_str += " -p http://%s:16992/RemoteControlService  -user admin -pass '%s' " % (self.host, self.password )
572                 else:
573                         cmd_str += " -A http://%s:16992/RemoteControlService -user admin -pass '%s' " % (self.host, self.password )
574                         
575                 print cmd_str
576                 return cmd.system(cmd_str, self.TELNET_TIMEOUT)
577
578 class DRACRacAdm(PCUControl):
579         def run(self, node_port, dryrun):
580
581                 print "trying racadm_reboot..."
582                 racadm_reboot(self.host, self.username, self.password, node_port, dryrun)
583
584                 return 0
585
586 class DRAC(PCUControl):
587         def run(self, node_port, dryrun):
588                 self.open(self.host, self.username)
589                 self.sendPassword(self.password)
590
591                 print "logging in..."
592                 self.transport.write("\r\n")
593                 # Testing Reboot ?
594                 if dryrun:
595                         self.ifThenSend("[%s]#" % self.username, "getsysinfo")
596                 else:
597                         # Reset this machine
598                         self.ifThenSend("[%s]#" % self.username, "serveraction powercycle")
599
600                 self.ifThenSend("[%s]#" % self.username, "exit")
601
602                 self.close()
603                 return 0
604
605 class HPiLO(PCUControl):
606         def run(self, node_port, dryrun):
607                 self.open(self.host, self.username)
608                 self.sendPassword(self.password)
609
610                 # </>hpiLO-> 
611                 self.ifThenSend("</>hpiLO->", "cd system1")
612
613                 # Reboot Outlet  N        (Y/N)?
614                 if dryrun:
615                         self.ifThenSend("</system1>hpiLO->", "POWER")
616                 else:
617                         # Reset this machine
618                         self.ifThenSend("</system1>hpiLO->", "reset")
619
620                 self.ifThenSend("</system1>hpiLO->", "exit")
621
622                 self.close()
623                 return 0
624
625                 
626 class HPiLOHttps(PCUControl):
627         def run(self, node_port, dryrun):
628                 import soltesz
629
630                 locfg = soltesz.CMD()
631                 cmd = "cmdhttps/locfg.pl -s %s -f %s -u %s -p '%s' | grep 'MESSAGE' | grep -v 'No error'" % (
632                                         self.host, "iloxml/Get_Network.xml", 
633                                         self.username, self.password)
634                 sout, serr = locfg.run_noexcept(cmd)
635
636                 if sout.strip() != "":
637                         print "sout: %s" % sout.strip()
638                         return sout.strip()
639
640                 if not dryrun:
641                         locfg = soltesz.CMD()
642                         cmd = "cmdhttps/locfg.pl -s %s -f %s -u %s -p '%s' | grep 'MESSAGE' | grep -v 'No error'" % (
643                                                 self.host, "iloxml/Reset_Server.xml", 
644                                                 self.username, self.password)
645                         sout, serr = locfg.run_noexcept(cmd)
646
647                         if sout.strip() != "":
648                                 print "sout: %s" % sout.strip()
649                                 #return sout.strip()
650                 return 0
651
652 class BayTechAU(PCUControl):
653         def run(self, node_port, dryrun):
654                 self.open(self.host, self.username, None, "Enter user name:")
655                 self.sendPassword(self.password, "Enter Password:")
656
657                 #self.ifThenSend("RPC-16>", "Status")
658                 self.ifThenSend("RPC3-NC>", "Reboot %d" % node_port)
659
660                 # Reboot Outlet  N        (Y/N)?
661                 if dryrun:
662                         self.ifThenSend("(Y/N)?", "N")
663                 else:
664                         self.ifThenSend("(Y/N)?", "Y")
665                 self.ifThenSend("RPC3-NC>", "")
666
667                 self.close()
668                 return 0
669
670 class BayTechGeorgeTown(PCUControl):
671         def run(self, node_port, dryrun):
672                 self.open(self.host, self.username, None, "Enter user name:")
673                 self.sendPassword(self.password, "Enter Password:")
674
675                 #self.ifThenSend("RPC-16>", "Status")
676
677                 self.ifThenSend("RPC-16>", "Reboot %d" % node_port)
678
679                 # Reboot Outlet  N        (Y/N)?
680                 if dryrun:
681                         self.ifThenSend("(Y/N)?", "N")
682                 else:
683                         self.ifThenSend("(Y/N)?", "Y")
684                 self.ifThenSend("RPC-16>", "")
685
686                 self.close()
687                 return 0
688
689 class BayTechCtrlCUnibe(PCUControl):
690         """
691                 For some reason, these units let you log in fine, but they hang
692                 indefinitely, unless you send a Ctrl-C after the password.  No idea
693                 why.
694         """
695         def run(self, node_port, dryrun):
696                 print "BayTechCtrlC %s" % self.host
697
698                 ssh_options="-o StrictHostKeyChecking=no -o PasswordAuthentication=yes -o PubkeyAuthentication=no"
699                 s = pxssh.pxssh()
700                 if not s.login(self.host, self.username, self.password, ssh_options):
701                         raise ExceptionPassword("Invalid Password")
702                 # Otherwise, the login succeeded.
703
704                 # Send a ctrl-c to the remote process.
705                 print "sending ctrl-c"
706                 s.send(chr(3))
707
708                 # Control Outlets  (5 ,1).........5
709                 try:
710                         index = s.expect(["Enter Request :"])
711
712                         if index == 0:
713                                 print "3"
714                                 s.send("3\r\n")
715                                 index = s.expect(["DS-RPC>", "Enter user name:"])
716                                 if index == 1:
717                                         s.send(self.username + "\r\n")
718                                         index = s.expect(["DS-RPC>"])
719
720                                 if index == 0:
721                                         print "Reboot %d" % node_port
722                                         s.send("Reboot %d\r\n" % node_port)
723
724                                         index = s.expect(["(Y/N)?"])
725                                         if index == 0:
726                                                 if dryrun:
727                                                         print "sending N"
728                                                         s.send("N\r\n")
729                                                 else:
730                                                         print "sending Y"
731                                                         s.send("Y\r\n")
732
733                                 #index = s.expect(["DS-RPC>"])
734                                 #print "got prompt back"
735
736                         s.close()
737
738                 except pexpect.EOF:
739                         raise ExceptionPrompt("EOF before 'Enter Request' Prompt")
740                 except pexpect.TIMEOUT:
741                         raise ExceptionPrompt("Timeout before 'Enter Request' Prompt")
742
743                 return 0
744
745 class BayTechCtrlC(PCUControl):
746         """
747                 For some reason, these units let you log in fine, but they hang
748                 indefinitely, unless you send a Ctrl-C after the password.  No idea
749                 why.
750         """
751         def run(self, node_port, dryrun):
752                 print "BayTechCtrlC %s" % self.host
753
754                 ssh_options="-o StrictHostKeyChecking=no -o PasswordAuthentication=yes -o PubkeyAuthentication=no"
755                 s = pxssh.pxssh()
756                 if not s.login(self.host, self.username, self.password, ssh_options):
757                         raise ExceptionPassword("Invalid Password")
758                 # Otherwise, the login succeeded.
759
760                 # Send a ctrl-c to the remote process.
761                 print "sending ctrl-c"
762                 s.send(chr(3))
763
764                 # Control Outlets  (5 ,1).........5
765                 try:
766                         index = s.expect(["Enter Request :"])
767
768                         if index == 0:
769                                 print "5"
770                                 s.send("5\r\n")
771                                 index = s.expect(["DS-RPC>", "Enter user name:"])
772                                 if index == 1:
773                                         print "sending username"
774                                         s.send(self.username + "\r\n")
775                                         index = s.expect(["DS-RPC>"])
776
777                                 if index == 0:
778                                         print "Reboot %d" % node_port
779                                         s.send("Reboot %d\r\n" % node_port)
780
781                                         index = s.expect(["(Y/N)?"])
782                                         if index == 0:
783                                                 if dryrun:
784                                                         print "sending N"
785                                                         s.send("N\r\n")
786                                                 else:
787                                                         print "sending Y"
788                                                         s.send("Y\r\n")
789
790                                 index = s.expect(["DS-RPC>"])
791                                 #print "got prompt back"
792
793                         s.close()
794
795                 except pexpect.EOF:
796                         raise ExceptionPrompt("EOF before 'Enter Request' Prompt")
797                 except pexpect.TIMEOUT:
798                         raise ExceptionPrompt("Timeout before Prompt")
799
800                 return 0
801
802 class BayTech(PCUControl):
803         def run(self, node_port, dryrun):
804                 self.open(self.host, self.username)
805                 self.sendPassword(self.password)
806
807                 # Control Outlets  (5 ,1).........5
808                 self.ifThenSend("Enter Request :", "5")
809
810                 # Reboot N
811                 try:
812                         self.ifThenSend("DS-RPC>", "Reboot %d" % node_port, ExceptionNotFound)
813                 except ExceptionNotFound, msg:
814                         # one machine is configured to ask for a username,
815                         # even after login...
816                         print "msg: %s" % msg
817                         self.transport.write(self.username + "\r\n")
818                         self.ifThenSend("DS-RPC>", "Reboot %d" % node_port)
819
820                 # Reboot Outlet  N        (Y/N)?
821                 if dryrun:
822                         self.ifThenSend("(Y/N)?", "N")
823                 else:
824                         self.ifThenSend("(Y/N)?", "Y")
825                 self.ifThenSend("DS-RPC>", "")
826
827                 self.close()
828                 return 0
829
830 class WTIIPS4(PCUControl):
831         def run(self, node_port, dryrun):
832                 self.open(self.host)
833                 self.sendPassword(self.password, "Enter Password:")
834
835                 self.ifThenSend("IPS> ", "/Boot %s" % node_port)
836                 if not dryrun:
837                         self.ifThenSend("Sure? (Y/N): ", "N")
838                 else:
839                         self.ifThenSend("Sure? (Y/N): ", "Y")
840
841                 self.ifThenSend("IPS> ", "")
842
843                 self.close()
844                 return 0
845
846 class ePowerSwitchGood(PCUControl):
847         # NOTE:
848         #               The old code used Python's HTTPPasswordMgrWithDefaultRealm()
849         #               For some reason this both doesn't work and in some cases, actually
850         #               hangs the PCU.  Definitely not what we want.
851         #               
852         #               The code below is much simpler.  Just letting things fail first,
853         #               and then, trying again with authentication string in the header.
854         #               
855         def run(self, node_port, dryrun):
856                 self.transport = None
857                 self.url = "http://%s:%d/" % (self.host,80)
858                 uri = "%s:%d" % (self.host,80)
859
860                 req = urllib2.Request(self.url)
861                 try:
862                         handle = urllib2.urlopen(req)
863                 except IOError, e:
864                         # NOTE: this is expected to fail initially
865                         pass
866                 else:
867                         print self.url
868                         print "-----------"
869                         print handle.read()
870                         print "-----------"
871                         return "ERROR: not protected by HTTP authentication"
872
873                 if not hasattr(e, 'code') or e.code != 401:
874                         return "ERROR: failed for: %s" % str(e)
875
876                 base64data = base64.encodestring("%s:%s" % (self.username, self.password))[:-1]
877                 # NOTE: assuming basic realm authentication.
878                 authheader = "Basic %s" % base64data
879                 req.add_header("Authorization", authheader)
880
881                 try:
882                         f = urllib2.urlopen(req)
883                 except IOError, e:
884                         # failing here means the User/passwd is wrong (hopefully)
885                         raise ExceptionPassword("Incorrect username/password")
886
887                 # NOTE: after verifying that the user/password is correct, 
888                 #               actually reboot the given node.
889                 if not dryrun:
890                         try:
891                                 data = urllib.urlencode({'P%d' % node_port : "r"})
892                                 req = urllib2.Request(self.url + "cmd.html")
893                                 req.add_header("Authorization", authheader)
894                                 # add data to handler,
895                                 f = urllib2.urlopen(req, data)
896                                 if self.verbose: print f.read()
897                         except:
898                                 import traceback; traceback.print_exc()
899
900                                 # fetch url one more time on cmd.html, econtrol.html or whatever.
901                                 # pass
902                 else:
903                         if self.verbose: print f.read()
904
905                 self.close()
906                 return 0
907
908 class CustomPCU(PCUControl):
909         def run(self, node_port, dryrun):
910                 url = "https://www-itec.uni-klu.ac.at/plab-pcu/index.php" 
911
912                 if not dryrun:
913                         # Turn host off, then on
914                         formstr = "plab%s=off" % node_port
915                         os.system("curl --user %s:%s --form '%s' --insecure %s" % (self.username, self.password, formstr, url))
916                         time.sleep(5)
917                         formstr = "plab%s=on" % node_port
918                         os.system("curl --user %s:%s --form '%s' --insecure %s" % (self.username, self.password, formstr, url))
919                 else:
920                         os.system("curl --user %s:%s --insecure %s" % (self.username, self.password, url))
921
922
923 class ePowerSwitchOld(PCUControl):
924         def run(self, node_port, dryrun):
925                 self.url = "http://%s:%d/" % (self.host,80)
926                 uri = "%s:%d" % (self.host,80)
927
928                 # create authinfo
929                 authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm()
930                 authinfo.add_password (None, uri, self.username, self.password)
931                 authhandler = urllib2.HTTPBasicAuthHandler( authinfo )
932
933                 # NOTE: it doesn't seem to matter whether this authinfo is here or not.
934                 transport = urllib2.build_opener(authinfo)
935                 f = transport.open(self.url)
936                 if self.verbose: print f.read()
937
938                 if not dryrun:
939                         transport = urllib2.build_opener(authhandler)
940                         f = transport.open(self.url + "cmd.html", "P%d=r" % node_port)
941                         if self.verbose: print f.read()
942
943                 self.close()
944                 return 0
945
946 class ePowerSwitch(PCUControl):
947         def run(self, node_port, dryrun):
948                 self.url = "http://%s:%d/" % (self.host,80)
949                 uri = "%s:%d" % (self.host,80)
950
951                 # TODO: I'm still not sure what the deal is here.
952                 #               two independent calls appear to need to be made before the
953                 #               reboot will succeed.  It doesn't seem to be possible to do
954                 #               this with a single call.  I have no idea why.
955
956                 # create authinfo
957                 authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm()
958                 authinfo.add_password (None, uri, self.username, self.password)
959                 authhandler = urllib2.HTTPBasicAuthHandler( authinfo )
960
961                 # NOTE: it doesn't seem to matter whether this authinfo is here or not.
962                 transport = urllib2.build_opener()
963                 f = transport.open(self.url + "elogin.html", "pwd=%s" % self.password)
964                 if self.verbose: print f.read()
965
966                 if not dryrun:
967                         transport = urllib2.build_opener(authhandler)
968                         f = transport.open(self.url + "econtrol.html", "P%d=r" % node_port)
969                         if self.verbose: print f.read()
970
971                 #       data= "P%d=r" % node_port
972                 #self.open(self.host, self.username, self.password)
973                 #self.sendHTTP("elogin.html", "pwd=%s" % self.password)
974                 #self.sendHTTP("econtrol.html", data)
975                 #self.sendHTTP("cmd.html", data)
976
977                 self.close()
978                 return 0
979                 
980
981 ### rebooting european BlackBox PSE boxes
982 # Thierry Parmentelat - May 11 2005
983 # tested on 4-ports models known as PSE505-FR
984 # uses http to POST a data 'P<port>=r'
985 # relies on basic authentication within http1.0
986 # first curl-based script was
987 # curl --http1.0 --basic --user <username>:<password> --data P<port>=r \
988 #       http://<hostname>:<http_port>/cmd.html && echo OK
989
990 def bbpse_reboot (pcu_ip,username,password,port_in_pcu,http_port, dryrun):
991
992         global verbose
993
994         url = "http://%s:%d/cmd.html" % (pcu_ip,http_port)
995         data= "P%d=r" % port_in_pcu
996         if verbose:
997                 logger.debug("POSTing '%s' on %s" % (data,url))
998
999         authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm()
1000         uri = "%s:%d" % (pcu_ip,http_port)
1001         authinfo.add_password (None, uri, username, password)
1002         authhandler = urllib2.HTTPBasicAuthHandler( authinfo )
1003
1004         opener = urllib2.build_opener(authhandler)
1005         urllib2.install_opener(opener)
1006
1007         if (dryrun):
1008                 return 0
1009
1010         try:
1011                 f = urllib2.urlopen(url,data)
1012
1013                 r= f.read()
1014                 if verbose:
1015                         logger.debug(r)
1016                 return 0
1017
1018         except urllib2.URLError,err:
1019                 logger.info('Could not open http connection', err)
1020                 return "bbpse error"
1021
1022 ### rebooting x10toggle based systems addressed by port
1023 # Marc E. Fiuczynski - May 31 2005
1024 # tested on 4-ports models known as PSE505-FR
1025 # uses ssh and password to login to an account
1026 # that will cause the system to be powercycled.
1027
1028 def x10toggle_reboot(ip, username, password, port, dryrun):
1029         global verbose
1030
1031         ssh = None
1032         try:
1033                 ssh = pyssh.Ssh(username, ip)
1034                 ssh.open()
1035
1036                 # Login
1037                 telnet_answer(ssh, "password:", password)
1038
1039                 if not dryrun:
1040                         # Reboot
1041                         telnet_answer(ssh, "x10toggle>", "A%d" % port)
1042
1043                 # Close
1044                 output = ssh.close()
1045                 if verbose:
1046                         logger.debug(output)
1047                 return 0
1048
1049         except Exception, err:
1050                 if verbose:
1051                         logger.debug(err)
1052                 if ssh:
1053                         output = ssh.close()
1054                         if verbose:
1055                                 logger.debug(output)
1056                 return errno.ETIMEDOUT
1057
1058 ### rebooting Dell systems via RAC card
1059 # Marc E. Fiuczynski - June 01 2005
1060 # tested with David Lowenthal's itchy/scratchy nodes at UGA
1061 #
1062
1063 def runcmd(command, args, username, password, timeout = None):
1064
1065         result = [None]
1066         result_ready = threading.Condition()
1067
1068         def set_result(x):
1069
1070                 result_ready.acquire()
1071                 try:
1072                         result[0] = x
1073                 finally:
1074                         result_ready.notify()
1075                         result_ready.release()
1076
1077         def do_command(command, username, password):
1078
1079                 try:
1080                         # Popen4 is a popen-type class that combines stdout and stderr
1081                         p = popen2.Popen4(command)
1082
1083                         # read all output data
1084                         p.tochild.write("%s\n" % username)
1085                         p.tochild.write("%s\n" % password)
1086                         p.tochild.close()
1087                         data = p.fromchild.read()
1088
1089                         while True:
1090                                 # might get interrupted by a signal in poll() or waitpid()
1091                                 try:
1092                                         retval = p.wait()
1093                                         set_result((retval, data))
1094                                         break
1095                                 except OSError, ex:
1096                                         if ex.errno == errno.EINTR:
1097                                                 continue
1098                                         raise ex
1099                 except Exception, ex:
1100                         set_result(ex)
1101
1102         if args:
1103                 command = " ".join([command] + args)
1104
1105         worker = threading.Thread(target = do_command, args = (command, username, password, ))
1106         worker.setDaemon(True)
1107         result_ready.acquire()
1108         worker.start()
1109         result_ready.wait(timeout)
1110         try:
1111                 if result == [None]:
1112                         raise Exception, "command timed-out: '%s'" % command
1113         finally:
1114                 result_ready.release()
1115         result = result[0]
1116
1117         if isinstance(result, Exception):
1118                 raise result
1119         else:
1120                 (retval, data) = result
1121                 if os.WIFEXITED(retval) and os.WEXITSTATUS(retval) == 0:
1122                         return data
1123                 else:
1124                         out = "system command ('%s') " % command
1125                         if os.WIFEXITED(retval):
1126                                 out += "failed, rc = %d" % os.WEXITSTATUS(retval)
1127                         else:
1128                                 out += "killed by signal %d" % os.WTERMSIG(retval)
1129                         if data:
1130                                 out += "; output follows:\n" + data
1131                         raise Exception, out
1132
1133 def racadm_reboot(host, username, password, port, dryrun):
1134         global verbose
1135
1136         ip = socket.gethostbyname(host)
1137         try:
1138                 cmd = "/usr/sbin/racadm"
1139                 os.stat(cmd)
1140                 if not dryrun:
1141                         output = runcmd(cmd, ["-r %s -i serveraction powercycle" % ip],
1142                                 username, password)
1143                 else:
1144                         output = runcmd(cmd, ["-r %s -i getsysinfo" % ip],
1145                                 username, password)
1146
1147                 print "RUNCMD: %s" % output
1148                 if verbose:
1149                         logger.debug(output)
1150                 return 0
1151
1152         except Exception, err:
1153                 logger.debug("runcmd raised exception %s" % err)
1154                 if verbose:
1155                         logger.debug(err)
1156                 return -1
1157
1158 def pcu_name(pcu):
1159         if pcu['hostname'] is not None and pcu['hostname'] is not "":
1160                 return pcu['hostname']
1161         elif pcu['ip'] is not None and pcu['ip'] is not "":
1162                 return pcu['ip']
1163         else:
1164                 return None
1165
1166 import soltesz
1167 fb =soltesz.dbLoad("findbadpcus")
1168
1169 def get_pcu_values(pcu_id):
1170         # TODO: obviously, this shouldn't be loaded each time...
1171
1172         try:
1173                 values = fb['nodes']["id_%s" % pcu_id]['values']
1174         except:
1175                 values = None
1176
1177         return values
1178
1179 def reboot(nodename):
1180         return reboot_policy(nodename, True, False)
1181         
1182 def reboot_policy(nodename, continue_probe, dryrun):
1183         global verbose
1184
1185         pcu = plc.getpcu(nodename)
1186         if not pcu:
1187                 logger.debug("no pcu for %s" % hostname)
1188                 print "no pcu for %s" % hostname
1189                 return False # "%s has no pcu" % nodename
1190
1191         values = get_pcu_values(pcu['pcu_id'])
1192         if values == None:
1193                 logger.debug("No values for pcu probe %s" % hostname)
1194                 print "No values for pcu probe %s" % hostname
1195                 return False #"no info for pcu_id %s" % pcu['pcu_id']
1196         
1197         # Try the PCU first
1198         logger.debug("Trying PCU %s %s" % (pcu['hostname'], pcu['model']))
1199
1200         ret = reboot_test(nodename, values, continue_probe, verbose, dryrun)
1201
1202         if ret != 0:
1203                 print ret
1204                 return False
1205         else:
1206                 print "return true"
1207                 return True
1208
1209 def reboot_test(nodename, values, continue_probe, verbose, dryrun):
1210         rb_ret = ""
1211
1212         try:
1213                 # DataProbe iPal (many sites)
1214                 if  continue_probe and values['model'].find("IP-41x_IP-81x") >= 0:
1215                         ipal = IPAL(values, verbose, ['23', '80', '9100'])
1216                         rb_ret = ipal.reboot(values[nodename], dryrun)
1217                                 
1218                 # APC Masterswitch (Berkeley)
1219                 elif continue_probe and ( values['model'].find("AP79xx") >= 0 or \
1220                                                                   values['model'].find("Masterswitch") >= 0 ):
1221                         print values
1222
1223                         # TODO: make a more robust version of APC
1224                         if values['pcu_id'] in [1163,1055,1111,1231,1113,1127,1128,1148]:
1225                                 apc = APCEurope(values, verbose, ['22', '23'])
1226                                 rb_ret = apc.reboot(values[nodename], dryrun)
1227
1228                         elif values['pcu_id'] in [1110,86]:
1229                                 apc = APCBrazil(values, verbose, ['22', '23'])
1230                                 rb_ret = apc.reboot(values[nodename], dryrun)
1231
1232                         elif values['pcu_id'] in [1221,1225]:
1233                                 apc = APCBerlin(values, verbose, ['22', '23'])
1234                                 rb_ret = apc.reboot(values[nodename], dryrun)
1235
1236                         elif values['pcu_id'] in [1173,1221,1220]:
1237                                 apc = APCFolsom(values, verbose, ['22', '23'])
1238                                 rb_ret = apc.reboot(values[nodename], dryrun)
1239
1240                         else:
1241                                 apc = APCMaster(values, verbose, ['22', '23'])
1242                                 rb_ret = apc.reboot(values[nodename], dryrun)
1243
1244                 # BayTech DS4-RPC
1245                 elif continue_probe and values['model'].find("DS4-RPC") >= 0:
1246                         if values['pcu_id'] in [1237,1052,1209,1002,1008,1041,1013,1022]:
1247                                 # These  require a 'ctrl-c' to be sent... 
1248                                 baytech = BayTechCtrlC(values, verbose, ['22', '23'])
1249                                 rb_ret = baytech.reboot(values[nodename], dryrun)
1250
1251                         elif values['pcu_id'] in [93]:
1252                                 baytech = BayTechAU(values, verbose, ['22', '23'])
1253                                 rb_ret = baytech.reboot(values[nodename], dryrun)
1254
1255                         elif values['pcu_id'] in [1057]:
1256                                 # These  require a 'ctrl-c' to be sent... 
1257                                 baytech = BayTechCtrlCUnibe(values, verbose, ['22', '23'])
1258                                 rb_ret = baytech.reboot(values[nodename], dryrun)
1259
1260                         elif values['pcu_id'] in [1012]:
1261                                 # This pcu sometimes doesn't present the 'Username' prompt,
1262                                 # unless you immediately try again...
1263                                 try:
1264                                         baytech = BayTechGeorgeTown(values, verbose, ['22', '23'])
1265                                         rb_ret = baytech.reboot(values[nodename], dryrun)
1266                                 except:
1267                                         baytech = BayTechGeorgeTown(values, verbose, ['22', '23'])
1268                                         rb_ret = baytech.reboot(values[nodename], dryrun)
1269                         else:
1270                                 baytech = BayTech(values, verbose, ['22', '23'])
1271                                 rb_ret = baytech.reboot(values[nodename], dryrun)
1272
1273                 # iLO
1274                 elif continue_probe and values['model'].find("ilo") >= 0:
1275                         try:
1276                                 hpilo = HPiLO(values, verbose, ['22'])
1277                                 rb_ret = hpilo.reboot(0, dryrun)
1278                                 if rb_ret != 0:
1279                                         hpilo = HPiLOHttps(values, verbose, ['443'])
1280                                         rb_ret = hpilo.reboot(0, dryrun)
1281                         except:
1282                                 hpilo = HPiLOHttps(values, verbose, ['443'])
1283                                 rb_ret = hpilo.reboot(0, dryrun)
1284
1285                 # DRAC ssh
1286                 elif continue_probe and values['model'].find("DRAC") >= 0:
1287                         # TODO: I don't think DRACRacAdm will throw an exception for the
1288                         # default method to catch...
1289                         try:
1290                                 drac = DRACRacAdm(values, verbose, ['443', '5869'])
1291                                 rb_ret = drac.reboot(0, dryrun)
1292                         except:
1293                                 drac = DRAC(values, verbose, ['22'])
1294                                 rb_ret = drac.reboot(0, dryrun)
1295
1296                 elif continue_probe and values['model'].find("WTI IPS-4") >= 0:
1297                                 wti = WTIIPS4(values, verbose, ['23'])
1298                                 rb_ret = wti.reboot(values[nodename], dryrun)
1299
1300                 elif continue_probe and values['model'].find("AMT") >= 0:
1301                                 amt = IntelAMT(values, verbose, ['16992'])
1302                                 rb_ret = amt.reboot(values[nodename], dryrun)
1303
1304                 # BlackBox PSExxx-xx (e.g. PSE505-FR)
1305                 elif continue_probe and values['model'].find("ePowerSwitch") >=0:
1306                         # TODO: allow a different port than http 80.
1307                         if values['pcu_id'] in [1089, 1071, 1046, 1035, 1118]:
1308                                 eps = ePowerSwitchGood(values, verbose, ['80'])
1309                         elif values['pcu_id'] in [1003]:
1310                                 # OLD EPOWER
1311                                 print "OLD EPOWER"
1312                                 eps = ePowerSwitch(values, verbose, ['80'])
1313                         else:
1314                                 eps = ePowerSwitchGood(values, verbose, ['80'])
1315
1316                         rb_ret = eps.reboot(values[nodename], dryrun)
1317                 elif continue_probe and values['pcu_id'] in [1122]:
1318                         custom = CustomPCU(values, verbose, ['80', '443'])
1319                         custom.reboot(values[nodename], dryrun)
1320
1321                 elif continue_probe:
1322                         rb_ret = "Unsupported_PCU"
1323
1324                 elif continue_probe == False:
1325                         if 'portstatus' in values:
1326                                 rb_ret = "NetDown"
1327                         else:
1328                                 rb_ret = "Not_Run"
1329                 else:
1330                         rb_ret = -1
1331
1332         except ExceptionPort, err:
1333                 rb_ret = str(err)
1334
1335         return rb_ret
1336         # ????
1337         #elif continue_probe and values['protocol'] == "racadm" and \
1338         #               values['model'] == "RAC":
1339         #       rb_ret = racadm_reboot(pcu_name(values),
1340         #                                                                 values['username'],
1341         #                                                                 values['password'],
1342         #                                                                 pcu[nodename],
1343         #                                                                 dryrun)
1344
1345 def main():
1346         logger.setLevel(logging.DEBUG)
1347         ch = logging.StreamHandler()
1348         ch.setLevel(logging.DEBUG)
1349         formatter = logging.Formatter('LOGGER - %(message)s')
1350         ch.setFormatter(formatter)
1351         logger.addHandler(ch)
1352
1353         try:
1354                 if "test" in sys.argv:
1355                         dryrun = True
1356                 else:
1357                         dryrun = False
1358
1359                 for node in sys.argv[1:]:
1360                         if node == "test": continue
1361
1362                         print "Rebooting %s" % node
1363                         if reboot_policy(node, True, dryrun):
1364                                 print "success"
1365                         else:
1366                                 print "failed"
1367         except Exception, err:
1368                 import traceback; traceback.print_exc()
1369                 print err
1370
1371 if __name__ == '__main__':
1372         import plc
1373         logger = logging.getLogger("monitor")
1374         main()