validators.py
829 lines
| 23.2 KiB
| text/x-python
|
PythonLexer
r0 | # -*- coding: utf-8 -*- | |||
r112 | # Copyright 2010 - 2017 RhodeCode GmbH and the AppEnlight project authors | |||
r0 | # | |||
r112 | # Licensed under the Apache License, Version 2.0 (the "License"); | |||
# you may not use this file except in compliance with the License. | ||||
# You may obtain a copy of the License at | ||||
r0 | # | |||
r112 | # http://www.apache.org/licenses/LICENSE-2.0 | |||
r0 | # | |||
r112 | # Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | ||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
# See the License for the specific language governing permissions and | ||||
# limitations under the License. | ||||
r0 | ||||
import datetime | ||||
import colander | ||||
from colander import null | ||||
# those keywords are here so we can distingush between searching for tags and | ||||
# normal properties of reports/logs | ||||
r153 | accepted_search_params = [ | |||
"resource", | ||||
"request_id", | ||||
"start_date", | ||||
"end_date", | ||||
"page", | ||||
"min_occurences", | ||||
"http_status", | ||||
"priority", | ||||
"error", | ||||
"url_path", | ||||
"url_domain", | ||||
"report_status", | ||||
"min_duration", | ||||
"max_duration", | ||||
"message", | ||||
"level", | ||||
"namespace", | ||||
] | ||||
r0 | ||||
@colander.deferred | ||||
def deferred_utcnow(node, kw): | ||||
r153 | return kw["utcnow"] | |||
r0 | ||||
r95 | @colander.deferred | |||
def optional_limited_date(node, kw): | ||||
r153 | if not kw.get("allow_permanent_storage"): | |||
r95 | return limited_date | |||
r0 | def lowercase_preparer(input_data): | |||
""" | ||||
Transforms a list of string entries to lowercase | ||||
Used in search query validation | ||||
""" | ||||
if not input_data: | ||||
return input_data | ||||
return [x.lower() for x in input_data] | ||||
def shortener_factory(cutoff_size=32): | ||||
""" | ||||
Limits the input data to specific character count | ||||
:arg cutoff_cutoff_size How much characters to store | ||||
""" | ||||
def shortener(input_data): | ||||
if not input_data: | ||||
return input_data | ||||
else: | ||||
if isinstance(input_data, str): | ||||
return input_data[:cutoff_size] | ||||
else: | ||||
return input_data | ||||
return shortener | ||||
def cast_to_unicode_or_null(value): | ||||
if value is not colander.null: | ||||
return str(value) | ||||
return None | ||||
class NonTZDate(colander.DateTime): | ||||
""" Returns null for incorrect date format - also removes tz info""" | ||||
def deserialize(self, node, cstruct): | ||||
# disabled for now | ||||
# if cstruct and isinstance(cstruct, str): | ||||
# if ':' not in cstruct: | ||||
# cstruct += ':0.0' | ||||
# if '.' not in cstruct: | ||||
# cstruct += '.0' | ||||
value = super(NonTZDate, self).deserialize(node, cstruct) | ||||
if value: | ||||
return value.replace(tzinfo=None) | ||||
return value | ||||
class UnknownType(object): | ||||
""" | ||||
Universal type that will accept a deserialized JSON object and store it unaltered | ||||
""" | ||||
def serialize(self, node, appstruct): | ||||
if appstruct is null: | ||||
return null | ||||
return appstruct | ||||
def deserialize(self, node, cstruct): | ||||
if cstruct is null: | ||||
return null | ||||
return cstruct | ||||
def cstruct_children(self): | ||||
return [] | ||||
# SLOW REPORT SCHEMA | ||||
r153 | ||||
r0 | def rewrite_type(input_data): | |||
""" | ||||
Fix for legacy appenlight clients | ||||
""" | ||||
r153 | if input_data == "remote_call": | |||
return "remote" | ||||
r0 | return input_data | |||
class ExtraTupleSchema(colander.TupleSchema): | ||||
r153 | name = colander.SchemaNode(colander.String(), validator=colander.Length(1, 64)) | |||
value = colander.SchemaNode( | ||||
UnknownType(), preparer=shortener_factory(512), missing=None | ||||
) | ||||
r0 | ||||
class ExtraSchemaList(colander.SequenceSchema): | ||||
tag = ExtraTupleSchema() | ||||
missing = None | ||||
class TagsTupleSchema(colander.TupleSchema): | ||||
r153 | name = colander.SchemaNode(colander.String(), validator=colander.Length(1, 128)) | |||
value = colander.SchemaNode( | ||||
UnknownType(), preparer=shortener_factory(128), missing=None | ||||
) | ||||
r0 | ||||
class TagSchemaList(colander.SequenceSchema): | ||||
tag = TagsTupleSchema() | ||||
missing = None | ||||
class NumericTagsTupleSchema(colander.TupleSchema): | ||||
r153 | name = colander.SchemaNode(colander.String(), validator=colander.Length(1, 128)) | |||
r0 | value = colander.SchemaNode(colander.Float(), missing=0) | |||
class NumericTagSchemaList(colander.SequenceSchema): | ||||
tag = NumericTagsTupleSchema() | ||||
missing = None | ||||
class SlowCallSchema(colander.MappingSchema): | ||||
""" | ||||
Validates slow call format in slow call list | ||||
""" | ||||
r153 | ||||
r0 | start = colander.SchemaNode(NonTZDate()) | |||
end = colander.SchemaNode(NonTZDate()) | ||||
r153 | statement = colander.SchemaNode(colander.String(), missing="") | |||
r0 | parameters = colander.SchemaNode(UnknownType(), missing=None) | |||
type = colander.SchemaNode( | ||||
colander.String(), | ||||
preparer=rewrite_type, | ||||
validator=colander.OneOf( | ||||
r153 | ["tmpl", "sql", "nosql", "remote", "unknown", "custom"] | |||
), | ||||
missing="unknown", | ||||
) | ||||
subtype = colander.SchemaNode( | ||||
colander.String(), validator=colander.Length(1, 16), missing="unknown" | ||||
) | ||||
location = colander.SchemaNode( | ||||
colander.String(), validator=colander.Length(1, 255), missing="" | ||||
) | ||||
r0 | ||||
def limited_date(node, value): | ||||
""" checks to make sure that the value is not older/newer than 2h """ | ||||
r50 | past_hours = 72 | |||
future_hours = 2 | ||||
r153 | min_time = datetime.datetime.utcnow() - datetime.timedelta(hours=past_hours) | |||
max_time = datetime.datetime.utcnow() + datetime.timedelta(hours=future_hours) | ||||
r0 | if min_time > value: | |||
r153 | msg = "%r is older from current UTC time by " + str(past_hours) | |||
msg += ( | ||||
" hours. Ask administrator to enable permanent logging for " | ||||
"your application to store logs with dates in past." | ||||
) | ||||
r0 | raise colander.Invalid(node, msg % value) | |||
if max_time < value: | ||||
r153 | msg = "%r is newer from current UTC time by " + str(future_hours) | |||
msg += ( | ||||
" hours. Ask administrator to enable permanent logging for " | ||||
"your application to store logs with dates in future." | ||||
) | ||||
r0 | raise colander.Invalid(node, msg % value) | |||
class SlowCallListSchema(colander.SequenceSchema): | ||||
""" | ||||
Validates list of individual slow calls | ||||
""" | ||||
r153 | ||||
r0 | slow_call = SlowCallSchema() | |||
class RequestStatsSchema(colander.MappingSchema): | ||||
""" | ||||
Validates format of requests statistics dictionary | ||||
""" | ||||
r153 | ||||
main = colander.SchemaNode(colander.Float(), validator=colander.Range(0), missing=0) | ||||
sql = colander.SchemaNode(colander.Float(), validator=colander.Range(0), missing=0) | ||||
nosql = colander.SchemaNode( | ||||
colander.Float(), validator=colander.Range(0), missing=0 | ||||
) | ||||
remote = colander.SchemaNode( | ||||
colander.Float(), validator=colander.Range(0), missing=0 | ||||
) | ||||
tmpl = colander.SchemaNode(colander.Float(), validator=colander.Range(0), missing=0) | ||||
custom = colander.SchemaNode( | ||||
colander.Float(), validator=colander.Range(0), missing=0 | ||||
) | ||||
sql_calls = colander.SchemaNode( | ||||
colander.Float(), validator=colander.Range(0), missing=0 | ||||
) | ||||
nosql_calls = colander.SchemaNode( | ||||
colander.Float(), validator=colander.Range(0), missing=0 | ||||
) | ||||
remote_calls = colander.SchemaNode( | ||||
colander.Float(), validator=colander.Range(0), missing=0 | ||||
) | ||||
tmpl_calls = colander.SchemaNode( | ||||
colander.Float(), validator=colander.Range(0), missing=0 | ||||
) | ||||
custom_calls = colander.SchemaNode( | ||||
colander.Float(), validator=colander.Range(0), missing=0 | ||||
) | ||||
r0 | ||||
class FrameInfoVarSchema(colander.SequenceSchema): | ||||
""" | ||||
Validates format of frame variables of a traceback | ||||
""" | ||||
r153 | ||||
vars = colander.SchemaNode(UnknownType(), validator=colander.Length(2, 2)) | ||||
r0 | ||||
class FrameInfoSchema(colander.MappingSchema): | ||||
""" | ||||
Validates format of a traceback line | ||||
""" | ||||
r153 | ||||
cline = colander.SchemaNode(colander.String(), missing="") | ||||
module = colander.SchemaNode(colander.String(), missing="") | ||||
line = colander.SchemaNode(colander.String(), missing="") | ||||
file = colander.SchemaNode(colander.String(), missing="") | ||||
fn = colander.SchemaNode(colander.String(), missing="") | ||||
r0 | vars = FrameInfoVarSchema() | |||
class FrameInfoListSchema(colander.SequenceSchema): | ||||
""" | ||||
Validates format of list of traceback lines | ||||
""" | ||||
r153 | ||||
r0 | frame = colander.SchemaNode(UnknownType()) | |||
class ReportDetailBaseSchema(colander.MappingSchema): | ||||
""" | ||||
Validates format of report - ie. request parameters and stats for a request in report group | ||||
""" | ||||
r153 | ||||
username = colander.SchemaNode( | ||||
colander.String(), | ||||
preparer=[shortener_factory(255), lambda x: x or ""], | ||||
missing="", | ||||
) | ||||
request_id = colander.SchemaNode( | ||||
colander.String(), preparer=shortener_factory(40), missing="" | ||||
) | ||||
url = colander.SchemaNode( | ||||
colander.String(), preparer=shortener_factory(1024), missing="" | ||||
) | ||||
ip = colander.SchemaNode( | ||||
colander.String(), preparer=shortener_factory(39), missing=None | ||||
) | ||||
start_time = colander.SchemaNode( | ||||
NonTZDate(), validator=optional_limited_date, missing=deferred_utcnow | ||||
) | ||||
end_time = colander.SchemaNode( | ||||
NonTZDate(), validator=optional_limited_date, missing=None | ||||
) | ||||
user_agent = colander.SchemaNode( | ||||
colander.String(), | ||||
preparer=[shortener_factory(512), lambda x: x or ""], | ||||
missing="", | ||||
) | ||||
message = colander.SchemaNode( | ||||
colander.String(), preparer=shortener_factory(2048), missing="" | ||||
) | ||||
group_string = colander.SchemaNode( | ||||
colander.String(), preparer=shortener_factory(512), missing=None | ||||
) | ||||
r0 | request_stats = RequestStatsSchema(missing=None) | |||
r153 | request = colander.SchemaNode(colander.Mapping(unknown="preserve"), missing={}) | |||
r0 | traceback = FrameInfoListSchema(missing=None) | |||
slow_calls = SlowCallListSchema(missing=[]) | ||||
extra = ExtraSchemaList() | ||||
class ReportDetailSchema_0_5(ReportDetailBaseSchema): | ||||
pass | ||||
r50 | class ReportDetailSchemaPermissiveDate_0_5(ReportDetailSchema_0_5): | |||
start_time = colander.SchemaNode(NonTZDate(), missing=deferred_utcnow) | ||||
end_time = colander.SchemaNode(NonTZDate(), missing=None) | ||||
r0 | ||||
class ReportSchemaBase(colander.MappingSchema): | ||||
""" | ||||
Validates format of report group | ||||
""" | ||||
r153 | ||||
client = colander.SchemaNode(colander.String(), preparer=lambda x: x or "unknown") | ||||
r0 | server = colander.SchemaNode( | |||
colander.String(), | ||||
r153 | preparer=[lambda x: x.lower() if x else "unknown", shortener_factory(128)], | |||
missing="unknown", | ||||
) | ||||
priority = colander.SchemaNode( | ||||
colander.Int(), | ||||
preparer=[lambda x: x or 5], | ||||
validator=colander.Range(1, 10), | ||||
missing=5, | ||||
) | ||||
language = colander.SchemaNode(colander.String(), missing="unknown") | ||||
error = colander.SchemaNode( | ||||
colander.String(), preparer=shortener_factory(512), missing="" | ||||
) | ||||
view_name = colander.SchemaNode( | ||||
colander.String(), | ||||
preparer=[shortener_factory(128), lambda x: x or ""], | ||||
missing="", | ||||
) | ||||
http_status = colander.SchemaNode( | ||||
colander.Int(), preparer=[lambda x: x or 200], validator=colander.Range(1) | ||||
) | ||||
occurences = colander.SchemaNode( | ||||
colander.Int(), validator=colander.Range(1, 99999999999), missing=1 | ||||
) | ||||
r0 | tags = TagSchemaList() | |||
class ReportSchema_0_5(ReportSchemaBase, ReportDetailSchema_0_5): | ||||
pass | ||||
r153 | class ReportSchemaPermissiveDate_0_5( | |||
ReportSchemaBase, ReportDetailSchemaPermissiveDate_0_5 | ||||
): | ||||
r50 | pass | |||
r0 | class ReportListSchema_0_5(colander.SequenceSchema): | |||
""" | ||||
Validates format of list of report groups | ||||
""" | ||||
r153 | ||||
r0 | report = ReportSchema_0_5() | |||
validator = colander.Length(1) | ||||
r50 | class ReportListPermissiveDateSchema_0_5(colander.SequenceSchema): | |||
""" | ||||
Validates format of list of report groups | ||||
""" | ||||
r153 | ||||
r50 | report = ReportSchemaPermissiveDate_0_5() | |||
validator = colander.Length(1) | ||||
r0 | class LogSchema(colander.MappingSchema): | |||
""" | ||||
Validates format if individual log entry | ||||
""" | ||||
r153 | ||||
primary_key = colander.SchemaNode( | ||||
UnknownType(), | ||||
preparer=[cast_to_unicode_or_null, shortener_factory(128)], | ||||
missing=None, | ||||
) | ||||
log_level = colander.SchemaNode( | ||||
colander.String(), preparer=shortener_factory(10), missing="UNKNOWN" | ||||
) | ||||
message = colander.SchemaNode( | ||||
colander.String(), preparer=shortener_factory(4096), missing="" | ||||
) | ||||
namespace = colander.SchemaNode( | ||||
colander.String(), preparer=shortener_factory(128), missing="" | ||||
) | ||||
request_id = colander.SchemaNode( | ||||
colander.String(), preparer=shortener_factory(40), missing="" | ||||
) | ||||
server = colander.SchemaNode( | ||||
colander.String(), preparer=shortener_factory(128), missing="unknown" | ||||
) | ||||
date = colander.SchemaNode( | ||||
NonTZDate(), validator=limited_date, missing=deferred_utcnow | ||||
) | ||||
r0 | tags = TagSchemaList() | |||
class LogSchemaPermanent(LogSchema): | ||||
r153 | date = colander.SchemaNode(NonTZDate(), missing=deferred_utcnow) | |||
r0 | permanent = colander.SchemaNode(colander.Boolean(), missing=False) | |||
class LogListSchema(colander.SequenceSchema): | ||||
""" | ||||
Validates format of list of log entries | ||||
""" | ||||
r153 | ||||
r0 | log = LogSchema() | |||
validator = colander.Length(1) | ||||
class LogListPermanentSchema(colander.SequenceSchema): | ||||
""" | ||||
Validates format of list of log entries | ||||
""" | ||||
r153 | ||||
r0 | log = LogSchemaPermanent() | |||
validator = colander.Length(1) | ||||
class ViewRequestStatsSchema(RequestStatsSchema): | ||||
r153 | requests = colander.SchemaNode( | |||
colander.Integer(), validator=colander.Range(0), missing=0 | ||||
) | ||||
r0 | ||||
class ViewMetricTupleSchema(colander.TupleSchema): | ||||
""" | ||||
Validates list of views and their corresponding request stats object ie: | ||||
["dir/module:func",{"custom": 0.0..}] | ||||
""" | ||||
r153 | ||||
view_name = colander.SchemaNode( | ||||
colander.String(), | ||||
preparer=[shortener_factory(128), lambda x: x or "unknown"], | ||||
missing="unknown", | ||||
) | ||||
r0 | metrics = ViewRequestStatsSchema() | |||
class ViewMetricListSchema(colander.SequenceSchema): | ||||
""" | ||||
Validates view breakdown stats objects list | ||||
{metrics key of server/time object} | ||||
""" | ||||
r153 | ||||
r0 | view_tuple = ViewMetricTupleSchema() | |||
validator = colander.Length(1) | ||||
class ViewMetricSchema(colander.MappingSchema): | ||||
""" | ||||
Validates server/timeinterval object, ie: | ||||
{server/time object} | ||||
""" | ||||
r153 | ||||
timestamp = colander.SchemaNode(NonTZDate(), validator=limited_date, missing=None) | ||||
server = colander.SchemaNode( | ||||
colander.String(), | ||||
preparer=[shortener_factory(128), lambda x: x or "unknown"], | ||||
missing="unknown", | ||||
) | ||||
r0 | metrics = ViewMetricListSchema() | |||
class GeneralMetricSchema(colander.MappingSchema): | ||||
""" | ||||
Validates universal metric schema | ||||
""" | ||||
r153 | namespace = colander.SchemaNode( | |||
colander.String(), missing="", preparer=shortener_factory(128) | ||||
) | ||||
server_name = colander.SchemaNode( | ||||
colander.String(), | ||||
preparer=[shortener_factory(128), lambda x: x or "unknown"], | ||||
missing="unknown", | ||||
) | ||||
timestamp = colander.SchemaNode( | ||||
NonTZDate(), validator=limited_date, missing=deferred_utcnow | ||||
) | ||||
r48 | tags = TagSchemaList(missing=colander.required) | |||
r0 | ||||
r51 | class GeneralMetricPermanentSchema(GeneralMetricSchema): | |||
""" | ||||
Validates universal metric schema | ||||
""" | ||||
r153 | ||||
r51 | timestamp = colander.SchemaNode(NonTZDate(), missing=deferred_utcnow) | |||
r0 | class GeneralMetricsListSchema(colander.SequenceSchema): | |||
metric = GeneralMetricSchema() | ||||
validator = colander.Length(1) | ||||
r51 | class GeneralMetricsPermanentListSchema(colander.SequenceSchema): | |||
metric = GeneralMetricPermanentSchema() | ||||
validator = colander.Length(1) | ||||
r0 | class MetricsListSchema(colander.SequenceSchema): | |||
""" | ||||
Validates list of metrics objects ie: | ||||
[{server/time object}, ] part | ||||
""" | ||||
r153 | ||||
r0 | metric = ViewMetricSchema() | |||
validator = colander.Length(1) | ||||
class StringToAppList(object): | ||||
""" | ||||
Returns validated list of application ids from user query and | ||||
set of applications user is allowed to look at | ||||
transform string to list containing single integer | ||||
""" | ||||
def serialize(self, node, appstruct): | ||||
if appstruct is null: | ||||
return null | ||||
return appstruct | ||||
def deserialize(self, node, cstruct): | ||||
if cstruct is null: | ||||
return null | ||||
r153 | apps = set([int(a) for a in node.bindings["resources"]]) | |||
r0 | ||||
if isinstance(cstruct, str): | ||||
cstruct = [cstruct] | ||||
cstruct = [int(a) for a in cstruct] | ||||
valid_apps = list(apps.intersection(set(cstruct))) | ||||
if valid_apps: | ||||
return valid_apps | ||||
return null | ||||
def cstruct_children(self): | ||||
return [] | ||||
@colander.deferred | ||||
def possible_applications_validator(node, kw): | ||||
r153 | possible_apps = [int(a) for a in kw["resources"]] | |||
return colander.All(colander.ContainsOnly(possible_apps), colander.Length(1)) | ||||
r0 | ||||
@colander.deferred | ||||
def possible_applications(node, kw): | ||||
r153 | return [int(a) for a in kw["resources"]] | |||
r0 | ||||
@colander.deferred | ||||
def today_start(node, kw): | ||||
r153 | return datetime.datetime.utcnow().replace(second=0, microsecond=0, minute=0, hour=0) | |||
r0 | ||||
@colander.deferred | ||||
def today_end(node, kw): | ||||
r153 | return datetime.datetime.utcnow().replace( | |||
second=0, microsecond=0, minute=59, hour=23 | ||||
) | ||||
r0 | ||||
@colander.deferred | ||||
def old_start(node, kw): | ||||
t_delta = datetime.timedelta(days=90) | ||||
r153 | return ( | |||
datetime.datetime.utcnow().replace(second=0, microsecond=0, minute=0, hour=0) | ||||
- t_delta | ||||
) | ||||
r0 | ||||
@colander.deferred | ||||
def today_end(node, kw): | ||||
r153 | return datetime.datetime.utcnow().replace( | |||
second=0, microsecond=0, minute=59, hour=23 | ||||
) | ||||
r0 | ||||
class PermissiveDate(colander.DateTime): | ||||
""" Returns null for incorrect date format - also removes tz info""" | ||||
def deserialize(self, node, cstruct): | ||||
if not cstruct: | ||||
return null | ||||
try: | ||||
result = colander.iso8601.parse_date( | ||||
r153 | cstruct, default_timezone=self.default_tzinfo | |||
) | ||||
r0 | except colander.iso8601.ParseError: | |||
return null | ||||
return result.replace(tzinfo=None) | ||||
class LogSearchSchema(colander.MappingSchema): | ||||
def schema_type(self, **kw): | ||||
r153 | return colander.Mapping(unknown="preserve") | |||
resource = colander.SchemaNode( | ||||
StringToAppList(), | ||||
validator=possible_applications_validator, | ||||
missing=possible_applications, | ||||
) | ||||
message = colander.SchemaNode( | ||||
colander.Sequence(accept_scalar=True), | ||||
colander.SchemaNode(colander.String()), | ||||
missing=None, | ||||
) | ||||
level = colander.SchemaNode( | ||||
colander.Sequence(accept_scalar=True), | ||||
colander.SchemaNode(colander.String()), | ||||
preparer=lowercase_preparer, | ||||
missing=None, | ||||
) | ||||
namespace = colander.SchemaNode( | ||||
colander.Sequence(accept_scalar=True), | ||||
colander.SchemaNode(colander.String()), | ||||
missing=None, | ||||
) | ||||
request_id = colander.SchemaNode( | ||||
colander.Sequence(accept_scalar=True), | ||||
colander.SchemaNode(colander.String()), | ||||
missing=None, | ||||
) | ||||
start_date = colander.SchemaNode(PermissiveDate(), missing=None) | ||||
end_date = colander.SchemaNode(PermissiveDate(), missing=None) | ||||
page = colander.SchemaNode( | ||||
colander.Integer(), validator=colander.Range(min=1), missing=1 | ||||
) | ||||
r0 | ||||
class ReportSearchSchema(colander.MappingSchema): | ||||
def schema_type(self, **kw): | ||||
r153 | return colander.Mapping(unknown="preserve") | |||
resource = colander.SchemaNode( | ||||
StringToAppList(), | ||||
validator=possible_applications_validator, | ||||
missing=possible_applications, | ||||
) | ||||
request_id = colander.SchemaNode( | ||||
colander.Sequence(accept_scalar=True), | ||||
colander.SchemaNode(colander.String()), | ||||
missing=None, | ||||
) | ||||
start_date = colander.SchemaNode(PermissiveDate(), missing=None) | ||||
end_date = colander.SchemaNode(PermissiveDate(), missing=None) | ||||
page = colander.SchemaNode( | ||||
colander.Integer(), validator=colander.Range(min=1), missing=1 | ||||
) | ||||
r0 | ||||
min_occurences = colander.SchemaNode( | ||||
colander.Sequence(accept_scalar=True), | ||||
colander.SchemaNode(colander.Integer()), | ||||
r153 | missing=None, | |||
) | ||||
http_status = colander.SchemaNode( | ||||
colander.Sequence(accept_scalar=True), | ||||
colander.SchemaNode(colander.Integer()), | ||||
missing=None, | ||||
) | ||||
priority = colander.SchemaNode( | ||||
colander.Sequence(accept_scalar=True), | ||||
colander.SchemaNode(colander.Integer()), | ||||
missing=None, | ||||
) | ||||
error = colander.SchemaNode( | ||||
colander.Sequence(accept_scalar=True), | ||||
colander.SchemaNode(colander.String()), | ||||
missing=None, | ||||
) | ||||
url_path = colander.SchemaNode( | ||||
colander.Sequence(accept_scalar=True), | ||||
colander.SchemaNode(colander.String()), | ||||
missing=None, | ||||
) | ||||
url_domain = colander.SchemaNode( | ||||
colander.Sequence(accept_scalar=True), | ||||
colander.SchemaNode(colander.String()), | ||||
missing=None, | ||||
) | ||||
report_status = colander.SchemaNode( | ||||
colander.Sequence(accept_scalar=True), | ||||
colander.SchemaNode(colander.String()), | ||||
missing=None, | ||||
) | ||||
min_duration = colander.SchemaNode( | ||||
colander.Sequence(accept_scalar=True), | ||||
colander.SchemaNode(colander.Float()), | ||||
missing=None, | ||||
) | ||||
max_duration = colander.SchemaNode( | ||||
colander.Sequence(accept_scalar=True), | ||||
colander.SchemaNode(colander.Float()), | ||||
missing=None, | ||||
) | ||||
r0 | ||||
class TagSchema(colander.MappingSchema): | ||||
""" | ||||
Used in log search | ||||
""" | ||||
r153 | ||||
name = colander.SchemaNode(colander.String(), validator=colander.Length(1, 32)) | ||||
value = colander.SchemaNode( | ||||
colander.Sequence(accept_scalar=True), | ||||
colander.SchemaNode(colander.String(), validator=colander.Length(1, 128)), | ||||
missing=None, | ||||
) | ||||
op = colander.SchemaNode( | ||||
colander.String(), validator=colander.Length(1, 128), missing=None | ||||
) | ||||
r0 | ||||
class TagListSchema(colander.SequenceSchema): | ||||
tag = TagSchema() | ||||
class RuleFieldType(object): | ||||
""" Validator which succeeds if the value passed to it is one of | ||||
a fixed set of values """ | ||||
def __init__(self, cast_to): | ||||
self.cast_to = cast_to | ||||
def __call__(self, node, value): | ||||
try: | ||||
r153 | if self.cast_to == "int": | |||
r0 | int(value) | |||
r153 | elif self.cast_to == "float": | |||
r0 | float(value) | |||
r153 | elif self.cast_to == "unicode": | |||
r0 | str(value) | |||
except: | ||||
r153 | raise colander.Invalid( | |||
node, "Can't cast {} to {}".format(value, self.cast_to) | ||||
) | ||||
r0 | ||||
def build_rule_schema(ruleset, check_matrix): | ||||
""" | ||||
Accepts ruleset and a map of fields/possible operations and builds | ||||
validation class | ||||
""" | ||||
schema = colander.SchemaNode(colander.Mapping()) | ||||
r153 | schema.add(colander.SchemaNode(colander.String(), name="field")) | |||
r0 | ||||
r153 | if ruleset["field"] in ["__AND__", "__OR__", "__NOT__"]: | |||
subrules = colander.SchemaNode(colander.Tuple(), name="rules") | ||||
for rule in ruleset["rules"]: | ||||
r0 | subrules.add(build_rule_schema(rule, check_matrix)) | |||
schema.add(subrules) | ||||
else: | ||||
r153 | op_choices = check_matrix[ruleset["field"]]["ops"] | |||
cast_to = check_matrix[ruleset["field"]]["type"] | ||||
schema.add( | ||||
colander.SchemaNode( | ||||
colander.String(), validator=colander.OneOf(op_choices), name="op" | ||||
) | ||||
) | ||||
schema.add( | ||||
colander.SchemaNode( | ||||
colander.String(), name="value", validator=RuleFieldType(cast_to) | ||||
) | ||||
) | ||||
r0 | return schema | |||
class ConfigTypeSchema(colander.MappingSchema): | ||||
type = colander.SchemaNode(colander.String(), missing=None) | ||||
config = colander.SchemaNode(UnknownType(), missing=None) | ||||
class MappingListSchema(colander.SequenceSchema): | ||||
config = colander.SchemaNode(UnknownType()) | ||||