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
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]))
TELNET = 1
SSH = 2
HTTP = 3
+ IPAL = 4
TELNET_TIMEOUT = 60
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
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")
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."
-
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!
+ """
+
+ 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
+
+ try:
+ # TODO: make sleep backoff, before stopping.
+ time.sleep(4)
+ ret = s.recv(count, socket.MSG_DONTWAIT)
+ except socket.error, e:
+ if e[0] == errno.EAGAIN:
+ raise Exception(e[1])
+ else:
+ # TODO: not other exceptions.
+ raise Exception(e)
+ return ret
+
def run(self, node_port, dryrun):
- self.open(self.host)
+ import errno
- # XXX Some iPals require you to hit Enter a few times first
- self.ifThenSend("Password >", "\r\n\r\n", ExceptionNotFound)
+ power_on = False
- # Login
- self.ifThenSend("Password >", self.password, ExceptionPassword)
- self.transport.write("\r\n\r\n")
+ 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])
+ 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' %s : %s" % (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
+ else:
+ raise Exception("Unknown status for PCU socket %s : %s" % (node_port, ret))
+ else:
+ raise Exception("Mismatch between configured port and PCU status: %s %s" % (node_port, ret))
+
- if not dryrun: # P# - Pulse relay
- self.ifThenSend("Enter >",
- "P%d" % node_port,
- ExceptionNotFound)
- # Get the next prompt
- self.ifElse("Enter >", ExceptionTimeout)
+ 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
+ else:
+ raise Exception("Unknown status for PCU socket %s : %s" % (node_port, ret))
+ else:
+ raise Exception("Mismatch between configured port and PCU status: %s %s" % (node_port, ret))
- self.close()
+ if power_on:
+ return 0
+ else:
+ return "Failed Power On"
+
+ 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):
self.open(self.host, self.username)
class APCMaster(PCUControl):
def run(self, node_port, dryrun):
+ print "Rebooting %s" % self.host
self.open(self.host, self.username)
self.sendPassword(self.password)
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):
class HPiLOHttps(PCUControl):
def run(self, node_port, dryrun):
- import soltesz
- #cmd = "cmdhttps/locfg.pl -s %s -f %s -u %s -p '%s'" % (
- # 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()
-
- locfg = soltesz.CMD()
+ 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)
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:
- locfg = soltesz.CMD()
+ 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)
- #cmd = "cmdhttps/locfg.pl -s %s -f %s -u %s -p '%s'" % (
- # self.host, "iloxml/Reset_Server.xml",
- # self.username, self.password)
- #print cmd
- #p_ilo = Popen(cmd, stdin=PIPE, stdout=PIPE, shell=True)
- #cmd2 = "grep 'MESSAGE' | grep -v 'No error'"
- #p_grep = Popen(cmd2, shell=True, stdin=p_ilo.stdout, stdout=PIPE, stderr=PIPE)
- #sout, serr = p_grep.communicate()
- #try: p_ilo.wait()
- #except:
- # print "p_ilo wait failed."
- # pass
- #try: p_grep.wait()
- #except:
- # print "p_grep wait failed."
- # pass
-
if sout.strip() != "":
print "sout: %s" % sout.strip()
#return sout.strip()
# Control Outlets (5 ,1).........5
try:
+ #index = s.expect("Enter Request")
index = s.expect(["Enter Request :"])
if index == 0:
print "Reboot %d" % node_port
s.send("Reboot %d\r\n" % node_port)
- index = s.expect(["(Y/N)?"])
+ time.sleep(5)
+ index = s.expect(["\(Y/N\)\?", "Port in use", "DS-RPC>"])
if index == 0:
if dryrun:
print "sending 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.")
- #index = s.expect(["DS-RPC>"])
+ time.sleep(5)
+ index = s.expect(["DS-RPC>"])
#print "got prompt back"
s.close()
except pexpect.EOF:
- raise ExceptionPrompt("EOF before 'Enter Request' Prompt")
+ raise ExceptionPrompt("EOF before expected Prompt")
except pexpect.TIMEOUT:
- raise ExceptionPrompt("Timeout before 'Enter Request' Prompt")
+ raise ExceptionPrompt("Timeout before expected Prompt")
return 0
# Otherwise, the login succeeded.
# Send a ctrl-c to the remote process.
- print "sending ctrl-c"
+ 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 "5"
+ print "SENDING: 5"
s.send("5\r\n")
- index = s.expect(["DS-RPC>", "Enter user name:"])
+ 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 "Reboot %d" % node_port
+ print "SENDING: Reboot %d" % node_port
s.send("Reboot %d\r\n" % node_port)
- index = s.expect(["(Y/N)?"])
+ 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"
+ 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"
+ print "got prompt back"
s.close()
except pexpect.EOF:
raise ExceptionPrompt("EOF before 'Enter Request' Prompt")
except pexpect.TIMEOUT:
- raise ExceptionPrompt("Timeout before 'Enter Request' Prompt")
+ raise ExceptionPrompt("Timeout before Prompt")
return 0
# 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)?
self.ifThenSend("(Y/N)?", "N")
else:
self.ifThenSend("(Y/N)?", "Y")
+ time.sleep(5)
self.ifThenSend("DS-RPC>", "")
self.close()
# 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()
- 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):
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:
pcu = plc.getpcu(nodename)
if not pcu:
+ logger.debug("no pcu for %s" % hostname)
+ print "no pcu for %s" % hostname
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" % hostname)
+ print "No values for pcu probe %s" % hostname
return False #"no info for pcu_id %s" % pcu['pcu_id']
# Try the PCU first
print ret
return False
else:
+ print "return true"
return True
def reboot_test(nodename, values, continue_probe, verbose, dryrun):
rb_ret = ""
+ if 'plc_pcu_stats' in values:
+ values.update(values['plc_pcu_stats'])
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)
apc = APCBrazil(values, verbose, ['22', '23'])
rb_ret = apc.reboot(values[nodename], dryrun)
- elif values['pcu_id'] in [1221,1225]:
+ 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,1221,1220]:
+ elif values['pcu_id'] in [1173,1240]:
apc = APCFolsom(values, verbose, ['22', '23'])
rb_ret = apc.reboot(values[nodename], 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 [1237,1052,1209,1002,1008,1041,1013,1022]:
+ 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)
rb_ret = baytech.reboot(values[nodename], dryrun)
# iLO
- elif continue_probe and values['model'].find("HP iLO") >= 0:
+ elif continue_probe and values['model'].find("ilo") >= 0:
try:
hpilo = HPiLO(values, verbose, ['22'])
rb_ret = hpilo.reboot(0, dryrun)
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:
wti = WTIIPS4(values, verbose, ['23'])
rb_ret = wti.reboot(values[nodename], 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("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"
logger.addHandler(ch)
try:
+ 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, False):
+ if reboot_policy(node, True, dryrun):
print "success"
else:
print "failed"
except Exception, err:
+ import traceback; traceback.print_exc()
print err
if __name__ == '__main__':