##// END OF EJS Templates
search: enable case sensitivity
ergo -
Show More
@@ -1,831 +1,829 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright 2010 - 2017 RhodeCode GmbH and the AppEnlight project authors
3 # Copyright 2010 - 2017 RhodeCode GmbH and the AppEnlight project authors
4 #
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
7 # You may obtain a copy of the License at
8 #
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
10 #
11 # Unless required by applicable law or agreed to in writing, software
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
15 # limitations under the License.
16
16
17 import datetime
17 import datetime
18
18
19 import colander
19 import colander
20 from colander import null
20 from colander import null
21
21
22 # those keywords are here so we can distingush between searching for tags and
22 # those keywords are here so we can distingush between searching for tags and
23 # normal properties of reports/logs
23 # normal properties of reports/logs
24 accepted_search_params = [
24 accepted_search_params = [
25 "resource",
25 "resource",
26 "request_id",
26 "request_id",
27 "start_date",
27 "start_date",
28 "end_date",
28 "end_date",
29 "page",
29 "page",
30 "min_occurences",
30 "min_occurences",
31 "http_status",
31 "http_status",
32 "priority",
32 "priority",
33 "error",
33 "error",
34 "url_path",
34 "url_path",
35 "url_domain",
35 "url_domain",
36 "report_status",
36 "report_status",
37 "min_duration",
37 "min_duration",
38 "max_duration",
38 "max_duration",
39 "message",
39 "message",
40 "level",
40 "level",
41 "namespace",
41 "namespace",
42 ]
42 ]
43
43
44
44
45 @colander.deferred
45 @colander.deferred
46 def deferred_utcnow(node, kw):
46 def deferred_utcnow(node, kw):
47 return kw["utcnow"]
47 return kw["utcnow"]
48
48
49
49
50 @colander.deferred
50 @colander.deferred
51 def optional_limited_date(node, kw):
51 def optional_limited_date(node, kw):
52 if not kw.get("allow_permanent_storage"):
52 if not kw.get("allow_permanent_storage"):
53 return limited_date
53 return limited_date
54
54
55
55
56 def lowercase_preparer(input_data):
56 def lowercase_preparer(input_data):
57 """
57 """
58 Transforms a list of string entries to lowercase
58 Transforms a list of string entries to lowercase
59 Used in search query validation
59 Used in search query validation
60 """
60 """
61 if not input_data:
61 if not input_data:
62 return input_data
62 return input_data
63 return [x.lower() for x in input_data]
63 return [x.lower() for x in input_data]
64
64
65
65
66 def shortener_factory(cutoff_size=32):
66 def shortener_factory(cutoff_size=32):
67 """
67 """
68 Limits the input data to specific character count
68 Limits the input data to specific character count
69 :arg cutoff_cutoff_size How much characters to store
69 :arg cutoff_cutoff_size How much characters to store
70
70
71 """
71 """
72
72
73 def shortener(input_data):
73 def shortener(input_data):
74 if not input_data:
74 if not input_data:
75 return input_data
75 return input_data
76 else:
76 else:
77 if isinstance(input_data, str):
77 if isinstance(input_data, str):
78 return input_data[:cutoff_size]
78 return input_data[:cutoff_size]
79 else:
79 else:
80 return input_data
80 return input_data
81
81
82 return shortener
82 return shortener
83
83
84
84
85 def cast_to_unicode_or_null(value):
85 def cast_to_unicode_or_null(value):
86 if value is not colander.null:
86 if value is not colander.null:
87 return str(value)
87 return str(value)
88 return None
88 return None
89
89
90
90
91 class NonTZDate(colander.DateTime):
91 class NonTZDate(colander.DateTime):
92 """ Returns null for incorrect date format - also removes tz info"""
92 """ Returns null for incorrect date format - also removes tz info"""
93
93
94 def deserialize(self, node, cstruct):
94 def deserialize(self, node, cstruct):
95 # disabled for now
95 # disabled for now
96 # if cstruct and isinstance(cstruct, str):
96 # if cstruct and isinstance(cstruct, str):
97 # if ':' not in cstruct:
97 # if ':' not in cstruct:
98 # cstruct += ':0.0'
98 # cstruct += ':0.0'
99 # if '.' not in cstruct:
99 # if '.' not in cstruct:
100 # cstruct += '.0'
100 # cstruct += '.0'
101 value = super(NonTZDate, self).deserialize(node, cstruct)
101 value = super(NonTZDate, self).deserialize(node, cstruct)
102 if value:
102 if value:
103 return value.replace(tzinfo=None)
103 return value.replace(tzinfo=None)
104 return value
104 return value
105
105
106
106
107 class UnknownType(object):
107 class UnknownType(object):
108 """
108 """
109 Universal type that will accept a deserialized JSON object and store it unaltered
109 Universal type that will accept a deserialized JSON object and store it unaltered
110 """
110 """
111
111
112 def serialize(self, node, appstruct):
112 def serialize(self, node, appstruct):
113 if appstruct is null:
113 if appstruct is null:
114 return null
114 return null
115 return appstruct
115 return appstruct
116
116
117 def deserialize(self, node, cstruct):
117 def deserialize(self, node, cstruct):
118 if cstruct is null:
118 if cstruct is null:
119 return null
119 return null
120 return cstruct
120 return cstruct
121
121
122 def cstruct_children(self):
122 def cstruct_children(self):
123 return []
123 return []
124
124
125
125
126 # SLOW REPORT SCHEMA
126 # SLOW REPORT SCHEMA
127
127
128
128
129 def rewrite_type(input_data):
129 def rewrite_type(input_data):
130 """
130 """
131 Fix for legacy appenlight clients
131 Fix for legacy appenlight clients
132 """
132 """
133 if input_data == "remote_call":
133 if input_data == "remote_call":
134 return "remote"
134 return "remote"
135 return input_data
135 return input_data
136
136
137
137
138 class ExtraTupleSchema(colander.TupleSchema):
138 class ExtraTupleSchema(colander.TupleSchema):
139 name = colander.SchemaNode(colander.String(), validator=colander.Length(1, 64))
139 name = colander.SchemaNode(colander.String(), validator=colander.Length(1, 64))
140 value = colander.SchemaNode(
140 value = colander.SchemaNode(
141 UnknownType(), preparer=shortener_factory(512), missing=None
141 UnknownType(), preparer=shortener_factory(512), missing=None
142 )
142 )
143
143
144
144
145 class ExtraSchemaList(colander.SequenceSchema):
145 class ExtraSchemaList(colander.SequenceSchema):
146 tag = ExtraTupleSchema()
146 tag = ExtraTupleSchema()
147 missing = None
147 missing = None
148
148
149
149
150 class TagsTupleSchema(colander.TupleSchema):
150 class TagsTupleSchema(colander.TupleSchema):
151 name = colander.SchemaNode(colander.String(), validator=colander.Length(1, 128))
151 name = colander.SchemaNode(colander.String(), validator=colander.Length(1, 128))
152 value = colander.SchemaNode(
152 value = colander.SchemaNode(
153 UnknownType(), preparer=shortener_factory(128), missing=None
153 UnknownType(), preparer=shortener_factory(128), missing=None
154 )
154 )
155
155
156
156
157 class TagSchemaList(colander.SequenceSchema):
157 class TagSchemaList(colander.SequenceSchema):
158 tag = TagsTupleSchema()
158 tag = TagsTupleSchema()
159 missing = None
159 missing = None
160
160
161
161
162 class NumericTagsTupleSchema(colander.TupleSchema):
162 class NumericTagsTupleSchema(colander.TupleSchema):
163 name = colander.SchemaNode(colander.String(), validator=colander.Length(1, 128))
163 name = colander.SchemaNode(colander.String(), validator=colander.Length(1, 128))
164 value = colander.SchemaNode(colander.Float(), missing=0)
164 value = colander.SchemaNode(colander.Float(), missing=0)
165
165
166
166
167 class NumericTagSchemaList(colander.SequenceSchema):
167 class NumericTagSchemaList(colander.SequenceSchema):
168 tag = NumericTagsTupleSchema()
168 tag = NumericTagsTupleSchema()
169 missing = None
169 missing = None
170
170
171
171
172 class SlowCallSchema(colander.MappingSchema):
172 class SlowCallSchema(colander.MappingSchema):
173 """
173 """
174 Validates slow call format in slow call list
174 Validates slow call format in slow call list
175 """
175 """
176
176
177 start = colander.SchemaNode(NonTZDate())
177 start = colander.SchemaNode(NonTZDate())
178 end = colander.SchemaNode(NonTZDate())
178 end = colander.SchemaNode(NonTZDate())
179 statement = colander.SchemaNode(colander.String(), missing="")
179 statement = colander.SchemaNode(colander.String(), missing="")
180 parameters = colander.SchemaNode(UnknownType(), missing=None)
180 parameters = colander.SchemaNode(UnknownType(), missing=None)
181 type = colander.SchemaNode(
181 type = colander.SchemaNode(
182 colander.String(),
182 colander.String(),
183 preparer=rewrite_type,
183 preparer=rewrite_type,
184 validator=colander.OneOf(
184 validator=colander.OneOf(
185 ["tmpl", "sql", "nosql", "remote", "unknown", "custom"]
185 ["tmpl", "sql", "nosql", "remote", "unknown", "custom"]
186 ),
186 ),
187 missing="unknown",
187 missing="unknown",
188 )
188 )
189 subtype = colander.SchemaNode(
189 subtype = colander.SchemaNode(
190 colander.String(), validator=colander.Length(1, 16), missing="unknown"
190 colander.String(), validator=colander.Length(1, 16), missing="unknown"
191 )
191 )
192 location = colander.SchemaNode(
192 location = colander.SchemaNode(
193 colander.String(), validator=colander.Length(1, 255), missing=""
193 colander.String(), validator=colander.Length(1, 255), missing=""
194 )
194 )
195
195
196
196
197 def limited_date(node, value):
197 def limited_date(node, value):
198 """ checks to make sure that the value is not older/newer than 2h """
198 """ checks to make sure that the value is not older/newer than 2h """
199 past_hours = 72
199 past_hours = 72
200 future_hours = 2
200 future_hours = 2
201 min_time = datetime.datetime.utcnow() - datetime.timedelta(hours=past_hours)
201 min_time = datetime.datetime.utcnow() - datetime.timedelta(hours=past_hours)
202 max_time = datetime.datetime.utcnow() + datetime.timedelta(hours=future_hours)
202 max_time = datetime.datetime.utcnow() + datetime.timedelta(hours=future_hours)
203 if min_time > value:
203 if min_time > value:
204 msg = "%r is older from current UTC time by " + str(past_hours)
204 msg = "%r is older from current UTC time by " + str(past_hours)
205 msg += (
205 msg += (
206 " hours. Ask administrator to enable permanent logging for "
206 " hours. Ask administrator to enable permanent logging for "
207 "your application to store logs with dates in past."
207 "your application to store logs with dates in past."
208 )
208 )
209 raise colander.Invalid(node, msg % value)
209 raise colander.Invalid(node, msg % value)
210 if max_time < value:
210 if max_time < value:
211 msg = "%r is newer from current UTC time by " + str(future_hours)
211 msg = "%r is newer from current UTC time by " + str(future_hours)
212 msg += (
212 msg += (
213 " hours. Ask administrator to enable permanent logging for "
213 " hours. Ask administrator to enable permanent logging for "
214 "your application to store logs with dates in future."
214 "your application to store logs with dates in future."
215 )
215 )
216 raise colander.Invalid(node, msg % value)
216 raise colander.Invalid(node, msg % value)
217
217
218
218
219 class SlowCallListSchema(colander.SequenceSchema):
219 class SlowCallListSchema(colander.SequenceSchema):
220 """
220 """
221 Validates list of individual slow calls
221 Validates list of individual slow calls
222 """
222 """
223
223
224 slow_call = SlowCallSchema()
224 slow_call = SlowCallSchema()
225
225
226
226
227 class RequestStatsSchema(colander.MappingSchema):
227 class RequestStatsSchema(colander.MappingSchema):
228 """
228 """
229 Validates format of requests statistics dictionary
229 Validates format of requests statistics dictionary
230 """
230 """
231
231
232 main = colander.SchemaNode(colander.Float(), validator=colander.Range(0), missing=0)
232 main = colander.SchemaNode(colander.Float(), validator=colander.Range(0), missing=0)
233 sql = colander.SchemaNode(colander.Float(), validator=colander.Range(0), missing=0)
233 sql = colander.SchemaNode(colander.Float(), validator=colander.Range(0), missing=0)
234 nosql = colander.SchemaNode(
234 nosql = colander.SchemaNode(
235 colander.Float(), validator=colander.Range(0), missing=0
235 colander.Float(), validator=colander.Range(0), missing=0
236 )
236 )
237 remote = colander.SchemaNode(
237 remote = colander.SchemaNode(
238 colander.Float(), validator=colander.Range(0), missing=0
238 colander.Float(), validator=colander.Range(0), missing=0
239 )
239 )
240 tmpl = colander.SchemaNode(colander.Float(), validator=colander.Range(0), missing=0)
240 tmpl = colander.SchemaNode(colander.Float(), validator=colander.Range(0), missing=0)
241 custom = colander.SchemaNode(
241 custom = colander.SchemaNode(
242 colander.Float(), validator=colander.Range(0), missing=0
242 colander.Float(), validator=colander.Range(0), missing=0
243 )
243 )
244 sql_calls = colander.SchemaNode(
244 sql_calls = colander.SchemaNode(
245 colander.Float(), validator=colander.Range(0), missing=0
245 colander.Float(), validator=colander.Range(0), missing=0
246 )
246 )
247 nosql_calls = colander.SchemaNode(
247 nosql_calls = colander.SchemaNode(
248 colander.Float(), validator=colander.Range(0), missing=0
248 colander.Float(), validator=colander.Range(0), missing=0
249 )
249 )
250 remote_calls = colander.SchemaNode(
250 remote_calls = colander.SchemaNode(
251 colander.Float(), validator=colander.Range(0), missing=0
251 colander.Float(), validator=colander.Range(0), missing=0
252 )
252 )
253 tmpl_calls = colander.SchemaNode(
253 tmpl_calls = colander.SchemaNode(
254 colander.Float(), validator=colander.Range(0), missing=0
254 colander.Float(), validator=colander.Range(0), missing=0
255 )
255 )
256 custom_calls = colander.SchemaNode(
256 custom_calls = colander.SchemaNode(
257 colander.Float(), validator=colander.Range(0), missing=0
257 colander.Float(), validator=colander.Range(0), missing=0
258 )
258 )
259
259
260
260
261 class FrameInfoVarSchema(colander.SequenceSchema):
261 class FrameInfoVarSchema(colander.SequenceSchema):
262 """
262 """
263 Validates format of frame variables of a traceback
263 Validates format of frame variables of a traceback
264 """
264 """
265
265
266 vars = colander.SchemaNode(UnknownType(), validator=colander.Length(2, 2))
266 vars = colander.SchemaNode(UnknownType(), validator=colander.Length(2, 2))
267
267
268
268
269 class FrameInfoSchema(colander.MappingSchema):
269 class FrameInfoSchema(colander.MappingSchema):
270 """
270 """
271 Validates format of a traceback line
271 Validates format of a traceback line
272 """
272 """
273
273
274 cline = colander.SchemaNode(colander.String(), missing="")
274 cline = colander.SchemaNode(colander.String(), missing="")
275 module = colander.SchemaNode(colander.String(), missing="")
275 module = colander.SchemaNode(colander.String(), missing="")
276 line = colander.SchemaNode(colander.String(), missing="")
276 line = colander.SchemaNode(colander.String(), missing="")
277 file = colander.SchemaNode(colander.String(), missing="")
277 file = colander.SchemaNode(colander.String(), missing="")
278 fn = colander.SchemaNode(colander.String(), missing="")
278 fn = colander.SchemaNode(colander.String(), missing="")
279 vars = FrameInfoVarSchema()
279 vars = FrameInfoVarSchema()
280
280
281
281
282 class FrameInfoListSchema(colander.SequenceSchema):
282 class FrameInfoListSchema(colander.SequenceSchema):
283 """
283 """
284 Validates format of list of traceback lines
284 Validates format of list of traceback lines
285 """
285 """
286
286
287 frame = colander.SchemaNode(UnknownType())
287 frame = colander.SchemaNode(UnknownType())
288
288
289
289
290 class ReportDetailBaseSchema(colander.MappingSchema):
290 class ReportDetailBaseSchema(colander.MappingSchema):
291 """
291 """
292 Validates format of report - ie. request parameters and stats for a request in report group
292 Validates format of report - ie. request parameters and stats for a request in report group
293 """
293 """
294
294
295 username = colander.SchemaNode(
295 username = colander.SchemaNode(
296 colander.String(),
296 colander.String(),
297 preparer=[shortener_factory(255), lambda x: x or ""],
297 preparer=[shortener_factory(255), lambda x: x or ""],
298 missing="",
298 missing="",
299 )
299 )
300 request_id = colander.SchemaNode(
300 request_id = colander.SchemaNode(
301 colander.String(), preparer=shortener_factory(40), missing=""
301 colander.String(), preparer=shortener_factory(40), missing=""
302 )
302 )
303 url = colander.SchemaNode(
303 url = colander.SchemaNode(
304 colander.String(), preparer=shortener_factory(1024), missing=""
304 colander.String(), preparer=shortener_factory(1024), missing=""
305 )
305 )
306 ip = colander.SchemaNode(
306 ip = colander.SchemaNode(
307 colander.String(), preparer=shortener_factory(39), missing=None
307 colander.String(), preparer=shortener_factory(39), missing=None
308 )
308 )
309 start_time = colander.SchemaNode(
309 start_time = colander.SchemaNode(
310 NonTZDate(), validator=optional_limited_date, missing=deferred_utcnow
310 NonTZDate(), validator=optional_limited_date, missing=deferred_utcnow
311 )
311 )
312 end_time = colander.SchemaNode(
312 end_time = colander.SchemaNode(
313 NonTZDate(), validator=optional_limited_date, missing=None
313 NonTZDate(), validator=optional_limited_date, missing=None
314 )
314 )
315 user_agent = colander.SchemaNode(
315 user_agent = colander.SchemaNode(
316 colander.String(),
316 colander.String(),
317 preparer=[shortener_factory(512), lambda x: x or ""],
317 preparer=[shortener_factory(512), lambda x: x or ""],
318 missing="",
318 missing="",
319 )
319 )
320 message = colander.SchemaNode(
320 message = colander.SchemaNode(
321 colander.String(), preparer=shortener_factory(2048), missing=""
321 colander.String(), preparer=shortener_factory(2048), missing=""
322 )
322 )
323 group_string = colander.SchemaNode(
323 group_string = colander.SchemaNode(
324 colander.String(), preparer=shortener_factory(512), missing=None
324 colander.String(), preparer=shortener_factory(512), missing=None
325 )
325 )
326 request_stats = RequestStatsSchema(missing=None)
326 request_stats = RequestStatsSchema(missing=None)
327 request = colander.SchemaNode(colander.Mapping(unknown="preserve"), missing={})
327 request = colander.SchemaNode(colander.Mapping(unknown="preserve"), missing={})
328 traceback = FrameInfoListSchema(missing=None)
328 traceback = FrameInfoListSchema(missing=None)
329 slow_calls = SlowCallListSchema(missing=[])
329 slow_calls = SlowCallListSchema(missing=[])
330 extra = ExtraSchemaList()
330 extra = ExtraSchemaList()
331
331
332
332
333 class ReportDetailSchema_0_5(ReportDetailBaseSchema):
333 class ReportDetailSchema_0_5(ReportDetailBaseSchema):
334 pass
334 pass
335
335
336
336
337 class ReportDetailSchemaPermissiveDate_0_5(ReportDetailSchema_0_5):
337 class ReportDetailSchemaPermissiveDate_0_5(ReportDetailSchema_0_5):
338 start_time = colander.SchemaNode(NonTZDate(), missing=deferred_utcnow)
338 start_time = colander.SchemaNode(NonTZDate(), missing=deferred_utcnow)
339 end_time = colander.SchemaNode(NonTZDate(), missing=None)
339 end_time = colander.SchemaNode(NonTZDate(), missing=None)
340
340
341
341
342 class ReportSchemaBase(colander.MappingSchema):
342 class ReportSchemaBase(colander.MappingSchema):
343 """
343 """
344 Validates format of report group
344 Validates format of report group
345 """
345 """
346
346
347 client = colander.SchemaNode(colander.String(), preparer=lambda x: x or "unknown")
347 client = colander.SchemaNode(colander.String(), preparer=lambda x: x or "unknown")
348 server = colander.SchemaNode(
348 server = colander.SchemaNode(
349 colander.String(),
349 colander.String(),
350 preparer=[lambda x: x.lower() if x else "unknown", shortener_factory(128)],
350 preparer=[lambda x: x.lower() if x else "unknown", shortener_factory(128)],
351 missing="unknown",
351 missing="unknown",
352 )
352 )
353 priority = colander.SchemaNode(
353 priority = colander.SchemaNode(
354 colander.Int(),
354 colander.Int(),
355 preparer=[lambda x: x or 5],
355 preparer=[lambda x: x or 5],
356 validator=colander.Range(1, 10),
356 validator=colander.Range(1, 10),
357 missing=5,
357 missing=5,
358 )
358 )
359 language = colander.SchemaNode(colander.String(), missing="unknown")
359 language = colander.SchemaNode(colander.String(), missing="unknown")
360 error = colander.SchemaNode(
360 error = colander.SchemaNode(
361 colander.String(), preparer=shortener_factory(512), missing=""
361 colander.String(), preparer=shortener_factory(512), missing=""
362 )
362 )
363 view_name = colander.SchemaNode(
363 view_name = colander.SchemaNode(
364 colander.String(),
364 colander.String(),
365 preparer=[shortener_factory(128), lambda x: x or ""],
365 preparer=[shortener_factory(128), lambda x: x or ""],
366 missing="",
366 missing="",
367 )
367 )
368 http_status = colander.SchemaNode(
368 http_status = colander.SchemaNode(
369 colander.Int(), preparer=[lambda x: x or 200], validator=colander.Range(1)
369 colander.Int(), preparer=[lambda x: x or 200], validator=colander.Range(1)
370 )
370 )
371
371
372 occurences = colander.SchemaNode(
372 occurences = colander.SchemaNode(
373 colander.Int(), validator=colander.Range(1, 99999999999), missing=1
373 colander.Int(), validator=colander.Range(1, 99999999999), missing=1
374 )
374 )
375 tags = TagSchemaList()
375 tags = TagSchemaList()
376
376
377
377
378 class ReportSchema_0_5(ReportSchemaBase, ReportDetailSchema_0_5):
378 class ReportSchema_0_5(ReportSchemaBase, ReportDetailSchema_0_5):
379 pass
379 pass
380
380
381
381
382 class ReportSchemaPermissiveDate_0_5(
382 class ReportSchemaPermissiveDate_0_5(
383 ReportSchemaBase, ReportDetailSchemaPermissiveDate_0_5
383 ReportSchemaBase, ReportDetailSchemaPermissiveDate_0_5
384 ):
384 ):
385 pass
385 pass
386
386
387
387
388 class ReportListSchema_0_5(colander.SequenceSchema):
388 class ReportListSchema_0_5(colander.SequenceSchema):
389 """
389 """
390 Validates format of list of report groups
390 Validates format of list of report groups
391 """
391 """
392
392
393 report = ReportSchema_0_5()
393 report = ReportSchema_0_5()
394 validator = colander.Length(1)
394 validator = colander.Length(1)
395
395
396
396
397 class ReportListPermissiveDateSchema_0_5(colander.SequenceSchema):
397 class ReportListPermissiveDateSchema_0_5(colander.SequenceSchema):
398 """
398 """
399 Validates format of list of report groups
399 Validates format of list of report groups
400 """
400 """
401
401
402 report = ReportSchemaPermissiveDate_0_5()
402 report = ReportSchemaPermissiveDate_0_5()
403 validator = colander.Length(1)
403 validator = colander.Length(1)
404
404
405
405
406 class LogSchema(colander.MappingSchema):
406 class LogSchema(colander.MappingSchema):
407 """
407 """
408 Validates format if individual log entry
408 Validates format if individual log entry
409 """
409 """
410
410
411 primary_key = colander.SchemaNode(
411 primary_key = colander.SchemaNode(
412 UnknownType(),
412 UnknownType(),
413 preparer=[cast_to_unicode_or_null, shortener_factory(128)],
413 preparer=[cast_to_unicode_or_null, shortener_factory(128)],
414 missing=None,
414 missing=None,
415 )
415 )
416 log_level = colander.SchemaNode(
416 log_level = colander.SchemaNode(
417 colander.String(), preparer=shortener_factory(10), missing="UNKNOWN"
417 colander.String(), preparer=shortener_factory(10), missing="UNKNOWN"
418 )
418 )
419 message = colander.SchemaNode(
419 message = colander.SchemaNode(
420 colander.String(), preparer=shortener_factory(4096), missing=""
420 colander.String(), preparer=shortener_factory(4096), missing=""
421 )
421 )
422 namespace = colander.SchemaNode(
422 namespace = colander.SchemaNode(
423 colander.String(), preparer=shortener_factory(128), missing=""
423 colander.String(), preparer=shortener_factory(128), missing=""
424 )
424 )
425 request_id = colander.SchemaNode(
425 request_id = colander.SchemaNode(
426 colander.String(), preparer=shortener_factory(40), missing=""
426 colander.String(), preparer=shortener_factory(40), missing=""
427 )
427 )
428 server = colander.SchemaNode(
428 server = colander.SchemaNode(
429 colander.String(), preparer=shortener_factory(128), missing="unknown"
429 colander.String(), preparer=shortener_factory(128), missing="unknown"
430 )
430 )
431 date = colander.SchemaNode(
431 date = colander.SchemaNode(
432 NonTZDate(), validator=limited_date, missing=deferred_utcnow
432 NonTZDate(), validator=limited_date, missing=deferred_utcnow
433 )
433 )
434 tags = TagSchemaList()
434 tags = TagSchemaList()
435
435
436
436
437 class LogSchemaPermanent(LogSchema):
437 class LogSchemaPermanent(LogSchema):
438 date = colander.SchemaNode(NonTZDate(), missing=deferred_utcnow)
438 date = colander.SchemaNode(NonTZDate(), missing=deferred_utcnow)
439 permanent = colander.SchemaNode(colander.Boolean(), missing=False)
439 permanent = colander.SchemaNode(colander.Boolean(), missing=False)
440
440
441
441
442 class LogListSchema(colander.SequenceSchema):
442 class LogListSchema(colander.SequenceSchema):
443 """
443 """
444 Validates format of list of log entries
444 Validates format of list of log entries
445 """
445 """
446
446
447 log = LogSchema()
447 log = LogSchema()
448 validator = colander.Length(1)
448 validator = colander.Length(1)
449
449
450
450
451 class LogListPermanentSchema(colander.SequenceSchema):
451 class LogListPermanentSchema(colander.SequenceSchema):
452 """
452 """
453 Validates format of list of log entries
453 Validates format of list of log entries
454 """
454 """
455
455
456 log = LogSchemaPermanent()
456 log = LogSchemaPermanent()
457 validator = colander.Length(1)
457 validator = colander.Length(1)
458
458
459
459
460 class ViewRequestStatsSchema(RequestStatsSchema):
460 class ViewRequestStatsSchema(RequestStatsSchema):
461 requests = colander.SchemaNode(
461 requests = colander.SchemaNode(
462 colander.Integer(), validator=colander.Range(0), missing=0
462 colander.Integer(), validator=colander.Range(0), missing=0
463 )
463 )
464
464
465
465
466 class ViewMetricTupleSchema(colander.TupleSchema):
466 class ViewMetricTupleSchema(colander.TupleSchema):
467 """
467 """
468 Validates list of views and their corresponding request stats object ie:
468 Validates list of views and their corresponding request stats object ie:
469 ["dir/module:func",{"custom": 0.0..}]
469 ["dir/module:func",{"custom": 0.0..}]
470 """
470 """
471
471
472 view_name = colander.SchemaNode(
472 view_name = colander.SchemaNode(
473 colander.String(),
473 colander.String(),
474 preparer=[shortener_factory(128), lambda x: x or "unknown"],
474 preparer=[shortener_factory(128), lambda x: x or "unknown"],
475 missing="unknown",
475 missing="unknown",
476 )
476 )
477 metrics = ViewRequestStatsSchema()
477 metrics = ViewRequestStatsSchema()
478
478
479
479
480 class ViewMetricListSchema(colander.SequenceSchema):
480 class ViewMetricListSchema(colander.SequenceSchema):
481 """
481 """
482 Validates view breakdown stats objects list
482 Validates view breakdown stats objects list
483 {metrics key of server/time object}
483 {metrics key of server/time object}
484 """
484 """
485
485
486 view_tuple = ViewMetricTupleSchema()
486 view_tuple = ViewMetricTupleSchema()
487 validator = colander.Length(1)
487 validator = colander.Length(1)
488
488
489
489
490 class ViewMetricSchema(colander.MappingSchema):
490 class ViewMetricSchema(colander.MappingSchema):
491 """
491 """
492 Validates server/timeinterval object, ie:
492 Validates server/timeinterval object, ie:
493 {server/time object}
493 {server/time object}
494
494
495 """
495 """
496
496
497 timestamp = colander.SchemaNode(NonTZDate(), validator=limited_date, missing=None)
497 timestamp = colander.SchemaNode(NonTZDate(), validator=limited_date, missing=None)
498 server = colander.SchemaNode(
498 server = colander.SchemaNode(
499 colander.String(),
499 colander.String(),
500 preparer=[shortener_factory(128), lambda x: x or "unknown"],
500 preparer=[shortener_factory(128), lambda x: x or "unknown"],
501 missing="unknown",
501 missing="unknown",
502 )
502 )
503 metrics = ViewMetricListSchema()
503 metrics = ViewMetricListSchema()
504
504
505
505
506 class GeneralMetricSchema(colander.MappingSchema):
506 class GeneralMetricSchema(colander.MappingSchema):
507 """
507 """
508 Validates universal metric schema
508 Validates universal metric schema
509
509
510 """
510 """
511
511
512 namespace = colander.SchemaNode(
512 namespace = colander.SchemaNode(
513 colander.String(), missing="", preparer=shortener_factory(128)
513 colander.String(), missing="", preparer=shortener_factory(128)
514 )
514 )
515
515
516 server_name = colander.SchemaNode(
516 server_name = colander.SchemaNode(
517 colander.String(),
517 colander.String(),
518 preparer=[shortener_factory(128), lambda x: x or "unknown"],
518 preparer=[shortener_factory(128), lambda x: x or "unknown"],
519 missing="unknown",
519 missing="unknown",
520 )
520 )
521 timestamp = colander.SchemaNode(
521 timestamp = colander.SchemaNode(
522 NonTZDate(), validator=limited_date, missing=deferred_utcnow
522 NonTZDate(), validator=limited_date, missing=deferred_utcnow
523 )
523 )
524 tags = TagSchemaList(missing=colander.required)
524 tags = TagSchemaList(missing=colander.required)
525
525
526
526
527 class GeneralMetricPermanentSchema(GeneralMetricSchema):
527 class GeneralMetricPermanentSchema(GeneralMetricSchema):
528 """
528 """
529 Validates universal metric schema
529 Validates universal metric schema
530
530
531 """
531 """
532
532
533 timestamp = colander.SchemaNode(NonTZDate(), missing=deferred_utcnow)
533 timestamp = colander.SchemaNode(NonTZDate(), missing=deferred_utcnow)
534
534
535
535
536 class GeneralMetricsListSchema(colander.SequenceSchema):
536 class GeneralMetricsListSchema(colander.SequenceSchema):
537 metric = GeneralMetricSchema()
537 metric = GeneralMetricSchema()
538 validator = colander.Length(1)
538 validator = colander.Length(1)
539
539
540
540
541 class GeneralMetricsPermanentListSchema(colander.SequenceSchema):
541 class GeneralMetricsPermanentListSchema(colander.SequenceSchema):
542 metric = GeneralMetricPermanentSchema()
542 metric = GeneralMetricPermanentSchema()
543 validator = colander.Length(1)
543 validator = colander.Length(1)
544
544
545
545
546 class MetricsListSchema(colander.SequenceSchema):
546 class MetricsListSchema(colander.SequenceSchema):
547 """
547 """
548 Validates list of metrics objects ie:
548 Validates list of metrics objects ie:
549 [{server/time object}, ] part
549 [{server/time object}, ] part
550
550
551
551
552 """
552 """
553
553
554 metric = ViewMetricSchema()
554 metric = ViewMetricSchema()
555 validator = colander.Length(1)
555 validator = colander.Length(1)
556
556
557
557
558 class StringToAppList(object):
558 class StringToAppList(object):
559 """
559 """
560 Returns validated list of application ids from user query and
560 Returns validated list of application ids from user query and
561 set of applications user is allowed to look at
561 set of applications user is allowed to look at
562 transform string to list containing single integer
562 transform string to list containing single integer
563 """
563 """
564
564
565 def serialize(self, node, appstruct):
565 def serialize(self, node, appstruct):
566 if appstruct is null:
566 if appstruct is null:
567 return null
567 return null
568 return appstruct
568 return appstruct
569
569
570 def deserialize(self, node, cstruct):
570 def deserialize(self, node, cstruct):
571 if cstruct is null:
571 if cstruct is null:
572 return null
572 return null
573
573
574 apps = set([int(a) for a in node.bindings["resources"]])
574 apps = set([int(a) for a in node.bindings["resources"]])
575
575
576 if isinstance(cstruct, str):
576 if isinstance(cstruct, str):
577 cstruct = [cstruct]
577 cstruct = [cstruct]
578
578
579 cstruct = [int(a) for a in cstruct]
579 cstruct = [int(a) for a in cstruct]
580
580
581 valid_apps = list(apps.intersection(set(cstruct)))
581 valid_apps = list(apps.intersection(set(cstruct)))
582 if valid_apps:
582 if valid_apps:
583 return valid_apps
583 return valid_apps
584 return null
584 return null
585
585
586 def cstruct_children(self):
586 def cstruct_children(self):
587 return []
587 return []
588
588
589
589
590 @colander.deferred
590 @colander.deferred
591 def possible_applications_validator(node, kw):
591 def possible_applications_validator(node, kw):
592 possible_apps = [int(a) for a in kw["resources"]]
592 possible_apps = [int(a) for a in kw["resources"]]
593 return colander.All(colander.ContainsOnly(possible_apps), colander.Length(1))
593 return colander.All(colander.ContainsOnly(possible_apps), colander.Length(1))
594
594
595
595
596 @colander.deferred
596 @colander.deferred
597 def possible_applications(node, kw):
597 def possible_applications(node, kw):
598 return [int(a) for a in kw["resources"]]
598 return [int(a) for a in kw["resources"]]
599
599
600
600
601 @colander.deferred
601 @colander.deferred
602 def today_start(node, kw):
602 def today_start(node, kw):
603 return datetime.datetime.utcnow().replace(second=0, microsecond=0, minute=0, hour=0)
603 return datetime.datetime.utcnow().replace(second=0, microsecond=0, minute=0, hour=0)
604
604
605
605
606 @colander.deferred
606 @colander.deferred
607 def today_end(node, kw):
607 def today_end(node, kw):
608 return datetime.datetime.utcnow().replace(
608 return datetime.datetime.utcnow().replace(
609 second=0, microsecond=0, minute=59, hour=23
609 second=0, microsecond=0, minute=59, hour=23
610 )
610 )
611
611
612
612
613 @colander.deferred
613 @colander.deferred
614 def old_start(node, kw):
614 def old_start(node, kw):
615 t_delta = datetime.timedelta(days=90)
615 t_delta = datetime.timedelta(days=90)
616 return (
616 return (
617 datetime.datetime.utcnow().replace(second=0, microsecond=0, minute=0, hour=0)
617 datetime.datetime.utcnow().replace(second=0, microsecond=0, minute=0, hour=0)
618 - t_delta
618 - t_delta
619 )
619 )
620
620
621
621
622 @colander.deferred
622 @colander.deferred
623 def today_end(node, kw):
623 def today_end(node, kw):
624 return datetime.datetime.utcnow().replace(
624 return datetime.datetime.utcnow().replace(
625 second=0, microsecond=0, minute=59, hour=23
625 second=0, microsecond=0, minute=59, hour=23
626 )
626 )
627
627
628
628
629 class PermissiveDate(colander.DateTime):
629 class PermissiveDate(colander.DateTime):
630 """ Returns null for incorrect date format - also removes tz info"""
630 """ Returns null for incorrect date format - also removes tz info"""
631
631
632 def deserialize(self, node, cstruct):
632 def deserialize(self, node, cstruct):
633 if not cstruct:
633 if not cstruct:
634 return null
634 return null
635
635
636 try:
636 try:
637 result = colander.iso8601.parse_date(
637 result = colander.iso8601.parse_date(
638 cstruct, default_timezone=self.default_tzinfo
638 cstruct, default_timezone=self.default_tzinfo
639 )
639 )
640 except colander.iso8601.ParseError:
640 except colander.iso8601.ParseError:
641 return null
641 return null
642 return result.replace(tzinfo=None)
642 return result.replace(tzinfo=None)
643
643
644
644
645 class LogSearchSchema(colander.MappingSchema):
645 class LogSearchSchema(colander.MappingSchema):
646 def schema_type(self, **kw):
646 def schema_type(self, **kw):
647 return colander.Mapping(unknown="preserve")
647 return colander.Mapping(unknown="preserve")
648
648
649 resource = colander.SchemaNode(
649 resource = colander.SchemaNode(
650 StringToAppList(),
650 StringToAppList(),
651 validator=possible_applications_validator,
651 validator=possible_applications_validator,
652 missing=possible_applications,
652 missing=possible_applications,
653 )
653 )
654
654
655 message = colander.SchemaNode(
655 message = colander.SchemaNode(
656 colander.Sequence(accept_scalar=True),
656 colander.Sequence(accept_scalar=True),
657 colander.SchemaNode(colander.String()),
657 colander.SchemaNode(colander.String()),
658 missing=None,
658 missing=None,
659 )
659 )
660 level = colander.SchemaNode(
660 level = colander.SchemaNode(
661 colander.Sequence(accept_scalar=True),
661 colander.Sequence(accept_scalar=True),
662 colander.SchemaNode(colander.String()),
662 colander.SchemaNode(colander.String()),
663 preparer=lowercase_preparer,
663 preparer=lowercase_preparer,
664 missing=None,
664 missing=None,
665 )
665 )
666 namespace = colander.SchemaNode(
666 namespace = colander.SchemaNode(
667 colander.Sequence(accept_scalar=True),
667 colander.Sequence(accept_scalar=True),
668 colander.SchemaNode(colander.String()),
668 colander.SchemaNode(colander.String()),
669 preparer=lowercase_preparer,
670 missing=None,
669 missing=None,
671 )
670 )
672 request_id = colander.SchemaNode(
671 request_id = colander.SchemaNode(
673 colander.Sequence(accept_scalar=True),
672 colander.Sequence(accept_scalar=True),
674 colander.SchemaNode(colander.String()),
673 colander.SchemaNode(colander.String()),
675 preparer=lowercase_preparer,
676 missing=None,
674 missing=None,
677 )
675 )
678 start_date = colander.SchemaNode(PermissiveDate(), missing=None)
676 start_date = colander.SchemaNode(PermissiveDate(), missing=None)
679 end_date = colander.SchemaNode(PermissiveDate(), missing=None)
677 end_date = colander.SchemaNode(PermissiveDate(), missing=None)
680 page = colander.SchemaNode(
678 page = colander.SchemaNode(
681 colander.Integer(), validator=colander.Range(min=1), missing=1
679 colander.Integer(), validator=colander.Range(min=1), missing=1
682 )
680 )
683
681
684
682
685 class ReportSearchSchema(colander.MappingSchema):
683 class ReportSearchSchema(colander.MappingSchema):
686 def schema_type(self, **kw):
684 def schema_type(self, **kw):
687 return colander.Mapping(unknown="preserve")
685 return colander.Mapping(unknown="preserve")
688
686
689 resource = colander.SchemaNode(
687 resource = colander.SchemaNode(
690 StringToAppList(),
688 StringToAppList(),
691 validator=possible_applications_validator,
689 validator=possible_applications_validator,
692 missing=possible_applications,
690 missing=possible_applications,
693 )
691 )
694 request_id = colander.SchemaNode(
692 request_id = colander.SchemaNode(
695 colander.Sequence(accept_scalar=True),
693 colander.Sequence(accept_scalar=True),
696 colander.SchemaNode(colander.String()),
694 colander.SchemaNode(colander.String()),
697 missing=None,
695 missing=None,
698 )
696 )
699 start_date = colander.SchemaNode(PermissiveDate(), missing=None)
697 start_date = colander.SchemaNode(PermissiveDate(), missing=None)
700 end_date = colander.SchemaNode(PermissiveDate(), missing=None)
698 end_date = colander.SchemaNode(PermissiveDate(), missing=None)
701 page = colander.SchemaNode(
699 page = colander.SchemaNode(
702 colander.Integer(), validator=colander.Range(min=1), missing=1
700 colander.Integer(), validator=colander.Range(min=1), missing=1
703 )
701 )
704
702
705 min_occurences = colander.SchemaNode(
703 min_occurences = colander.SchemaNode(
706 colander.Sequence(accept_scalar=True),
704 colander.Sequence(accept_scalar=True),
707 colander.SchemaNode(colander.Integer()),
705 colander.SchemaNode(colander.Integer()),
708 missing=None,
706 missing=None,
709 )
707 )
710
708
711 http_status = colander.SchemaNode(
709 http_status = colander.SchemaNode(
712 colander.Sequence(accept_scalar=True),
710 colander.Sequence(accept_scalar=True),
713 colander.SchemaNode(colander.Integer()),
711 colander.SchemaNode(colander.Integer()),
714 missing=None,
712 missing=None,
715 )
713 )
716 priority = colander.SchemaNode(
714 priority = colander.SchemaNode(
717 colander.Sequence(accept_scalar=True),
715 colander.Sequence(accept_scalar=True),
718 colander.SchemaNode(colander.Integer()),
716 colander.SchemaNode(colander.Integer()),
719 missing=None,
717 missing=None,
720 )
718 )
721 error = colander.SchemaNode(
719 error = colander.SchemaNode(
722 colander.Sequence(accept_scalar=True),
720 colander.Sequence(accept_scalar=True),
723 colander.SchemaNode(colander.String()),
721 colander.SchemaNode(colander.String()),
724 missing=None,
722 missing=None,
725 )
723 )
726 url_path = colander.SchemaNode(
724 url_path = colander.SchemaNode(
727 colander.Sequence(accept_scalar=True),
725 colander.Sequence(accept_scalar=True),
728 colander.SchemaNode(colander.String()),
726 colander.SchemaNode(colander.String()),
729 missing=None,
727 missing=None,
730 )
728 )
731 url_domain = colander.SchemaNode(
729 url_domain = colander.SchemaNode(
732 colander.Sequence(accept_scalar=True),
730 colander.Sequence(accept_scalar=True),
733 colander.SchemaNode(colander.String()),
731 colander.SchemaNode(colander.String()),
734 missing=None,
732 missing=None,
735 )
733 )
736 report_status = colander.SchemaNode(
734 report_status = colander.SchemaNode(
737 colander.Sequence(accept_scalar=True),
735 colander.Sequence(accept_scalar=True),
738 colander.SchemaNode(colander.String()),
736 colander.SchemaNode(colander.String()),
739 missing=None,
737 missing=None,
740 )
738 )
741 min_duration = colander.SchemaNode(
739 min_duration = colander.SchemaNode(
742 colander.Sequence(accept_scalar=True),
740 colander.Sequence(accept_scalar=True),
743 colander.SchemaNode(colander.Float()),
741 colander.SchemaNode(colander.Float()),
744 missing=None,
742 missing=None,
745 )
743 )
746 max_duration = colander.SchemaNode(
744 max_duration = colander.SchemaNode(
747 colander.Sequence(accept_scalar=True),
745 colander.Sequence(accept_scalar=True),
748 colander.SchemaNode(colander.Float()),
746 colander.SchemaNode(colander.Float()),
749 missing=None,
747 missing=None,
750 )
748 )
751
749
752
750
753 class TagSchema(colander.MappingSchema):
751 class TagSchema(colander.MappingSchema):
754 """
752 """
755 Used in log search
753 Used in log search
756 """
754 """
757
755
758 name = colander.SchemaNode(colander.String(), validator=colander.Length(1, 32))
756 name = colander.SchemaNode(colander.String(), validator=colander.Length(1, 32))
759 value = colander.SchemaNode(
757 value = colander.SchemaNode(
760 colander.Sequence(accept_scalar=True),
758 colander.Sequence(accept_scalar=True),
761 colander.SchemaNode(colander.String(), validator=colander.Length(1, 128)),
759 colander.SchemaNode(colander.String(), validator=colander.Length(1, 128)),
762 missing=None,
760 missing=None,
763 )
761 )
764 op = colander.SchemaNode(
762 op = colander.SchemaNode(
765 colander.String(), validator=colander.Length(1, 128), missing=None
763 colander.String(), validator=colander.Length(1, 128), missing=None
766 )
764 )
767
765
768
766
769 class TagListSchema(colander.SequenceSchema):
767 class TagListSchema(colander.SequenceSchema):
770 tag = TagSchema()
768 tag = TagSchema()
771
769
772
770
773 class RuleFieldType(object):
771 class RuleFieldType(object):
774 """ Validator which succeeds if the value passed to it is one of
772 """ Validator which succeeds if the value passed to it is one of
775 a fixed set of values """
773 a fixed set of values """
776
774
777 def __init__(self, cast_to):
775 def __init__(self, cast_to):
778 self.cast_to = cast_to
776 self.cast_to = cast_to
779
777
780 def __call__(self, node, value):
778 def __call__(self, node, value):
781 try:
779 try:
782 if self.cast_to == "int":
780 if self.cast_to == "int":
783 int(value)
781 int(value)
784 elif self.cast_to == "float":
782 elif self.cast_to == "float":
785 float(value)
783 float(value)
786 elif self.cast_to == "unicode":
784 elif self.cast_to == "unicode":
787 str(value)
785 str(value)
788 except:
786 except:
789 raise colander.Invalid(
787 raise colander.Invalid(
790 node, "Can't cast {} to {}".format(value, self.cast_to)
788 node, "Can't cast {} to {}".format(value, self.cast_to)
791 )
789 )
792
790
793
791
794 def build_rule_schema(ruleset, check_matrix):
792 def build_rule_schema(ruleset, check_matrix):
795 """
793 """
796 Accepts ruleset and a map of fields/possible operations and builds
794 Accepts ruleset and a map of fields/possible operations and builds
797 validation class
795 validation class
798 """
796 """
799
797
800 schema = colander.SchemaNode(colander.Mapping())
798 schema = colander.SchemaNode(colander.Mapping())
801 schema.add(colander.SchemaNode(colander.String(), name="field"))
799 schema.add(colander.SchemaNode(colander.String(), name="field"))
802
800
803 if ruleset["field"] in ["__AND__", "__OR__", "__NOT__"]:
801 if ruleset["field"] in ["__AND__", "__OR__", "__NOT__"]:
804 subrules = colander.SchemaNode(colander.Tuple(), name="rules")
802 subrules = colander.SchemaNode(colander.Tuple(), name="rules")
805 for rule in ruleset["rules"]:
803 for rule in ruleset["rules"]:
806 subrules.add(build_rule_schema(rule, check_matrix))
804 subrules.add(build_rule_schema(rule, check_matrix))
807 schema.add(subrules)
805 schema.add(subrules)
808 else:
806 else:
809 op_choices = check_matrix[ruleset["field"]]["ops"]
807 op_choices = check_matrix[ruleset["field"]]["ops"]
810 cast_to = check_matrix[ruleset["field"]]["type"]
808 cast_to = check_matrix[ruleset["field"]]["type"]
811 schema.add(
809 schema.add(
812 colander.SchemaNode(
810 colander.SchemaNode(
813 colander.String(), validator=colander.OneOf(op_choices), name="op"
811 colander.String(), validator=colander.OneOf(op_choices), name="op"
814 )
812 )
815 )
813 )
816
814
817 schema.add(
815 schema.add(
818 colander.SchemaNode(
816 colander.SchemaNode(
819 colander.String(), name="value", validator=RuleFieldType(cast_to)
817 colander.String(), name="value", validator=RuleFieldType(cast_to)
820 )
818 )
821 )
819 )
822 return schema
820 return schema
823
821
824
822
825 class ConfigTypeSchema(colander.MappingSchema):
823 class ConfigTypeSchema(colander.MappingSchema):
826 type = colander.SchemaNode(colander.String(), missing=None)
824 type = colander.SchemaNode(colander.String(), missing=None)
827 config = colander.SchemaNode(UnknownType(), missing=None)
825 config = colander.SchemaNode(UnknownType(), missing=None)
828
826
829
827
830 class MappingListSchema(colander.SequenceSchema):
828 class MappingListSchema(colander.SequenceSchema):
831 config = colander.SchemaNode(UnknownType())
829 config = colander.SchemaNode(UnknownType())
General Comments 4
Under Review
author

Auto status change to "Under Review"

Under Review
author

Auto status change to "Under Review"

You need to be logged in to leave comments. Login now