svn merge -r 12308:13112 https://svn.planet-lab.org/svn/Monitor/branches/2.0/
[monitor.git] / pcucontrol / models / DRAC.py
1 from pcucontrol.reboot import *
2 import time
3
4 class DRAC(PCUControl):
5         supported_ports = [22,443,5869]
6         def run_drac(self, node_port, dryrun):
7                 print "trying racadm_reboot..."
8                 return racadm_reboot(self.host, self.username, self.password, node_port, dryrun)
9
10         def run_ssh(self, node_port, dryrun):
11                 ssh_options="-o StrictHostKeyChecking=no "+\
12                             "-o PasswordAuthentication=yes "+\
13                                         "-o PubkeyAuthentication=no"
14                 s = pxssh.pxssh()
15                 try:
16                         if not s.login(self.host, self.username, self.password, ssh_options,
17                                                 original_prompts="Dell", login_timeout=Transport.TELNET_TIMEOUT):
18                                 raise ExceptionPassword("Invalid Password")
19                 except pexpect.EOF:
20                         raise ExceptionPrompt("Disconnect before login prompt")
21                         
22                 print "logging in... %s" % self.host
23                 s.send("\r\n\r\n")
24                 try:
25                         # Testing Reboot ?
26                         #index = s.expect(["DRAC 5", "[%s]#" % self.username ])
27                         # NOTE: be careful to escape any characters used by 're.compile'
28                         index = s.expect(["\$", "\[%s\]#" % self.username ])
29                         print "INDEX:", index
30                         print s
31                         if dryrun:
32                                 if index == 0:
33                                         s.sendline("racadm getsysinfo")
34                                 elif index == 1:
35                                         s.sendline("getsysinfo")
36                         else:
37                                 print "serveraction powercycle"
38                                 if index == 0:
39                                         s.sendline("racadm serveraction powercycle")
40                                 elif index == 1:
41                                         s.sendline("serveraction powercycle")
42                                 
43                         # TODO:  this is really lousy.  Without the sleep, the sendlines
44                         # don't completely get through.  Even the added, expect line
45                         # returns right away without waiting for the commands above to
46                         # complete...  Therefore, this delay is guaranteed to fail in some
47                         # other context...
48                         time.sleep(5)
49                         index = s.expect(["\$", "\[%s\]#" % self.username ])
50                         print s
51                         print "INDEX 2:", index
52                         s.sendline("exit")
53
54                 except pexpect.EOF:
55                         raise ExceptionPrompt("EOF before expected Prompt")
56                 except pexpect.TIMEOUT:
57                         print s
58                         raise ExceptionPrompt("Timeout before expected Prompt")
59
60                 s.close()
61
62                 return 0
63
64 ### rebooting Dell systems via RAC card
65 # Marc E. Fiuczynski - June 01 2005
66 # tested with David Lowenthal's itchy/scratchy nodes at UGA
67 #
68 def runcmd(command, args, username, password, timeout = None):
69
70         result = [None]
71         result_ready = threading.Condition()
72
73         def set_result(x):
74
75                 result_ready.acquire()
76                 try:
77                         result[0] = x
78                 finally:
79                         result_ready.notify()
80                         result_ready.release()
81
82         def do_command(command, username, password):
83
84                 try:
85                         # Popen4 is a popen-type class that combines stdout and stderr
86                         p = popen2.Popen4(command)
87
88                         # read all output data
89                         p.tochild.write("%s\n" % username)
90                         p.tochild.write("%s\n" % password)
91                         p.tochild.close()
92                         data = p.fromchild.read()
93
94                         while True:
95                                 # might get interrupted by a signal in poll() or waitpid()
96                                 try:
97                                         retval = p.wait()
98                                         set_result((retval, data))
99                                         break
100                                 except OSError, ex:
101                                         if ex.errno == errno.EINTR:
102                                                 continue
103                                         raise ex
104                 except Exception, ex:
105                         set_result(ex)
106
107         if args:
108                 command = " ".join([command] + args)
109
110         worker = threading.Thread(target = do_command, args = (command, username, password, ))
111         worker.setDaemon(True)
112         result_ready.acquire()
113         worker.start()
114         result_ready.wait(timeout)
115         try:
116                 if result == [None]:
117                         raise Exception, "command timed-out: '%s'" % command
118         finally:
119                 result_ready.release()
120         result = result[0]
121
122         if isinstance(result, Exception):
123                 raise result
124         else:
125                 (retval, data) = result
126                 if os.WIFEXITED(retval) and os.WEXITSTATUS(retval) == 0:
127                         return data
128                 else:
129                         out = "system command ('%s') " % command
130                         if os.WIFEXITED(retval):
131                                 out += "failed, rc = %d" % os.WEXITSTATUS(retval)
132                         else:
133                                 out += "killed by signal %d" % os.WTERMSIG(retval)
134                         if data:
135                                 out += "; output follows:\n" + data
136                         raise Exception, out
137
138 def racadm_reboot(host, username, password, port, dryrun):
139         global verbose
140
141         ip = socket.gethostbyname(host)
142         try:
143                 cmd = "/usr/sbin/racadm"
144                 os.stat(cmd)
145                 if not dryrun:
146                         output = runcmd(cmd, ["-r %s -i serveraction powercycle" % ip],
147                                 username, password)
148                 else:
149                         output = runcmd(cmd, ["-r %s -i getsysinfo" % ip],
150                                 username, password)
151
152                 print "RUNCMD: %s" % output
153                 if verbose:
154                         print output
155                 return 0
156
157         except Exception, err:
158                 print "runcmd raised exception %s" % err
159                 return str(err)