OLD | NEW |
1 """The main job wrapper | 1 """The main job wrapper |
2 | 2 |
3 This is the core infrastructure. | 3 This is the core infrastructure. |
4 | 4 |
5 Copyright Andy Whitcroft, Martin J. Bligh 2006 | 5 Copyright Andy Whitcroft, Martin J. Bligh 2006 |
6 """ | 6 """ |
7 | 7 |
8 import copy, os, platform, re, shutil, sys, time, traceback, types, glob | 8 import copy, os, platform, re, shutil, sys, time, traceback, types, glob |
9 import logging, getpass, errno, weakref | 9 import logging, getpass, errno, weakref |
10 import cPickle as pickle | 10 import cPickle as pickle |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 verbose=options.verbose) | 172 verbose=options.verbose) |
173 logging.info('Writing results to %s', self.resultdir) | 173 logging.info('Writing results to %s', self.resultdir) |
174 | 174 |
175 # init_group_level needs the state | 175 # init_group_level needs the state |
176 self.control = os.path.realpath(control) | 176 self.control = os.path.realpath(control) |
177 self._is_continuation = options.cont | 177 self._is_continuation = options.cont |
178 self._current_step_ancestry = [] | 178 self._current_step_ancestry = [] |
179 self._next_step_index = 0 | 179 self._next_step_index = 0 |
180 self._load_state() | 180 self._load_state() |
181 | 181 |
182 # harness is chosen by following rules: | 182 _harness = self.handle_persistent_option(options, 'harness') |
183 # 1. explicitly specified via command line | 183 _harness_args = self.handle_persistent_option(options, 'harness_args') |
184 # 2. harness stored in state file (if continuing job '-c') | |
185 # 3. default harness | |
186 selected_harness = None | |
187 if options.harness: | |
188 selected_harness = options.harness | |
189 self._state.set('client', 'harness', selected_harness) | |
190 else: | |
191 stored_harness = self._state.get('client', 'harness', None) | |
192 if stored_harness: | |
193 selected_harness = stored_harness | |
194 | 184 |
195 self.harness = harness.select(selected_harness, self) | 185 self.harness = harness.select(_harness, self, _harness_args) |
196 | 186 |
197 # set up the status logger | 187 # set up the status logger |
198 def client_job_record_hook(entry): | 188 def client_job_record_hook(entry): |
199 msg_tag = '' | 189 msg_tag = '' |
200 if '.' in self._logger.global_filename: | 190 if '.' in self._logger.global_filename: |
201 msg_tag = self._logger.global_filename.split('.', 1)[1] | 191 msg_tag = self._logger.global_filename.split('.', 1)[1] |
202 # send the entry to the job harness | 192 # send the entry to the job harness |
203 message = '\n'.join([entry.message] + entry.extra_message_lines) | 193 message = '\n'.join([entry.message] + entry.extra_message_lines) |
204 rendered_entry = self._logger.render_entry(entry) | 194 rendered_entry = self._logger.render_entry(entry) |
205 self.harness.test_status_detail(entry.status_code, entry.subdir, | 195 self.harness.test_status_detail(entry.status_code, entry.subdir, |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
381 | 371 |
382 | 372 |
383 def control_get(self): | 373 def control_get(self): |
384 return self.control | 374 return self.control |
385 | 375 |
386 | 376 |
387 def control_set(self, control): | 377 def control_set(self, control): |
388 self.control = os.path.abspath(control) | 378 self.control = os.path.abspath(control) |
389 | 379 |
390 | 380 |
391 def harness_select(self, which): | 381 def harness_select(self, which, harness_args): |
392 self.harness = harness.select(which, self) | 382 self.harness = harness.select(which, self, harness_args) |
393 | 383 |
394 | 384 |
395 def config_set(self, name, value): | 385 def config_set(self, name, value): |
396 self._config.set(name, value) | 386 self._config.set(name, value) |
397 | 387 |
398 | 388 |
399 def config_get(self, name): | 389 def config_get(self, name): |
400 return self._config.get(name) | 390 return self._config.get(name) |
401 | 391 |
402 | 392 |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
594 subroutine to run | 584 subroutine to run |
595 *args: | 585 *args: |
596 arguments for the function | 586 arguments for the function |
597 | 587 |
598 Returns the result of the passed in function | 588 Returns the result of the passed in function |
599 """ | 589 """ |
600 | 590 |
601 try: | 591 try: |
602 self.record('START', subdir, testname) | 592 self.record('START', subdir, testname) |
603 self._state.set('client', 'unexpected_reboot', (subdir, testname)) | 593 self._state.set('client', 'unexpected_reboot', (subdir, testname)) |
604 result = function(*args, **dargs) | 594 try: |
605 self.record('END GOOD', subdir, testname) | 595 result = function(*args, **dargs) |
606 return result | 596 self.record('END GOOD', subdir, testname) |
607 except error.TestBaseException, e: | 597 return result |
608 self.record('END %s' % e.exit_status, subdir, testname) | 598 except error.TestBaseException, e: |
609 raise | 599 self.record('END %s' % e.exit_status, subdir, testname) |
610 except error.JobError, e: | 600 raise |
611 self.record('END ABORT', subdir, testname) | 601 except error.JobError, e: |
612 raise | 602 self.record('END ABORT', subdir, testname) |
613 except Exception, e: | 603 raise |
614 # This should only ever happen due to a bug in the given | 604 except Exception, e: |
615 # function's code. The common case of being called by | 605 # This should only ever happen due to a bug in the given |
616 # run_test() will never reach this. If a control file called | 606 # function's code. The common case of being called by |
617 # run_group() itself, bugs in its function will be caught | 607 # run_test() will never reach this. If a control file called |
618 # here. | 608 # run_group() itself, bugs in its function will be caught |
619 err_msg = str(e) + '\n' + traceback.format_exc() | 609 # here. |
620 self.record('END ERROR', subdir, testname, err_msg) | 610 err_msg = str(e) + '\n' + traceback.format_exc() |
621 raise | 611 self.record('END ERROR', subdir, testname, err_msg) |
| 612 raise |
622 finally: | 613 finally: |
623 self._state.discard('client', 'unexpected_reboot') | 614 self._state.discard('client', 'unexpected_reboot') |
624 | 615 |
625 | 616 |
626 def run_group(self, function, tag=None, **dargs): | 617 def run_group(self, function, tag=None, **dargs): |
627 """ | 618 """ |
628 Run a function nested within a group level. | 619 Run a function nested within a group level. |
629 | 620 |
630 function: | 621 function: |
631 Callable to run. | 622 Callable to run. |
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
917 has_steps = self._state.has('client', 'steps') | 908 has_steps = self._state.has('client', 'steps') |
918 if not self._is_continuation and has_steps: | 909 if not self._is_continuation and has_steps: |
919 raise RuntimeError('Loaded state can only contain client.steps if ' | 910 raise RuntimeError('Loaded state can only contain client.steps if ' |
920 'this is a continuation') | 911 'this is a continuation') |
921 | 912 |
922 if not has_steps: | 913 if not has_steps: |
923 logging.info('Initializing the state engine') | 914 logging.info('Initializing the state engine') |
924 self._state.set('client', 'steps', []) | 915 self._state.set('client', 'steps', []) |
925 | 916 |
926 | 917 |
| 918 def handle_persistent_option(self, options, option_name): |
| 919 """ |
| 920 Select option from command line or persistent state. |
| 921 Store selected option to allow standalone client to continue |
| 922 after reboot with previously selected options. |
| 923 Priority: |
| 924 1. explicitly specified via command line |
| 925 2. stored in state file (if continuing job '-c') |
| 926 3. default == None |
| 927 """ |
| 928 option = None |
| 929 cmd_line_option = getattr(options, option_name) |
| 930 if cmd_line_option: |
| 931 option = cmd_line_option |
| 932 self._state.set('client', option_name, option) |
| 933 else: |
| 934 stored_option = self._state.get('client', option_name, None) |
| 935 if stored_option: |
| 936 option = stored_option |
| 937 logging.debug('Persistent option %s now set to %s', option_name, option) |
| 938 return option |
| 939 |
| 940 |
927 def __create_step_tuple(self, fn, args, dargs): | 941 def __create_step_tuple(self, fn, args, dargs): |
928 # Legacy code passes in an array where the first arg is | 942 # Legacy code passes in an array where the first arg is |
929 # the function or its name. | 943 # the function or its name. |
930 if isinstance(fn, list): | 944 if isinstance(fn, list): |
931 assert(len(args) == 0) | 945 assert(len(args) == 0) |
932 assert(len(dargs) == 0) | 946 assert(len(dargs) == 0) |
933 args = fn[1:] | 947 args = fn[1:] |
934 fn = fn[0] | 948 fn = fn[0] |
935 # Pickling actual functions is hairy, thus we have to call | 949 # Pickling actual functions is hairy, thus we have to call |
936 # them by name. Unfortunately, this means only functions | 950 # them by name. Unfortunately, this means only functions |
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1244 assert myjob._record_indent == 0 | 1258 assert myjob._record_indent == 0 |
1245 | 1259 |
1246 myjob.complete(0) | 1260 myjob.complete(0) |
1247 | 1261 |
1248 | 1262 |
1249 site_job = utils.import_site_class( | 1263 site_job = utils.import_site_class( |
1250 __file__, "autotest_lib.client.bin.site_job", "site_job", base_client_job) | 1264 __file__, "autotest_lib.client.bin.site_job", "site_job", base_client_job) |
1251 | 1265 |
1252 class job(site_job): | 1266 class job(site_job): |
1253 pass | 1267 pass |
OLD | NEW |