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