Update CLI to allow scheduling jobs against labels

Signed-off-by: Ryan Kubiak <[email protected]>


git-svn-id: http://test.kernel.org/svn/autotest/trunk@3070 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/cli/action_common.py b/cli/action_common.py
index 388c4ac..e926d47 100755
--- a/cli/action_common.py
+++ b/cli/action_common.py
@@ -185,8 +185,8 @@
                     meta_hosts += int(num) * [host]
                 elif re.match('^[*](\w*)', host):
                     meta_hosts += [re.match('^[*](\w*)', host).group(1)]
-                elif host != '':
-                    # Real hostname
+                elif host != '' and host not in hosts:
+                    # Real hostname and not a duplicate
                     hosts.append(host)
 
         return (hosts, meta_hosts)
diff --git a/cli/job.py b/cli/job.py
index 0b291a1..51c13fb 100755
--- a/cli/job.py
+++ b/cli/job.py
@@ -202,10 +202,10 @@
     [--synch_count] [--control-file </path/to/cfile>]
     [--on-server] [--test <test1,test2>] [--kernel <http://kernel>]
     [--mlist </path/to/machinelist>] [--machine <host1 host2 host3>]
-    [--labels <labels this job is dependent on>]
+    [--labels <list of labels of machines to run on>]
     [--reboot_before <option>] [--reboot_after <option>]
     [--noverify] [--timeout <timeout>] [--one-time-hosts <hosts>]
-    [--email <email>]
+    [--email <email>] [--dependencies <labels this job is dependent on>]
     job_name
 
     Creating a job is rather different from the other create operations,
@@ -235,8 +235,11 @@
                                help='List of tests to run')
         self.parser.add_option('-k', '--kernel', help='Install kernel from this'
                                ' URL before beginning job')
+        self.parser.add_option('-d', '--dependencies', help='Comma separated '
+                               'list of labels this job is dependent on.',
+                               default='')
         self.parser.add_option('-b', '--labels', help='Comma separated list of '
-                               'labels this job is dependent on.', default='')
+                               'labels to get machine list from.', default='')
         self.parser.add_option('-m', '--machine', help='List of machines to '
                                'run on')
         self.parser.add_option('-M', '--mlist',
@@ -294,9 +297,10 @@
             self.reuse_hosts = options.reuse_hosts
             return (options, leftover)
 
-        if len(self.hosts) == 0 and not options.one_time_hosts:
+        if (len(self.hosts) == 0 and not options.one_time_hosts
+            and not options.labels):
             self.invalid_syntax('Must specify at least one machine '
-                                '(-m, -M or --one-time-hosts).')
+                                '(-m, -M, -b or --one-time-hosts).')
         if not options.control_file and not options.test:
             self.invalid_syntax('Must specify either --test or --control-file'
                                 ' to create a job.')
@@ -349,13 +353,20 @@
         if options.one_time_hosts:
             one_time_hosts = self._file_list(options, opt_list='one_time_hosts')
             self.data['one_time_hosts'] = one_time_hosts
+        if options.labels:
+            labels = options.labels.split(',')
+            labels = [label.strip() for label in labels if label.strip()]
+            label_hosts = self.execute_rpc(op='get_hosts',
+                                           multiple_labels=labels)
+            for host in label_hosts:
+                self.hosts.append(host['hostname'])
 
         self.data['name'] = self.jobname
 
         (self.data['hosts'],
          self.data['meta_hosts']) = self.parse_hosts(self.hosts)
 
-        deps = options.labels.split(',')
+        deps = options.dependencies.split(',')
         deps = [dep.strip() for dep in deps if dep.strip()]
         self.data['dependencies'] = deps
 
diff --git a/cli/job_unittest.py b/cli/job_unittest.py
index 279ebe9..7b5d0c9 100755
--- a/cli/job_unittest.py
+++ b/cli/job_unittest.py
@@ -601,12 +601,12 @@
                      out_words_no=['Uploading', 'Done'])
 
 
-    def test_execute_create_job_with_control_and_label(self):
+    def test_execute_create_job_with_control_and_dependencies(self):
         data = self.data.copy()
         data['dependencies'] = ['dep1', 'dep2']
         filename = cli_mock.create_file(self.ctrl_file)
         self.run_cmd(argv=['atest', 'job', 'create', '-f', filename,
-                           'test_job0', '-m', 'host0', '-b', 'dep1, dep2 ',
+                           'test_job0', '-m', 'host0', '-d', 'dep1, dep2 ',
                            '--ignore_site_file'],
                      rpcs=[('create_job', data, True, 42)],
                      out_words_ok=['test_job0', 'Created'],
@@ -625,11 +625,11 @@
                      out_words_no=['Uploading', 'Done'])
 
 
-    def test_execute_create_job_with_test_and_label(self):
+    def test_execute_create_job_with_test_and_dependencies(self):
         data = self.data.copy()
         data['dependencies'] = ['dep1', 'dep2', 'dep3']
         self.run_cmd(argv=['atest', 'job', 'create', '-t', 'sleeptest',
-                           'test_job0', '-m', 'host0', '-b', 'dep1, dep2 ',
+                           'test_job0', '-m', 'host0', '-d', 'dep1, dep2 ',
                            '--ignore_site_file'],
                      rpcs=[('generate_control_file',
                             {'tests': ['sleeptest']},
@@ -832,6 +832,54 @@
                      err_words_ok=['failed', 'already exists'])
 
 
+    def test_execute_create_job_with_control_and_labels(self):
+        data = self.data.copy()
+        data['hosts'] = ['host0', 'host1', 'host2']
+        filename = cli_mock.create_file(self.ctrl_file)
+        self.run_cmd(argv=['atest', 'job', 'create', '-f', filename,
+                           'test_job0', '-m', 'host0', '-b', 'label1,label2',
+                           '--ignore_site_file'],
+                     rpcs=[('get_hosts', {'multiple_labels': ['label1',
+                            'label2']}, True,
+                            [{u'status': u'Running', u'lock_time': None,
+                              u'hostname': u'host1', u'locked': False,
+                              u'locked_by': None, u'invalid': False, u'id': 42,
+                              u'labels': [u'label1'], u'platform':
+                              u'Warp18_Diskfull', u'protection':
+                              u'Repair software only', u'dirty':
+                              True, u'synch_id': None},
+                             {u'status': u'Running', u'lock_time': None,
+                              u'hostname': u'host2', u'locked': False,
+                              u'locked_by': None, u'invalid': False, u'id': 43,
+                              u'labels': [u'label2'], u'platform':
+                              u'Warp18_Diskfull', u'protection':
+                              u'Repair software only', u'dirty': True,
+                              u'synch_id': None}]),
+                            ('create_job', data, True, 42)],
+                     out_words_ok=['test_job0', 'Created'],
+                     out_words_no=['Uploading', 'Done'])
+
+
+    def test_execute_create_job_with_label_and_duplicate_hosts(self):
+        data = self.data.copy()
+        data['hosts'] = ['host1', 'host0']
+        filename = cli_mock.create_file(self.ctrl_file)
+        self.run_cmd(argv=['atest', 'job', 'create', '-f', filename,
+                           'test_job0', '-m', 'host0,host1', '-b', 'label1',
+                           '--ignore_site_file'],
+                     rpcs=[('get_hosts', {'multiple_labels': ['label1']}, True,
+                            [{u'status': u'Running', u'lock_time': None,
+                              u'hostname': u'host1', u'locked': False,
+                              u'locked_by': None, u'invalid': False, u'id': 42,
+                              u'labels': [u'label1'], u'platform':
+                              u'Warp18_Diskfull', u'protection':
+                              u'Repair software only', u'dirty':
+                              True, u'synch_id': None}]),
+                            ('create_job', data, True, 42)],
+                     out_words_ok=['test_job0', 'Created'],
+                     out_words_no=['Uploading', 'Done'])
+
+
     def _test_parse_hosts(self, args, exp_hosts=[], exp_meta_hosts=[]):
         testjob = job.job_create()
         (hosts, meta_hosts) = testjob.parse_hosts(args)