Add options to control reboots before and after a job.

-add reboot_before and reboot_after fields to Job, along with enums for each
-add options to create_job RPC for reboot_before and reboot_after
-add options to job create CLI for these fields, and made job stat -v display them
-add widgets to job create page in AFE for these fields and made job detail view display them

-add dirty field to Hosts, defaulting to True, and set to True when a host is locked
-made scheduler set this field when a job runs and clear it when a host is rebooted

-updated scheduler's PidfileRunMonitor to read a new three-line .autoserv_execute format, where the third line contains the number of tests that failed
-made scheduler Job.run() include a RebootTask before the verify task according to the reboot_before option
-made QueueTask.epilog() launch a RebootTask for each host according to the reboot_after option

-updated autoserv to write out a third line to .autoserv_execute containing the number of failed tests.

Other changes:
-added support for displaying Job.run_verify in the CLI (job stat -v) and job detail page on AFE
-updated ModelExtensions to convert BooleanField values to actual booleans.  The MySQL Django backend just leaves them as ints (as they are represented in the DB), and it's stupid and annoying (Yes, bool is a subclass of int, so it's often not a problem.  But yes, it can be.).
-get rid of use of Job.synch_count since we don't actually support it.  I think this was meant for inclusion in a previous change and got left out.
-made the scheduler use the new setup_django_environment stuff to import and use the django models.  It doesn't *really* use the models yet -- it just uses the Job.Reboot{Before,After} enum objects -- but this shows we could easily start using the models, and that's definitely the direction I want to go long term.
-refactored PidfileRunMonitor generally and made it a bit more robust by having it email errors for corrupt pidfiles and continue gracefully, instead of just crashing the scheduler
-changed the way Agent.tick() works.  now, it basically runs through as much work as it can in a single call.  for example, if there's a RebootTask and a VerifyTask, and the RebootTask has just finished, in a single call it will finish up the RebootTask and start the VerifyTask.  this used to take two cycles and that was problematic for cases like this one -- the RebootTask would like to set host.status=Ready, but then the host could get snatched up on the next scheduling round, before the VerifyTask got started.  This was sort of solved previously by keeping the HostQueueEntry active, and we could apply that approach here by making a new status for HostQueueEntries like "Rebooting".  But I prefer this approach as I think it's more efficient, more powerful and easier to work with.

Risk: extremely high
Visibility: new reboot options for jobs, skip verify now displayed in AFE + CLI

Signed-off-by: Steve Howard <showard@google.com>


git-svn-id: http://test.kernel.org/svn/autotest/trunk@2308 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/cli/job.py b/cli/job.py
index 80f3119..bff180b 100755
--- a/cli/job.py
+++ b/cli/job.py
@@ -188,7 +188,8 @@
             keys = ['id', 'name', 'priority', 'status_counts', 'hosts_status']
         else:
             keys = ['id', 'name', 'priority', 'status_counts', 'hosts_status',
-                    'owner', 'control_type',  'synch_type', 'created_on']
+                    'owner', 'control_type',  'synch_type', 'created_on',
+                    'run_verify', 'reboot_before', 'reboot_after']
 
         if self.show_control_file:
             keys.append('control_file')
@@ -201,6 +202,8 @@
     [--is-synchronous] [--container] [--control-file </path/to/cfile>]
     [--on-server] [--test <test1,test2>] [--kernel <http://kernel>]
     [--mlist </path/to/machinelist>] [--machine <host1 host2 host3>]
+    [--dependencies <list of dependency labels]
+    [--reboot_before <option>] [--reboot_after <option>]
     job_name
 
     Creating a job is rather different from the other create operations,
@@ -244,6 +247,18 @@
         self.parser.add_option('-e', '--email', help='A comma seperated list '
                                'of email addresses to notify of job completion',
                                default='')
+        self.parser.add_option('-b', '--reboot_before',
+                               help='Whether or not to reboot the machine '
+                                    'before the job (never/if dirty/always)',
+                               type='choice',
+                               choices=('never', 'if dirty', 'always'))
+        self.parser.add_option('-a', '--reboot_after',
+                               help='Whether or not to reboot the machine '
+                                    'after the job (never/if all tests passed/'
+                                    'always)',
+                               type='choice',
+                               choices=('never', 'if all tests passed',
+                                        'always'))
 
 
     def parse_hosts(self, args):
@@ -317,6 +332,10 @@
 
         if options.priority:
             self.data['priority'] = options.priority.capitalize()
+        if options.reboot_before:
+            self.data['reboot_before'] = options.reboot_before.capitalize()
+        if options.reboot_after:
+            self.data['reboot_after'] = options.reboot_after.capitalize()
 
         if len(self.jobname) > 1:
             self.invalid_syntax('Too many arguments specified, only expected '