##// END OF EJS Templates
rule engine: add support for NOT rule
ergo -
Show More
@@ -29,6 +29,10 b' To run celery queue processing:'
29
29
30 celery worker -A appenlight.celery -Q "reports,logs,metrics,default" --ini=development.ini
30 celery worker -A appenlight.celery -Q "reports,logs,metrics,default" --ini=development.ini
31
31
32 To run celery beats scheduling:
33
34 celery beat -A appenlight.celery --ini=development.ini
35
32 You should also run the channelstream websocket server for real-time notifications
36 You should also run the channelstream websocket server for real-time notifications
33
37
34 channelstream -i filename.ini
38 channelstream -i filename.ini
@@ -188,6 +188,10 b' class Rule(RuleBase):'
188 rule = OR(self.config['rules'], self.type_matrix,
188 rule = OR(self.config['rules'], self.type_matrix,
189 config_manipulator=self.config_manipulator)
189 config_manipulator=self.config_manipulator)
190 return rule.match(struct)
190 return rule.match(struct)
191 elif field_name == '__NOT__':
192 rule = NOT(self.config['rules'], self.type_matrix,
193 config_manipulator=self.config_manipulator)
194 return rule.match(struct)
191
195
192 if test_value is None:
196 if test_value is None:
193 return False
197 return False
@@ -236,6 +240,16 b' class AND(Rule):'
236 in self.rules])
240 in self.rules])
237
241
238
242
243 class NOT(Rule):
244 def __init__(self, rules, *args, **kwargs):
245 super(NOT, self).__init__({}, *args, **kwargs)
246 self.rules = rules
247
248 def match(self, struct):
249 return all([not self.subrule_check(r_conf, struct) for r_conf
250 in self.rules])
251
252
239 class OR(Rule):
253 class OR(Rule):
240 def __init__(self, rules, *args, **kwargs):
254 def __init__(self, rules, *args, **kwargs):
241 super(OR, self).__init__({}, *args, **kwargs)
255 super(OR, self).__init__({}, *args, **kwargs)
@@ -266,7 +280,8 b' class RuleService(object):'
266 if manipulator_func is None:
280 if manipulator_func is None:
267 def label_rewriter_func(rule):
281 def label_rewriter_func(rule):
268 field = rule.config.get('field')
282 field = rule.config.get('field')
269 if not field or rule.config['field'] in ['__OR__', '__AND__']:
283 if not field or rule.config['field'] in ['__OR__',
284 '__AND__', '__NOT__']:
270 return
285 return
271
286
272 to_map = field_mappings.get(rule.config['field'])
287 to_map = field_mappings.get(rule.config['field'])
@@ -5376,11 +5376,11 b' function kickstartAE() {'
5376 " {{rule_ctrlr.readOnlyPossibleFields[rule_ctrlr.rule.field]}}\n" +
5376 " {{rule_ctrlr.readOnlyPossibleFields[rule_ctrlr.rule.field]}}\n" +
5377 " </span>\n" +
5377 " </span>\n" +
5378 "\n" +
5378 "\n" +
5379 " <span ng-if=\"rule_ctrlr.rule.field != '__AND__' && rule_ctrlr.rule.field !='__OR__'\">\n" +
5379 " <span ng-if=\"rule_ctrlr.rule.field != '__AND__' && rule_ctrlr.rule.field !='__OR__' && rule_ctrlr.rule.field !='__NOT__'\">\n" +
5380 " is {{rule_ctrlr.ruleDefinitions.allOps[rule_ctrlr.rule.op]}} {{rule_ctrlr.rule.value}}\n" +
5380 " is {{rule_ctrlr.ruleDefinitions.allOps[rule_ctrlr.rule.op]}} {{rule_ctrlr.rule.value}}\n" +
5381 " </span>\n" +
5381 " </span>\n" +
5382 "\n" +
5382 "\n" +
5383 " <span ng-if=\"rule_ctrlr.rule.field == '__AND__' || rule_ctrlr.rule.field =='__OR__'\">\n" +
5383 " <span ng-if=\"rule_ctrlr.rule.field == '__AND__' || rule_ctrlr.rule.field =='__OR__' || rule_ctrlr.rule.field =='__NOT__'\">\n" +
5384 " <p ng-if=\"parent\"><strong>Subrules</strong></p>\n" +
5384 " <p ng-if=\"parent\"><strong>Subrules</strong></p>\n" +
5385 " <div ng-repeat=\"subrule in rule_ctrlr.rule.rules\" class=\"m-l-2\">\n" +
5385 " <div ng-repeat=\"subrule in rule_ctrlr.rule.rules\" class=\"m-l-2\">\n" +
5386 "\n" +
5386 "\n" +
@@ -5408,7 +5408,7 b' function kickstartAE() {'
5408 " ng-options=\"key as label for (key, label) in rule_ctrlr.ruleDefinitions.possibleFields\"></select>\n" +
5408 " ng-options=\"key as label for (key, label) in rule_ctrlr.ruleDefinitions.possibleFields\"></select>\n" +
5409 " </div>\n" +
5409 " </div>\n" +
5410 "\n" +
5410 "\n" +
5411 " <div ng-if=\"rule_ctrlr.rule.field != '__AND__' && rule_ctrlr.rule.field !='__OR__'\" class=\"form-group\">\n" +
5411 " <div ng-if=\"rule_ctrlr.rule.field != '__AND__' && rule_ctrlr.rule.field !='__OR__' && rule_ctrlr.rule.field !='__NOT__'\" class=\"form-group\">\n" +
5412 "\n" +
5412 "\n" +
5413 " <select ng-model=\"rule_ctrlr.rule.op\" class=\"form-control\"\n" +
5413 " <select ng-model=\"rule_ctrlr.rule.op\" class=\"form-control\"\n" +
5414 " ng-change=\"rule_ctrlr.setDirty()\"\n" +
5414 " ng-change=\"rule_ctrlr.setDirty()\"\n" +
@@ -5419,7 +5419,7 b' function kickstartAE() {'
5419 "\n" +
5419 "\n" +
5420 " </div>\n" +
5420 " </div>\n" +
5421 "\n" +
5421 "\n" +
5422 " <span ng-if=\"rule_ctrlr.rule.field == '__AND__' || rule_ctrlr.rule.field =='__OR__'\">\n" +
5422 " <span ng-if=\"rule_ctrlr.rule.field == '__AND__' || rule_ctrlr.rule.field =='__OR__' || rule_ctrlr.rule.field =='__NOT__'\">\n" +
5423 " <p ng-if=\"parent\"><strong>Subrules</strong></p>\n" +
5423 " <p ng-if=\"parent\"><strong>Subrules</strong></p>\n" +
5424 " <div ng-repeat=\"subrule in rule_ctrlr.rule.rules\" class=\"m-l-2\">\n" +
5424 " <div ng-repeat=\"subrule in rule_ctrlr.rule.rules\" class=\"m-l-2\">\n" +
5425 " <div class=\"panel panel-default\">\n" +
5425 " <div class=\"panel panel-default\">\n" +
@@ -10694,6 +10694,7 b' function AlertChannelsController(userSelfPropertyResource, applicationsNoIdResou'
10694 var possibleFields = {
10694 var possibleFields = {
10695 '__AND__': 'All met (composite rule)',
10695 '__AND__': 'All met (composite rule)',
10696 '__OR__': 'One met (composite rule)',
10696 '__OR__': 'One met (composite rule)',
10697 '__NOT__': 'Not met (composite rule)',
10697 'http_status': 'HTTP Status',
10698 'http_status': 'HTTP Status',
10698 'duration': 'Request duration',
10699 'duration': 'Request duration',
10699 'group:priority': 'Group -> Priority',
10700 'group:priority': 'Group -> Priority',
@@ -11610,6 +11611,7 b" angular.module('appenlight.directives.postProcessAction', []).directive('postPro"
11610 var possibleFields = {
11611 var possibleFields = {
11611 '__AND__': 'All met (composite rule)',
11612 '__AND__': 'All met (composite rule)',
11612 '__OR__': 'One met (composite rule)',
11613 '__OR__': 'One met (composite rule)',
11614 '__NOT__': 'Not met (composite rule)',
11613 'http_status': 'HTTP Status',
11615 'http_status': 'HTTP Status',
11614 'duration': 'Request duration',
11616 'duration': 'Request duration',
11615 'group:priority': 'Group -> Priority',
11617 'group:priority': 'Group -> Priority',
@@ -11927,8 +11929,9 b" angular.module('appenlight.directives.rule', []).directive('rule', function () {"
11927 };
11929 };
11928
11930
11929 vm.fieldChange = function () {
11931 vm.fieldChange = function () {
11930 var new_is_compound = ['__AND__', '__OR__'].indexOf(vm.rule.field) !== -1;
11932 var compound_types = ['__AND__', '__OR__', '__NOT__'];
11931 var old_was_compound = ['__AND__', '__OR__'].indexOf(vm.oldField) !== -1;
11933 var new_is_compound = compound_types.indexOf(vm.rule.field) !== -1;
11934 var old_was_compound = compound_types.indexOf(vm.oldField) !== -1;
11932
11935
11933 if (!new_is_compound) {
11936 if (!new_is_compound) {
11934 vm.rule.op = vm.ruleDefinitions.fieldOps[vm.rule.field][0];
11937 vm.rule.op = vm.ruleDefinitions.fieldOps[vm.rule.field][0];
@@ -1031,6 +1031,38 b' class TestRulesParsing():'
1031
1031
1032 @pytest.mark.usefixtures('report_type_matrix')
1032 @pytest.mark.usefixtures('report_type_matrix')
1033 class TestNestedRuleParsing():
1033 class TestNestedRuleParsing():
1034
1035 @pytest.mark.parametrize("data, result", [
1036 ({"http_status": 501, "group": {"priority": 7, "occurences": 11}},
1037 False),
1038 ({"http_status": 101, "group": {"priority": 7, "occurences": 11}},
1039 False),
1040 ({"http_status": 500, "group": {"priority": 1, "occurences": 11}},
1041 False),
1042 ({"http_status": 101, "group": {"priority": 3, "occurences": 5}},
1043 True),
1044 ])
1045 def test_NOT_rule(self, data, result, report_type_matrix):
1046 from appenlight.lib.rule import Rule
1047 rule_config = {
1048 "field": "__NOT__",
1049 "rules": [
1050 {
1051 "op": "ge",
1052 "field": "group:occurences",
1053 "value": "10"
1054 },
1055 {
1056 "op": "ge",
1057 "field": "group:priority",
1058 "value": "4"
1059 }
1060 ]
1061 }
1062
1063 rule = Rule(rule_config, report_type_matrix)
1064 assert rule.match(data) is result
1065
1034 @pytest.mark.parametrize("data, result", [
1066 @pytest.mark.parametrize("data, result", [
1035 ({"http_status": 501, "group": {"priority": 7, "occurences": 11}},
1067 ({"http_status": 501, "group": {"priority": 7, "occurences": 11}},
1036 True),
1068 True),
@@ -716,7 +716,7 b' def build_rule_schema(ruleset, check_matrix):'
716 schema = colander.SchemaNode(colander.Mapping())
716 schema = colander.SchemaNode(colander.Mapping())
717 schema.add(colander.SchemaNode(colander.String(), name='field'))
717 schema.add(colander.SchemaNode(colander.String(), name='field'))
718
718
719 if ruleset['field'] in ['__AND__', '__OR__']:
719 if ruleset['field'] in ['__AND__', '__OR__', '__NOT__']:
720 subrules = colander.SchemaNode(colander.Tuple(), name='rules')
720 subrules = colander.SchemaNode(colander.Tuple(), name='rules')
721 for rule in ruleset['rules']:
721 for rule in ruleset['rules']:
722 subrules.add(build_rule_schema(rule, check_matrix))
722 subrules.add(build_rule_schema(rule, check_matrix))
@@ -70,6 +70,7 b' function AlertChannelsController(userSelfPropertyResource, applicationsNoIdResou'
70 var possibleFields = {
70 var possibleFields = {
71 '__AND__': 'All met (composite rule)',
71 '__AND__': 'All met (composite rule)',
72 '__OR__': 'One met (composite rule)',
72 '__OR__': 'One met (composite rule)',
73 '__NOT__': 'Not met (composite rule)',
73 'http_status': 'HTTP Status',
74 'http_status': 'HTTP Status',
74 'duration': 'Request duration',
75 'duration': 'Request duration',
75 'group:priority': 'Group -> Priority',
76 'group:priority': 'Group -> Priority',
@@ -61,6 +61,7 b" angular.module('appenlight.directives.postProcessAction', []).directive('postPro"
61 var possibleFields = {
61 var possibleFields = {
62 '__AND__': 'All met (composite rule)',
62 '__AND__': 'All met (composite rule)',
63 '__OR__': 'One met (composite rule)',
63 '__OR__': 'One met (composite rule)',
64 '__NOT__': 'Not met (composite rule)',
64 'http_status': 'HTTP Status',
65 'http_status': 'HTTP Status',
65 'duration': 'Request duration',
66 'duration': 'Request duration',
66 'group:priority': 'Group -> Priority',
67 'group:priority': 'Group -> Priority',
@@ -56,8 +56,9 b" angular.module('appenlight.directives.rule', []).directive('rule', function () {"
56 };
56 };
57
57
58 vm.fieldChange = function () {
58 vm.fieldChange = function () {
59 var new_is_compound = ['__AND__', '__OR__'].indexOf(vm.rule.field) !== -1;
59 var compound_types = ['__AND__', '__OR__', '__NOT__'];
60 var old_was_compound = ['__AND__', '__OR__'].indexOf(vm.oldField) !== -1;
60 var new_is_compound = compound_types.indexOf(vm.rule.field) !== -1;
61 var old_was_compound = compound_types.indexOf(vm.oldField) !== -1;
61
62
62 if (!new_is_compound) {
63 if (!new_is_compound) {
63 vm.rule.op = vm.ruleDefinitions.fieldOps[vm.rule.field][0];
64 vm.rule.op = vm.ruleDefinitions.fieldOps[vm.rule.field][0];
@@ -7,7 +7,7 b''
7 ng-options="key as label for (key, label) in rule_ctrlr.ruleDefinitions.possibleFields"></select>
7 ng-options="key as label for (key, label) in rule_ctrlr.ruleDefinitions.possibleFields"></select>
8 </div>
8 </div>
9
9
10 <div ng-if="rule_ctrlr.rule.field != '__AND__' && rule_ctrlr.rule.field !='__OR__'" class="form-group">
10 <div ng-if="rule_ctrlr.rule.field != '__AND__' && rule_ctrlr.rule.field !='__OR__' && rule_ctrlr.rule.field !='__NOT__'" class="form-group">
11
11
12 <select ng-model="rule_ctrlr.rule.op" class="form-control"
12 <select ng-model="rule_ctrlr.rule.op" class="form-control"
13 ng-change="rule_ctrlr.setDirty()"
13 ng-change="rule_ctrlr.setDirty()"
@@ -18,7 +18,7 b''
18
18
19 </div>
19 </div>
20
20
21 <span ng-if="rule_ctrlr.rule.field == '__AND__' || rule_ctrlr.rule.field =='__OR__'">
21 <span ng-if="rule_ctrlr.rule.field == '__AND__' || rule_ctrlr.rule.field =='__OR__' || rule_ctrlr.rule.field =='__NOT__'">
22 <p ng-if="parent"><strong>Subrules</strong></p>
22 <p ng-if="parent"><strong>Subrules</strong></p>
23 <div ng-repeat="subrule in rule_ctrlr.rule.rules" class="m-l-2">
23 <div ng-repeat="subrule in rule_ctrlr.rule.rules" class="m-l-2">
24 <div class="panel panel-default">
24 <div class="panel panel-default">
@@ -4,11 +4,11 b''
4 {{rule_ctrlr.readOnlyPossibleFields[rule_ctrlr.rule.field]}}
4 {{rule_ctrlr.readOnlyPossibleFields[rule_ctrlr.rule.field]}}
5 </span>
5 </span>
6
6
7 <span ng-if="rule_ctrlr.rule.field != '__AND__' && rule_ctrlr.rule.field !='__OR__'">
7 <span ng-if="rule_ctrlr.rule.field != '__AND__' && rule_ctrlr.rule.field !='__OR__' && rule_ctrlr.rule.field !='__NOT__'">
8 is {{rule_ctrlr.ruleDefinitions.allOps[rule_ctrlr.rule.op]}} {{rule_ctrlr.rule.value}}
8 is {{rule_ctrlr.ruleDefinitions.allOps[rule_ctrlr.rule.op]}} {{rule_ctrlr.rule.value}}
9 </span>
9 </span>
10
10
11 <span ng-if="rule_ctrlr.rule.field == '__AND__' || rule_ctrlr.rule.field =='__OR__'">
11 <span ng-if="rule_ctrlr.rule.field == '__AND__' || rule_ctrlr.rule.field =='__OR__' || rule_ctrlr.rule.field =='__NOT__'">
12 <p ng-if="parent"><strong>Subrules</strong></p>
12 <p ng-if="parent"><strong>Subrules</strong></p>
13 <div ng-repeat="subrule in rule_ctrlr.rule.rules" class="m-l-2">
13 <div ng-repeat="subrule in rule_ctrlr.rule.rules" class="m-l-2">
14
14
General Comments 0
You need to be logged in to leave comments. Login now