blob: d4c329e7504f83178b8399b66273b6e4d955498a [file] [log] [blame]
Ahmad Shariffd356fb2012-05-07 12:02:16 -07001#!/usr/bin/python
2#
3# Copyright 2011 Google Inc. All Rights Reserved.
4#
5
Ahmad Sharif70de27b2011-06-15 17:51:24 -07006import getpass
Ahmad Sharif70de27b2011-06-15 17:51:24 -07007import os
Ahmad Sharif70de27b2011-06-15 17:51:24 -07008import re
9import select
10import subprocess
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -080011import tempfile
Ahmad Sharif70de27b2011-06-15 17:51:24 -070012import time
Ahmad Shariffd356fb2012-05-07 12:02:16 -070013
14import logger
15import misc
Ahmad Sharif70de27b2011-06-15 17:51:24 -070016
17mock_default = False
18
cmtice13909242014-03-11 13:38:07 -070019LOG_LEVEL=("quiet", "average", "verbose")
Ahmad Sharif70de27b2011-06-15 17:51:24 -070020
21def InitCommandExecuter(mock=False):
22 global mock_default
23 # Whether to default to a mock command executer or not
24 mock_default = mock
25
26
cmtice13909242014-03-11 13:38:07 -070027def GetCommandExecuter(logger_to_set=None, mock=False, log_level="verbose"):
Ahmad Sharif70de27b2011-06-15 17:51:24 -070028 # If the default is a mock executer, always return one.
29 if mock_default or mock:
30 return MockCommandExecuter(logger_to_set)
31 else:
cmtice13909242014-03-11 13:38:07 -070032 return CommandExecuter(log_level, logger_to_set)
Ahmad Sharif70de27b2011-06-15 17:51:24 -070033
34
35class CommandExecuter:
cmtice13909242014-03-11 13:38:07 -070036 def __init__(self, log_level, logger_to_set=None):
37 self.log_level = log_level
Ahmad Sharif70de27b2011-06-15 17:51:24 -070038 if logger_to_set is not None:
39 self.logger = logger_to_set
40 else:
41 self.logger = logger.GetLogger()
42
cmtice13909242014-03-11 13:38:07 -070043 def GetLogLevel(self):
44 return self.log_level
45
46 def SetLogLevel(self, log_level):
47 self.log_level = log_level
48
Ahmad Sharif70de27b2011-06-15 17:51:24 -070049 def RunCommand(self, cmd, return_output=False, machine=None,
50 username=None, command_terminator=None,
51 command_timeout=None,
Ahmad Shariff395c262012-10-09 17:48:09 -070052 terminated_timeout=10,
53 print_to_console=True):
Ahmad Sharif70de27b2011-06-15 17:51:24 -070054 """Run a command."""
55
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -080056 cmd = str(cmd)
57
cmtice13909242014-03-11 13:38:07 -070058 if self.log_level == "quiet":
59 print_to_console=False
60
61 if self.log_level == "verbose":
62 self.logger.LogCmd(cmd, machine, username, print_to_console)
cmtice05379562014-04-07 13:19:01 -070063 else:
64 self.logger.LogCmdToFileOnly(cmd, machine, username)
Ahmad Sharif70de27b2011-06-15 17:51:24 -070065 if command_terminator and command_terminator.IsTerminated():
Ahmad Shariff395c262012-10-09 17:48:09 -070066 self.logger.LogError("Command was terminated!", print_to_console)
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -080067 if return_output:
68 return [1, "", ""]
69 else:
70 return 1
Ahmad Sharif70de27b2011-06-15 17:51:24 -070071
72 if machine is not None:
73 user = ""
74 if username is not None:
75 user = username + "@"
76 cmd = "ssh -t -t %s%s -- '%s'" % (user, machine, cmd)
77
Ahmad Sharif70de27b2011-06-15 17:51:24 -070078 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
79 stderr=subprocess.PIPE,
Ahmad Sharif134905c2013-05-03 16:05:15 -070080 shell=True)
Ahmad Sharif70de27b2011-06-15 17:51:24 -070081
82 full_stdout = ""
83 full_stderr = ""
84
85 # Pull output from pipes, send it to file/stdout/string
86 out = err = None
87 pipes = [p.stdout, p.stderr]
88
Luis Lozanof81680c2013-03-15 14:44:13 -070089 my_poll = select.poll()
90 my_poll.register(p.stdout, select.POLLIN)
91 my_poll.register(p.stderr, select.POLLIN)
92
Ahmad Sharif70de27b2011-06-15 17:51:24 -070093 terminated_time = None
94 started_time = time.time()
95
96 while len(pipes):
Ahmad Sharif70de27b2011-06-15 17:51:24 -070097 if command_terminator and command_terminator.IsTerminated():
Ahmad Sharif4467f002012-12-20 12:09:49 -080098 self.RunCommand("sudo kill -9 " + str(p.pid),
99 print_to_console=print_to_console)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700100 wait = p.wait()
Ahmad Shariff395c262012-10-09 17:48:09 -0700101 self.logger.LogError("Command was terminated!", print_to_console)
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800102 if return_output:
103 return (p.wait, full_stdout, full_stderr)
104 else:
105 return wait
Luis Lozanof81680c2013-03-15 14:44:13 -0700106
107 l=my_poll.poll(100)
108 for (fd, evt) in l:
109 if fd == p.stdout.fileno():
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700110 out = os.read(p.stdout.fileno(), 16384)
111 if return_output:
112 full_stdout += out
Ahmad Shariff395c262012-10-09 17:48:09 -0700113 self.logger.LogCommandOutput(out, print_to_console)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700114 if out == "":
115 pipes.remove(p.stdout)
Luis Lozanof81680c2013-03-15 14:44:13 -0700116 my_poll.unregister(p.stdout)
117 if fd == p.stderr.fileno():
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700118 err = os.read(p.stderr.fileno(), 16384)
119 if return_output:
120 full_stderr += err
Ahmad Shariff395c262012-10-09 17:48:09 -0700121 self.logger.LogCommandError(err, print_to_console)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700122 if err == "":
123 pipes.remove(p.stderr)
Luis Lozanof81680c2013-03-15 14:44:13 -0700124 my_poll.unregister(p.stderr)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700125
126 if p.poll() is not None:
127 if terminated_time is None:
128 terminated_time = time.time()
129 elif (terminated_timeout is not None and
130 time.time() - terminated_time > terminated_timeout):
131 m = ("Timeout of %s seconds reached since process termination."
132 % terminated_timeout)
Ahmad Shariff395c262012-10-09 17:48:09 -0700133 self.logger.LogWarning(m, print_to_console)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700134 break
135
136 if (command_timeout is not None and
137 time.time() - started_time > command_timeout):
138 m = ("Timeout of %s seconds reached since process started."
139 % command_timeout)
Ahmad Shariff395c262012-10-09 17:48:09 -0700140 self.logger.LogWarning(m, print_to_console)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700141 self.RunCommand("kill %d || sudo kill %d || sudo kill -9 %d" %
Ahmad Sharif4467f002012-12-20 12:09:49 -0800142 (p.pid, p.pid, p.pid),
143 print_to_console=print_to_console)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700144 break
145
146 if out == err == "":
147 break
148
149 p.wait()
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700150 if return_output:
151 return (p.returncode, full_stdout, full_stderr)
152 return p.returncode
153
154 def RemoteAccessInitCommand(self, chromeos_root, machine):
155 command = ""
156 command += "\nset -- --remote=" + machine
157 command += "\n. " + chromeos_root + "/src/scripts/common.sh"
158 command += "\n. " + chromeos_root + "/src/scripts/remote_access.sh"
159 command += "\nTMP=$(mktemp -d)"
160 command += "\nFLAGS \"$@\" || exit 1"
161 command += "\nremote_access_init"
162 return command
163
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800164 def WriteToTempShFile(self, contents):
165 handle, command_file = tempfile.mkstemp(prefix=os.uname()[1],
166 suffix=".sh")
167 os.write(handle, "#!/bin/bash\n")
168 os.write(handle, contents)
169 os.close(handle)
170 return command_file
171
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700172
173 def CrosLearnBoard(self, chromeos_root, machine):
174 command = self.RemoteAccessInitCommand(chromeos_root, machine)
175 command += "\nlearn_board"
176 command += "\necho ${FLAGS_board}"
177 retval, output, err = self.RunCommand(command, True)
178 self.logger.LogFatalIf(retval, "learn_board command failed")
179 return output.split()[-1]
180
181 def CrosRunCommand(self, cmd, return_output=False, machine=None,
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800182 username=None, command_terminator=None, chromeos_root=None,
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700183 command_timeout=None,
Ahmad Shariff395c262012-10-09 17:48:09 -0700184 terminated_timeout=10,
185 print_to_console=True):
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700186 """Run a command on a chromeos box"""
cmtice13909242014-03-11 13:38:07 -0700187
188 if self.log_level != "verbose":
189 print_to_console=False
190
191 self.logger.LogCmd(cmd, print_to_console=print_to_console)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700192 self.logger.LogFatalIf(not machine, "No machine provided!")
193 self.logger.LogFatalIf(not chromeos_root, "chromeos_root not given!")
194 chromeos_root = os.path.expanduser(chromeos_root)
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800195
196 # Write all commands to a file.
197 command_file = self.WriteToTempShFile(cmd)
Ahmad Sharif4467f002012-12-20 12:09:49 -0800198 retval = self.CopyFiles(command_file, command_file,
199 dest_machine=machine,
200 command_terminator=command_terminator,
201 chromeos_root=chromeos_root,
202 dest_cros=True,
203 recursive=False,
204 print_to_console=print_to_console)
205 if retval:
206 self.logger.LogError("Could not run remote command on machine."
207 " Is the machine up?")
208 return retval
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800209
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700210 command = self.RemoteAccessInitCommand(chromeos_root, machine)
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800211 command += "\nremote_sh bash %s" % command_file
Luis Lozanodd75bad2014-04-21 13:58:16 -0700212 command += "\nl_retval=$?; echo \"$REMOTE_OUT\"; exit $l_retval"
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800213 retval = self.RunCommand(command, return_output,
214 command_terminator=command_terminator,
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700215 command_timeout=command_timeout,
Ahmad Sharif4467f002012-12-20 12:09:49 -0800216 terminated_timeout=terminated_timeout,
217 print_to_console=print_to_console)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700218 if return_output:
219 connect_signature = ("Initiating first contact with remote host\n" +
220 "Connection OK\n")
221 connect_signature_re = re.compile(connect_signature)
222 modded_return = []
223 for r in retval:
224 modded_return.append(r)
225 modded_return[1] = connect_signature_re.sub("", modded_return[1])
226 return modded_return
227 return retval
228
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800229 def ChrootRunCommand(self, chromeos_root, command, return_output=False,
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700230 command_terminator=None, command_timeout=None,
Ahmad Shariff395c262012-10-09 17:48:09 -0700231 terminated_timeout=10,
Ahmad Sharif4467f002012-12-20 12:09:49 -0800232 print_to_console=True,
233 cros_sdk_options=""):
cmtice13909242014-03-11 13:38:07 -0700234
235 if self.log_level != "verbose":
236 print_to_console = False
237
238 self.logger.LogCmd(command, print_to_console=print_to_console)
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800239
240 handle, command_file = tempfile.mkstemp(dir=os.path.join(chromeos_root,
241 "src/scripts"),
242 suffix=".sh",
243 prefix="in_chroot_cmd")
244 os.write(handle, "#!/bin/bash\n")
245 os.write(handle, command)
246 os.close(handle)
247
248 os.chmod(command_file, 0777)
249
Ahmad Sharif4467f002012-12-20 12:09:49 -0800250 command = "cd %s; cros_sdk %s -- ./%s" % (chromeos_root, cros_sdk_options,
251 os.path.basename(command_file))
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800252 ret = self.RunCommand(command, return_output,
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700253 command_terminator=command_terminator,
254 command_timeout=command_timeout,
Ahmad Sharif4467f002012-12-20 12:09:49 -0800255 terminated_timeout=terminated_timeout,
256 print_to_console=print_to_console)
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800257 os.remove(command_file)
258 return ret
259
260
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700261 def RunCommands(self, cmdlist, return_output=False, machine=None,
262 username=None, command_terminator=None):
263 cmd = " ;\n" .join(cmdlist)
264 return self.RunCommand(cmd, return_output, machine, username,
265 command_terminator)
266
267 def CopyFiles(self, src, dest, src_machine=None, dest_machine=None,
268 src_user=None, dest_user=None, recursive=True,
269 command_terminator=None,
Ahmad Sharif4467f002012-12-20 12:09:49 -0800270 chromeos_root=None, src_cros=False, dest_cros=False,
271 print_to_console=True):
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700272 src = os.path.expanduser(src)
273 dest = os.path.expanduser(dest)
274
275 if recursive:
276 src = src + "/"
277 dest = dest + "/"
278
279 if src_cros == True or dest_cros == True:
280 self.logger.LogFatalIf(not (src_cros ^ dest_cros), "Only one of src_cros "
281 "and desc_cros can be non-null.")
282 self.logger.LogFatalIf(not chromeos_root, "chromeos_root not given!")
283 if src_cros == True:
284 cros_machine = src_machine
285 else:
286 cros_machine = dest_machine
287
288 command = self.RemoteAccessInitCommand(chromeos_root, cros_machine)
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700289 src_parent, src_child = misc.GetRoot(src)
290 dest_parent, dest_child = misc.GetRoot(dest)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700291 ssh_command = ("ssh -p ${FLAGS_ssh_port}" +
292 " -o StrictHostKeyChecking=no" +
293 " -o UserKnownHostsFile=$(mktemp)" +
294 " -i $TMP_PRIVATE_KEY")
295 rsync_prefix = "\nrsync -r -e \"%s\" " % ssh_command
296 if dest_cros == True:
297 command += rsync_prefix + "%s root@%s:%s" % (src, dest_machine, dest)
298 return self.RunCommand(command,
299 machine=src_machine,
300 username=src_user,
Ahmad Sharif4467f002012-12-20 12:09:49 -0800301 command_terminator=command_terminator,
302 print_to_console=print_to_console)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700303 else:
304 command += rsync_prefix + "root@%s:%s %s" % (src_machine, src, dest)
305 return self.RunCommand(command,
306 machine=dest_machine,
307 username=dest_user,
Ahmad Sharif4467f002012-12-20 12:09:49 -0800308 command_terminator=command_terminator,
309 print_to_console=print_to_console)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700310
311
312 if dest_machine == src_machine:
313 command = ("rsync -a %s %s" %
314 (src,
315 dest))
316 else:
317 if src_machine is None:
318 src_machine = os.uname()[1]
319 src_user = getpass.getuser()
320 command = ("rsync -a %s@%s:%s %s" %
321 (src_user, src_machine, src,
322 dest))
323 return self.RunCommand(command,
324 machine=dest_machine,
325 username=dest_user,
Ahmad Sharif4467f002012-12-20 12:09:49 -0800326 command_terminator=command_terminator,
327 print_to_console=print_to_console)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700328
329
330class MockCommandExecuter(CommandExecuter):
331 def __init__(self, logger_to_set=None):
332 if logger is not None:
333 self.logger = logger_to_set
334 else:
335 self.logger = logger.GetLogger()
336
337 def RunCommand(self, cmd, return_output=False, machine=None, username=None,
338 command_terminator=None):
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800339 cmd = str(cmd)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700340 if machine is None:
341 machine = "localhost"
342 if username is None:
343 username = "current"
344 logger.GetLogger().LogCmd("(Mock) " + cmd, machine, username)
345 return 0
346
347
348class CommandTerminator:
349 def __init__(self):
350 self.terminated = False
351
352 def Terminate(self):
353 self.terminated = True
354
355 def IsTerminated(self):
356 return self.terminated