blob: e57a1832b174058f1d3bfa4008c50717ba6e4824 [file] [log] [blame]
mblighe8819cd2008-02-15 16:48:40 +00001"""\
2Utility functions for rpc_interface.py. We keep them in a separate file so that
3only RPC interface functions go into that file.
4"""
5
6__author__ = 'showard@google.com (Steve Howard)'
7
8import datetime, xmlrpclib, threading
9from frontend.afe import models
10
11def prepare_for_serialization(objects):
12 """\
13 Do necessary type conversions to values in data to allow for RPC
14 serialization.
15 -convert datetimes to strings
16 """
showard1c8c2212008-04-03 20:33:58 +000017 objects = gather_unique_dicts(objects)
showardb8d34242008-04-25 18:11:16 +000018 return _prepare_data(objects)
19
20
21def _prepare_data(data):
22 'Recursively process data structures'
23 if isinstance(data, dict):
mblighe8819cd2008-02-15 16:48:40 +000024 new_data = {}
25 for key, value in data.iteritems():
showardb8d34242008-04-25 18:11:16 +000026 new_data[key] = _prepare_data(value)
27 return new_data
28 elif isinstance(data, list):
29 return [_prepare_data(item) for item in data]
30 elif isinstance(data, datetime.datetime):
31 return str(data)
32 else:
33 return data
mblighe8819cd2008-02-15 16:48:40 +000034
35
36def extra_job_filters(not_yet_run=False, running=False, finished=False):
37 """\
38 Generate a SQL WHERE clause for job status filtering, and return it in
39 a dict of keyword args to pass to query.extra(). No more than one of
40 the parameters should be passed as True.
41 """
42 assert not ((not_yet_run and running) or
43 (not_yet_run and finished) or
44 (running and finished)), ('Cannot specify more than one '
45 'filter to this function')
46 if not_yet_run:
47 where = ['id NOT IN (SELECT job_id FROM host_queue_entries '
48 'WHERE active OR complete)']
49 elif running:
50 where = ['(id IN (SELECT job_id FROM host_queue_entries '
51 'WHERE active OR complete)) AND '
52 '(id IN (SELECT job_id FROM host_queue_entries '
53 'WHERE not complete OR active))']
54 elif finished:
55 where = ['id NOT IN (SELECT job_id FROM host_queue_entries '
56 'WHERE not complete OR active)']
57 else:
58 return None
59 return {'where': where}
60
61
showard8e3aa5e2008-04-08 19:42:32 +000062def extra_host_filters(multiple_labels=[]):
63 """\
64 Generate SQL WHERE clauses for matching hosts in an intersection of
65 labels.
66 """
67 extra_args = {}
68 where_str = ('hosts.id in (select host_id from hosts_labels '
69 'where label_id=%s)')
70 extra_args['where'] = [where_str] * len(multiple_labels)
71 extra_args['params'] = [models.Label.smart_get(label).id
72 for label in multiple_labels]
73 return extra_args
74
75
mblighe8819cd2008-02-15 16:48:40 +000076local_vars = threading.local()
77
78def set_user(user):
79 """\
80 Sets the current request's logged-in user. user should be a
81 afe.models.User object.
82 """
83 local_vars.user = user
84
85
86def get_user():
87 'Get the currently logged-in user as a afe.models.User object.'
88 return local_vars.user
89
90
showard8fd58242008-03-10 21:29:07 +000091class InconsistencyException(Exception):
92 'Raised when a list of objects does not have a consistent value'
93
94
95def get_consistent_value(objects, field):
96 value = getattr(objects[0], field)
97 for obj in objects:
98 this_value = getattr(obj, field)
99 if this_value != value:
100 raise InconsistencyException(objects[0], obj)
101 return value
102
103
mblighe8819cd2008-02-15 16:48:40 +0000104def prepare_generate_control_file(tests, kernel, label):
105 test_objects = [models.Test.smart_get(test) for test in tests]
106 # ensure tests are all the same type
showard8fd58242008-03-10 21:29:07 +0000107 try:
108 test_type = get_consistent_value(test_objects, 'test_type')
109 except InconsistencyException, exc:
110 test1, test2 = exc.args
111 raise models.ValidationError(
112 {'tests' : 'You cannot run both server- and client-side '
113 'tests together (tests %s and %s differ' % (
114 test1.name, test2.name)})
115
116 try:
117 synch_type = get_consistent_value(test_objects, 'synch_type')
118 except InconsistencyException, exc:
119 test1, test2 = exc.args
120 raise models.ValidationError(
121 {'tests' : 'You cannot run both synchronous and '
122 'asynchronous tests together (tests %s and %s differ)' % (
123 test1.name, test2.name)})
mblighe8819cd2008-02-15 16:48:40 +0000124
125 is_server = (test_type == models.Test.Types.SERVER)
showard8fd58242008-03-10 21:29:07 +0000126 is_synchronous = (synch_type == models.Test.SynchType.SYNCHRONOUS)
mblighe8819cd2008-02-15 16:48:40 +0000127 if label:
128 label = models.Label.smart_get(label)
129
showard8fd58242008-03-10 21:29:07 +0000130 return is_server, is_synchronous, test_objects, label
showard1385b162008-03-13 15:59:40 +0000131
132
133def gather_unique_dicts(dict_iterable):
134 """\
135 Pick out unique objects (by ID) from an iterable of object dicts.
136 """
137 id_set = set()
138 result = []
139 for obj in dict_iterable:
140 if obj['id'] not in id_set:
141 id_set.add(obj['id'])
142 result.append(obj)
143 return result
showard8e3aa5e2008-04-08 19:42:32 +0000144
145
146def sorted(in_list):
147 new_list = list(in_list)
148 new_list.sort()
149 return new_list