blob: 14fa9877052a99ecbe55b3119923425f9a1dd20f [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):
mblighe8819cd2008-02-15 16:48:40 +000012 """
showardb0dfb9f2008-06-06 18:08:02 +000013 Prepare Python objects to be returned via RPC.
14 """
15 if (isinstance(objects, list) and len(objects) and
16 isinstance(objects[0], dict) and 'id' in objects[0]):
17 objects = gather_unique_dicts(objects)
showardb8d34242008-04-25 18:11:16 +000018 return _prepare_data(objects)
19
20
21def _prepare_data(data):
showardb0dfb9f2008-06-06 18:08:02 +000022 """
23 Recursively process data structures, performing necessary type
24 conversions to values in data to allow for RPC serialization:
25 -convert datetimes to strings
26 -convert tuples to lists
27 """
showardb8d34242008-04-25 18:11:16 +000028 if isinstance(data, dict):
mblighe8819cd2008-02-15 16:48:40 +000029 new_data = {}
30 for key, value in data.iteritems():
showardb8d34242008-04-25 18:11:16 +000031 new_data[key] = _prepare_data(value)
32 return new_data
showardb0dfb9f2008-06-06 18:08:02 +000033 elif isinstance(data, list) or isinstance(data, tuple):
showardb8d34242008-04-25 18:11:16 +000034 return [_prepare_data(item) for item in data]
35 elif isinstance(data, datetime.datetime):
36 return str(data)
37 else:
38 return data
mblighe8819cd2008-02-15 16:48:40 +000039
40
showardb0dfb9f2008-06-06 18:08:02 +000041def gather_unique_dicts(dict_iterable):
42 """\
43 Pick out unique objects (by ID) from an iterable of object dicts.
44 """
45 id_set = set()
46 result = []
47 for obj in dict_iterable:
48 if obj['id'] not in id_set:
49 id_set.add(obj['id'])
50 result.append(obj)
51 return result
52
53
mblighe8819cd2008-02-15 16:48:40 +000054def extra_job_filters(not_yet_run=False, running=False, finished=False):
55 """\
56 Generate a SQL WHERE clause for job status filtering, and return it in
57 a dict of keyword args to pass to query.extra(). No more than one of
58 the parameters should be passed as True.
59 """
60 assert not ((not_yet_run and running) or
61 (not_yet_run and finished) or
62 (running and finished)), ('Cannot specify more than one '
63 'filter to this function')
64 if not_yet_run:
65 where = ['id NOT IN (SELECT job_id FROM host_queue_entries '
66 'WHERE active OR complete)']
67 elif running:
68 where = ['(id IN (SELECT job_id FROM host_queue_entries '
69 'WHERE active OR complete)) AND '
70 '(id IN (SELECT job_id FROM host_queue_entries '
71 'WHERE not complete OR active))']
72 elif finished:
73 where = ['id NOT IN (SELECT job_id FROM host_queue_entries '
74 'WHERE not complete OR active)']
75 else:
76 return None
77 return {'where': where}
78
79
showard8e3aa5e2008-04-08 19:42:32 +000080def extra_host_filters(multiple_labels=[]):
81 """\
82 Generate SQL WHERE clauses for matching hosts in an intersection of
83 labels.
84 """
85 extra_args = {}
86 where_str = ('hosts.id in (select host_id from hosts_labels '
87 'where label_id=%s)')
88 extra_args['where'] = [where_str] * len(multiple_labels)
89 extra_args['params'] = [models.Label.smart_get(label).id
90 for label in multiple_labels]
91 return extra_args
92
93
mblighe8819cd2008-02-15 16:48:40 +000094local_vars = threading.local()
95
96def set_user(user):
97 """\
98 Sets the current request's logged-in user. user should be a
99 afe.models.User object.
100 """
101 local_vars.user = user
102
103
104def get_user():
105 'Get the currently logged-in user as a afe.models.User object.'
106 return local_vars.user
107
108
showard8fd58242008-03-10 21:29:07 +0000109class InconsistencyException(Exception):
110 'Raised when a list of objects does not have a consistent value'
111
112
113def get_consistent_value(objects, field):
114 value = getattr(objects[0], field)
115 for obj in objects:
116 this_value = getattr(obj, field)
117 if this_value != value:
118 raise InconsistencyException(objects[0], obj)
119 return value
120
121
mblighe8819cd2008-02-15 16:48:40 +0000122def prepare_generate_control_file(tests, kernel, label):
123 test_objects = [models.Test.smart_get(test) for test in tests]
124 # ensure tests are all the same type
showard8fd58242008-03-10 21:29:07 +0000125 try:
126 test_type = get_consistent_value(test_objects, 'test_type')
127 except InconsistencyException, exc:
128 test1, test2 = exc.args
129 raise models.ValidationError(
130 {'tests' : 'You cannot run both server- and client-side '
131 'tests together (tests %s and %s differ' % (
132 test1.name, test2.name)})
133
134 try:
135 synch_type = get_consistent_value(test_objects, 'synch_type')
136 except InconsistencyException, exc:
137 test1, test2 = exc.args
138 raise models.ValidationError(
139 {'tests' : 'You cannot run both synchronous and '
140 'asynchronous tests together (tests %s and %s differ)' % (
141 test1.name, test2.name)})
mblighe8819cd2008-02-15 16:48:40 +0000142
143 is_server = (test_type == models.Test.Types.SERVER)
showard8fd58242008-03-10 21:29:07 +0000144 is_synchronous = (synch_type == models.Test.SynchType.SYNCHRONOUS)
mblighe8819cd2008-02-15 16:48:40 +0000145 if label:
146 label = models.Label.smart_get(label)
147
showard8fd58242008-03-10 21:29:07 +0000148 return is_server, is_synchronous, test_objects, label
showard1385b162008-03-13 15:59:40 +0000149
150
showard8e3aa5e2008-04-08 19:42:32 +0000151def sorted(in_list):
152 new_list = list(in_list)
153 new_list.sort()
154 return new_list