changes for 3.0
[monitor.git] / reboot.py
index 9674bda..ba641c4 100755 (executable)
--- a/reboot.py
+++ b/reboot.py
@@ -8,15 +8,16 @@ import os, sys
 import xml, xmlrpclib
 import errno, time, traceback
 import urllib2
+import urllib
 import threading, popen2
 import array, struct
-#from socket import *
-import socket
 import plc
 import base64
 from subprocess import PIPE, Popen
-
-plc_lock = threading.Lock()
+import ssh.pxssh as pxssh
+import ssh.pexpect as pexpect
+import socket
+import moncommands 
 
 # Use our versions of telnetlib and pyssh
 sys.path.insert(0, os.path.dirname(sys.argv[0]))
@@ -25,7 +26,7 @@ sys.path.insert(0, os.path.dirname(sys.argv[0]) + "/pyssh")
 import pyssh
 
 # Timeouts in seconds
-TELNET_TIMEOUT = 30
+TELNET_TIMEOUT = 45
 
 # Event class ID from pcu events
 #NODE_POWER_CONTROL = 3
@@ -114,6 +115,7 @@ class Transport:
        TELNET = 1
        SSH    = 2
        HTTP   = 3
+       IPAL   = 4
 
        TELNET_TIMEOUT = 60
 
@@ -122,10 +124,6 @@ class Transport:
                self.verbose = verbose
                self.transport = None
 
-#      def __del__(self):
-#              if self.transport:
-#                      self.close()
-
        def open(self, host, username=None, password=None, prompt="User Name"):
                transport = None
 
@@ -223,6 +221,7 @@ class PCUControl(Transport,PCUModel,PCURecord):
        def __init__(self, plc_pcu_record, verbose, supported_ports=[]):
                PCUModel.__init__(self, plc_pcu_record)
                PCURecord.__init__(self, plc_pcu_record)
+               type = None
                if self.portstatus:
                        if '22' in supported_ports and self.portstatus['22'] == "open":
                                type = Transport.SSH
@@ -233,11 +232,16 @@ class PCUControl(Transport,PCUModel,PCURecord):
                        elif '443' in supported_ports and self.portstatus['443'] == "open":
                                type = Transport.HTTP
                        elif '5869' in supported_ports and self.portstatus['5869'] == "open":
-                               # For DRAC cards.  not sure how much it's used in the
-                               # protocol.. but racadm opens this port.
+                               # For DRAC cards. Racadm opens this port.
+                               type = Transport.HTTP
+                       elif '9100' in supported_ports and self.portstatus['9100'] == "open":
+                               type = Transport.IPAL
+                       elif '16992' in supported_ports and self.portstatus['16992'] == "open":
                                type = Transport.HTTP
                        else:
                                raise ExceptionPort("Unsupported Port: No transport from open ports")
+               else:
+                       raise Exception("No Portstatus: No transport because no open ports")
                Transport.__init__(self, type, verbose)
 
        def run(self, node_port, dryrun):
@@ -271,116 +275,197 @@ class PCUControl(Transport,PCUModel,PCURecord):
                        import traceback
                        traceback.print_exc()
                        return "EOF connection reset" + str(err)
-               #except Exception, err:
-               #       if self.verbose:
-               #               logger.debug("reboot: Exception")
-               #               logger.debug(err)
-               #       if self.transport:
-               #               self.transport.close()
-               #       import traceback
-               #       traceback.print_exc()
-               #       return  "generic exception; unknown problem."
-
+               except:
+                       from nodecommon import email_exception
+                       email_exception()
+                       raise Exception('unknown')
                
 class IPAL(PCUControl):
-       def run(self, node_port, dryrun):
-               self.open(self.host)
-
-               # XXX Some iPals require you to hit Enter a few times first
-               self.ifThenSend("Password >", "\r\n\r\n", ExceptionNotFound)
+       """ 
+               This now uses a proprietary format for communicating with the PCU.  I
+               prefer it to Telnet, and Web access, since it's much lighter weight
+               and, more importantly, IT WORKS!! HHAHHHAHAHAHAHAHA!
+       """
 
-               # Login
-               self.ifThenSend("Password >", self.password, ExceptionPassword)
-               self.transport.write("\r\n\r\n")
+       def format_msg(self, data, cmd):
+               esc = chr(int('1b',16))
+               return "%c%s%c%s%c" % (esc, self.password, esc, data, cmd) # esc, 'q', chr(4))
+       
+       def recv_noblock(self, s, count):
+               import errno
 
-               if not dryrun: # P# - Pulse relay
-                       self.ifThenSend("Enter >", 
-                                                       "P%d" % node_port, 
-                                                       ExceptionNotFound)
-               # Get the next prompt
-               self.ifElse("Enter >", ExceptionTimeout)
+               try:
+                       # TODO: make sleep backoff, before stopping.
+                       time.sleep(8)
+                       ret = s.recv(count, socket.MSG_DONTWAIT)
+               except socket.error, e:
+                       if e[0] == errno.EAGAIN:
+                               #raise Exception(e[1])
+                               raise ExceptionNotFound(e[1])
+                       else:
+                               # TODO: not other exceptions.
+                               raise Exception(e)
+               return ret
 
-               self.close()
-               return 0
+       def run(self, node_port, dryrun):
+               import errno
 
-def ipal_reboot(ip, password, port, dryrun):
-       global verbose
-       global plc_lock
-       telnet = None
+               power_on = False
 
-       try:
-               #plc_lock.acquire()
-               #print "lock acquired"
+               print "open socket"
+               s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+               try:
+                       print "connect"
+                       s.connect((self.host, 9100))
+               except socket.error, e:
+                       s.close()
+                       if e[0] == errno.ECONNREFUSED:
+                               # cannot connect to remote host
+                               raise Exception(e[1])
+                       elif e[0] == errno.ETIMEDOUT:
+                               raise ExceptionTimeout(e[1])
+                       else:
+                               # TODO: what other conditions are there?
+                               raise Exception(e)
+                               
+               # get current status
+               print "Checking status"
+               s.send(self.format_msg("", 'O'))
+               ret = self.recv_noblock(s, 8)
+               print "Current status is '%s'" % ret
+
+               if ret == '':
+                       raise Exception("Status returned 'another session already open' on %s %s : %s" % (self.host, node_port, ret))
+                       
+                               
+               if node_port < len(ret):
+                       status = ret[node_port]
+                       if status == '1':
+                               # up
+                               power_on = True
+                       elif status == '0':
+                               # down
+                               power_on = False
+                       elif status == '6':
+                               raise ExceptionPort("IPAL reported 'Cable Error' on %s socket %s : %s" % (self.host, node_port, ret))
+                       else:
+                               raise Exception("Unknown status for PCU %s socket %s : %s" % (self.host, node_port, ret))
+               else:
+                       raise Exception("Mismatch between configured port and PCU %s status: %s %s" % (self.host, node_port, ret))
+                       
 
-               #try:
-                       #telnet = telnetlib.Telnet(ip) # , timeout=TELNET_TIMEOUT)
-               telnet = telnetlib.Telnet(ip, timeout=TELNET_TIMEOUT)
-               #except:
-               #       import traceback
-               #       traceback.print_exc()
+               if not dryrun:
+                       if power_on:
+                               print "Pulsing %s" % node_port
+                               s.send(self.format_msg("%s" % node_port, 'P'))
+                       else:
+                               # NOTE: turn power on ; do not pulse the port.
+                               print "Power was off, so turning on ..."
+                               s.send(self.format_msg("%s" % node_port, 'E'))
+                               #s.send(self.format_msg("%s" % node_port, 'P'))
+
+                       print "Receiving response."
+                       ret = self.recv_noblock(s, 8)
+                       print "Current status is '%s'" % ret
+
+                       if node_port < len(ret):
+                               status = ret[node_port]
+                               if status == '1':
+                                       # up
+                                       power_on = True
+                               elif status == '0':
+                                       # down
+                                       power_on = False
+                               elif status == '6':
+                                       raise ExceptionPort("IPAL reported 'Cable Error' on %s socket %s : %s" % (self.host, node_port, ret))
+                               else:
+                                       raise Exception("Unknown status for PCU %s socket %s : %s" % (self.host, node_port, ret))
+                       else:
+                               raise Exception("Mismatch between configured port and PCU %s status: %s %s" % (self.host, node_port, ret))
 
+                       if power_on:
+                               return 0
+                       else:
+                               return "Failed Power On"
 
-               telnet.set_debuglevel(verbose)
+               s.close()
+               return 0
 
-               # XXX Some iPals require you to hit Enter a few times first
-               telnet_answer(telnet, "Password >", "\r\n\r\n")
+# TELNET version of protocol...
+#              #self.open(self.host)
+#              ## XXX Some iPals require you to hit Enter a few times first
+#              #self.ifThenSend("Password >", "\r\n\r\n", ExceptionNotFound)
+#              # Login
+#              self.ifThenSend("Password >", self.password, ExceptionPassword)
+#              self.transport.write("\r\n\r\n")
+#              if not dryrun: # P# - Pulse relay
+#                      print "node_port %s" % node_port
+#                      self.ifThenSend("Enter >", 
+#                                                      "P7", # % node_port, 
+#                                                      ExceptionNotFound)
+#                      print "send newlines"
+#                      self.transport.write("\r\n\r\n")
+#                      print "after new lines"
+#              # Get the next prompt
+#              print "wait for enter"
+#              self.ifElse("Enter >", ExceptionTimeout)
+#              print "closing "
+#              self.close()
+#              return 0
 
-               # Login
-               telnet_answer(telnet, "Password >", password)
+class APCEurope(PCUControl):
+       def run(self, node_port, dryrun):
+               self.open(self.host, self.username)
+               self.sendPassword(self.password)
 
-               # XXX Some iPals require you to hit Enter a few times first
-               telnet.write("\r\n\r\n")
+               self.ifThenSend("\r\n> ", "1", ExceptionPassword)
+               self.ifThenSend("\r\n> ", "2")
+               self.ifThenSend("\r\n> ", str(node_port))
+               # 3- Immediate Reboot             
+               self.ifThenSend("\r\n> ", "3")
 
-               # P# - Pulse relay
                if not dryrun:
-                       telnet_answer(telnet, "Enter >", "P%d" % port)
+                       self.ifThenSend("Enter 'YES' to continue or <ENTER> to cancel", 
+                                                       "YES\r\n",
+                                                       ExceptionSequence)
+               else:
+                       self.ifThenSend("Enter 'YES' to continue or <ENTER> to cancel", 
+                                                       "", ExceptionSequence)
+               self.ifThenSend("Press <ENTER> to continue...", "", ExceptionSequence)
 
-               telnet.read_until("Enter >", TELNET_TIMEOUT)
+               self.close()
+               return 0
 
-               # Close
-               telnet.close()
+class APCBrazil(PCUControl):
+       def run(self, node_port, dryrun):
+               self.open(self.host, self.username)
+               self.sendPassword(self.password)
 
-               #print "lock released"
-               #plc_lock.release()
-               return 0
+               self.ifThenSend("\r\n> ", "1", ExceptionPassword)
+               self.ifThenSend("\r\n> ", str(node_port))
+               # 4- Immediate Reboot             
+               self.ifThenSend("\r\n> ", "4")
 
-       except EOFError, err:
-               if verbose:
-                       logger.debug("ipal_reboot: EOF")
-                       logger.debug(err)
-               telnet.close()
-               import traceback
-               traceback.print_exc()
-               #print "lock released"
-               #plc_lock.release()
-               return errno.ECONNRESET
-       except socket.error, err:
-               logger.debug("ipal_reboot: Socket Error")
-               logger.debug(err)
-               import traceback
-               traceback.print_exc()
+               if not dryrun:
+                       self.ifThenSend("Enter 'YES' to continue or <ENTER> to cancel", 
+                                                       "YES\r\n",
+                                                       ExceptionSequence)
+               else:
+                       self.ifThenSend("Enter 'YES' to continue or <ENTER> to cancel", 
+                                                       "", ExceptionSequence)
+               self.ifThenSend("Press <ENTER> to continue...", "", ExceptionSequence)
 
-               return errno.ETIMEDOUT
-               
-       except Exception, err:
-               if verbose:
-                       logger.debug("ipal_reboot: Exception")
-                       logger.debug(err)
-               if telnet:
-                       telnet.close()
-               import traceback
-               traceback.print_exc()
-               #print "lock released"
-               #plc_lock.release()
-               return  "ipal error"
+               self.close()
+               return 0
 
-class APCEurope(PCUControl):
+class APCBerlin(PCUControl):
        def run(self, node_port, dryrun):
                self.open(self.host, self.username)
                self.sendPassword(self.password)
 
                self.ifThenSend("\r\n> ", "1", ExceptionPassword)
                self.ifThenSend("\r\n> ", "2")
+               self.ifThenSend("\r\n> ", "1")
                self.ifThenSend("\r\n> ", str(node_port))
                # 3- Immediate Reboot             
                self.ifThenSend("\r\n> ", "3")
@@ -425,6 +510,7 @@ class APCFolsom(PCUControl):
 
 class APCMaster(PCUControl):
        def run(self, node_port, dryrun):
+               print "Rebooting %s" % self.host
                self.open(self.host, self.username)
                self.sendPassword(self.password)
 
@@ -481,6 +567,23 @@ class APC(PCUControl):
                else:
                        return ret
 
+class IntelAMT(PCUControl):
+       def run(self, node_port, dryrun):
+
+               cmd = moncommands.CMD()
+               #[cmd_str = "IntelAMTSDK/Samples/RemoteControl/remoteControl"
+               cmd_str = "cmdamt/remoteControl"
+
+               if dryrun:
+                       # NOTE: -p checks the power state of the host.
+                       # TODO: parse the output to find out if it's ok or not.
+                       cmd_str += " -p http://%s:16992/RemoteControlService  -user admin -pass '%s' " % (self.host, self.password )
+               else:
+                       cmd_str += " -A http://%s:16992/RemoteControlService -user admin -pass '%s' " % (self.host, self.password )
+                       
+               print cmd_str
+               return cmd.system(cmd_str, self.TELNET_TIMEOUT)
+
 class DRACRacAdm(PCUControl):
        def run(self, node_port, dryrun):
 
@@ -532,39 +635,55 @@ class HPiLO(PCUControl):
 class HPiLOHttps(PCUControl):
        def run(self, node_port, dryrun):
 
-               cmd = "cmdhttps/locfg.pl -s %s -f %s -u %s -p %s" % (
+               locfg = moncommands.CMD()
+               cmd = "cmdhttps/locfg.pl -s %s -f %s -u %s -p '%s' | grep 'MESSAGE' | grep -v 'No error'" % (
                                        self.host, "iloxml/Get_Network.xml", 
                                        self.username, self.password)
-               p_ilo  = Popen(cmd, stdout=PIPE, shell=True)
-               cmd2 = "grep 'MESSAGE' | grep -v 'No error'"
-               p_grep = Popen(cmd2, stdin=p_ilo.stdout, stdout=PIPE, stderr=PIPE, shell=True)
-               sout, serr = p_grep.communicate()
+               sout, serr = locfg.run_noexcept(cmd)
 
-               p_ilo.wait()
-               p_grep.wait()
                if sout.strip() != "":
                        print "sout: %s" % sout.strip()
                        return sout.strip()
 
                if not dryrun:
-                       cmd = "cmdhttps/locfg.pl -s %s -f %s -u %s -p %s" % (
-                                       self.host, "iloxml/Reset_Server.xml", 
-                                       self.username, self.password)
-                       p_ilo = Popen(cmd, stdin=PIPE, stdout=PIPE, shell=True)
-                       cmd2 = "grep 'MESSAGE' | grep -v 'No error'"
-                       p_grep = Popen(cmd2, stdin=p_ilo.stdout, stdout=PIPE, stderr=PIPE)
-                       sout, serr = p_grep.communicate()
-                       p_ilo.wait()
-                       p_grep.wait()
+                       locfg = moncommands.CMD()
+                       cmd = "cmdhttps/locfg.pl -s %s -f %s -u %s -p '%s' | grep 'MESSAGE' | grep -v 'No error'" % (
+                                               self.host, "iloxml/Reset_Server.xml", 
+                                               self.username, self.password)
+                       sout, serr = locfg.run_noexcept(cmd)
 
                        if sout.strip() != "":
                                print "sout: %s" % sout.strip()
-                               return sout.strip()
+                               #return sout.strip()
+               return 0
+
+class BayTechAU(PCUControl):
+       def run(self, node_port, dryrun):
+               self.open(self.host, self.username, None, "Enter user name:")
+               self.sendPassword(self.password, "Enter Password:")
 
+               #self.ifThenSend("RPC-16>", "Status")
+               self.ifThenSend("RPC3-NC>", "Reboot %d" % node_port)
+
+               # Reboot Outlet  N        (Y/N)?
+               if dryrun:
+                       self.ifThenSend("(Y/N)?", "N")
+               else:
+                       self.ifThenSend("(Y/N)?", "Y")
+               self.ifThenSend("RPC3-NC>", "")
+
+               self.close()
                return 0
 
 class BayTechGeorgeTown(PCUControl):
        def run(self, node_port, dryrun):
+               # this initial open/close is to prevent things from raising an
+               # exception.  the pcu always is weird during the first connection, and
+               # even if it's not, what does it matter to open a second connection
+               # right away?
+               self.open(self.host, self.username, None, "Enter user name:")
+               self.close()
+               time.sleep(1)
                self.open(self.host, self.username, None, "Enter user name:")
                self.sendPassword(self.password, "Enter Password:")
 
@@ -582,7 +701,7 @@ class BayTechGeorgeTown(PCUControl):
                self.close()
                return 0
 
-class BayTechCtrlC(PCUControl):
+class BayTechCtrlCUnibe(PCUControl):
        """
                For some reason, these units let you log in fine, but they hang
                indefinitely, unless you send a Ctrl-C after the password.  No idea
@@ -590,38 +709,133 @@ class BayTechCtrlC(PCUControl):
        """
        def run(self, node_port, dryrun):
                print "BayTechCtrlC %s" % self.host
-               self.open(self.host, self.username)
-               self.sendPassword(self.password)
 
-               #self.transport.write('\ 3')
-               self.transport.write("\r\n")
-               self.transport.write(pyssh.CTRL_C)
-               #self.transport.write(chr(3))
-               #self.transport.write(chr(24))
-               #self.transport.write(chr(26))
-               #self.transport.write('\18')
-               # Control Outlets  (5 ,1).........5
-               self.ifThenSend("Enter Request :", "5")
+               ssh_options="-o StrictHostKeyChecking=no -o PasswordAuthentication=yes -o PubkeyAuthentication=no"
+               s = pxssh.pxssh()
+               if not s.login(self.host, self.username, self.password, ssh_options):
+                       raise ExceptionPassword("Invalid Password")
+               # Otherwise, the login succeeded.
 
-               # Reboot N
+               # Send a ctrl-c to the remote process.
+               print "sending ctrl-c"
+               s.send(chr(3))
+
+               # Control Outlets  (5 ,1).........5
                try:
-                       self.ifThenSend("DS-RPC>", "Reboot %d" % node_port)
-               except ExceptionNotFound, msg:
-                       # one machine is configured to ask for a username,
-                       # even after login...
-                       print "msg: %s" % msg
-                       self.transport.write(self.username + "\r\n")
-                       self.ifThenSend("DS-RPC>", "Reboot %d" % node_port)
-                       
+                       #index = s.expect("Enter Request")
+                       index = s.expect(["Enter Request :"])
+
+                       if index == 0:
+                               print "3"
+                               s.send("3\r\n")
+                               index = s.expect(["DS-RPC>", "Enter user name:"])
+                               if index == 1:
+                                       s.send(self.username + "\r\n")
+                                       index = s.expect(["DS-RPC>"])
+
+                               if index == 0:
+                                       print "Reboot %d" % node_port
+                                       s.send("Reboot %d\r\n" % node_port)
+
+                                       time.sleep(5)
+                                       index = s.expect(["\(Y/N\)\?", "Port in use", "DS-RPC>"])
+                                       if index == 0:
+                                               if dryrun:
+                                                       print "sending N"
+                                                       s.send("N\r\n")
+                                               else:
+                                                       print "sending Y"
+                                                       s.send("Y\r\n")
+                                       elif index == 1:
+                                               raise ExceptionPrompt("PCU Reported 'Port in use.'")
+                                       elif index == 2:
+                                               raise ExceptionSequence("Issued command 'Reboot' failed.")
+
+                               time.sleep(5)
+                               index = s.expect(["DS-RPC>"])
+                               #print "got prompt back"
+
+                       s.close()
+
+               except pexpect.EOF:
+                       raise ExceptionPrompt("EOF before expected Prompt")
+               except pexpect.TIMEOUT:
+                       raise ExceptionPrompt("Timeout before expected Prompt")
 
-               # Reboot Outlet  N        (Y/N)?
-               if dryrun:
-                       self.ifThenSend("(Y/N)?", "N")
-               else:
-                       self.ifThenSend("(Y/N)?", "Y")
-               self.ifThenSend("DS-RPC>", "")
+               return 0
+
+class BayTechCtrlC(PCUControl):
+       """
+               For some reason, these units let you log in fine, but they hang
+               indefinitely, unless you send a Ctrl-C after the password.  No idea
+               why.
+       """
+       def run(self, node_port, dryrun):
+               print "BayTechCtrlC %s" % self.host
+
+               ssh_options="-o StrictHostKeyChecking=no -o PasswordAuthentication=yes -o PubkeyAuthentication=no"
+               s = pxssh.pxssh()
+               if not s.login(self.host, self.username, self.password, ssh_options):
+                       raise ExceptionPassword("Invalid Password")
+               # Otherwise, the login succeeded.
+
+               # Send a ctrl-c to the remote process.
+               print "SENDING ctrl-c"
+               s.send(chr(3))
+
+               # Control Outlets  (5 ,1).........5
+               try:
+                       print "EXPECTING: ", "Enter Request :"
+                       index = s.expect(["Enter Request :"])
+
+                       if index == 0:
+                               print "SENDING: 5"
+                               s.send("5\r\n")
+                               print "EXPECTING: ", "DS-RPC>"
+                               index = s.expect(["DS-RPC>", "Enter user name:", "Port in use."])
+                               if index == 1:
+                                       print "sending username"
+                                       s.send(self.username + "\r\n")
+                                       index = s.expect(["DS-RPC>"])
+                               elif index == 2:
+                                       raise ExceptionPrompt("PCU Reported 'Port in use.'")
+
+                               if index == 0:
+                                       print "SENDING: Reboot %d" % node_port
+                                       s.send("Reboot %d\r\n" % node_port)
+
+                                       print "SLEEPING: 5"
+                                       time.sleep(5)
+                                       print "EXPECTING: ", "Y/N?"
+                                       index = s.expect(["\(Y/N\)\?", "Port in use", "DS-RPC>"])
+                                       if index == 0:
+                                               if dryrun:
+                                                       print "sending N"
+                                                       s.send("N\r\n")
+                                               else:
+                                                       print "SENDING: Y"
+                                                       s.send("Y\r\n")
+                                       elif index == 1:
+                                               raise ExceptionPrompt("PCU Reported 'Port in use.'")
+                                       elif index == 2:
+                                               raise ExceptionSequence("Issued command 'Reboot' failed.")
+
+                               # NOTE: for some reason, the script times out with the
+                               # following line.  In manual tests, it works correctly, but
+                               # with automated tests, evidently it fails.
+                               print "SLEEPING: 5"
+                               time.sleep(5)
+                               #print "TOTAL--", s.allstr, "--EOT"
+                               index = s.expect(["DS-RPC>"])
+                               print "got prompt back"
+
+                       s.close()
+
+               except pexpect.EOF:
+                       raise ExceptionPrompt("EOF before 'Enter Request' Prompt")
+               except pexpect.TIMEOUT:
+                       raise ExceptionPrompt("Timeout before Prompt")
 
-               self.close()
                return 0
 
 class BayTech(PCUControl):
@@ -634,25 +848,42 @@ class BayTech(PCUControl):
 
                # Reboot N
                try:
-                       self.ifThenSend("DS-RPC>", "Reboot %d" % node_port)
+                       self.ifThenSend("DS-RPC>", "Reboot %d" % node_port, ExceptionNotFound)
                except ExceptionNotFound, msg:
                        # one machine is configured to ask for a username,
                        # even after login...
                        print "msg: %s" % msg
                        self.transport.write(self.username + "\r\n")
+                       time.sleep(5)
                        self.ifThenSend("DS-RPC>", "Reboot %d" % node_port)
-                       
 
                # Reboot Outlet  N        (Y/N)?
                if dryrun:
                        self.ifThenSend("(Y/N)?", "N")
                else:
                        self.ifThenSend("(Y/N)?", "Y")
+               time.sleep(5)
                self.ifThenSend("DS-RPC>", "")
 
                self.close()
                return 0
 
+class WTIIPS4(PCUControl):
+       def run(self, node_port, dryrun):
+               self.open(self.host)
+               self.sendPassword(self.password, "Enter Password:")
+
+               self.ifThenSend("IPS> ", "/Boot %s" % node_port)
+               if not dryrun:
+                       self.ifThenSend("Sure? (Y/N): ", "N")
+               else:
+                       self.ifThenSend("Sure? (Y/N): ", "Y")
+
+               self.ifThenSend("IPS> ", "")
+
+               self.close()
+               return 0
+
 class ePowerSwitchGood(PCUControl):
        # NOTE:
        #               The old code used Python's HTTPPasswordMgrWithDefaultRealm()
@@ -694,19 +925,43 @@ class ePowerSwitchGood(PCUControl):
                        # failing here means the User/passwd is wrong (hopefully)
                        raise ExceptionPassword("Incorrect username/password")
 
-               # TODO: after verifying that the user/password is correct, we should
-               # actually reboot the given node.
-
+               # NOTE: after verifying that the user/password is correct, 
+               #               actually reboot the given node.
                if not dryrun:
-                       # add data to handler,
-                       # fetch url one more time on cmd.html, econtrol.html or whatever.
-                       pass
+                       try:
+                               data = urllib.urlencode({'P%d' % node_port : "r"})
+                               req = urllib2.Request(self.url + "cmd.html")
+                               req.add_header("Authorization", authheader)
+                               # add data to handler,
+                               f = urllib2.urlopen(req, data)
+                               if self.verbose: print f.read()
+                       except:
+                               import traceback; traceback.print_exc()
+                               from nodecommon import email_exception
+                               email_exception()
 
-               if self.verbose: print f.read()
+                               # fetch url one more time on cmd.html, econtrol.html or whatever.
+                               # pass
+               else:
+                       if self.verbose: print f.read()
 
                self.close()
                return 0
 
+class CustomPCU(PCUControl):
+       def run(self, node_port, dryrun):
+               url = "https://www-itec.uni-klu.ac.at/plab-pcu/index.php" 
+
+               if not dryrun:
+                       # Turn host off, then on
+                       formstr = "plab%s=off" % node_port
+                       os.system("curl --user %s:%s --form '%s' --insecure %s" % (self.username, self.password, formstr, url))
+                       time.sleep(5)
+                       formstr = "plab%s=on" % node_port
+                       os.system("curl --user %s:%s --form '%s' --insecure %s" % (self.username, self.password, formstr, url))
+               else:
+                       os.system("curl --user %s:%s --insecure %s" % (self.username, self.password, url))
+
 
 class ePowerSwitchOld(PCUControl):
        def run(self, node_port, dryrun):
@@ -918,9 +1173,10 @@ def runcmd(command, args, username, password, timeout = None):
                                out += "; output follows:\n" + data
                        raise Exception, out
 
-def racadm_reboot(ip, username, password, port, dryrun):
+def racadm_reboot(host, username, password, port, dryrun):
        global verbose
 
+       ip = socket.gethostbyname(host)
        try:
                cmd = "/usr/sbin/racadm"
                os.stat(cmd)
@@ -950,11 +1206,16 @@ def pcu_name(pcu):
        else:
                return None
 
-def get_pcu_values(pcu_id):
-       # TODO: obviously, this shouldn't be loaded each time...
-       import soltesz
-       fb =soltesz.dbLoad("findbadpcus")
+#import database
+from monitor import database
+fb = None
 
+def get_pcu_values(pcu_id):
+       global fb
+       if fb == None:
+               # this shouldn't be loaded each time...
+               fb = database.dbLoad("findbadpcus")
+               
        try:
                values = fb['nodes']["id_%s" % pcu_id]['values']
        except:
@@ -962,27 +1223,22 @@ def get_pcu_values(pcu_id):
 
        return values
 
-def check_open_port(values, port_list):
-       ret = False
-
-       if 'portstatus' in values:
-               for port in port_list:
-                       if      port in values['portstatus'] and \
-                               values['portstatus'][port] == "open":
-
-                               ret = True
-       
-       return ret
+def reboot(nodename):
+       return reboot_policy(nodename, True, False)
        
 def reboot_policy(nodename, continue_probe, dryrun):
        global verbose
 
        pcu = plc.getpcu(nodename)
        if not pcu:
+               logger.debug("no pcu for %s" % nodename)
+               print "no pcu for %s" % nodename
                return False # "%s has no pcu" % nodename
 
        values = get_pcu_values(pcu['pcu_id'])
        if values == None:
+               logger.debug("No values for pcu probe %s" % nodename)
+               print "No values for pcu probe %s" % nodename
                return False #"no info for pcu_id %s" % pcu['pcu_id']
        
        # Try the PCU first
@@ -990,9 +1246,11 @@ def reboot_policy(nodename, continue_probe, dryrun):
 
        ret = reboot_test(nodename, values, continue_probe, verbose, dryrun)
 
-       if rb_ret != 0:
+       if ret != 0:
+               print ret
                return False
        else:
+               print "return true"
                return True
 
 def reboot_test(nodename, values, continue_probe, verbose, dryrun):
@@ -1000,19 +1258,29 @@ def reboot_test(nodename, values, continue_probe, verbose, dryrun):
 
        try:
                # DataProbe iPal (many sites)
-               if  continue_probe and values['model'].find("Dataprobe IP-41x/IP-81x") >= 0:
-                       ipal = IPAL(values, verbose, ['23'])
+               if  continue_probe and values['model'].find("IP-41x_IP-81x") >= 0:
+                       ipal = IPAL(values, verbose, ['23', '80', '9100'])
                        rb_ret = ipal.reboot(values[nodename], dryrun)
                                
                # APC Masterswitch (Berkeley)
-               elif continue_probe and values['model'].find("APC AP79xx/Masterswitch") >= 0:
+               elif continue_probe and ( values['model'].find("AP79xx") >= 0 or \
+                                                                 values['model'].find("Masterswitch") >= 0 ):
+                       print values
 
                        # TODO: make a more robust version of APC
-                       if values['pcu_id'] in [1163,1055,1111,1231,1113,1127,1128,1148]:
+                       if values['pcu_id'] in [1102,1163,1055,1111,1231,1113,1127,1128,1148]:
                                apc = APCEurope(values, verbose, ['22', '23'])
                                rb_ret = apc.reboot(values[nodename], dryrun)
 
-                       elif values['pcu_id'] in [1173,1221,1220,1225]:
+                       elif values['pcu_id'] in [1110,86]:
+                               apc = APCBrazil(values, verbose, ['22', '23'])
+                               rb_ret = apc.reboot(values[nodename], dryrun)
+
+                       elif values['pcu_id'] in [1221,1225,1220]:
+                               apc = APCBerlin(values, verbose, ['22', '23'])
+                               rb_ret = apc.reboot(values[nodename], dryrun)
+
+                       elif values['pcu_id'] in [1173,1240,47]:
                                apc = APCFolsom(values, verbose, ['22', '23'])
                                rb_ret = apc.reboot(values[nodename], dryrun)
 
@@ -1021,12 +1289,21 @@ def reboot_test(nodename, values, continue_probe, verbose, dryrun):
                                rb_ret = apc.reboot(values[nodename], dryrun)
 
                # BayTech DS4-RPC
-               elif continue_probe and values['model'].find("Baytech DS4-RPC") >= 0:
-                       if values['pcu_id'] in [1041,1209,1025,1052,1057]:
+               elif continue_probe and values['model'].find("DS4-RPC") >= 0:
+                       if values['pcu_id'] in [1056,1237,1052,1209,1002,1008,1041,1013,1022]:
                                # These  require a 'ctrl-c' to be sent... 
                                baytech = BayTechCtrlC(values, verbose, ['22', '23'])
                                rb_ret = baytech.reboot(values[nodename], dryrun)
 
+                       elif values['pcu_id'] in [93]:
+                               baytech = BayTechAU(values, verbose, ['22', '23'])
+                               rb_ret = baytech.reboot(values[nodename], dryrun)
+
+                       elif values['pcu_id'] in [1057]:
+                               # These  require a 'ctrl-c' to be sent... 
+                               baytech = BayTechCtrlCUnibe(values, verbose, ['22', '23'])
+                               rb_ret = baytech.reboot(values[nodename], dryrun)
+
                        elif values['pcu_id'] in [1012]:
                                # This pcu sometimes doesn't present the 'Username' prompt,
                                # unless you immediately try again...
@@ -1041,38 +1318,56 @@ def reboot_test(nodename, values, continue_probe, verbose, dryrun):
                                rb_ret = baytech.reboot(values[nodename], dryrun)
 
                # iLO
-               elif continue_probe and values['model'].find("HP iLO") >= 0:
-                       hpilo = HPiLO(values, verbose, ['22'])
-                       rb_ret = hpilo.reboot(0, dryrun)
-                       if rb_ret != 0:
+               elif continue_probe and values['model'].find("ilo") >= 0:
+                       try:
+                               hpilo = HPiLO(values, verbose, ['22'])
+                               rb_ret = hpilo.reboot(0, dryrun)
+                               if rb_ret != 0:
+                                       hpilo = HPiLOHttps(values, verbose, ['443'])
+                                       rb_ret = hpilo.reboot(0, dryrun)
+                       except:
                                hpilo = HPiLOHttps(values, verbose, ['443'])
                                rb_ret = hpilo.reboot(0, dryrun)
 
                # DRAC ssh
-               elif continue_probe and values['model'].find("Dell RAC") >= 0:
+               elif continue_probe and values['model'].find("DRAC") >= 0:
                        # TODO: I don't think DRACRacAdm will throw an exception for the
                        # default method to catch...
                        try:
-                               drac = DRACRacAdm(values, verbose, ['443', '5869'])
-                               rb_ret = drac.reboot(0, dryrun)
+                               if values['pcu_id'] in [1402]:
+                                       drac = DRAC(values, verbose, ['22'])
+                                       rb_ret = drac.reboot(0, dryrun)
+                               else:
+                                       drac = DRACRacAdm(values, verbose, ['443', '5869'])
+                                       rb_ret = drac.reboot(0, dryrun)
                        except:
                                drac = DRAC(values, verbose, ['22'])
                                rb_ret = drac.reboot(0, dryrun)
 
-               # BlackBox PSExxx-xx (e.g. PSE505-FR)
-               elif continue_probe and \
-                       (values['model'].find("BlackBox PS5xx") >= 0 or
-                        values['model'].find("ePowerSwitch 1/4/8x") >=0 ):
+               elif continue_probe and values['model'].find("WTI IPS-4") >= 0:
+                               wti = WTIIPS4(values, verbose, ['23'])
+                               rb_ret = wti.reboot(values[nodename], dryrun)
 
+               elif continue_probe and values['model'].find("AMT") >= 0:
+                               amt = IntelAMT(values, verbose, ['16992'])
+                               rb_ret = amt.reboot(values[nodename], dryrun)
+
+               # BlackBox PSExxx-xx (e.g. PSE505-FR)
+               elif continue_probe and values['model'].find("ePowerSwitch") >=0:
                        # TODO: allow a different port than http 80.
                        if values['pcu_id'] in [1089, 1071, 1046, 1035, 1118]:
                                eps = ePowerSwitchGood(values, verbose, ['80'])
                        elif values['pcu_id'] in [1003]:
+                               # OLD EPOWER
+                               print "OLD EPOWER"
                                eps = ePowerSwitch(values, verbose, ['80'])
                        else:
                                eps = ePowerSwitchGood(values, verbose, ['80'])
 
                        rb_ret = eps.reboot(values[nodename], dryrun)
+               elif continue_probe and values['pcu_id'] in [1122]:
+                       custom = CustomPCU(values, verbose, ['80', '443'])
+                       custom.reboot(values[nodename], dryrun)
 
                elif continue_probe:
                        rb_ret = "Unsupported_PCU"
@@ -1098,48 +1393,6 @@ def reboot_test(nodename, values, continue_probe, verbose, dryrun):
        #                                                                 pcu[nodename],
        #                                                                 dryrun)
 
-# Returns true if rebooted via PCU
-def reboot_old(nodename, dryrun):
-       pcu = plc.getpcu(nodename)
-       if not pcu:
-               plc.nodePOD(nodename)
-               return False
-       # Try the PCU first
-       logger.debug("Trying PCU %s %s" % (pcu['hostname'], pcu['model']))
-
-       # APC Masterswitch (Berkeley)
-       if pcu['model'] == "APC Masterswitch":
-               err = apc_reboot(pcu['ip'], pcu['username'],pcu['password'], 
-                               pcu[nodename], pcu['protocol'], dryrun)
-
-       # DataProbe iPal (many sites)
-       elif pcu['protocol'] == "telnet" and pcu['model'].find("IP-4") >= 0:
-               err = ipal_reboot(pcu['ip'],pcu['password'], pcu[nodename], dryrun)
-
-       # BayTech DS4-RPC
-       elif pcu['protocol'] == "ssh" and \
-       (pcu['model'].find("Baytech") >= 0 or pcu['model'].find("DS4") >= 0):
-               err = baytech_reboot(pcu['ip'], pcu['username'],pcu['password'], pcu[nodename], dryrun)
-
-       # BlackBox PSExxx-xx (e.g. PSE505-FR)
-       elif pcu['protocol'] == "http" and (pcu['model'] == "bbpse"):
-               err = bbpse_reboot(pcu['ip'], pcu['username'], pcu['password'], pcu[nodename],80, dryrun)
-
-       # x10toggle
-       elif pcu['protocol'] == "ssh" and (pcu['model'] == "x10toggle"):
-               err = x10toggle_reboot(pcu['ip'], pcu['username'],pcu['password'], pcu[nodename], dryrun)
-
-       # 
-       elif pcu['protocol'] == "racadm" and (pcu['model'] == "RAC"):
-               err = racadm_reboot(pcu['ip'], pcu['username'],pcu['password'], pcu_[nodename], dryrun)
-
-       # Unknown or unsupported
-       else:
-               err = errno.EPROTONOSUPPORT
-               return False
-       return True 
-
-
 def main():
        logger.setLevel(logging.DEBUG)
        ch = logging.StreamHandler()
@@ -1149,9 +1402,23 @@ def main():
        logger.addHandler(ch)
 
        try:
-               reboot("planetlab2.cs.uchicago.edu")
-               reboot("alice.cs.princeton.edu")
+               if "test" in sys.argv:
+                       dryrun = True
+               else:
+                       dryrun = False
+
+               for node in sys.argv[1:]:
+                       if node == "test": continue
+
+                       print "Rebooting %s" % node
+                       if reboot_policy(node, True, dryrun):
+                               print "success"
+                       else:
+                               print "failed"
        except Exception, err:
+               import traceback; traceback.print_exc()
+               from nodecommon import email_exception
+               email_exception()
                print err
 
 if __name__ == '__main__':