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