added httpd/conf.d/monitorweb.conf to /etc/plc.d/monitor.init
[monitor.git] / pcucontrol / reboot.py
index f753471..5b322d3 100755 (executable)
@@ -117,7 +117,7 @@ class Transport:
        HTTP   = 3
        IPAL   = 4
 
-       TELNET_TIMEOUT = 60
+       TELNET_TIMEOUT = 120
 
        def __init__(self, type, verbose):
                self.type = type
@@ -204,6 +204,7 @@ class Transport:
                if self.transport != None:
                        output = self.transport.read_until(expected, self.TELNET_TIMEOUT)
                        if output.find(expected) == -1:
+                               print "OUTPUT: --%s--" % output
                                raise ErrorClass, "'%s' not found" % expected
                        else:
                                self.transport.write(buffer + "\r\n")
@@ -218,6 +219,9 @@ class Transport:
                        
 
 class PCUControl(Transport,PCUModel,PCURecord):
+
+       supported_ports = []
+
        def __init__(self, plc_pcu_record, verbose, supported_ports=[]):
                PCUModel.__init__(self, plc_pcu_record)
                PCURecord.__init__(self, plc_pcu_record)
@@ -275,13 +279,37 @@ class PCUControl(Transport,PCUModel,PCURecord):
                        import traceback
                        traceback.print_exc()
                        return "EOF connection reset" + str(err)
-               
+
+class IPMI(PCUControl):
+
+       supported_ports = [80,443,623]
+
+       # TODO: get exit codes to determine success or failure...
+       def run(self, node_port, dryrun):
+
+               if not dryrun:
+                       cmd = "ipmitool -I lanplus -H %s -U %s -P '%s' power cycle"
+                       p = os.popen(cmd % ( self.host, self.username, self.password) )
+                       result = p.read()
+                       print "RESULT: ", result
+               else:
+                       cmd = "ipmitool -I lanplus -H %s -U %s -P '%s' user list"
+                       p = os.popen(cmd % ( self.host, self.username, self.password) )
+                       result = p.read()
+                       print "RESULT: ", result
+
+               if "Error" in result:
+                       return result
+               else:
+                       return 0
+                       
 class IPAL(PCUControl):
        """ 
                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!
        """
+       supported_ports = [23,80,9100]
 
        def format_msg(self, data, cmd):
                esc = chr(int('1b',16))
@@ -303,6 +331,37 @@ class IPAL(PCUControl):
                return ret
 
        def run(self, node_port, dryrun):
+               if self.type == Transport.IPAL:
+                       return self.run_ipal(node_port, dryrun)
+               elif self.type == Transport.TELNET:
+                       return self.run_telnet(node_port, dryrun)
+               else:
+                       raise Exception("Unimplemented Transport for IPAL")
+       
+       def run_telnet(self, node_port, dryrun):
+               # 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
+
+       def run_ipal(self, node_port, dryrun):
                import errno
 
                power_on = False
@@ -329,7 +388,6 @@ class IPAL(PCUControl):
 
                if ret == '':
                        raise Exception("Status returned 'another session already open' %s : %s" % (node_port, ret))
-                       
                                
                if node_port < len(ret):
                        status = ret[node_port]
@@ -380,27 +438,6 @@ class IPAL(PCUControl):
                s.close()
                return 0
 
-# 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
 
 class APCEurope(PCUControl):
        def run(self, node_port, dryrun):
@@ -498,6 +535,7 @@ class APCFolsom(PCUControl):
                return 0
 
 class APCMaster(PCUControl):
+       supported_ports = [22,23]
        def run(self, node_port, dryrun):
                print "Rebooting %s" % self.host
                self.open(self.host, self.username)
@@ -557,11 +595,13 @@ class APC(PCUControl):
                        return ret
 
 class IntelAMT(PCUControl):
+       supported_ports = [16992]
+
        def run(self, node_port, dryrun):
 
                cmd = command.CMD()
-               #[cmd_str = "IntelAMTSDK/Samples/RemoteControl/remoteControl"
-               cmd_str = "cmdamt/remoteControl"
+               # TODO: need to make this path universal; not relative to pwd.
+               cmd_str = "pcucontrol/models/intelamt/remoteControl"
 
                if dryrun:
                        # NOTE: -p checks the power state of the host.
@@ -582,6 +622,7 @@ class DRACRacAdm(PCUControl):
                return 0
 
 class DRAC(PCUControl):
+       supported_ports = [22,443,5869]
        def run(self, node_port, dryrun):
                self.open(self.host, self.username)
                self.sendPassword(self.password)
@@ -601,6 +642,7 @@ class DRAC(PCUControl):
                return 0
 
 class HPiLO(PCUControl):
+       supported_ports = [22,443]
        def run(self, node_port, dryrun):
                self.open(self.host, self.username)
                self.sendPassword(self.password)
@@ -622,6 +664,7 @@ class HPiLO(PCUControl):
 
                
 class HPiLOHttps(PCUControl):
+       supported_ports = [22,443]
        def run(self, node_port, dryrun):
 
                locfg = command.CMD()
@@ -821,6 +864,7 @@ class BayTechCtrlC(PCUControl):
                return 0
 
 class BayTech(PCUControl):
+       supported_ports = [22,23]
        def run(self, node_port, dryrun):
                self.open(self.host, self.username)
                self.sendPassword(self.password)
@@ -851,6 +895,7 @@ class BayTech(PCUControl):
                return 0
 
 class WTIIPS4(PCUControl):
+       supported_ports = [23]
        def run(self, node_port, dryrun):
                self.open(self.host)
                self.sendPassword(self.password, "Enter Password:")
@@ -967,6 +1012,7 @@ class ePowerSwitchOld(PCUControl):
                return 0
 
 class ePowerSwitch(PCUControl):
+       supported_ports = [80]
        def run(self, node_port, dryrun):
                self.url = "http://%s:%d/" % (self.host,80)
                uri = "%s:%d" % (self.host,80)
@@ -1000,6 +1046,16 @@ class ePowerSwitch(PCUControl):
                self.close()
                return 0
                
+class ManualPCU(PCUControl):
+       supported_ports = [22,23,80,443,9100,16992]
+
+       def run(self, node_port, dryrun):
+               if not dryrun:
+                       # TODO: send email message to monitor admin requesting manual
+                       # intervention.  This should always be an option for ridiculous,
+                       # custom jobs.
+                       pass
+               return 0
 
 ### rebooting european BlackBox PSE boxes
 # Thierry Parmentelat - May 11 2005
@@ -1010,6 +1066,29 @@ class ePowerSwitch(PCUControl):
 # curl --http1.0 --basic --user <username>:<password> --data P<port>=r \
 #      http://<hostname>:<http_port>/cmd.html && echo OK
 
+# log in:
+
+## BB PSMaverick
+class BlackBoxPSMaverick(PCUControl):
+       supported_ports = [80]
+
+       def run(self, node_port, dryrun):
+               if not dryrun:
+                       # send reboot signal.
+                       cmd = "curl -s --data 'P%s=r' --anyauth --user '%s:%s' http://%s/config/home_f.html" % ( node_port, self.username, self.password, self.host)
+               else:
+                       # else, just try to log in
+                       cmd = "curl -s --anyauth --user '%s:%s' http://%s/config/home_f.html" % ( self.username, self.password, self.host)
+
+               p = os.popen(cmd)
+               result = p.read()
+               print "RESULT: ", result
+
+               if len(result.split()) > 3:
+                       return 0
+               else:
+                       return result
+
 def bbpse_reboot (pcu_ip,username,password,port_in_pcu,http_port, dryrun):
 
        global verbose
@@ -1233,6 +1312,33 @@ def reboot_policy(nodename, continue_probe, dryrun):
                print "return true"
                return True
 
+class Unknown(PCUControl):
+       supported_ports = [22,23,80,443,5869,9100,16992]
+
+def model_to_object(modelname):
+       if "AMT" in modelname:
+               return IntelAMT
+       elif "DS4-RPC" in modelname:
+               return BayTech
+       elif "ilo2" in modelname:
+               return HPiLO
+       elif "IP-41x" in modelname:
+               return IPAL
+       elif "AP79xx" in modelname or "Masterswitch" in modelname:
+               return APCMaster
+       elif "DRAC" in modelname:
+               return DRAC
+       elif "WTI" in modelname:
+               return WTIIPS4
+       elif "ePowerSwitch" in modelname:
+               return ePowerSwitch
+       elif "ipmi" in modelname:
+               return IPMI
+       elif "bbsemaverick" in modelname:
+               return BlackBoxPSMaverick
+       else:
+               return Unknown
+
 def reboot_test(nodename, values, continue_probe, verbose, dryrun):
        rb_ret = ""
        if 'plc_pcu_stats' in values:
@@ -1258,11 +1364,11 @@ def reboot_test(nodename, values, continue_probe, verbose, dryrun):
                                apc = APCBrazil(values, verbose, ['22', '23'])
                                rb_ret = apc.reboot(values[nodename], dryrun)
 
-                       elif values['pcu_id'] in [1221,1225,1220]:
+                       elif values['pcu_id'] in [1221,1225,1220,1192]:
                                apc = APCBerlin(values, verbose, ['22', '23'])
                                rb_ret = apc.reboot(values[nodename], dryrun)
 
-                       elif values['pcu_id'] in [1173,1240,47]:
+                       elif values['pcu_id'] in [1173,1240,47,1363,1405,1401,1372,1371]:
                                apc = APCFolsom(values, verbose, ['22', '23'])
                                rb_ret = apc.reboot(values[nodename], dryrun)
 
@@ -1330,7 +1436,17 @@ def reboot_test(nodename, values, continue_probe, verbose, dryrun):
                                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("bbsemaverick") >=0:
+                       print "TRYING BlackBoxPSMaverick"
+                       bbe = BlackBoxPSMaverick(values, verbose, ['80'])
+                       rb_ret = bbe.reboot(values[nodename], dryrun)
+
+               elif continue_probe and values['model'].find("ipmi") >=0:
+
+                       print "TRYING IPMI"
+                       ipmi = IPMI(values, verbose, ['80', '443', '623'])
+                       rb_ret = ipmi.reboot(values[nodename], dryrun)
+
                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]: