pull in additional changes from 2.0 branch.
[monitor.git] / pcucontrol / models / IPAL.py
1 from pcucontrol.reboot import *
2
3 class IPAL(PCUControl):
4         """ 
5                 This now uses a proprietary format for communicating with the PCU.  I
6                 prefer it to Telnet, and Web access, since it's much lighter weight
7                 and, more importantly, IT WORKS!! HHAHHHAHAHAHAHAHA!
8         """
9         supported_ports = [9100,23,80]
10
11         def format_msg(self, data, cmd):
12                 esc = chr(int('1b',16))
13                 return "%c%s%c%s%c" % (esc, self.password, esc, data, cmd) # esc, 'q', chr(4))
14         
15         def recv_noblock(self, s, count):
16                 import errno
17
18                 try:
19                         # TODO: make sleep backoff, before stopping.
20                         time.sleep(8)
21                         ret = s.recv(count, socket.MSG_DONTWAIT)
22                 except socket.error, e:
23                         if e[0] == errno.EAGAIN:
24                                 #raise Exception(e[1])
25                                 raise ExceptionNotFound(e[1])
26                         elif e[0] == errno.ETIMEDOUT:
27                                 raise ExceptionTimeout(e[1])
28                         else:
29                                 # TODO: not other exceptions.
30                                 raise Exception(e)
31                 return ret
32
33         #def run(self, node_port, dryrun):
34         #       if self.type == Transport.IPAL:
35         #               ret = self.run_ipal(node_port, dryrun)
36         #               if ret != 0:
37         #                       ret2 = self.run_telnet(node_port, dryrun)
38         #                       if ret2 != 0:
39         #                               return ret
40         #                       return ret2
41         #               return ret
42         #       elif self.type == Transport.TELNET:
43         #               return self.run_telnet(node_port, dryrun)
44         #       else:
45         #               raise ExceptionNoTransport("Unimplemented Transport for IPAL")
46         
47         def run_telnet(self, node_port, dryrun):
48                 # TELNET version of protocol...
49                 self.transport.open(self.host)
50                 ## XXX Some iPals require you to hit Enter a few times first
51                 self.transport.ifThenSend("Password >", "\r\n\r\n", ExceptionNotFound)
52                 # Login
53                 self.transport.ifThenSend("Password >", self.password, ExceptionPassword)
54                 self.transport.write("\r\n\r\n")
55                 if not dryrun: # P# - Pulse relay
56                         print "node_port %s" % node_port
57                         self.transport.ifThenSend("Enter >", 
58                                                         "P7", # % node_port, 
59                                                         ExceptionNotFound)
60                         print "send newlines"
61                         self.transport.write("\r\n\r\n")
62                         print "after new lines"
63                 # Get the next prompt
64                 print "wait for enter"
65                 self.transport.ifElse("Enter >", ExceptionTimeout)
66                 print "closing "
67                 self.transport.close()
68                 return 0
69
70         def run_ipal(self, node_port, dryrun):
71                 import errno
72
73                 power_on = False
74
75                 print "open socket"
76                 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
77                 try:
78                         print "connect"
79                         s.connect((self.host, 9100))
80                 except socket.error, e:
81                         s.close()
82                         if e[0] == errno.ECONNREFUSED:
83                                 # cannot connect to remote host
84                                 raise ExceptionNotFound(e[1])
85                         elif e[0] == errno.ETIMEDOUT:
86                                 raise ExceptionTimeout(e[1])
87                         else:
88                                 # TODO: what other conditions are there?
89                                 raise Exception(e)
90                                 
91                 # get current status
92                 print "Checking status"
93                 s.send(self.format_msg("", 'O'))
94                 ret = self.recv_noblock(s, 8)
95                 print "Current status is '%s'" % ret
96
97                 if ret == '':
98                         raise Exception("Status returned 'another session already open' on %s %s : %s" % (self.host, node_port, ret))
99                                 
100                 if node_port < len(ret):
101                         status = ret[node_port]
102                         if status == '1':
103                                 # up
104                                 power_on = True
105                         elif status == '0':
106                                 # down
107                                 power_on = False
108                         elif status == '6':
109                                 raise ExceptionPort("IPAL reported 'Cable Error' on %s socket %s : %s" % (self.host, node_port, ret))
110                         else:
111                                 raise Exception("Unknown status for PCU %s socket %s : %s" % (self.host, node_port, ret))
112                 else:
113                         raise Exception("Mismatch between configured port and PCU %s status: %s %s" % (self.host, node_port, ret))
114                         
115
116                 if not dryrun:
117                         if power_on:
118                                 print "Pulsing %s" % node_port
119                                 s.send(self.format_msg("%s" % node_port, 'P'))
120                         else:
121                                 # NOTE: turn power on ; do not pulse the port.
122                                 print "Power was off, so turning on ..."
123                                 s.send(self.format_msg("%s" % node_port, 'E'))
124                                 #s.send(self.format_msg("%s" % node_port, 'P'))
125
126                         print "Receiving response."
127                         ret = self.recv_noblock(s, 8)
128                         print "Current status is '%s'" % ret
129
130                         if node_port < len(ret):
131                                 status = ret[node_port]
132                                 if status == '1':
133                                         # up
134                                         power_on = True
135                                 elif status == '0':
136                                         # down
137                                         power_on = False
138                                 elif status == '6':
139                                         raise ExceptionPort("IPAL reported 'Cable Error' on %s socket %s : %s" % (self.host, node_port, ret))
140                                 else:
141                                         raise Exception("Unknown status for PCU %s socket %s : %s" % (self.host, node_port, ret))
142                         else:
143                                 raise Exception("Mismatch between configured port and PCU %s status: %s %s" % (self.host, node_port, ret))
144
145                         if power_on:
146                                 return 0
147                         else:
148                                 return "Failed Power On"
149
150                 s.close()
151                 return 0