Ahmad Sharif | fd356fb | 2012-05-07 12:02:16 -0700 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | # |
| 3 | # Copyright 2011 Google Inc. All Rights Reserved. |
| 4 | # |
| 5 | |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 6 | import getpass |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 7 | import os |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 8 | import re |
| 9 | import select |
| 10 | import subprocess |
Ahmad Sharif | 0dcbc4b | 2012-02-02 16:37:18 -0800 | [diff] [blame] | 11 | import tempfile |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 12 | import time |
Ahmad Sharif | fd356fb | 2012-05-07 12:02:16 -0700 | [diff] [blame] | 13 | |
| 14 | import logger |
| 15 | import misc |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 16 | |
| 17 | mock_default = False |
| 18 | |
cmtice | 1390924 | 2014-03-11 13:38:07 -0700 | [diff] [blame] | 19 | LOG_LEVEL=("quiet", "average", "verbose") |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 20 | |
| 21 | def InitCommandExecuter(mock=False): |
| 22 | global mock_default |
| 23 | # Whether to default to a mock command executer or not |
| 24 | mock_default = mock |
| 25 | |
| 26 | |
cmtice | 1390924 | 2014-03-11 13:38:07 -0700 | [diff] [blame] | 27 | def GetCommandExecuter(logger_to_set=None, mock=False, log_level="verbose"): |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 28 | # If the default is a mock executer, always return one. |
| 29 | if mock_default or mock: |
| 30 | return MockCommandExecuter(logger_to_set) |
| 31 | else: |
cmtice | 1390924 | 2014-03-11 13:38:07 -0700 | [diff] [blame] | 32 | return CommandExecuter(log_level, logger_to_set) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 33 | |
| 34 | |
| 35 | class CommandExecuter: |
cmtice | 1390924 | 2014-03-11 13:38:07 -0700 | [diff] [blame] | 36 | def __init__(self, log_level, logger_to_set=None): |
| 37 | self.log_level = log_level |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 38 | if logger_to_set is not None: |
| 39 | self.logger = logger_to_set |
| 40 | else: |
| 41 | self.logger = logger.GetLogger() |
| 42 | |
cmtice | 1390924 | 2014-03-11 13:38:07 -0700 | [diff] [blame] | 43 | def GetLogLevel(self): |
| 44 | return self.log_level |
| 45 | |
| 46 | def SetLogLevel(self, log_level): |
| 47 | self.log_level = log_level |
| 48 | |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 49 | def RunCommand(self, cmd, return_output=False, machine=None, |
| 50 | username=None, command_terminator=None, |
| 51 | command_timeout=None, |
Ahmad Sharif | f395c26 | 2012-10-09 17:48:09 -0700 | [diff] [blame] | 52 | terminated_timeout=10, |
| 53 | print_to_console=True): |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 54 | """Run a command.""" |
| 55 | |
Ahmad Sharif | 0dcbc4b | 2012-02-02 16:37:18 -0800 | [diff] [blame] | 56 | cmd = str(cmd) |
| 57 | |
cmtice | 1390924 | 2014-03-11 13:38:07 -0700 | [diff] [blame] | 58 | 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) |
cmtice | 0537956 | 2014-04-07 13:19:01 -0700 | [diff] [blame] | 63 | else: |
| 64 | self.logger.LogCmdToFileOnly(cmd, machine, username) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 65 | if command_terminator and command_terminator.IsTerminated(): |
Ahmad Sharif | f395c26 | 2012-10-09 17:48:09 -0700 | [diff] [blame] | 66 | self.logger.LogError("Command was terminated!", print_to_console) |
Ahmad Sharif | 0dcbc4b | 2012-02-02 16:37:18 -0800 | [diff] [blame] | 67 | if return_output: |
| 68 | return [1, "", ""] |
| 69 | else: |
| 70 | return 1 |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 71 | |
| 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 Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 78 | p = subprocess.Popen(cmd, stdout=subprocess.PIPE, |
| 79 | stderr=subprocess.PIPE, |
Ahmad Sharif | 134905c | 2013-05-03 16:05:15 -0700 | [diff] [blame] | 80 | shell=True) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 81 | |
| 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 Lozano | f81680c | 2013-03-15 14:44:13 -0700 | [diff] [blame] | 89 | my_poll = select.poll() |
| 90 | my_poll.register(p.stdout, select.POLLIN) |
| 91 | my_poll.register(p.stderr, select.POLLIN) |
| 92 | |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 93 | terminated_time = None |
| 94 | started_time = time.time() |
| 95 | |
| 96 | while len(pipes): |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 97 | if command_terminator and command_terminator.IsTerminated(): |
Ahmad Sharif | 4467f00 | 2012-12-20 12:09:49 -0800 | [diff] [blame] | 98 | self.RunCommand("sudo kill -9 " + str(p.pid), |
| 99 | print_to_console=print_to_console) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 100 | wait = p.wait() |
Ahmad Sharif | f395c26 | 2012-10-09 17:48:09 -0700 | [diff] [blame] | 101 | self.logger.LogError("Command was terminated!", print_to_console) |
Ahmad Sharif | 0dcbc4b | 2012-02-02 16:37:18 -0800 | [diff] [blame] | 102 | if return_output: |
| 103 | return (p.wait, full_stdout, full_stderr) |
| 104 | else: |
| 105 | return wait |
Luis Lozano | f81680c | 2013-03-15 14:44:13 -0700 | [diff] [blame] | 106 | |
| 107 | l=my_poll.poll(100) |
| 108 | for (fd, evt) in l: |
| 109 | if fd == p.stdout.fileno(): |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 110 | out = os.read(p.stdout.fileno(), 16384) |
| 111 | if return_output: |
| 112 | full_stdout += out |
Ahmad Sharif | f395c26 | 2012-10-09 17:48:09 -0700 | [diff] [blame] | 113 | self.logger.LogCommandOutput(out, print_to_console) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 114 | if out == "": |
| 115 | pipes.remove(p.stdout) |
Luis Lozano | f81680c | 2013-03-15 14:44:13 -0700 | [diff] [blame] | 116 | my_poll.unregister(p.stdout) |
| 117 | if fd == p.stderr.fileno(): |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 118 | err = os.read(p.stderr.fileno(), 16384) |
| 119 | if return_output: |
| 120 | full_stderr += err |
Ahmad Sharif | f395c26 | 2012-10-09 17:48:09 -0700 | [diff] [blame] | 121 | self.logger.LogCommandError(err, print_to_console) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 122 | if err == "": |
| 123 | pipes.remove(p.stderr) |
Luis Lozano | f81680c | 2013-03-15 14:44:13 -0700 | [diff] [blame] | 124 | my_poll.unregister(p.stderr) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 125 | |
| 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 Sharif | f395c26 | 2012-10-09 17:48:09 -0700 | [diff] [blame] | 133 | self.logger.LogWarning(m, print_to_console) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 134 | 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 Sharif | f395c26 | 2012-10-09 17:48:09 -0700 | [diff] [blame] | 140 | self.logger.LogWarning(m, print_to_console) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 141 | self.RunCommand("kill %d || sudo kill %d || sudo kill -9 %d" % |
Ahmad Sharif | 4467f00 | 2012-12-20 12:09:49 -0800 | [diff] [blame] | 142 | (p.pid, p.pid, p.pid), |
| 143 | print_to_console=print_to_console) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 144 | break |
| 145 | |
| 146 | if out == err == "": |
| 147 | break |
| 148 | |
| 149 | p.wait() |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 150 | 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 Sharif | 0dcbc4b | 2012-02-02 16:37:18 -0800 | [diff] [blame] | 164 | 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 Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 172 | |
| 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 Sharif | 0dcbc4b | 2012-02-02 16:37:18 -0800 | [diff] [blame] | 182 | username=None, command_terminator=None, chromeos_root=None, |
Ahmad Sharif | fd356fb | 2012-05-07 12:02:16 -0700 | [diff] [blame] | 183 | command_timeout=None, |
Ahmad Sharif | f395c26 | 2012-10-09 17:48:09 -0700 | [diff] [blame] | 184 | terminated_timeout=10, |
| 185 | print_to_console=True): |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 186 | """Run a command on a chromeos box""" |
cmtice | 1390924 | 2014-03-11 13:38:07 -0700 | [diff] [blame] | 187 | |
| 188 | if self.log_level != "verbose": |
| 189 | print_to_console=False |
| 190 | |
| 191 | self.logger.LogCmd(cmd, print_to_console=print_to_console) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 192 | 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 Sharif | 0dcbc4b | 2012-02-02 16:37:18 -0800 | [diff] [blame] | 195 | |
| 196 | # Write all commands to a file. |
| 197 | command_file = self.WriteToTempShFile(cmd) |
Ahmad Sharif | 4467f00 | 2012-12-20 12:09:49 -0800 | [diff] [blame] | 198 | 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 Sharif | 0dcbc4b | 2012-02-02 16:37:18 -0800 | [diff] [blame] | 209 | |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 210 | command = self.RemoteAccessInitCommand(chromeos_root, machine) |
Ahmad Sharif | 0dcbc4b | 2012-02-02 16:37:18 -0800 | [diff] [blame] | 211 | command += "\nremote_sh bash %s" % command_file |
Luis Lozano | dd75bad | 2014-04-21 13:58:16 -0700 | [diff] [blame^] | 212 | command += "\nl_retval=$?; echo \"$REMOTE_OUT\"; exit $l_retval" |
Ahmad Sharif | 0dcbc4b | 2012-02-02 16:37:18 -0800 | [diff] [blame] | 213 | retval = self.RunCommand(command, return_output, |
| 214 | command_terminator=command_terminator, |
Ahmad Sharif | fd356fb | 2012-05-07 12:02:16 -0700 | [diff] [blame] | 215 | command_timeout=command_timeout, |
Ahmad Sharif | 4467f00 | 2012-12-20 12:09:49 -0800 | [diff] [blame] | 216 | terminated_timeout=terminated_timeout, |
| 217 | print_to_console=print_to_console) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 218 | 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 Sharif | 0dcbc4b | 2012-02-02 16:37:18 -0800 | [diff] [blame] | 229 | def ChrootRunCommand(self, chromeos_root, command, return_output=False, |
Ahmad Sharif | fd356fb | 2012-05-07 12:02:16 -0700 | [diff] [blame] | 230 | command_terminator=None, command_timeout=None, |
Ahmad Sharif | f395c26 | 2012-10-09 17:48:09 -0700 | [diff] [blame] | 231 | terminated_timeout=10, |
Ahmad Sharif | 4467f00 | 2012-12-20 12:09:49 -0800 | [diff] [blame] | 232 | print_to_console=True, |
| 233 | cros_sdk_options=""): |
cmtice | 1390924 | 2014-03-11 13:38:07 -0700 | [diff] [blame] | 234 | |
| 235 | if self.log_level != "verbose": |
| 236 | print_to_console = False |
| 237 | |
| 238 | self.logger.LogCmd(command, print_to_console=print_to_console) |
Ahmad Sharif | 0dcbc4b | 2012-02-02 16:37:18 -0800 | [diff] [blame] | 239 | |
| 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 Sharif | 4467f00 | 2012-12-20 12:09:49 -0800 | [diff] [blame] | 250 | command = "cd %s; cros_sdk %s -- ./%s" % (chromeos_root, cros_sdk_options, |
| 251 | os.path.basename(command_file)) |
Ahmad Sharif | 0dcbc4b | 2012-02-02 16:37:18 -0800 | [diff] [blame] | 252 | ret = self.RunCommand(command, return_output, |
Ahmad Sharif | fd356fb | 2012-05-07 12:02:16 -0700 | [diff] [blame] | 253 | command_terminator=command_terminator, |
| 254 | command_timeout=command_timeout, |
Ahmad Sharif | 4467f00 | 2012-12-20 12:09:49 -0800 | [diff] [blame] | 255 | terminated_timeout=terminated_timeout, |
| 256 | print_to_console=print_to_console) |
Ahmad Sharif | 0dcbc4b | 2012-02-02 16:37:18 -0800 | [diff] [blame] | 257 | os.remove(command_file) |
| 258 | return ret |
| 259 | |
| 260 | |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 261 | 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 Sharif | 4467f00 | 2012-12-20 12:09:49 -0800 | [diff] [blame] | 270 | chromeos_root=None, src_cros=False, dest_cros=False, |
| 271 | print_to_console=True): |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 272 | 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 Sharif | fd356fb | 2012-05-07 12:02:16 -0700 | [diff] [blame] | 289 | src_parent, src_child = misc.GetRoot(src) |
| 290 | dest_parent, dest_child = misc.GetRoot(dest) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 291 | 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 Sharif | 4467f00 | 2012-12-20 12:09:49 -0800 | [diff] [blame] | 301 | command_terminator=command_terminator, |
| 302 | print_to_console=print_to_console) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 303 | 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 Sharif | 4467f00 | 2012-12-20 12:09:49 -0800 | [diff] [blame] | 308 | command_terminator=command_terminator, |
| 309 | print_to_console=print_to_console) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 310 | |
| 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 Sharif | 4467f00 | 2012-12-20 12:09:49 -0800 | [diff] [blame] | 326 | command_terminator=command_terminator, |
| 327 | print_to_console=print_to_console) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 328 | |
| 329 | |
| 330 | class 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 Sharif | 0dcbc4b | 2012-02-02 16:37:18 -0800 | [diff] [blame] | 339 | cmd = str(cmd) |
Ahmad Sharif | 70de27b | 2011-06-15 17:51:24 -0700 | [diff] [blame] | 340 | 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 | |
| 348 | class 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 |