mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | # |
| 3 | # Copyright 2007 Google Inc. Released under the GPL v2 |
| 4 | |
mbligh | dc735a2 | 2007-08-02 16:54:37 +0000 | [diff] [blame] | 5 | """ |
| 6 | This module defines the Autotest class |
mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 7 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 8 | Autotest: software to run tests automatically |
mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 9 | """ |
| 10 | |
mbligh | dc735a2 | 2007-08-02 16:54:37 +0000 | [diff] [blame] | 11 | __author__ = """ |
| 12 | mbligh@google.com (Martin J. Bligh), |
mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 13 | poirier@google.com (Benjamin Poirier), |
mbligh | dc735a2 | 2007-08-02 16:54:37 +0000 | [diff] [blame] | 14 | stutsman@google.com (Ryan Stutsman) |
| 15 | """ |
mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 16 | |
mbligh | 02ff2d5 | 2008-06-03 15:00:21 +0000 | [diff] [blame] | 17 | import re, os, sys, traceback, subprocess, tempfile, shutil, time |
mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 18 | |
mbligh | ccb9e18 | 2008-04-17 15:42:10 +0000 | [diff] [blame] | 19 | from autotest_lib.server import installable_object, utils, server_job |
| 20 | from autotest_lib.client.common_lib import logging |
mbligh | c5ddfd1 | 2008-08-04 17:15:00 +0000 | [diff] [blame] | 21 | from autotest_lib.client.common_lib import error, global_config, packages |
mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 22 | |
| 23 | |
mbligh | 3c7a150 | 2008-07-24 18:08:47 +0000 | [diff] [blame] | 24 | |
mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 25 | AUTOTEST_SVN = 'svn://test.kernel.org/autotest/trunk/client' |
| 26 | AUTOTEST_HTTP = 'http://test.kernel.org/svn/autotest/trunk/client' |
| 27 | |
| 28 | # Timeouts for powering down and up respectively |
| 29 | HALT_TIME = 300 |
mbligh | 07c1eac | 2007-11-05 18:39:29 +0000 | [diff] [blame] | 30 | BOOT_TIME = 1800 |
jadmanski | ec85914 | 2008-05-29 21:33:39 +0000 | [diff] [blame] | 31 | CRASH_RECOVERY_TIME = 9000 |
mbligh | 0e4613b | 2007-10-29 16:55:07 +0000 | [diff] [blame] | 32 | |
mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 33 | |
mbligh | d8b3925 | 2008-03-20 21:15:03 +0000 | [diff] [blame] | 34 | class BaseAutotest(installable_object.InstallableObject): |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 35 | """ |
| 36 | This class represents the Autotest program. |
mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 37 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 38 | Autotest is used to run tests automatically and collect the results. |
| 39 | It also supports profilers. |
mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 40 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 41 | Implementation details: |
| 42 | This is a leaf class in an abstract class hierarchy, it must |
| 43 | implement the unimplemented methods in parent classes. |
| 44 | """ |
mbligh | 119c12a | 2007-11-12 22:13:44 +0000 | [diff] [blame] | 45 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 46 | def __init__(self, host = None): |
| 47 | self.host = host |
| 48 | self.got = False |
| 49 | self.installed = False |
| 50 | self.serverdir = utils.get_server_dir() |
| 51 | super(BaseAutotest, self).__init__() |
mbligh | c8949b8 | 2007-07-23 16:33:58 +0000 | [diff] [blame] | 52 | |
mbligh | dc735a2 | 2007-08-02 16:54:37 +0000 | [diff] [blame] | 53 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 54 | @logging.record |
| 55 | def install(self, host = None): |
| 56 | """ |
| 57 | Install autotest. If get() was not called previously, an |
| 58 | attempt will be made to install from the autotest svn |
| 59 | repository. |
mbligh | 9a3f5e5 | 2008-05-28 21:21:43 +0000 | [diff] [blame] | 60 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 61 | Args: |
| 62 | host: a Host instance on which autotest will be |
| 63 | installed |
mbligh | 9a3f5e5 | 2008-05-28 21:21:43 +0000 | [diff] [blame] | 64 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 65 | Raises: |
| 66 | AutoservError: if a tarball was not specified and |
| 67 | the target host does not have svn installed in its path |
mbligh | 9a3f5e5 | 2008-05-28 21:21:43 +0000 | [diff] [blame] | 68 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 69 | TODO(poirier): check dependencies |
| 70 | autotest needs: |
| 71 | bzcat |
| 72 | liboptdev (oprofile) |
| 73 | binutils-dev (oprofile) |
| 74 | make |
| 75 | psutils (netperf) |
| 76 | """ |
| 77 | if not host: |
| 78 | host = self.host |
| 79 | if not self.got: |
| 80 | self.get() |
| 81 | host.wait_up(timeout=30) |
| 82 | host.setup() |
| 83 | print "Installing autotest on %s" % host.hostname |
mbligh | 40f122a | 2007-11-03 23:08:46 +0000 | [diff] [blame] | 84 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 85 | # Let's try to figure out where autotest is installed. If we can't, |
| 86 | # (autotest not installed) just assume '/usr/local/autotest' and |
| 87 | # proceed. |
| 88 | try: |
| 89 | autodir = _get_autodir(host) |
| 90 | except error.AutotestRunError: |
| 91 | autodir = '/usr/local/autotest' |
mbligh | 2974230 | 2008-05-09 16:06:37 +0000 | [diff] [blame] | 92 | |
mbligh | 0562e65 | 2008-08-20 20:11:45 +0000 | [diff] [blame] | 93 | # Make the host object know as to where autotest is installed |
| 94 | host.set_autodir(autodir) |
| 95 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 96 | host.run('mkdir -p "%s"' % utils.sh_escape(autodir)) |
mbligh | 40f122a | 2007-11-03 23:08:46 +0000 | [diff] [blame] | 97 | |
mbligh | c5ddfd1 | 2008-08-04 17:15:00 +0000 | [diff] [blame] | 98 | # Fetch the autotest client from the nearest repository |
| 99 | try: |
| 100 | c = global_config.global_config |
| 101 | repos = c.get_config_value("PACKAGES", 'fetch_location', type=list) |
| 102 | pkgmgr = packages.PackageManager( |
| 103 | autodir, repo_urls=repos, do_locking=False, |
| 104 | run_function=host.run, |
| 105 | run_function_dargs=dict(timeout=600)) |
| 106 | # The packages dir is used to store all the packages that |
| 107 | # are fetched on that client. (for the tests,deps etc. |
| 108 | # too apart from the client) |
| 109 | pkg_dir = os.path.join(autodir, 'packages') |
| 110 | # clean up the autodir except for the packages directory |
| 111 | host.run('cd %s && ls | grep -v "^packages$"' |
| 112 | ' | xargs rm -rf && rm -rf .[^.]*' % autodir) |
| 113 | pkgmgr.install_pkg('autotest', 'client', pkg_dir, autodir, |
| 114 | preserve_install_dir=True) |
| 115 | self.installed = True |
| 116 | return |
| 117 | except global_config.ConfigError, e: |
| 118 | print ("Could not install autotest using the" |
| 119 | " packaging system %s" % e) |
| 120 | except (packages.PackageInstallError, error.AutoservRunError), e: |
| 121 | print "Could not install autotest from %s : %s " % (repos, e) |
| 122 | |
mbligh | 40f122a | 2007-11-03 23:08:46 +0000 | [diff] [blame] | 123 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 124 | # try to install from file or directory |
| 125 | if self.source_material: |
| 126 | if os.path.isdir(self.source_material): |
| 127 | # Copy autotest recursively |
| 128 | host.send_file(self.source_material, autodir) |
| 129 | else: |
| 130 | # Copy autotest via tarball |
| 131 | e_msg = 'Installation method not yet implemented!' |
| 132 | raise NotImplementedError(e_msg) |
| 133 | print "Installation of autotest completed" |
| 134 | self.installed = True |
| 135 | return |
mbligh | 9133490 | 2007-09-28 01:47:59 +0000 | [diff] [blame] | 136 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 137 | # if that fails try to install using svn |
| 138 | if utils.run('which svn').exit_status: |
mbligh | 78bf535 | 2008-07-11 20:27:36 +0000 | [diff] [blame] | 139 | raise error.AutoservError('svn not found on target machine: %s' |
| 140 | % host.name) |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 141 | try: |
mbligh | 78bf535 | 2008-07-11 20:27:36 +0000 | [diff] [blame] | 142 | host.run('svn checkout %s %s' % (AUTOTEST_SVN, autodir)) |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 143 | except error.AutoservRunError, e: |
mbligh | 78bf535 | 2008-07-11 20:27:36 +0000 | [diff] [blame] | 144 | host.run('svn checkout %s %s' % (AUTOTEST_HTTP, autodir)) |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 145 | print "Installation of autotest completed" |
| 146 | self.installed = True |
mbligh | 9133490 | 2007-09-28 01:47:59 +0000 | [diff] [blame] | 147 | |
| 148 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 149 | def get(self, location = None): |
| 150 | if not location: |
| 151 | location = os.path.join(self.serverdir, '../client') |
| 152 | location = os.path.abspath(location) |
| 153 | # If there's stuff run on our client directory already, it |
| 154 | # can cause problems. Try giving it a quick clean first. |
| 155 | cwd = os.getcwd() |
| 156 | os.chdir(location) |
| 157 | os.system('tools/make_clean') |
| 158 | os.chdir(cwd) |
| 159 | super(BaseAutotest, self).get(location) |
| 160 | self.got = True |
mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 161 | |
| 162 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 163 | def run(self, control_file, results_dir = '.', host = None, |
| 164 | timeout=None, tag=None, parallel_flag=False): |
| 165 | """ |
| 166 | Run an autotest job on the remote machine. |
mbligh | 9a3f5e5 | 2008-05-28 21:21:43 +0000 | [diff] [blame] | 167 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 168 | Args: |
| 169 | control_file: an open file-like-obj of the control file |
| 170 | results_dir: a str path where the results should be stored |
| 171 | on the local filesystem |
| 172 | host: a Host instance on which the control file should |
| 173 | be run |
| 174 | tag: tag name for the client side instance of autotest |
| 175 | parallel_flag: flag set when multiple jobs are run at the |
| 176 | same time |
| 177 | Raises: |
| 178 | AutotestRunError: if there is a problem executing |
| 179 | the control file |
| 180 | """ |
| 181 | host = self._get_host_and_setup(host) |
| 182 | results_dir = os.path.abspath(results_dir) |
mbligh | c1cbc99 | 2008-05-27 20:01:45 +0000 | [diff] [blame] | 183 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 184 | if tag: |
| 185 | results_dir = os.path.join(results_dir, tag) |
mbligh | c1cbc99 | 2008-05-27 20:01:45 +0000 | [diff] [blame] | 186 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 187 | atrun = _Run(host, results_dir, tag, parallel_flag) |
| 188 | self._do_run(control_file, results_dir, host, atrun, timeout) |
mbligh | d8b3925 | 2008-03-20 21:15:03 +0000 | [diff] [blame] | 189 | |
| 190 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 191 | def _get_host_and_setup(self, host): |
| 192 | if not host: |
| 193 | host = self.host |
| 194 | if not self.installed: |
| 195 | self.install(host) |
mbligh | 9133490 | 2007-09-28 01:47:59 +0000 | [diff] [blame] | 196 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 197 | host.wait_up(timeout=30) |
| 198 | return host |
mbligh | d8b3925 | 2008-03-20 21:15:03 +0000 | [diff] [blame] | 199 | |
| 200 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 201 | def _do_run(self, control_file, results_dir, host, atrun, timeout): |
| 202 | try: |
| 203 | atrun.verify_machine() |
| 204 | except: |
mbligh | 78bf535 | 2008-07-11 20:27:36 +0000 | [diff] [blame] | 205 | print "Verify machine failed on %s. Reinstalling" % host.hostname |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 206 | self.install(host) |
| 207 | atrun.verify_machine() |
| 208 | debug = os.path.join(results_dir, 'debug') |
| 209 | try: |
| 210 | os.makedirs(debug) |
| 211 | except: |
| 212 | pass |
mbligh | 9a3f5e5 | 2008-05-28 21:21:43 +0000 | [diff] [blame] | 213 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 214 | # Ready .... Aim .... |
| 215 | for control in [atrun.remote_control_file, |
| 216 | atrun.remote_control_file + '.state', |
| 217 | atrun.manual_control_file, |
| 218 | atrun.manual_control_file + '.state']: |
| 219 | host.run('rm -f ' + control) |
mbligh | 9a3f5e5 | 2008-05-28 21:21:43 +0000 | [diff] [blame] | 220 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 221 | tmppath = utils.get(control_file) |
mbligh | c5ddfd1 | 2008-08-04 17:15:00 +0000 | [diff] [blame] | 222 | |
| 223 | # Insert the job.add_repository() lines in the control file |
| 224 | # if there are any repos defined in global_config.ini |
| 225 | try: |
| 226 | cfile = open(tmppath, 'r') |
| 227 | cfile_orig = cfile.read() |
| 228 | cfile.close() |
| 229 | c = global_config.global_config |
| 230 | repos = c.get_config_value("PACKAGES", 'fetch_location', type=list) |
| 231 | control_file_new = [] |
| 232 | control_file_new.append('job.add_repository(%s)\n' % repos) |
| 233 | control_file_new.append(cfile_orig) |
| 234 | |
| 235 | # Overwrite the control file with the new one |
| 236 | cfile = open(tmppath, 'w') |
| 237 | cfile.write('\n'.join(control_file_new)) |
| 238 | cfile.close() |
| 239 | except global_config.ConfigError, e: |
| 240 | pass |
| 241 | |
| 242 | |
| 243 | # Copy control_file to remote_control_file on the host |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 244 | host.send_file(tmppath, atrun.remote_control_file) |
| 245 | if os.path.abspath(tmppath) != os.path.abspath(control_file): |
| 246 | os.remove(tmppath) |
mbligh | 0e4613b | 2007-10-29 16:55:07 +0000 | [diff] [blame] | 247 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 248 | try: |
| 249 | atrun.execute_control(timeout=timeout) |
| 250 | finally: |
jadmanski | a1f3c20 | 2008-09-15 19:17:16 +0000 | [diff] [blame^] | 251 | collector = server_job.log_collector(host, atrun.tag, results_dir) |
| 252 | collector.collect_client_job_results() |
mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 253 | |
mbligh | 0e4613b | 2007-10-29 16:55:07 +0000 | [diff] [blame] | 254 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 255 | def run_timed_test(self, test_name, results_dir='.', host=None, |
| 256 | timeout=None, tag=None, *args, **dargs): |
| 257 | """ |
| 258 | Assemble a tiny little control file to just run one test, |
| 259 | and run it as an autotest client-side test |
| 260 | """ |
| 261 | if not host: |
| 262 | host = self.host |
| 263 | if not self.installed: |
| 264 | self.install(host) |
| 265 | opts = ["%s=%s" % (o[0], repr(o[1])) for o in dargs.items()] |
| 266 | cmd = ", ".join([repr(test_name)] + map(repr, args) + opts) |
| 267 | control = "job.run_test(%s)\n" % cmd |
| 268 | self.run(control, results_dir, host, timeout=timeout, tag=tag) |
mbligh | 0e4613b | 2007-10-29 16:55:07 +0000 | [diff] [blame] | 269 | |
| 270 | |
jadmanski | 169ecad | 2008-09-12 15:49:44 +0000 | [diff] [blame] | 271 | def run_test(self, test_name, results_dir='.', host=None, tag=None, |
| 272 | *args, **dargs): |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 273 | self.run_timed_test(test_name, results_dir, host, timeout=None, |
| 274 | tag=tag, *args, **dargs) |
mbligh | d54832b | 2007-07-25 16:46:56 +0000 | [diff] [blame] | 275 | |
| 276 | |
mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 277 | class _Run(object): |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 278 | """ |
| 279 | Represents a run of autotest control file. This class maintains |
| 280 | all the state necessary as an autotest control file is executed. |
mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 281 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 282 | It is not intended to be used directly, rather control files |
| 283 | should be run using the run method in Autotest. |
| 284 | """ |
| 285 | def __init__(self, host, results_dir, tag, parallel_flag): |
| 286 | self.host = host |
| 287 | self.results_dir = results_dir |
| 288 | self.env = host.env |
| 289 | self.tag = tag |
| 290 | self.parallel_flag = parallel_flag |
| 291 | self.autodir = _get_autodir(self.host) |
mbligh | 78bf535 | 2008-07-11 20:27:36 +0000 | [diff] [blame] | 292 | control = os.path.join(self.autodir, 'control') |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 293 | if tag: |
mbligh | 78bf535 | 2008-07-11 20:27:36 +0000 | [diff] [blame] | 294 | control += '.' + tag |
| 295 | self.manual_control_file = control |
| 296 | self.remote_control_file = control + '.autoserv' |
mbligh | dc735a2 | 2007-08-02 16:54:37 +0000 | [diff] [blame] | 297 | |
| 298 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 299 | def verify_machine(self): |
| 300 | binary = os.path.join(self.autodir, 'bin/autotest') |
| 301 | try: |
| 302 | self.host.run('ls %s > /dev/null 2>&1' % binary) |
| 303 | except: |
| 304 | raise "Autotest does not appear to be installed" |
mbligh | dc735a2 | 2007-08-02 16:54:37 +0000 | [diff] [blame] | 305 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 306 | if not self.parallel_flag: |
| 307 | tmpdir = os.path.join(self.autodir, 'tmp') |
| 308 | download = os.path.join(self.autodir, 'tests/download') |
| 309 | self.host.run('umount %s' % tmpdir, ignore_status=True) |
| 310 | self.host.run('umount %s' % download, ignore_status=True) |
mbligh | dc735a2 | 2007-08-02 16:54:37 +0000 | [diff] [blame] | 311 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 312 | def get_full_cmd(self, section): |
| 313 | # build up the full command we want to run over the host |
jadmanski | b6eb2f1 | 2008-09-12 16:39:36 +0000 | [diff] [blame] | 314 | cmd = [os.path.join(self.autodir, 'bin/autotest_client'), |
| 315 | '-H autoserv'] |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 316 | if section > 0: |
| 317 | cmd.append('-c') |
| 318 | if self.tag: |
| 319 | cmd.append('-t %s' % self.tag) |
| 320 | if self.host.job.use_external_logging(): |
| 321 | cmd.append('-l') |
| 322 | cmd.append(self.remote_control_file) |
| 323 | return ' '.join(cmd) |
mbligh | adf2aab | 2007-11-29 18:16:43 +0000 | [diff] [blame] | 324 | |
mbligh | d8b3925 | 2008-03-20 21:15:03 +0000 | [diff] [blame] | 325 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 326 | def get_client_log(self, section): |
| 327 | # open up the files we need for our logging |
| 328 | client_log_file = os.path.join(self.results_dir, 'debug', |
| 329 | 'client.log.%d' % section) |
| 330 | return open(client_log_file, 'w', 0) |
mbligh | d8b3925 | 2008-03-20 21:15:03 +0000 | [diff] [blame] | 331 | |
| 332 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 333 | def execute_section(self, section, timeout): |
mbligh | 4e4961c | 2008-07-11 21:08:10 +0000 | [diff] [blame] | 334 | print "Executing %s/bin/autotest %s/control phase %d" % \ |
| 335 | (self.autodir, self.autodir, section) |
mbligh | d8b3925 | 2008-03-20 21:15:03 +0000 | [diff] [blame] | 336 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 337 | full_cmd = self.get_full_cmd(section) |
| 338 | client_log = self.get_client_log(section) |
jadmanski | a1f3c20 | 2008-09-15 19:17:16 +0000 | [diff] [blame^] | 339 | redirector = server_job.client_logger(self.host, self.tag, |
| 340 | self.results_dir) |
mbligh | d528d30 | 2007-12-19 16:19:05 +0000 | [diff] [blame] | 341 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 342 | try: |
| 343 | old_resultdir = self.host.job.resultdir |
| 344 | self.host.job.resultdir = self.results_dir |
| 345 | result = self.host.run(full_cmd, ignore_status=True, |
| 346 | timeout=timeout, |
| 347 | stdout_tee=client_log, |
| 348 | stderr_tee=redirector) |
| 349 | finally: |
| 350 | redirector.close() |
| 351 | self.host.job.resultdir = old_resultdir |
mbligh | 2bf2db6 | 2007-11-27 00:53:18 +0000 | [diff] [blame] | 352 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 353 | if result.exit_status == 1: |
| 354 | self.host.job.aborted = True |
jadmanski | 8947606 | 2008-07-01 23:57:21 +0000 | [diff] [blame] | 355 | raise error.AutotestRunError("client job was aborted") |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 356 | if not result.stderr: |
| 357 | raise error.AutotestRunError( |
| 358 | "execute_section: %s failed to return anything\n" |
| 359 | "stdout:%s\n" % (full_cmd, result.stdout)) |
mbligh | 0e4613b | 2007-10-29 16:55:07 +0000 | [diff] [blame] | 360 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 361 | return redirector.last_line |
mbligh | dc735a2 | 2007-08-02 16:54:37 +0000 | [diff] [blame] | 362 | |
| 363 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 364 | def execute_control(self, timeout=None): |
| 365 | section = 0 |
| 366 | time_left = None |
| 367 | if timeout: |
| 368 | end_time = time.time() + timeout |
| 369 | time_left = end_time - time.time() |
| 370 | while not timeout or time_left > 0: |
| 371 | last = self.execute_section(section, time_left) |
| 372 | if timeout: |
| 373 | time_left = end_time - time.time() |
| 374 | if time_left <= 0: |
| 375 | break |
| 376 | section += 1 |
| 377 | if re.match(r'^END .*\t----\t----\t.*$', last): |
| 378 | print "Client complete" |
| 379 | return |
| 380 | elif re.match('^\t*GOOD\t----\treboot\.start.*$', last): |
| 381 | print "Client is rebooting" |
| 382 | print "Waiting for client to halt" |
| 383 | if not self.host.wait_down(HALT_TIME): |
jadmanski | 169ecad | 2008-09-12 15:49:44 +0000 | [diff] [blame] | 384 | err = "%s failed to shutdown after %d" |
| 385 | err %= (self.host.hostname, HALT_TIME) |
mbligh | 78bf535 | 2008-07-11 20:27:36 +0000 | [diff] [blame] | 386 | raise error.AutotestRunError(err) |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 387 | print "Client down, waiting for restart" |
| 388 | if not self.host.wait_up(BOOT_TIME): |
| 389 | # since reboot failed |
| 390 | # hardreset the machine once if possible |
| 391 | # before failing this control file |
mbligh | 78bf535 | 2008-07-11 20:27:36 +0000 | [diff] [blame] | 392 | print "Hardresetting %s" % self.host.hostname |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 393 | try: |
| 394 | self.host.hardreset(wait=False) |
| 395 | except error.AutoservUnsupportedError: |
mbligh | 78bf535 | 2008-07-11 20:27:36 +0000 | [diff] [blame] | 396 | print "Hardreset unsupported on %s" % self.host.hostname |
| 397 | raise error.AutotestRunError("%s failed to boot after %ds" % |
| 398 | (self.host.hostname, BOOT_TIME)) |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 399 | self.host.reboot_followup() |
| 400 | continue |
jadmanski | c66e93c | 2008-07-29 21:25:22 +0000 | [diff] [blame] | 401 | self.host.job.record("END ABORT", None, None, |
mbligh | 78bf535 | 2008-07-11 20:27:36 +0000 | [diff] [blame] | 402 | "Autotest client terminated unexpectedly") |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 403 | # give the client machine a chance to recover from |
| 404 | # possible crash |
| 405 | self.host.wait_up(CRASH_RECOVERY_TIME) |
mbligh | 78bf535 | 2008-07-11 20:27:36 +0000 | [diff] [blame] | 406 | raise error.AutotestRunError("Aborting - unexpected final status " |
| 407 | "message from client: %s\n" % last) |
mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 408 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 409 | # should only get here if we timed out |
| 410 | assert timeout |
| 411 | raise error.AutotestTimeoutError() |
mbligh | 0e4613b | 2007-10-29 16:55:07 +0000 | [diff] [blame] | 412 | |
mbligh | dcd57a8 | 2007-07-11 23:06:47 +0000 | [diff] [blame] | 413 | |
| 414 | def _get_autodir(host): |
mbligh | 3c7a150 | 2008-07-24 18:08:47 +0000 | [diff] [blame] | 415 | autodir = host.get_autodir() |
| 416 | if autodir: |
| 417 | return autodir |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 418 | try: |
| 419 | # There's no clean way to do this. readlink may not exist |
| 420 | cmd = "python -c 'import os,sys; print os.readlink(sys.argv[1])' /etc/autotest.conf 2> /dev/null" |
mbligh | 3c7a150 | 2008-07-24 18:08:47 +0000 | [diff] [blame] | 421 | autodir = os.path.dirname(host.run(cmd).stdout) |
| 422 | if autodir: |
| 423 | return autodir |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 424 | except error.AutoservRunError: |
| 425 | pass |
| 426 | for path in ['/usr/local/autotest', '/home/autotest']: |
| 427 | try: |
jadmanski | 169ecad | 2008-09-12 15:49:44 +0000 | [diff] [blame] | 428 | host.run('ls %s > /dev/null 2>&1' % |
| 429 | os.path.join(path, 'bin/autotest')) |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 430 | return path |
| 431 | except error.AutoservRunError: |
| 432 | pass |
| 433 | raise error.AutotestRunError("Cannot figure out autotest directory") |
mbligh | d8b3925 | 2008-03-20 21:15:03 +0000 | [diff] [blame] | 434 | |
| 435 | |
| 436 | # site_autotest.py may be non-existant or empty, make sure that an appropriate |
| 437 | # SiteAutotest class is created nevertheless |
| 438 | try: |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 439 | from site_autotest import SiteAutotest |
mbligh | d8b3925 | 2008-03-20 21:15:03 +0000 | [diff] [blame] | 440 | except ImportError: |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 441 | class SiteAutotest(BaseAutotest): |
| 442 | pass |
mbligh | d8b3925 | 2008-03-20 21:15:03 +0000 | [diff] [blame] | 443 | |
| 444 | |
| 445 | class Autotest(SiteAutotest): |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 446 | pass |