75668dbabc2b52fa5274d9566ad68162ea3e4db9
[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(4)
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 Exception(e[1])
82                         else:
83                                 # TODO: what other conditions are there?
84                                 raise Exception(e)
85                                 
86                 # get current status
87                 print "Checking status"
88                 s.send(self.format_msg("", 'O'))
89                 ret = self.recv_noblock(s, 8)
90                 print "Current status is '%s'" % ret
91
92                 if ret == '':
93                         raise Exception("Status returned 'another session already open' %s : %s" % (node_port, ret))
94                                 
95                 if node_port < len(ret):
96                         status = ret[node_port]
97                         if status == '1':
98                                 # up
99                                 power_on = True
100                         elif status == '0':
101                                 # down
102                                 power_on = False
103                         else:
104                                 raise Exception("Unknown status for PCU socket %s : %s" % (node_port, ret))
105                 else:
106                         raise Exception("Mismatch between configured port and PCU status: %s %s" % (node_port, ret))
107                         
108
109                 if not dryrun:
110                         if power_on:
111                                 print "Pulsing %s" % node_port
112                                 s.send(self.format_msg("%s" % node_port, 'P'))
113                         else:
114                                 # NOTE: turn power on ; do not pulse the port.
115                                 print "Power was off, so turning on ..."
116                                 s.send(self.format_msg("%s" % node_port, 'E'))
117                                 #s.send(self.format_msg("%s" % node_port, 'P'))
118
119                         print "Receiving response."
120                         ret = self.recv_noblock(s, 8)
121                         print "Current status is '%s'" % ret
122
123                         if node_port < len(ret):
124                                 status = ret[node_port]
125                                 if status == '1':
126                                         # up
127                                         power_on = True
128                                 elif status == '0':
129                                         # down
130                                         power_on = False
131                                 else:
132                                         raise Exception("Unknown status for PCU socket %s : %s" % (node_port, ret))
133                         else:
134                                 raise Exception("Mismatch between configured port and PCU status: %s %s" % (node_port, ret))
135
136                         if power_on:
137                                 return 0
138                         else:
139                                 return "Failed Power On"
140
141                 s.close()
142                 return 0