Bugfix for SIM-63
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / faults / faults_processing.c
1 /*************************************************************************
2 *
3 * Copyright 2020 highstreet technologies GmbH and others
4 *
5 * Licensed under the Apache License, Version 2.0 (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
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
17
18 #define _GNU_SOURCE
19
20 #include "faults.h"
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
23 #include "core/framework.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <assert.h>
27
28 #include <cjson/cJSON.h>
29
30 static char *fault_process_vars(const char *template, const fault_details_t *details);
31 static char *fault_process_function(const char *function);
32
33 fault_settings_t *faults_settings_read(const char *json_plain) {
34     if(json_plain == 0) {
35         return 0;
36     }
37
38     fault_settings_t *ret = (fault_settings_t *)malloc(sizeof(fault_settings_t));
39     if(ret == 0) {
40         log_error("malloc failed\n");
41         goto faults_settings_read_failed_cleanup;
42     }
43
44     ret->yang_notif_template = 0;
45     ret->choosing_method = 0;
46     ret->fault = 0;
47     ret->fault_count = 0;
48
49     cJSON *json = cJSON_Parse(json_plain);
50     if(!json) {
51         log_error("json parsing error: %s\n", cJSON_GetErrorPtr());
52         goto faults_settings_read_failed_cleanup;
53     }
54
55     cJSON *main_node = cJSON_GetObjectItem(json, "fault-rules");
56     if(main_node == 0) {
57         goto faults_settings_read_failed_cleanup;
58     }
59
60     cJSON *node = cJSON_GetObjectItem(main_node, "yang-notif-template");
61     if(node && cJSON_IsString(node)) {
62         ret->yang_notif_template = strdup(node->valuestring);
63     }
64     else {
65         log_error("could not find yang-notif-template\n");
66         goto faults_settings_read_failed_cleanup;
67     }
68
69     node = cJSON_GetObjectItem(main_node, "choosing-method");
70     if(node && cJSON_IsString(node)) {
71         ret->choosing_method = strdup(node->valuestring);
72     }
73     else {
74         log_error("could not find choosing-method\n");
75         goto faults_settings_read_failed_cleanup;
76     }
77
78     node = cJSON_GetObjectItem(main_node, "faults");
79     if(node && cJSON_IsArray(node)) {
80         cJSON *fault_detail;
81         cJSON_ArrayForEach(fault_detail, node) {
82             cJSON *object;
83             ret->fault_count++;
84             ret->fault = (fault_details_t *)realloc(ret->fault, sizeof(fault_details_t)*ret->fault_count);
85             if(ret->fault == 0) {
86                 ret->fault_count--;
87                 log_error("realloc failed\n");
88                 goto faults_settings_read_failed_cleanup;
89             }
90
91             ret->fault[ret->fault_count - 1].condition = 0;
92             ret->fault[ret->fault_count - 1].object = 0;
93             ret->fault[ret->fault_count - 1].severity = 0;
94             ret->fault[ret->fault_count - 1].date_time = 0;
95             ret->fault[ret->fault_count - 1].specific_problem = 0;
96             ret->fault[ret->fault_count - 1].field_name = 0;
97             ret->fault[ret->fault_count - 1].field_value = 0;
98             ret->fault[ret->fault_count - 1].field_count = 0;
99             ret->fault[ret->fault_count - 1].yang_notif_processed = 0;
100
101             cJSON_ArrayForEach(object, fault_detail) {
102                 ret->fault[ret->fault_count - 1].field_count++;
103                 ret->fault[ret->fault_count - 1].field_name = (char **)realloc(ret->fault[ret->fault_count - 1].field_name, sizeof(char*) * ret->fault[ret->fault_count - 1].field_count);
104                 if(ret->fault[ret->fault_count - 1].field_name == 0) {
105                     ret->fault[ret->fault_count - 1].field_count--;
106                     log_error("realloc failed\n");
107                     goto faults_settings_read_failed_cleanup;
108                 }
109
110                 ret->fault[ret->fault_count - 1].field_value = (char **)realloc(ret->fault[ret->fault_count - 1].field_value, sizeof(char*) * ret->fault[ret->fault_count - 1].field_count);
111                 if(ret->fault[ret->fault_count - 1].field_value == 0) {
112                     ret->fault[ret->fault_count - 1].field_count--;
113                     log_error("realloc failed\n");
114                     goto faults_settings_read_failed_cleanup;
115                 }
116
117                 asprintf(&ret->fault[ret->fault_count - 1].field_name[ret->fault[ret->fault_count - 1].field_count - 1], "%%%%%s%%%%", object->string);
118                 ret->fault[ret->fault_count - 1].field_value[ret->fault[ret->fault_count - 1].field_count - 1] = strdup(object->valuestring);
119             }
120         }
121     }
122     else {
123         log_error("could not find faults list\n");
124         goto faults_settings_read_failed_cleanup;
125     }
126
127     cJSON_Delete(json);
128     return ret;
129
130     faults_settings_read_failed_cleanup:
131     faults_settings_free(ret);
132     cJSON_Delete(json);
133     return 0;
134 }
135
136 void faults_settings_free(fault_settings_t *faults) {
137     if(faults) {
138         free(faults->yang_notif_template);
139         free(faults->choosing_method);
140
141         for(int i = 0; i < faults->fault_count; i++) {
142             free(faults->fault[i].condition);
143             free(faults->fault[i].object);
144             free(faults->fault[i].severity);
145             free(faults->fault[i].date_time);
146             free(faults->fault[i].specific_problem);
147
148             for(int j = 0; j < faults->fault[i].field_count; j++) {
149                 free(faults->fault[i].field_name[j]);
150                 free(faults->fault[i].field_value[j]);
151             }
152             free(faults->fault[i].field_name);
153             free(faults->fault[i].field_value);
154
155             free(faults->fault[i].yang_notif_processed);
156         }
157     }
158 }
159
160 int faults_settings_process(fault_settings_t *faults, int fault_no) {
161     assert(faults);
162     assert(fault_no < faults->fault_count);
163
164     free(faults->fault[fault_no].condition);
165     free(faults->fault[fault_no].object);
166     free(faults->fault[fault_no].severity);
167     free(faults->fault[fault_no].date_time);
168     free(faults->fault[fault_no].specific_problem);
169     free(faults->fault[fault_no].yang_notif_processed);
170
171     faults->fault[fault_no].condition = 0;
172     faults->fault[fault_no].object = 0;
173     faults->fault[fault_no].severity = 0;
174     faults->fault[fault_no].date_time = 0;
175     faults->fault[fault_no].specific_problem = 0;
176     faults->fault[fault_no].yang_notif_processed = 0;
177     
178     for(int j = 0; j < faults->fault[fault_no].field_count; j++) {
179         if(strcmp(faults->fault[fault_no].field_name[j], "%%condition%%") == 0) {
180             faults->fault[fault_no].condition = fault_process_vars(faults->fault[fault_no].field_value[j], &faults->fault[fault_no]);
181         }
182         else if(strcmp(faults->fault[fault_no].field_name[j], "%%object%%") == 0) {
183             faults->fault[fault_no].object = fault_process_vars(faults->fault[fault_no].field_value[j], &faults->fault[fault_no]);
184         }
185         else if(strcmp(faults->fault[fault_no].field_name[j], "%%severity%%") == 0) {
186             faults->fault[fault_no].severity = fault_process_vars(faults->fault[fault_no].field_value[j], &faults->fault[fault_no]);
187         }
188         else if(strcmp(faults->fault[fault_no].field_name[j], "%%date-time%%") == 0) {
189             faults->fault[fault_no].date_time = fault_process_vars(faults->fault[fault_no].field_value[j], &faults->fault[fault_no]);
190         }
191         else if(strcmp(faults->fault[fault_no].field_name[j], "%%specific-problem%%") == 0) {
192             faults->fault[fault_no].specific_problem = fault_process_vars(faults->fault[fault_no].field_value[j], &faults->fault[fault_no]);
193         }
194     }
195
196     faults->fault[fault_no].yang_notif_processed = fault_process_vars(faults->yang_notif_template, &faults->fault[fault_no]);
197
198     if(faults->fault[fault_no].condition == 0) {
199         log_error("could not find condition in fault\n");
200         return NTS_ERR_FAILED;
201     }
202
203     if(faults->fault[fault_no].object == 0) {
204         log_error("could not find object in fault\n");
205         return NTS_ERR_FAILED;
206     }
207
208     if(faults->fault[fault_no].severity == 0) {
209         log_error("could not find severity in fault\n");
210         return NTS_ERR_FAILED;
211     }
212
213     if(faults->fault[fault_no].date_time == 0) {
214         log_error("could not find date_time in fault\n");
215         return NTS_ERR_FAILED;
216     }
217
218     if(faults->fault[fault_no].specific_problem == 0) {
219         log_error("could not find specific_problem in fault\n");
220         return NTS_ERR_FAILED;
221     }
222
223     if(faults->fault[fault_no].yang_notif_processed == 0) {
224         log_error("could not find yang_notif_processed in fault\n");
225         return NTS_ERR_FAILED;
226     }
227
228     return NTS_ERR_OK;
229 }
230
231 static char *fault_process_vars(const char *template, const fault_details_t *details) {
232     assert(template);
233     assert(details);
234
235     char *ret = strdup(template);
236     if(ret == 0) {
237         log_error("strdup error\n");
238         return 0;
239     }
240
241     //if template is blank, do not process anything, means nc notif disabled
242     if(ret[0] == 0) {
243         return ret;
244     }
245
246     char **vars = 0;
247     int vars_count = 0;
248     
249     char **funcs = 0;
250     int funcs_count = 0;
251
252     char *var = 0;
253     char *func = 0;
254
255     //do replacements until no replacement is done
256     int replaced = 1;
257     while(replaced) {
258         replaced = 0;
259
260         var = 0;
261         vars = 0;
262         vars_count = 0;
263         func = 0;
264         funcs = 0;
265         funcs_count = 0;
266
267         char *pos_start;
268
269         //look for vars
270         pos_start = strstr(ret, "%%");
271         while(pos_start) {
272             char *pos_end = strstr(pos_start + 2, "%%");
273             int var_size = pos_end - pos_start + 2;
274             var = (char *)malloc(sizeof(char) * (var_size + 1));
275             if(var == 0) {
276                 log_error("bad malloc\n");
277                 goto fault_process_vars_failed;
278             }
279
280             for(int i = 0; i < var_size; i++) {
281                 var[i] = pos_start[i];
282             }
283             var[var_size] = 0;
284
285             // found var
286             vars_count++;
287             vars = (char **)realloc(vars, sizeof(char *) * vars_count);
288             if(!vars) {
289                 vars_count = 0;
290                 log_error("bad malloc\n");
291                 goto fault_process_vars_failed;
292             }
293
294             vars[vars_count - 1] = strdup(var);
295             if(!vars[vars_count - 1]) {
296                 vars_count--;
297                 log_error("bad malloc\n");
298                 goto fault_process_vars_failed;
299             }
300             free(var);
301             var = 0;
302
303             pos_start = strstr(pos_end + 2, "%%");
304         }
305
306         //look for functions
307         pos_start = strstr(ret, "$$");
308         while(pos_start) {
309             char *pos_end = strstr(pos_start + 2, "$$");
310             int func_size = pos_end - pos_start + 2;
311             func = (char *)malloc(sizeof(char) * (func_size + 1));
312             if(func == 0) {
313                 log_error("bad malloc\n");
314                 goto fault_process_vars_failed;
315             }
316
317             for(int i = 0; i < func_size; i++) {
318                 func[i] = pos_start[i];
319             }
320             func[func_size] = 0;
321
322             // found func
323             funcs_count++;
324             funcs = (char **)realloc(funcs, sizeof(char *) * funcs_count);
325             if(!funcs) {
326                 funcs_count = 0;
327                 log_error("bad malloc\n");
328                 goto fault_process_vars_failed;
329             }
330
331             funcs[funcs_count - 1] = strdup(func);
332             if(!funcs[funcs_count - 1]) {
333                 funcs_count--;
334                 log_error("bad malloc\n");
335                 goto fault_process_vars_failed;
336             }
337             free(func);
338             func = 0;
339
340             pos_start = strstr(pos_end + 2, "$$");
341         }
342
343         //replace vars
344         for(int i = 0; i < vars_count; i++) {
345             char *var_value = 0;
346             for(int j = 0; j < details->field_count; j++) {
347                 if(strcmp(details->field_name[j], vars[i]) == 0) {
348                     var_value = strdup(details->field_value[j]);
349                 }
350             }
351
352             if(var_value == 0) {
353                 log_error("value %s not found\n", vars[i]);
354                 goto fault_process_vars_failed;
355             }
356
357             ret = str_replace(ret, vars[i], var_value);
358             if(ret == 0) {
359                 free(var_value);
360                 var_value = 0;
361                 goto fault_process_vars_failed;
362             }
363
364             free(var_value);
365             var_value = 0;
366             replaced++;
367         }
368
369         //replace functions
370         for(int i = 0; i < funcs_count; i++) {
371             char *func_value = fault_process_function(funcs[i]);
372             if(func_value == 0) {
373                 log_error("function %s not found\n", vars[i]);
374                 goto fault_process_vars_failed;
375             }
376
377             ret = str_replace(ret, funcs[i], func_value);
378             if(ret == 0) {
379                 free(func_value);
380                 goto fault_process_vars_failed;
381             }
382
383             free(func_value);
384             func_value = 0;
385             replaced++;
386         }
387
388         for(int i = 0; i < vars_count; i++) {
389             free(vars[i]);
390         }
391         free(vars);
392         vars = 0;
393         vars_count = 0;
394
395         for(int i = 0; i < funcs_count; i++) {
396             free(funcs[i]);
397         }
398         free(funcs);
399         funcs = 0;
400         funcs_count = 0;
401     }
402
403
404     free(var);
405     free(func);
406     for(int i = 0; i < vars_count; i++) {
407         free(vars[i]);
408     }
409     free(vars);
410
411     for(int i = 0; i < funcs_count; i++) {
412         free(funcs[i]);
413     }
414     free(funcs);
415     return ret;
416
417     fault_process_vars_failed:
418     free(var);
419     free(func);
420
421     for(int i = 0; i < vars_count; i++) {
422         free(vars[i]);
423     }
424     free(vars);
425
426     for(int i = 0; i < funcs_count; i++) {
427         free(funcs[i]);
428     }
429     free(funcs);
430     return 0;
431 }
432
433 static char *fault_process_function(const char *function) {
434     assert(function);
435
436     static uint8_t uint8_counter = 0;
437     static uint16_t uint16_counter = 0;
438     static uint32_t uint32_counter = 0;
439
440     if(strcmp(function, "$$time$$") == 0) {
441         return get_current_date_and_time();
442     }
443     else if(strcmp(function, "$$uint8_counter$$") == 0) {
444         char *ret = 0;
445         asprintf(&ret, "%d", uint8_counter);
446         uint8_counter++;
447         return ret;
448     }
449     else if(strcmp(function, "$$uint16_counter$$") == 0) {
450         char *ret = 0;
451         asprintf(&ret, "%d", uint16_counter);
452         uint16_counter++;
453         return ret;
454     }
455     else if(strcmp(function, "$$uint32_counter$$") == 0) {
456         char *ret = 0;
457         asprintf(&ret, "%d", uint32_counter);
458         uint32_counter++;
459         return ret;
460     }
461     else if(strcmp(function, "$$hostname$$") == 0) {
462         char *ret = 0;
463         asprintf(&ret, "%s", framework_environment.settings.hostname);
464         return ret;
465     }
466
467     return 0;
468 }