Add simulator enhancements.
[sim/o1-interface.git] / ntsimulator / src / o-ran-notifications / o-ran-notifications.c
1 /*************************************************************************
2 *
3 * Copyright 2019 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 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <signal.h>
22 #include <inttypes.h>
23 #include <time.h>
24 #include <math.h>
25 #include <sys/time.h>
26 #include <cjson/cJSON.h>
27 #include <string.h>
28
29 #include "sysrepo.h"
30 #include "sysrepo/values.h"
31
32 #include "utils.h"
33
34 #define LINE_BUFSIZE 128
35 #define ORAN_FAULT_ALARMS_NUMBER 10
36 #define AFFECTED_OBJECTS_MAX_NUMBER 100
37
38 volatile int exit_application = 0;
39
40 static counterAlarms netconf_alarm_counter = {
41     .normal = 0,
42     .warning = 0,
43     .minor = 0,
44     .major = 0,
45     .critical = 0
46 };
47 static counterAlarms ves_alarm_counter= {
48     .normal = 0,
49     .warning = 0,
50     .minor = 0,
51     .major = 0,
52     .critical = 0
53 };
54
55 struct faultAlarms
56 {
57         int             faultId;
58         char*           faultSource;
59         int             cleared[10];
60         char*           faultSeverity;
61         char*           faultText;
62         char*           affectedObjects[AFFECTED_OBJECTS_MAX_NUMBER];
63 };
64 struct faultAlarms oran_fault_alarms[ORAN_FAULT_ALARMS_NUMBER] = {
65                 {.faultId = 1, .faultSource = "jknsdfnui", .affectedObjects = {"akddconoj", "asodmnjvf", "roiemfkmods"}, .cleared = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, .faultSeverity = "MAJOR", .faultText = "sdnjosopnojnsd"},
66                 {.faultId = 2, .faultSource = "onascokjnasc", .affectedObjects = {"sdouvncsjdfv13", "asjdn13ejlncd4"}, .cleared = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, .faultSeverity = "WARNING", .faultText = "4pionfcsofn42on"},
67                 {.faultId = 3, .faultSource = "asonxpkn", .affectedObjects = {"0j4fiwef320fd", "sdlvkmsdv-9023"}, .cleared = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, .faultSeverity = "CRITICAL", .faultText = "sdjnonj32onjsa23"},
68                 {.faultId = 4, .faultSource = "asnjcpkd", .affectedObjects = {"0j4fiwef320fd", "sdlvkmsdv-9023", "laksmdklmdas21"}, .cleared = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, .faultSeverity = "MINOR", .faultText = "asdjln12osa453"},
69                 {.faultId = 5, .faultSource = "dskmfl", .affectedObjects = {"sdkm31wdlk"}, .cleared = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, .faultSeverity = "MAJOR", .faultText = "dknovrf34ekl"},
70                 {.faultId = 6, .faultSource = "dsllkje232kl", .affectedObjects = {"sFKOM24KLMerw"}, .cleared = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, .faultSeverity = "MAJOR", .faultText = "frpkm24k lsd     kmewfpm"},
71                 {.faultId = 7, .faultSource = "fvkdlsfjnwej23kloe", .affectedObjects = {"fvkm24km", "sdfk23d", "kmdfkmo32", "wekl2332"}, .cleared = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, .faultSeverity = "WARNING", .faultText = "dsm 2d 32j sdfmr32"},
72                 {.faultId = 8, .faultSource = "dkom32", .affectedObjects = {"kmsdfkpm23ds", "sdmkp32"}, .cleared = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, .faultSeverity = "CRITICAL", .faultText = "dsonj32 don32 mdson32pk654"},
73                 {.faultId = 9, .faultSource = "weflm3", .affectedObjects = {"klklm32kl3", "dsfln234poewj23-", "spmd32k"}, .cleared = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, .faultSeverity = "MINOR", .faultText = "dsflknjwej32"},
74                 {.faultId = 10, .faultSource = "fweiunvfrem32", .affectedObjects = {"sfkm23klsdf2343"}, .cleared = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, .faultSeverity = "MAJOR", .faultText = "dfskjnl4j dsfknl2 fodn54 65k"}
75 };
76
77 static  CURL *curl;
78
79 static int _init_curl()
80 {
81         curl = curl_easy_init();
82
83         if (curl == NULL) {
84                 printf("cURL initialization error! Aborting call!\n");
85                 return SR_ERR_OPERATION_FAILED;
86         }
87
88         return SR_ERR_OK;
89 }
90
91 static int cleanup_curl()
92 {
93         if (curl != NULL)
94         {
95                 curl_easy_cleanup(curl);
96         }
97
98         return SR_ERR_OK;
99 }
100
101 static int send_fault_ves_message(char *alarm_condition, char *alarm_object, char *severity, char *date_time, char *specific_problem, int port)
102 {
103         CURLcode res;
104         static int sequence_id = 0;
105         int netconf_port_base = 0;
106
107         prepare_ves_message_curl(curl);
108
109         cJSON *postDataJson = cJSON_CreateObject();
110
111         cJSON *event = cJSON_CreateObject();
112         if (event == NULL)
113         {
114                 printf("Could not create JSON object: event\n");
115                 return SR_ERR_OPERATION_FAILED;
116         }
117         cJSON_AddItemToObject(postDataJson, "event", event);
118
119         char *hostname = getenv("HOSTNAME");
120
121     netconf_port_base = getIntFromString(getenv("NETCONF_BASE"), 1);
122     netconf_port_base += port;
123
124         char source_name[100];
125         sprintf(source_name, "%s_%d", hostname, netconf_port_base);
126
127         cJSON *commonEventHeader = vesCreateCommonEventHeader("fault", "O_RAN_COMPONENT_Alarms", source_name, sequence_id++);
128         if (commonEventHeader == NULL)
129         {
130                 printf("Could not create JSON object: commonEventHeader\n");
131                 return SR_ERR_OPERATION_FAILED;
132         }
133         cJSON_AddItemToObject(event, "commonEventHeader", commonEventHeader);
134
135         cJSON *faultFields = vesCreateFaultFields(alarm_condition, alarm_object, severity, date_time, specific_problem);
136         if (faultFields == NULL)
137         {
138                 printf("Could not create JSON object: faultFields\n");
139                 if (postDataJson != NULL)
140                 {
141                         cJSON_Delete(postDataJson);
142                 }
143                 return SR_ERR_OPERATION_FAILED;
144         }
145         cJSON_AddItemToObject(event, "faultFields", faultFields);
146
147     char *post_data_string = NULL;
148
149         post_data_string = cJSON_PrintUnformatted(postDataJson);
150
151         printf("Post data JSON:\n%s\n", post_data_string);
152
153         if (postDataJson != NULL)
154         {
155                 cJSON_Delete(postDataJson);
156         }
157
158         curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data_string);
159
160         res = curl_easy_perform(curl);
161
162         if (res != CURLE_OK)
163         {
164                 printf("Failed to send cURL...\n");
165                 return SR_ERR_OPERATION_FAILED;
166         }
167
168         return SR_ERR_OK;
169 }
170
171 static int send_dummy_notif(sr_session_ctx_t *sess)
172 {
173         int rc;
174
175     char dateAndTime[256];
176     time_t t = time(NULL);
177     struct tm tm = *localtime(&t);
178     struct timeval tv;
179     int millisec;
180
181     gettimeofday(&tv, NULL);
182     millisec = lrint(tv.tv_usec/1000.0); // Round to nearest millisec
183     if (millisec>=1000)
184     { // Allow for rounding up to nearest second
185         millisec -=1000;
186         tv.tv_sec++;
187         millisec /= 100;
188     }
189     sprintf(dateAndTime, "%04d-%02d-%02dT%02d:%02d:%02d.%01dZ",
190     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
191     tm.tm_hour, tm.tm_min, tm.tm_sec, millisec/100);
192
193     int ran = (int) random_at_most(ORAN_FAULT_ALARMS_NUMBER - 1);
194
195     //TODO we hardcode here the number of ports for each device, 10
196     int random_port = (int) random_at_most(9);
197
198     if (oran_fault_alarms[ran].cleared[random_port] == 1)
199     {
200         oran_fault_alarms[ran].cleared[random_port] = 0;
201     }
202     else
203     {
204         oran_fault_alarms[ran].cleared[random_port] = 1;
205     }
206
207         sr_val_t *vnotif;
208         size_t current_num_of_values= 0;
209
210         CREATE_NEW_VALUE(rc, vnotif, current_num_of_values);
211
212         sr_val_build_xpath(&vnotif[current_num_of_values - 1], "%s", "/o-ran-fm:alarm-notif/fault-id");
213         vnotif[current_num_of_values - 1].type = SR_UINT16_T;
214         vnotif[current_num_of_values - 1].data.uint16_val = oran_fault_alarms[ran].faultId;
215
216         CREATE_NEW_VALUE(rc, vnotif, current_num_of_values);
217
218         sr_val_build_xpath(&vnotif[current_num_of_values - 1], "%s", "/o-ran-fm:alarm-notif/fault-source");
219         sr_val_set_str_data(&vnotif[current_num_of_values - 1], SR_STRING_T, oran_fault_alarms[ran].faultSource);
220
221         CREATE_NEW_VALUE(rc, vnotif, current_num_of_values);
222
223         sr_val_build_xpath(&vnotif[current_num_of_values - 1], "%s", "/o-ran-fm:alarm-notif/fault-severity");
224         sr_val_set_str_data(&vnotif[current_num_of_values - 1], SR_ENUM_T, oran_fault_alarms[ran].faultSeverity);
225
226         CREATE_NEW_VALUE(rc, vnotif, current_num_of_values);
227
228         sr_val_build_xpath(&vnotif[current_num_of_values - 1], "%s", "/o-ran-fm:alarm-notif/is-cleared");
229         vnotif[current_num_of_values - 1].type = SR_BOOL_T;
230         vnotif[current_num_of_values - 1].data.bool_val = oran_fault_alarms[ran].cleared[random_port];
231
232         CREATE_NEW_VALUE(rc, vnotif, current_num_of_values);
233
234         sr_val_build_xpath(&vnotif[current_num_of_values - 1], "%s", "/o-ran-fm:alarm-notif/fault-text");
235         sr_val_set_str_data(&vnotif[current_num_of_values - 1], SR_STRING_T, oran_fault_alarms[ran].faultText);
236
237         CREATE_NEW_VALUE(rc, vnotif, current_num_of_values);
238
239         sr_val_build_xpath(&vnotif[current_num_of_values - 1], "%s", "/o-ran-fm:alarm-notif/event-time");
240         sr_val_build_str_data(&vnotif[current_num_of_values - 1], SR_STRING_T, "%s", dateAndTime);
241
242         for (int  i = 0; i < AFFECTED_OBJECTS_MAX_NUMBER; ++i)
243         {
244                 char path[400];
245                 if (oran_fault_alarms[ran].affectedObjects[i] == NULL)
246                 {
247                         break;
248                 }
249
250                 sprintf(path, "/o-ran-fm:alarm-notif/affected-objects[name='%s']", oran_fault_alarms[ran].affectedObjects[i]);
251
252                 CREATE_NEW_VALUE(rc, vnotif, current_num_of_values);
253
254                 sr_val_build_xpath(&vnotif[current_num_of_values - 1], "%s", path);
255                 vnotif[current_num_of_values - 1].type = SR_LIST_T;
256         }
257
258         int isNetconfAvailable = getNetconfAvailableFromConfigJson();
259         int isVesAvailable = getVesAvailableFromConfigJson();
260
261         if (isNetconfAvailable)
262         {
263                 rc = sr_event_notif_send(sess, "/o-ran-fm:alarm-notif", vnotif, current_num_of_values, SR_EV_NOTIF_DEFAULT);
264                 if (rc != SR_ERR_OK)
265                 {
266                         printf("Failed to send notification send_dummy_notif\n");
267                         return SR_ERR_OPERATION_FAILED;
268                 }
269                 if (oran_fault_alarms[ran].cleared[random_port])
270                 {
271                         netconf_alarm_counter.normal++;
272                 }
273                 else
274                 {
275             if (strcmp(oran_fault_alarms[ran].faultSeverity, "WARNING") == 0)
276             {
277                 netconf_alarm_counter.warning++;
278             }
279             else if (strcmp(oran_fault_alarms[ran].faultSeverity, "MINOR") == 0)
280             {
281                 netconf_alarm_counter.minor++;
282             }
283             else if (strcmp(oran_fault_alarms[ran].faultSeverity, "MAJOR") == 0)
284             {
285                 netconf_alarm_counter.major++;
286             }
287             else if (strcmp(oran_fault_alarms[ran].faultSeverity, "CRITICAL") == 0)
288             {
289                 netconf_alarm_counter.critical++;
290             }
291                 }
292                 
293                 printf("Successfully sent notification with timestamp=\"%s\"\n", dateAndTime);
294         }
295         if (isVesAvailable)
296         {
297                 char faultId[10];
298                 sprintf(faultId, "%d", oran_fault_alarms[ran].faultId);
299                 rc = send_fault_ves_message(faultId, oran_fault_alarms[ran].faultSource,
300                                 (oran_fault_alarms[ran].cleared[random_port]) ? "NORMAL" : oran_fault_alarms[ran].faultSeverity, dateAndTime, oran_fault_alarms[ran].faultText, random_port);
301                 if (rc != SR_ERR_OK)
302                 {
303                         printf("Could not send Fault VES message\n");
304                 }
305         if (oran_fault_alarms[ran].cleared[random_port])
306                 {
307                         ves_alarm_counter.normal++;
308                 }
309                 else
310                 {
311             if (strcmp(oran_fault_alarms[ran].faultSeverity, "WARNING") == 0)
312             {
313                 ves_alarm_counter.warning++;
314             }
315             else if (strcmp(oran_fault_alarms[ran].faultSeverity, "MINOR") == 0)
316             {
317                 ves_alarm_counter.minor++;
318             }
319             else if (strcmp(oran_fault_alarms[ran].faultSeverity, "MAJOR") == 0)
320             {
321                 ves_alarm_counter.major++;
322             }
323             else if (strcmp(oran_fault_alarms[ran].faultSeverity, "CRITICAL") == 0)
324             {
325                 ves_alarm_counter.critical++;
326             }
327                 }
328         }
329     printf("Writing counters to file...\n");
330     rc = writeStatusNotificationCounters(ves_alarm_counter, netconf_alarm_counter);
331     if (rc != SR_ERR_OK)
332     {
333         printf("Could not write status to file...\n");
334     }
335
336         sr_free_values(vnotif, current_num_of_values);
337
338         return SR_ERR_OK;
339 }
340
341 static void
342 sigint_handler(int signum)
343 {
344     exit_application = 1;
345 }
346
347 int
348 main(int argc, char **argv)
349 {
350     sr_conn_ctx_t *connection = NULL;
351     sr_session_ctx_t *session = NULL;
352     sr_subscription_ctx_t *subscription = NULL;
353     int rc = SR_ERR_OK;
354
355     setbuf(stdout, NULL);
356
357     /* connect to sysrepo */
358     rc = sr_connect("oran_notifications", SR_CONN_DEFAULT, &connection);
359     if (SR_ERR_OK != rc) {
360         fprintf(stderr, "Error by sr_connect: %s\n", sr_strerror(rc));
361         goto cleanup;
362     }
363
364     /* start session */
365     rc = sr_session_start(connection, SR_DS_RUNNING, SR_SESS_DEFAULT, &session);
366     if (SR_ERR_OK != rc) {
367         fprintf(stderr, "Error by sr_session_start: %s\n", sr_strerror(rc));
368         goto cleanup;
369     }
370
371     rc = _init_curl();
372     if (rc != SR_ERR_OK)
373     {
374         fprintf(stderr, "Could not initialize cURL: %s\n", sr_strerror(rc));
375         goto cleanup;
376     }
377
378     /* loop until ctrl-c is pressed / SIGINT is received */
379     signal(SIGINT, sigint_handler);
380     signal(SIGPIPE, SIG_IGN);
381
382     while (!exit_application) {
383         int notif_delay[100], count = 0;
384
385         rc = getFaultNotificationDelayPeriodFromConfigJson(notif_delay, &count);
386         if (rc != SR_ERR_OK)
387         {
388             printf("Could not get fault notification delay period.");
389             sleep(1);
390             continue;
391         }
392
393         if (count > 1)
394         {
395             for (int i = 0; i < count; ++i)
396             {
397                 sleep(notif_delay[i]);
398                 send_dummy_notif(session);                
399             }
400         }
401         else if (count == 1)
402         {
403             if (notif_delay[0] > 0)
404             {
405                 sleep(notif_delay[0]);
406                 send_dummy_notif(session);
407             }
408             else 
409             {
410                 sleep(1);
411                 // reset the counters when the notifciation delay period is switched back to 0
412                 netconf_alarm_counter.normal = netconf_alarm_counter.warning = \
413                 netconf_alarm_counter.minor = netconf_alarm_counter.major = \
414                 netconf_alarm_counter.critical = 0;
415                 
416                 ves_alarm_counter.normal = ves_alarm_counter.warning = \
417                 ves_alarm_counter.minor = ves_alarm_counter.major = \
418                 ves_alarm_counter.critical = 0;
419             }
420         }
421
422     }
423
424     printf("Application exit requested, exiting.\n");
425
426 cleanup:
427     if (NULL != subscription) {
428         sr_unsubscribe(session, subscription);
429     }
430     if (NULL != session) {
431         sr_session_stop(session);
432     }
433     if (NULL != connection) {
434         sr_disconnect(connection);
435     }
436     cleanup_curl();
437     printf("Error encountered. Exiting...");
438     return rc;
439 }
440
441
442
443