two new major features:
(1) added test and job dependencies
-added M2M relationship between tests and labels and between jobs and labels, for tracking the labels on which a test/job depends
-modified test_importer to read the DEPENDENCIES field and create the right M2M relationships
-modified generate_control_file() RPC to compute and return the union of test dependencies. since generate_control_file now returns four pieces of information, i converted its return type from tuple to dict, and changed clients accordingly.
-modified job creation clients (GWT and CLI) to pass this dependency list to the create_job() RPC
-modified the create_job() RPC to check that hosts satisfy job dependencies, and to create M2M relationships
-modified the scheduler to check dependencies when scheduling jobs
-modified JobDetailView to show a job's dependencies
(2) added "only_if_needed" bit to labels; if true, a machine with this label can only be used if the label is requested (either by job dependencies or by the metahost label)
-added boolean field to Labels
-modified CLI label creation/viewing to support this new field
-made create_job() RPC and scheduler check for hosts with such a label that was not requested, and reject such hosts
also did some slight refactoring of other code in create_job() to simplify it while I was changing things there.
a couple notes:
-an only_if_needed label can be used if either the job depends on the label or it's a metahost for that label. we assume that if the user specifically requests the label in a metahost, then it's OK, even if the job doesn't depend on that label.
-one-time-hosts are assumed to satisfy job dependencies.
Signed-off-by: Steve Howard <showard@google.com>
git-svn-id: http://test.kernel.org/svn/autotest/trunk@2215 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/frontend/afe/rpc_utils.py b/frontend/afe/rpc_utils.py
index ac175f0..fcdc0ba 100644
--- a/frontend/afe/rpc_utils.py
+++ b/frontend/afe/rpc_utils.py
@@ -142,4 +142,44 @@
if label:
label = models.Label.smart_get(label)
- return is_server, is_synchronous, test_objects, profiler_objects, label
+ dependencies = set(label.name for label
+ in models.Label.objects.filter(test__in=test_objects))
+
+ return (dict(is_server=is_server, is_synchronous=is_synchronous,
+ dependencies=list(dependencies)),
+ test_objects, profiler_objects, label)
+
+
+def check_job_dependencies(host_objects, job_dependencies):
+ """
+ Check that a set of machines satisfies a job's dependencies.
+ host_objects: list of models.Host objects
+ job_dependencies: list of names of labels
+ """
+ # check that hosts satisfy dependencies
+ host_ids = [host.id for host in host_objects]
+ hosts_in_job = models.Host.objects.filter(id__in=host_ids)
+ ok_hosts = hosts_in_job
+ for index, dependency in enumerate(job_dependencies):
+ ok_hosts &= models.Host.objects.filter_custom_join(
+ '_label%d' % index, labels__name=dependency)
+ failing_hosts = (set(host.hostname for host in host_objects) -
+ set(host.hostname for host in ok_hosts))
+ if failing_hosts:
+ raise model_logic.ValidationError(
+ {'hosts' : 'Host(s) failed to meet job dependencies: ' +
+ ', '.join(failing_hosts)})
+
+ # check for hosts that have only_if_needed labels that aren't requested
+ labels_not_requested = models.Label.objects.filter(only_if_needed=True,
+ host__id__in=host_ids)
+ labels_not_requested = labels_not_requested.exclude(
+ name__in=job_dependencies)
+ errors = []
+ for label in labels_not_requested:
+ hosts_in_label = hosts_in_job.filter(labels=label)
+ errors.append('Cannot use hosts with label "%s" unless requested: %s' %
+ (label.name,
+ ', '.join(host.hostname for host in hosts_in_label)))
+ if errors:
+ raise model_logic.ValidationError({'hosts' : '\n'.join(errors)})