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