a2ea026ebd6802490383aed2576cd6993b8e788a
[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                         else:
26                                 # TODO: not other exceptions.
27                                 raise Exception(e)
28                 return ret
29
30         #def run(self, node_port, dryrun):
31         #       if self.type == Transport.IPAL:
32         #               ret = self.run_ipal(node_port, dryrun)
33         #               if ret != 0:
34         #                       ret2 = self.run_telnet(node_port, dryrun)
35         #                       if ret2 != 0:
36         #                               return ret
37         #                       return ret2
38         #               return ret
39         #       elif self.type == Transport.TELNET:
40         #               return self.run_telnet(node_port, dryrun)
41         #       else:
42         #               raise ExceptionNoTransport("Unimplemented Transport for IPAL")
43         
44         def run_telnet(self, node_port, dryrun):
45                 # TELNET version of protocol...
46                 self.transport.open(self.host)
47                 ## XXX Some iPals require you to hit Enter a few times first
48                 self.transport.ifThenSend("Password >", "\r\n\r\n", ExceptionNotFound)
49                 # Login
50                 self.transport.ifThenSend("Password >", self.password, ExceptionPassword)
51                 self.transport.write("\r\n\r\n")
52                 if not dryrun: # P# - Pulse relay
53                         print "node_port %s" % node_port
54                         self.transport.ifThenSend("Enter >", 
55                                                         "P7", # % node_port, 
56                                                         ExceptionNotFound)
57                         print "send newlines"
58                         self.transport.write("\r\n\r\n")
59                         print "after new lines"
60                 # Get the next prompt
61                 print "wait for enter"
62                 self.transport.ifElse("Enter >", ExceptionTimeout)
63                 print "closing "
64                 self.transport.close()
65                 return 0
66
67         def run_ipal(self, node_port, dryrun):
68                 import errno
69
70                 power_on = False
71
72                 print "open socket"
73                 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
74                 try:
75                         print "connect"
76                         s.connect((self.host, 9100))
77                 except socket.error, e:
78                         s.close()
79                         if e[0] == errno.ECONNREFUSED:
80                                 # cannot connect to remote host
81                                 raise ExceptionNotFound(e[1])
82                         elif e[0] == errno.ETIMEDOUT:
83                                 raise ExceptionTimeout(e[1])
84                         else:
85                                 # TODO: what other conditions are there?
86                                 raise Exception(e)
87                                 
88                 # get current status
89                 print "Checking status"
90                 s.send(self.format_msg("", 'O'))
91                 ret = self.recv_noblock(s, 8)
92                 print "Current status is '%s'" % ret
93
94                 if ret == '':
95                         raise Exception("Status returned 'another session already open' on %s %s : %s" % (self.host, node_port, ret))
96                                 
97                 if node_port < len(ret):
98                         status = ret[node_port]
99                         if status == '1':
100                                 # up
101                                 power_on = True
102                         elif status == '0':
103                                 # down
104                                 power_on = False
105                         elif status == '6':
106                                 raise ExceptionPort("IPAL reported 'Cable Error' on %s socket %s : %s" % (self.host, node_port, ret))
107                         else:
108                                 raise Exception("Unknown status for PCU %s socket %s : %s" % (self.host, node_port, ret))
109                 else:
110                         raise Exception("Mismatch between configured port and PCU %s status: %s %s" % (self.host, node_port, ret))
111                         
112
113                 if not dryrun:
114                         if power_on:
115                                 print "Pulsing %s" % node_port
116                                 s.send(self.format_msg("%s" % node_port, 'P'))
117                         else:
118                                 # NOTE: turn power on ; do not pulse the port.
119                                 print "Power was off, so turning on ..."
120                                 s.send(self.format_msg("%s" % node_port, 'E'))
121                                 #s.send(self.format_msg("%s" % node_port, 'P'))
122
123                         print "Receiving response."
124                         ret = self.recv_noblock(s, 8)
125                         print "Current status is '%s'" % ret
126
127                         if node_port < len(ret):
128                                 status = ret[node_port]
129                                 if status == '1':
130                                         # up
131                                         power_on = True
132                                 elif status == '0':
133                                         # down
134                                         power_on = False
135                                 elif status == '6':
136                                         raise ExceptionPort("IPAL reported 'Cable Error' on %s socket %s : %s" % (self.host, node_port, ret))
137                                 else:
138                                         raise Exception("Unknown status for PCU %s socket %s : %s" % (self.host, node_port, ret))
139                         else:
140                                 raise Exception("Mismatch between configured port and PCU %s status: %s %s" % (self.host, node_port, ret))
141
142                         if power_on:
143                                 return 0
144                         else:
145                                 return "Failed Power On"
146
147                 s.close()
148                 return 0