Add counters for generated notifications. 43/3243/1
authorAlex Stancu <alexandru.stancu@highstreet-technologies.com>
Fri, 10 Apr 2020 15:19:53 +0000 (18:19 +0300)
committerAlex Stancu <alexandru.stancu@highstreet-technologies.com>
Fri, 10 Apr 2020 15:20:08 +0000 (18:20 +0300)
Add status counters for generated notifications (VES and NETCONF).

Issue-ID: SIM-21
Change-Id: I370532efd7bb9d06f3ed81a2f66cdef4e9750a51
Signed-off-by: Alex Stancu <alexandru.stancu@highstreet-technologies.com>
ntsimulator/deploy/nts-manager/container-tag.yaml
ntsimulator/deploy/o-ran-sc/o-ran-ru/container-tag.yaml
ntsimulator/deploy/o-ran/ru-fh/container-tag.yaml
ntsimulator/deploy/x-ran/container-tag.yaml
ntsimulator/inc/utils/utils.h
ntsimulator/src/ntsimulator-manager/ntsimulator-manager.c
ntsimulator/src/ntsimulator-manager/simulator-operations.c
ntsimulator/src/o-ran-notifications/o-ran-notifications.c
ntsimulator/src/utils/utils.c
ntsimulator/yang/nts-manager/network-topology-simulator.yang
ntsimulator/yang/sysrepo-configuration-load.sh

index c049c66..9ce7e1f 100644 (file)
                                                                                num++;\
                                                                                }
 
+typedef struct
+{
+       int normal;
+       int warning;
+       int minor;
+       int major;
+       int critical;
+} counterAlarms;
+
 void           set_curl_common_info_ves(CURL *curl);
 
 long           random_at_most(long max);
@@ -75,4 +84,15 @@ int  getVesAvailableFromConfigJson(void);
 
 void   generateRandomMacAddress(char *mac_address);
 
+int    writeSkeletonStatusFile(void);
+char*  readStatusFileInString(void);
+
+int     writeStatusNotificationCounters(counterAlarms ves_counter, counterAlarms netconf_counter);
+void    writeStatusFile(char *status);
+int     removeDeviceEntryFromStatusFile(char *deviceName);
+
+cJSON*  getDeviceListFromStatusFile(void);
+int     compute_notifications_count(counterAlarms *ves_counter, counterAlarms *netconf_counter);
+int     getDeviceCounters(char *containerId, counterAlarms *ves_counter, counterAlarms *netconf_counter);
+
 #endif /* EXAMPLES_NTSIMULATOR_UTILS_H_ */
index e5312b1..836fc6f 100644 (file)
@@ -341,7 +341,14 @@ simulator_status_cb(const char *xpath, sr_val_t **values, size_t *values_cnt,
 {
        int rc;
 
-       printf("\n\n ========== Called simulator_status_cb for xpath: %s ==========\n\n", xpath);
+       // printf("\n\n ========== Called simulator_status_cb for xpath: %s ==========\n\n", xpath);
+
+    counterAlarms ves_counter, netconf_counter;
+    rc = compute_notifications_count(&ves_counter, &netconf_counter);
+    if (rc != SR_ERR_OK)
+    {
+        printf("Could not compute the total number of notification count.\n");
+    }
 
        if (sr_xpath_node_name_eq(xpath, "simulated-devices-list")) {
                sr_val_t *v;
@@ -366,6 +373,13 @@ simulator_status_cb(const char *xpath, sr_val_t **values, size_t *values_cnt,
 
                while (current_device != NULL)
                {
+            counterAlarms vesCount, netconfCount;
+            rc = getDeviceCounters(current_device->device_id, &vesCount, &netconfCount);
+            if (rc != SR_ERR_OK)
+            {
+                printf("Could not get Notification Counters for device with uuid=\"%s\"", current_device->device_id);
+            }            
+
                        CREATE_NEW_VALUE(rc, v, current_num_of_values);
 
                        sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/%s", xpath, current_device->device_id, "device-ip");
@@ -394,6 +408,66 @@ simulator_status_cb(const char *xpath, sr_val_t **values, size_t *values_cnt,
                        sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/%s", xpath, current_device->device_id, "operational-state");
                        sr_val_build_str_data(&v[current_num_of_values - 1], SR_ENUM_T, "%s", operational_state);
 
+            CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+            sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/ves-notifications/%s", xpath, current_device->device_id, "normal");
+            v[current_num_of_values - 1].type = SR_UINT32_T;
+            v[current_num_of_values - 1].data.uint32_val = vesCount.normal;
+
+            CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+            sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/ves-notifications/%s", xpath, current_device->device_id, "warning");
+            v[current_num_of_values - 1].type = SR_UINT32_T;
+            v[current_num_of_values - 1].data.uint32_val = vesCount.warning;
+
+            CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+            sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/ves-notifications/%s", xpath, current_device->device_id, "minor");
+            v[current_num_of_values - 1].type = SR_UINT32_T;
+            v[current_num_of_values - 1].data.uint32_val = vesCount.minor;
+
+            CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+            sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/ves-notifications/%s", xpath, current_device->device_id, "major");
+            v[current_num_of_values - 1].type = SR_UINT32_T;
+            v[current_num_of_values - 1].data.uint32_val = vesCount.major;
+
+            CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+            sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/ves-notifications/%s", xpath, current_device->device_id, "critical");
+            v[current_num_of_values - 1].type = SR_UINT32_T;
+            v[current_num_of_values - 1].data.uint32_val = vesCount.critical;
+
+            CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+            sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/netconf-notifications/%s", xpath, current_device->device_id, "normal");
+            v[current_num_of_values - 1].type = SR_UINT32_T;
+            v[current_num_of_values - 1].data.uint32_val = netconfCount.normal;
+
+            CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+            sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/netconf-notifications/%s", xpath, current_device->device_id, "warning");
+            v[current_num_of_values - 1].type = SR_UINT32_T;
+            v[current_num_of_values - 1].data.uint32_val = netconfCount.warning;
+
+            CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+            sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/netconf-notifications/%s", xpath, current_device->device_id, "minor");
+            v[current_num_of_values - 1].type = SR_UINT32_T;
+            v[current_num_of_values - 1].data.uint32_val = netconfCount.minor;
+
+            CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+            sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/netconf-notifications/%s", xpath, current_device->device_id, "major");
+            v[current_num_of_values - 1].type = SR_UINT32_T;
+            v[current_num_of_values - 1].data.uint32_val = netconfCount.major;
+
+            CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+            sr_val_build_xpath(&v[current_num_of_values - 1], "%s[uuid='%s']/notification-count/netconf-notifications/%s", xpath, current_device->device_id, "critical");
+            v[current_num_of_values - 1].type = SR_UINT32_T;
+            v[current_num_of_values - 1].data.uint32_val = netconfCount.critical;
+
                        current_device = current_device->next;
                }
 
@@ -453,6 +527,86 @@ simulator_status_cb(const char *xpath, sr_val_t **values, size_t *values_cnt,
                *values = v;
                *values_cnt = current_num_of_values;
         }
+     else if (sr_xpath_node_name_eq(xpath, "total-ves-notifications"))
+     {
+        sr_val_t *v;
+        /* convenient functions such as this can be found in sysrepo/values.h */
+        size_t current_num_of_values= 0;
+
+        CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+        sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "normal");
+        v[current_num_of_values - 1].type = SR_UINT32_T;
+        v[current_num_of_values - 1].data.uint32_val = ves_counter.normal;
+
+        CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+        sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "warning");
+        v[current_num_of_values - 1].type = SR_UINT32_T;
+        v[current_num_of_values - 1].data.uint32_val = ves_counter.warning;
+
+        CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+        sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "minor");
+        v[current_num_of_values - 1].type = SR_UINT32_T;
+        v[current_num_of_values - 1].data.uint32_val = ves_counter.minor;
+
+        CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+        sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "major");
+        v[current_num_of_values - 1].type = SR_UINT32_T;
+        v[current_num_of_values - 1].data.uint32_val = ves_counter.major;
+
+        CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+        sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "critical");
+        v[current_num_of_values - 1].type = SR_UINT32_T;
+        v[current_num_of_values - 1].data.uint32_val = ves_counter.critical;
+
+        //return the values that we have just created
+        *values = v;
+        *values_cnt = current_num_of_values;
+     }
+     else if (sr_xpath_node_name_eq(xpath, "total-netconf-notifications"))
+     {
+        sr_val_t *v;
+        /* convenient functions such as this can be found in sysrepo/values.h */
+        size_t current_num_of_values= 0;
+
+        CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+        sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "normal");
+        v[current_num_of_values - 1].type = SR_UINT32_T;
+        v[current_num_of_values - 1].data.uint32_val = netconf_counter.normal;
+
+        CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+        sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "warning");
+        v[current_num_of_values - 1].type = SR_UINT32_T;
+        v[current_num_of_values - 1].data.uint32_val = netconf_counter.warning;
+
+        CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+        sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "minor");
+        v[current_num_of_values - 1].type = SR_UINT32_T;
+        v[current_num_of_values - 1].data.uint32_val = netconf_counter.minor;
+
+        CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+        sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "major");
+        v[current_num_of_values - 1].type = SR_UINT32_T;
+        v[current_num_of_values - 1].data.uint32_val = netconf_counter.major;
+
+        CREATE_NEW_VALUE(rc, v, current_num_of_values);
+
+        sr_val_build_xpath(&v[current_num_of_values - 1], "%s/%s", xpath, "critical");
+        v[current_num_of_values - 1].type = SR_UINT32_T;
+        v[current_num_of_values - 1].data.uint32_val = netconf_counter.critical;
+
+        //return the values that we have just created
+        *values = v;
+        *values_cnt = current_num_of_values;
+     }
 
     return SR_ERR_OK;
 }
@@ -556,6 +710,12 @@ main(int argc, char **argv)
 
        printf("\n\n ========== STARTUP CONFIG network-topology-simulator APPLIED AS RUNNING ==========\n\n");
 
+    rc = writeSkeletonStatusFile();
+    if (rc != SR_ERR_OK)
+    {
+        fprintf(stderr, "Could not initialize status JSON file: %s\n", sr_strerror(rc));
+    }
+
     /* loop until ctrl-c is pressed / SIGINT is received */
     signal(SIGINT, sigint_handler);
     signal(SIGTERM, sigint_handler);
index 2ff4207..5f55f4e 100644 (file)
@@ -908,6 +908,12 @@ int stop_device(device_stack_t *theStack)
                printf("Could not kill and remove docker container with uuid=\"%s\"\n", last_id);
        }
 
+    rc = removeDeviceEntryFromStatusFile(last_id);
+    if (rc != SR_ERR_OK)
+    {
+        printf("Could not remove entry from status file for uuid=\"%s\"\n", last_id);
+    }
+
        pop_device(theStack);
 
        return SR_ERR_OK;
index ad282d1..230fad2 100644 (file)
@@ -23,6 +23,7 @@
 #include <time.h>
 #include <math.h>
 #include <sys/time.h>
+#include <cjson/cJSON.h>
 
 #include "sysrepo.h"
 #include "sysrepo/values.h"
 
 volatile int exit_application = 0;
 
+static counterAlarms netconf_alarm_counter = {
+    .normal = 0,
+    .warning = 0,
+    .minor = 0,
+    .major = 0,
+    .critical = 0
+};
+static counterAlarms ves_alarm_counter= {
+    .normal = 0,
+    .warning = 0,
+    .minor = 0,
+    .major = 0,
+    .critical = 0
+};
+
 struct faultAlarms
 {
        int             faultId;
@@ -259,6 +275,30 @@ static int send_dummy_notif(sr_session_ctx_t *sess)
                        printf("Failed to send notification send_dummy_notif\n");
                        return SR_ERR_OPERATION_FAILED;
                }
+               if (oran_fault_alarms[ran].cleared[random_port])
+               {
+                       netconf_alarm_counter.normal++;
+               }
+               else
+               {
+            if (strcmp(oran_fault_alarms[ran].faultSeverity, "WARNING") == 0)
+            {
+                netconf_alarm_counter.warning++;
+            }
+            else if (strcmp(oran_fault_alarms[ran].faultSeverity, "MINOR") == 0)
+            {
+                netconf_alarm_counter.minor++;
+            }
+            else if (strcmp(oran_fault_alarms[ran].faultSeverity, "MAJOR") == 0)
+            {
+                netconf_alarm_counter.major++;
+            }
+            else if (strcmp(oran_fault_alarms[ran].faultSeverity, "CRITICAL") == 0)
+            {
+                netconf_alarm_counter.critical++;
+            }
+               }
+               
                printf("Successfully sent notification with timestamp=\"%s\"\n", dateAndTime);
        }
        if (isVesAvailable)
@@ -271,7 +311,36 @@ static int send_dummy_notif(sr_session_ctx_t *sess)
                {
                        printf("Could not send Fault VES message\n");
                }
+        if (oran_fault_alarms[ran].cleared[random_port])
+               {
+                       ves_alarm_counter.normal++;
+               }
+               else
+               {
+            if (strcmp(oran_fault_alarms[ran].faultSeverity, "WARNING") == 0)
+            {
+                ves_alarm_counter.warning++;
+            }
+            else if (strcmp(oran_fault_alarms[ran].faultSeverity, "MINOR") == 0)
+            {
+                ves_alarm_counter.minor++;
+            }
+            else if (strcmp(oran_fault_alarms[ran].faultSeverity, "MAJOR") == 0)
+            {
+                ves_alarm_counter.major++;
+            }
+            else if (strcmp(oran_fault_alarms[ran].faultSeverity, "CRITICAL") == 0)
+            {
+                ves_alarm_counter.critical++;
+            }
+               }
        }
+    printf("Writing counters to file...\n");
+    rc = writeStatusNotificationCounters(ves_alarm_counter, netconf_alarm_counter);
+    if (rc != SR_ERR_OK)
+    {
+        printf("Could not write status to file...\n");
+    }
 
        sr_free_values(vnotif, current_num_of_values);
 
@@ -333,6 +402,14 @@ main(int argc, char **argv)
         else
         {
                sleep(1);
+            // reset the counters when the notifciation delay period is switched back to 0
+            netconf_alarm_counter.normal = netconf_alarm_counter.warning = \
+            netconf_alarm_counter.minor = netconf_alarm_counter.major = \
+            netconf_alarm_counter.critical = 0;
+            
+            ves_alarm_counter.normal = ves_alarm_counter.warning = \
+            ves_alarm_counter.minor = ves_alarm_counter.major = \
+            ves_alarm_counter.critical = 0;
         }
 
     }
index 0300ff9..7d1d2a0 100644 (file)
@@ -74,23 +74,31 @@ void        generateRandomMacAddress(char *mac_address)
        return;
 }
 
-long random_at_most(long max) {
-  unsigned long
-    // max <= RAND_MAX < ULONG_MAX, so this is okay.
-    num_bins = (unsigned long) max + 1,
-    num_rand = (unsigned long) RAND_MAX + 1,
-    bin_size = num_rand / num_bins,
-    defect   = num_rand % num_bins;
-
-  long x;
-  do {
-   x = random();
-  }
-  // This is carefully written not to overflow
-  while (num_rand - defect <= (unsigned long)x);
-
-  // Truncated division is intentional
-  return x/bin_size;
+long random_at_most(long max) 
+{
+    unsigned long
+        // max <= RAND_MAX < ULONG_MAX, so this is okay.
+        num_bins = (unsigned long) max + 1,
+        num_rand = (unsigned long) RAND_MAX + 1,
+        bin_size = num_rand / num_bins,
+        defect   = num_rand % num_bins;
+
+    unsigned int seed;
+    FILE* urandom = fopen("/dev/urandom", "r");
+    fread(&seed, sizeof(int), 1, urandom);
+    fclose(urandom);
+    srandom(seed);
+
+    long x;
+    do 
+    {
+        x = random();
+    }
+    // This is carefully written not to overflow
+    while (num_rand - defect <= (unsigned long)x);
+
+    // Truncated division is intentional
+    return x/bin_size;
 }
 
 int getSecondsFromLastQuarterInterval(void)
@@ -1170,3 +1178,706 @@ cJSON*  vesCreateFaultFields(char *alarm_condition, char *alarm_object, char *sev
 
        return faultFields;
 }
+
+static cJSON* createSeverityCounters(counterAlarms count)
+{
+    cJSON *severityCounters = cJSON_CreateObject();
+    if (severityCounters == NULL)
+    {
+        printf("Could not create JSON object: severityCounters\n");
+        return NULL;
+    }
+
+    if (cJSON_AddNumberToObject(severityCounters, "severity-normal", count.normal) == NULL)
+    {
+        printf("Could not create JSON object: severity-normal\n");
+        return NULL;
+    }
+
+    if (cJSON_AddNumberToObject(severityCounters, "severity-warning", count.warning) == NULL)
+    {
+        printf("Could not create JSON object: severity-warning\n");
+        return NULL;
+    }
+
+    if (cJSON_AddNumberToObject(severityCounters, "severity-minor", count.minor) == NULL)
+    {
+        printf("Could not create JSON object: severity-minor\n");
+        return NULL;
+    }
+
+    if (cJSON_AddNumberToObject(severityCounters, "severity-major", count.major) == NULL)
+    {
+        printf("Could not create JSON object: severity-major\n");
+        return NULL;
+    }
+
+    if (cJSON_AddNumberToObject(severityCounters, "severity-critical", count.critical) == NULL)
+    {
+        printf("Could not create JSON object: severity-critical\n");
+        return NULL;
+    }
+
+    return severityCounters;
+}
+
+void writeStatusFile(char *status)
+{
+       char status_file[200];
+       sprintf(status_file, "%s/status.json", getenv("SCRIPTS_DIR"));
+       FILE * f = fopen (status_file, "w");
+
+       if (f)
+       {
+               fputs(status, f);
+               fclose(f);
+       }
+       else
+       {
+               printf("Could not write status file!\n");
+       }
+}
+
+int    writeSkeletonStatusFile()
+{
+    cJSON *statusObject = cJSON_CreateObject();
+    if (statusObject == NULL)
+    {
+        printf("Could not create JSON object: statusObject\n");
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    // counterAlarms counter = {
+    //     .normal = 0,
+    //     .warning = 0,
+    //     .minor = 0,
+    //     .major = 0,
+    //     .critical = 0
+    // };
+
+    // cJSON *totalVesNotifications = createSeverityCounters(counter);
+    // if (totalVesNotifications == NULL)
+    // {
+    //     printf("Could not create JSON object: totalVesNotifications\n");
+    //     cJSON_Delete(statusObject);
+    //     return SR_ERR_OPERATION_FAILED;
+    // }
+    // cJSON_AddItemToObject(statusObject, "total-ves-notifications-sent", totalVesNotifications);
+
+    // cJSON *totalNetconfNotifications = createSeverityCounters(counter);
+    // if (totalNetconfNotifications == NULL)
+    // {
+    //     printf("Could not create JSON object: totalNetconfNotifications\n");
+    //     cJSON_Delete(statusObject);
+    //     return SR_ERR_OPERATION_FAILED;
+    // }
+    // cJSON_AddItemToObject(statusObject, "total-netconf-notifications-sent", totalNetconfNotifications);
+
+    cJSON *deviceList = cJSON_CreateArray();
+    if (deviceList == NULL)
+    {
+        printf("Could not create JSON object: deviceList\n");
+        cJSON_Delete(statusObject);
+        return SR_ERR_OPERATION_FAILED;
+       }
+    cJSON_AddItemToObject(statusObject, "device-list", deviceList);
+
+    char *status_string = NULL;
+
+    status_string = cJSON_PrintUnformatted(statusObject);
+
+    writeStatusFile(status_string);
+
+    return SR_ERR_OK;
+}
+
+/*
+ * Dynamically allocated memory;
+ * Caller needs to free the memory after it uses the value.
+ *
+*/
+char*  readStatusFileInString(void)
+{
+       char * buffer = 0;
+       long length;
+       char config_file[200];
+       sprintf(config_file, "%s/status.json", getenv("SCRIPTS_DIR"));
+       FILE * f = fopen (config_file, "rb");
+
+       if (f)
+       {
+         fseek (f, 0, SEEK_END);
+         length = ftell (f);
+         fseek (f, 0, SEEK_SET);
+         buffer = malloc (length + 1);
+         if (buffer)
+         {
+           fread (buffer, 1, length, f);
+         }
+         fclose (f);
+         buffer[length] = '\0';
+       }
+
+       if (buffer)
+       {
+         return buffer;
+       }
+
+       return NULL;
+}
+
+/*
+ * Dynamically allocated memory;
+ * Caller needs to free the memory after it uses the value.
+ *
+*/
+cJSON*  getDeviceListFromStatusFile(void)
+{
+    char *stringStatus = readStatusFileInString();
+
+       if (stringStatus == NULL)
+       {
+               printf("Could not read status file!\n");
+               return NULL;
+       }
+
+       cJSON *jsonStatus = cJSON_Parse(stringStatus);
+       if (jsonStatus == NULL)
+       {
+               free(stringStatus);
+               const char *error_ptr = cJSON_GetErrorPtr();
+               if (error_ptr != NULL)
+               {
+                       fprintf(stderr, "Could not parse JSON status! Error before: %s\n", error_ptr);
+               }
+               return NULL;
+       }
+       //we don't need the string anymore
+       free(stringStatus);
+       stringStatus = NULL;
+
+    return jsonStatus;
+}
+
+cJSON* createDeviceListEntry(counterAlarms ves_counter, counterAlarms netconf_counter)
+{
+    cJSON *deviceListEntry = cJSON_CreateObject();
+    if (deviceListEntry == NULL)
+    {
+        printf("Could not create JSON object: deviceListEntry\n");
+        return NULL;
+    }
+
+    char hostname[100];
+    sprintf(hostname, "%s", getenv("HOSTNAME"));
+
+    if (cJSON_AddStringToObject(deviceListEntry, "device-name", hostname) == NULL)
+    {
+        printf("Could not create JSON object: device-name\n");
+        cJSON_Delete(deviceListEntry);
+        return NULL;
+    }
+
+    cJSON *vesNotificationsSent = createSeverityCounters(ves_counter);
+    if (vesNotificationsSent == NULL)
+    {
+        printf("Could not create JSON object: vesNotificationsSent\n");
+        cJSON_Delete(deviceListEntry);
+        return NULL;
+    }
+    cJSON_AddItemToObject(deviceListEntry, "ves-notifications-sent", vesNotificationsSent);
+
+    cJSON *netconfNotificationsSent = createSeverityCounters(netconf_counter);
+    if (netconfNotificationsSent == NULL)
+    {
+        printf("Could not create JSON object: netconfNotificationsSent\n");
+        cJSON_Delete(deviceListEntry);
+        return NULL;
+    }
+    cJSON_AddItemToObject(deviceListEntry, "netconf-notifications-sent", netconfNotificationsSent);
+
+    return deviceListEntry;
+}
+
+static void modifySeverityCounters(cJSON **severityCounters, counterAlarms count)
+{
+    cJSON *severity= cJSON_GetObjectItemCaseSensitive(*severityCounters, "severity-normal");
+    if (!cJSON_IsNumber(severity))
+    {
+        printf("Status JSON is not as expected: severity-normal is not an number");
+        return;
+    }
+    //we set the value of the severity-normal object
+    cJSON_SetNumberValue(severity, count.normal);
+
+    severity= cJSON_GetObjectItemCaseSensitive(*severityCounters, "severity-warning");
+    if (!cJSON_IsNumber(severity))
+    {
+        printf("Status JSON is not as expected: severity-warning is not an number");
+        return;
+    }
+    //we set the value of the severity-warning object
+    cJSON_SetNumberValue(severity, count.warning);
+
+    severity= cJSON_GetObjectItemCaseSensitive(*severityCounters, "severity-minor");
+    if (!cJSON_IsNumber(severity))
+    {
+        printf("Status JSON is not as expected: severity-minor is not an number");
+        return;
+    }
+    //we set the value of the severity-minor object
+    cJSON_SetNumberValue(severity, count.minor);
+
+    severity= cJSON_GetObjectItemCaseSensitive(*severityCounters, "severity-major");
+    if (!cJSON_IsNumber(severity))
+    {
+        printf("Status JSON is not as expected: severity-major is not an number");
+        return;
+    }
+    //we set the value of the severity-major object
+       cJSON_SetNumberValue(severity, count.major);
+
+    severity= cJSON_GetObjectItemCaseSensitive(*severityCounters, "severity-critical");
+    if (!cJSON_IsNumber(severity))
+    {
+        printf("Status JSON is not as expected: severity-critical is not an number");
+        return;
+    }
+    //we set the value of the severity-critical object
+       cJSON_SetNumberValue(severity, count.critical);
+
+    return;
+}
+
+static void modifyDeviceListEntry(cJSON **deviceListEntry, counterAlarms ves_counter, counterAlarms netconf_counter)
+{
+    cJSON *vesNotificationsSent= cJSON_GetObjectItemCaseSensitive(*deviceListEntry, "ves-notifications-sent");
+    if (!cJSON_IsObject(vesNotificationsSent))
+    {
+        printf("Status JSON is not as expected: ves-notifications-sent is not a object");
+        return;
+    }
+
+    modifySeverityCounters(&vesNotificationsSent, ves_counter);
+
+    cJSON *netconfNotificationsSent= cJSON_GetObjectItemCaseSensitive(*deviceListEntry, "netconf-notifications-sent");
+    if (!cJSON_IsObject(netconfNotificationsSent))
+    {
+        printf("Status JSON is not as expected: netconf-notifications-sent is not a object");
+        return;
+    }
+
+    modifySeverityCounters(&netconfNotificationsSent, netconf_counter);
+}
+
+int writeStatusNotificationCounters(counterAlarms ves_counter, counterAlarms netconf_counter)
+{
+       cJSON *jsonStatus = getDeviceListFromStatusFile();
+
+       cJSON *deviceList = cJSON_GetObjectItemCaseSensitive(jsonStatus, "device-list");
+       if (!cJSON_IsArray(deviceList))
+       {
+               printf("Status JSON is not as expected: device-list is not an object");
+               cJSON_Delete(jsonStatus);
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+    int array_size = cJSON_GetArraySize(deviceList);
+
+    int found = 0;
+    for (int i=0; i<array_size; ++i)
+    {
+        cJSON *deviceListEntry = cJSON_GetArrayItem(deviceList, i);
+        char hostname[100];
+        sprintf(hostname, "%s", getenv("HOSTNAME"));
+
+        cJSON *deviceName = cJSON_GetObjectItemCaseSensitive(deviceListEntry, "device-name");
+        if (!cJSON_IsString(deviceName))
+        {
+            printf("Status JSON is not as expected: device-name is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        char *deviceNameString = cJSON_GetStringValue(deviceName);
+
+        if (strcmp(hostname, deviceNameString) == 0)
+        {
+            modifyDeviceListEntry(&deviceListEntry, ves_counter, netconf_counter);
+            found = 1;
+            break;
+        }
+    }
+    if (found == 0)
+    {
+        cJSON* deviceListEntry = createDeviceListEntry(ves_counter, netconf_counter);
+    
+        cJSON_AddItemToArray(deviceList, deviceListEntry);  
+    }
+
+       //writing the new JSON to the configuration file
+       char *stringStatus = cJSON_PrintUnformatted(jsonStatus);
+       writeStatusFile(stringStatus);
+
+       cJSON_Delete(jsonStatus);
+
+       return SR_ERR_OK;
+}
+
+
+int removeDeviceEntryFromStatusFile(char *containerId)
+{
+    cJSON *jsonStatus = getDeviceListFromStatusFile();
+
+       cJSON *deviceList = cJSON_GetObjectItemCaseSensitive(jsonStatus, "device-list");
+       if (!cJSON_IsArray(deviceList))
+       {
+               printf("Status JSON is not as expected: device-list is not an object");
+               cJSON_Delete(jsonStatus);
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+    int array_size = cJSON_GetArraySize(deviceList);
+    int found = array_size;
+
+    for (int i=0; i<array_size; ++i)
+    {
+        cJSON *deviceListEntry = cJSON_GetArrayItem(deviceList, i);
+        char hostname[100];
+        sprintf(hostname, "%s", getenv("HOSTNAME"));
+
+        cJSON *deviceName = cJSON_GetObjectItemCaseSensitive(deviceListEntry, "device-name");
+        if (!cJSON_IsString(deviceName))
+        {
+            printf("Status JSON is not as expected: device-name is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        char *deviceNameString = cJSON_GetStringValue(deviceName);
+
+        if (strcmp(containerId, deviceNameString) == 0)
+        {
+            found = i;
+            break;
+        }
+    }
+
+    if (found < array_size)
+    {
+        cJSON_DeleteItemFromArray(deviceList, found);
+    }
+    else
+    {
+        printf("Could not find status file entry for device with id=\"%s\"", containerId);
+    }
+
+       //writing the new JSON to the configuration file
+       char *stringStatus = cJSON_PrintUnformatted(jsonStatus);
+       writeStatusFile(stringStatus);
+
+       cJSON_Delete(jsonStatus);
+
+       return SR_ERR_OK;
+}
+
+int compute_notifications_count(counterAlarms *ves_counter, counterAlarms *netconf_counter)
+{
+    ves_counter->normal = ves_counter->warning = \
+            ves_counter->minor = ves_counter->major = \
+            ves_counter->critical = 0;
+    netconf_counter->normal = netconf_counter->warning = \
+            netconf_counter->minor = netconf_counter->major = \
+            netconf_counter->critical = 0;
+
+    cJSON *jsonStatus = getDeviceListFromStatusFile();
+
+    cJSON *deviceList = cJSON_GetObjectItemCaseSensitive(jsonStatus, "device-list");
+       if (!cJSON_IsArray(deviceList))
+       {
+               printf("Status JSON is not as expected: device-list is not an object");
+               cJSON_Delete(jsonStatus);
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+    int array_size = cJSON_GetArraySize(deviceList);
+
+    for (int i=0; i<array_size; ++i)
+    {
+        cJSON *deviceListEntry = cJSON_GetArrayItem(deviceList, i);
+
+        cJSON *vesNotifications = cJSON_GetObjectItemCaseSensitive(deviceListEntry, "ves-notifications-sent");
+        if (!cJSON_IsObject(vesNotifications))
+        {
+            printf("Status JSON is not as expected: ves-notifications-sent is not an object.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+
+        cJSON *severity = cJSON_GetObjectItemCaseSensitive(vesNotifications, "severity-normal");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-normal is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        int counter = (int)(severity->valuedouble);
+        ves_counter->normal += counter;
+
+        severity = cJSON_GetObjectItemCaseSensitive(vesNotifications, "severity-warning");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-warning is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        counter = (int)(severity->valuedouble);
+        ves_counter->warning += counter;
+
+        severity = cJSON_GetObjectItemCaseSensitive(vesNotifications, "severity-minor");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-minor is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        counter = (int)(severity->valuedouble);
+        ves_counter->minor += counter;
+
+        severity = cJSON_GetObjectItemCaseSensitive(vesNotifications, "severity-major");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-major is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        counter = (int)(severity->valuedouble);
+        ves_counter->major += counter;
+
+        severity = cJSON_GetObjectItemCaseSensitive(vesNotifications, "severity-critical");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-critical is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        counter = (int)(severity->valuedouble);
+        ves_counter->critical += counter;
+
+        cJSON *netconfNotifications = cJSON_GetObjectItemCaseSensitive(deviceListEntry, "netconf-notifications-sent");
+        if (!cJSON_IsObject(netconfNotifications))
+        {
+            printf("Status JSON is not as expected: netconf-notifications-sent is not an object.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+
+        severity = cJSON_GetObjectItemCaseSensitive(netconfNotifications, "severity-normal");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-normal is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        
+        counter = (int)(severity->valuedouble);
+        netconf_counter->normal += (counter * NETCONF_CONNECTIONS_PER_DEVICE);
+
+        severity = cJSON_GetObjectItemCaseSensitive(netconfNotifications, "severity-warning");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-warning is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        counter = (int)(severity->valuedouble);
+        netconf_counter->warning += (counter * NETCONF_CONNECTIONS_PER_DEVICE);
+
+        severity = cJSON_GetObjectItemCaseSensitive(netconfNotifications, "severity-minor");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-minor is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        counter = (int)(severity->valuedouble);
+        netconf_counter->minor += (counter * NETCONF_CONNECTIONS_PER_DEVICE);
+
+        severity = cJSON_GetObjectItemCaseSensitive(netconfNotifications, "severity-major");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-major is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        counter = (int)(severity->valuedouble);
+        netconf_counter->major += (counter * NETCONF_CONNECTIONS_PER_DEVICE);
+
+        severity = cJSON_GetObjectItemCaseSensitive(netconfNotifications, "severity-critical");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-critical is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        counter = (int)(severity->valuedouble);
+        netconf_counter->critical += (counter * NETCONF_CONNECTIONS_PER_DEVICE);
+    }
+
+    cJSON_Delete(jsonStatus);
+
+    return SR_ERR_OK;
+}
+
+int getDeviceCounters(char *containerId, counterAlarms *ves_counter, counterAlarms *netconf_counter)
+{
+    cJSON *jsonStatus = getDeviceListFromStatusFile();
+
+    cJSON *deviceList = cJSON_GetObjectItemCaseSensitive(jsonStatus, "device-list");
+       if (!cJSON_IsArray(deviceList))
+       {
+               printf("Status JSON is not as expected: device-list is not an object");
+               cJSON_Delete(jsonStatus);
+               return SR_ERR_OPERATION_FAILED;
+       }
+
+    int array_size = cJSON_GetArraySize(deviceList);
+
+    for (int i=0; i<array_size; ++i)
+    {
+        cJSON *deviceListEntry = cJSON_GetArrayItem(deviceList, i);
+
+        cJSON *deviceName = cJSON_GetObjectItemCaseSensitive(deviceListEntry, "device-name");
+        if (!cJSON_IsString(deviceName))
+        {
+            printf("Status JSON is not as expected: device-name is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        char *deviceNameString = cJSON_GetStringValue(deviceName);
+
+        if (strcmp(deviceNameString, containerId) != 0)
+        {
+            continue;
+        }
+
+        cJSON *vesNotifications = cJSON_GetObjectItemCaseSensitive(deviceListEntry, "ves-notifications-sent");
+        if (!cJSON_IsObject(vesNotifications))
+        {
+            printf("Status JSON is not as expected: ves-notifications-sent is not an object.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+
+        cJSON *severity = cJSON_GetObjectItemCaseSensitive(vesNotifications, "severity-normal");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-normal is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        int counter = (int)(severity->valuedouble);
+        ves_counter->normal = counter;
+
+        severity = cJSON_GetObjectItemCaseSensitive(vesNotifications, "severity-warning");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-warning is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        counter = (int)(severity->valuedouble);
+        ves_counter->warning = counter;
+
+        severity = cJSON_GetObjectItemCaseSensitive(vesNotifications, "severity-minor");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-minor is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        counter = (int)(severity->valuedouble);
+        ves_counter->minor = counter;
+
+        severity = cJSON_GetObjectItemCaseSensitive(vesNotifications, "severity-major");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-major is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        counter = (int)(severity->valuedouble);
+        ves_counter->major = counter;
+
+        severity = cJSON_GetObjectItemCaseSensitive(vesNotifications, "severity-critical");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-critical is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        counter = (int)(severity->valuedouble);
+        ves_counter->critical = counter;
+
+        cJSON *netconfNotifications = cJSON_GetObjectItemCaseSensitive(deviceListEntry, "netconf-notifications-sent");
+        if (!cJSON_IsObject(netconfNotifications))
+        {
+            printf("Status JSON is not as expected: netconf-notifications-sent is not an object.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+
+        severity = cJSON_GetObjectItemCaseSensitive(netconfNotifications, "severity-normal");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-normal is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        
+        counter = (int)(severity->valuedouble);
+        netconf_counter->normal = (counter * NETCONF_CONNECTIONS_PER_DEVICE);
+
+        severity = cJSON_GetObjectItemCaseSensitive(netconfNotifications, "severity-warning");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-warning is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        counter = (int)(severity->valuedouble);
+        netconf_counter->warning = (counter * NETCONF_CONNECTIONS_PER_DEVICE);
+
+        severity = cJSON_GetObjectItemCaseSensitive(netconfNotifications, "severity-minor");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-minor is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        counter = (int)(severity->valuedouble);
+        netconf_counter->minor = (counter * NETCONF_CONNECTIONS_PER_DEVICE);
+
+        severity = cJSON_GetObjectItemCaseSensitive(netconfNotifications, "severity-major");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-major is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        counter = (int)(severity->valuedouble);
+        netconf_counter->major = (counter * NETCONF_CONNECTIONS_PER_DEVICE);
+
+        severity = cJSON_GetObjectItemCaseSensitive(netconfNotifications, "severity-critical");
+        if (!cJSON_IsNumber(severity))
+        {
+            printf("Status JSON is not as expected: severity-critical is not a string.");
+            cJSON_Delete(jsonStatus);
+            return SR_ERR_OPERATION_FAILED;
+        }
+        counter = (int)(severity->valuedouble);
+        netconf_counter->critical = (counter * NETCONF_CONNECTIONS_PER_DEVICE);
+    }
+
+    cJSON_Delete(jsonStatus);
+
+    return SR_ERR_OK;
+}
\ No newline at end of file
index ac2cf8d..32570eb 100644 (file)
@@ -16,6 +16,13 @@ module network-topology-simulator {
   description
     "This module contains a collection of YANG definitions for managing the Network Topology Simulator.";
 
+  
+  revision 2020-04-10 {
+    description
+      "Add notification count in status.";
+    reference
+      "O-RAN SC SIM project";
+  }
   revision 2019-10-25 {
     description
       "Modify notifications. Add VES message configuration options.";
@@ -145,6 +152,36 @@ module network-topology-simulator {
       "none";
   }
 
+  grouping notification-count-per-severity-g {
+    leaf normal {
+    type uint32;
+    description
+    "The number of normal notifications.";
+    }
+    leaf warning {
+    type uint32;
+    description
+    "The number of warning notifications.";
+    }
+    leaf minor {
+    type uint32;
+    description
+    "The number of minor notifications.";
+    }
+    leaf major {
+    type uint32;
+    description
+    "The number of major notifications.";
+    }
+    leaf critical {
+    type uint32;
+    description
+    "The number of normal notifications.";
+    }
+    description
+      "none";
+  }
+
   container simulator-config {
     description
       "Configuration container of the simulator.";
@@ -274,10 +311,46 @@ module network-topology-simulator {
       description
         "The details about the simulation, including resources consumed.";
     }
+    container notification-count {
+        config false;
+        container total-ves-notifications {
+            config false;
+            uses  notification-count-per-severity-g;
+            description
+              "The total number of VES notifications that were sent by all the simulated devices managed by this NTS Manager instance.";
+        }
+        container total-netconf-notifications {
+            config false;
+            uses  notification-count-per-severity-g;
+            description
+              "The total number of NETCONF notifications that were sent by all the simulated devices managed by this NTS Manager instance.";
+        }
+        description 
+          "The total number of notifications sent by the devices managed by this NTS Manager instance.";
+        
+    }
     list simulated-devices-list {
       key "uuid";
       config false;
       uses simulated-devices-type-g;
+      container notification-count {
+        config false;
+        container ves-notifications {
+            config false;
+            uses  notification-count-per-severity-g;
+            description
+              "The total number of VES notifications that were sent by this simulated device.";
+        }
+        container netconf-notifications {
+            config false;
+            uses  notification-count-per-severity-g;
+            description
+              "The total number of NETCONF notifications that were sent by this simulated device.";
+        }
+        description 
+          "The total number of notifications sent by this simulated device.";
+        
+    }
       description
         "The list of the devices that are currently simulated.";
     }
index 8c41b40..71ba5d4 100755 (executable)
@@ -20,16 +20,6 @@ sleep 20
 
 echo "Loading data into sysrepo..."
 
-#SSH_PUB_KEY="$(cat /home/netconf/.ssh/id_dsa.pub| awk '{print $2}')"
-
-#echo '<system xmlns="urn:ietf:params:xml:ns:yang:ietf-system"><authentication><user><name>netconf</name><authorized-key><name>ssh_key</name><algorithm>ssh-dss</algorithm>' >> load_auth_pubkey.xml
-#echo '<key-data>'"$SSH_PUB_KEY"'</key-data></authorized-key></user></authentication></system>' >> load_auth_pubkey.xml
-
-#sysrepocfg --merge=load_auth_pubkey.xml --format=xml ietf-system
-#rm load_auth_pubkey.xml
-#
-#ssh-keyscan -p 830 localhost >> ~/.ssh/known_hosts
-
 pyang -f sample-xml-skeleton --sample-xml-list-entries 2 *.yang
 
 result=$(netopeer2-cli <<-END