Add VES stndDefined PM and subscription for O-DU.
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / datastore / populate.c
index 19f6ee9..c083b1f 100644 (file)
@@ -1,6 +1,6 @@
 /*************************************************************************
 *
-* Copyright 2020 highstreet technologies GmbH and others
+* Copyright 2021 highstreet technologies GmbH and others
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * limitations under the License.
 ***************************************************************************/
 
-#define _GNU_SOURCE
-
 #include "populate.h"
+#include "populate_internal.h"
 #include "utils/log_utils.h"
+#include "utils/debug_utils.h"
 #include "utils/rand_utils.h"
 #include "utils/type_utils.h"
-#include <stdio.h>
-#include <assert.h>
-
-#include "core/session.h"
-#include "core/framework.h"
 
 #include "core/datastore/schema.h"
+#include "core/datastore/operations.h"
+#include "core/framework.h"
+#include "core/session.h"
 
-static int schema_populate_late_resolve(populate_job_t *job);
-static int schema_populate_validate(populate_instance_t *instance, int count);
-static int schema_populate_commit_to_datastore(populate_job_t *job);
-
-int schema_populate(void) {
-    assert_session();
-
-    log_message(1, LOG_COLOR_BOLD_YELLOW"schema_populate() begin\n"LOG_COLOR_RESET);
+#include <sysrepo.h>
+#include <libyang/libyang.h>
 
-    char **xpaths = 0;
-    int instance_count = schema_get_xpaths(&xpaths);
-    if(instance_count < 0) {
-        log_error("schema_get_xpaths failed");
-        return NTS_ERR_FAILED;
-    }
+#include <stdlib.h>
+#include <assert.h>
 
-    populate_job_t job;
-    job.operational = 0;
-    job.running = 0;
-    job.late_resolve_count = 0;
-    job.late_resolve_instance = 0;
-    job.late_resolve_schema = 0;
-    job.late_resolve_parent_o = 0;
-    job.late_resolve_parent_r = 0;
-    job.late_resolving = false;
-
-    populate_instance_t *instance = (populate_instance_t *)malloc(sizeof(populate_instance_t) * instance_count);
-    if(!instance) {
-        log_error("bad malloc");
-        return NTS_ERR_FAILED;
-    }
-    
-    //populate everything
-    for(int i = 0; i < instance_count; i++) {
-        log_message(1, "populating "LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" with data...\n", xpaths[i]);
+populate_job_t populate_job = {0};
 
-        struct lys_node *schema_node = (struct lys_node *)ly_ctx_get_node(session_context, 0, xpaths[i], 0);
-        if(schema_node == 0) {
-            log_error("ly_ctx_get_node failed for %s", xpaths[i]);
-            return NTS_ERR_FAILED;
-        }
+int datastore_populate_all() {
+    log_add_verbose(1, "populate starting...\n");
 
-        if(schema_node == 0) {
-            log_message(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
-            log_error("ly_ctx_get_node failed for %s", xpaths[i]);
-            return NTS_ERR_FAILED;
+    //load pre-populated data
+    for(int i = 0; i < framework_config.datastore_populate.preg_running_count; i++) {
+        char *filename = framework_config.datastore_populate.preg_running[i];
+        struct lyd_node *data = datastore_load_external(filename, false);
+        if(data == 0) {
+            log_add_verbose(2, "datastore_load_external() could not load %s\n", filename);
         }
+        else {
+            log_add_verbose(1, "loaded into running %s (%s)\n", filename, data->schema->module->name);
+            if(populate_job.running) {
+                int rc = lyd_merge(populate_job.running, data, 0);
+                if(rc != 0) {
+                    log_error("lyd_merge failed\n");
+                }
 
-        if(!schema_node->module->implemented) {
-            log_message(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
-            log_error("module is not implemented for %s", xpaths[i]);
-            return NTS_ERR_FAILED;
+                lyd_free_withsiblings(data);
+            }
+            else {
+                populate_job.running = data;
+            }
         }
 
-        if((schema_node->flags & LYS_STATUS_DEPRC) != 0) {
-            log_message(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
-            log_error("module is deprecated for %s", xpaths[i]);
-            return NTS_ERR_FAILED;
+        //also load as dev
+        data = datastore_load_external(filename, false);
+        if(data == 0) {
+            log_add_verbose(2, "datastore_load_external() could not load %s\n", filename);
         }
+        else {
+            log_add_verbose(1, "loaded into dev %s (%s)\n", filename, data->schema->module->name);
+            if(populate_job.dev) {
+                int rc = lyd_merge(populate_job.dev, data, 0);
+                if(rc != 0) {
+                    log_error("lyd_merge failed\n");
+                }
 
-        //populate current instance vals
-        instance[i].init = 0;
-        instance[i].xpath = strdup(xpaths[i]);
-        instance[i].modules = 0;
-        instance[i].mod_count = 0;
-        instance[i].operational = 0;
-        instance[i].running = 0;
-        
-        //do the actual population
-        int rc = schema_populate_recursive(&job, &instance[i], schema_node, 0, 0);
-        if(rc != NTS_ERR_OK) {
-            log_error("schema_populate_recursive failed instance %d with xpath %s", i, instance[i].xpath);
-            return rc;
+                lyd_free_withsiblings(data);
+            }
+            else {
+                populate_job.dev = data;
+            }
         }
     }
 
-    //link everything so we would be able to find everything in late-resolve
-    log_message(1, LOG_COLOR_BOLD_YELLOW"schema_populate() done populating, now linking... (%d root nodes)\n"LOG_COLOR_RESET, instance_count);
-    for(int i = 0; i < instance_count; i++) {
-
-        if(instance[i].operational) {
-            if(job.operational) {
-                int rc = lyd_insert_sibling(&job.operational, instance[i].operational);
+    for(int i = 0; i < framework_config.datastore_populate.preg_operational_count; i++) {
+        char *filename = framework_config.datastore_populate.preg_operational[i];
+        struct lyd_node *data = datastore_load_external(filename, true);
+        if(data == 0) {
+            log_add_verbose(2, "datastore_load_external() could not load %s\n", filename);
+        }
+        else {
+            log_add_verbose(1, "loaded into operational %s (%s)\n", filename, data->schema->module->name);
+            if(populate_job.operational) {
+                int rc = lyd_merge(populate_job.operational, data, 0);
                 if(rc != 0) {
-                    log_error("lyd_insert_sibling");
-                    return NTS_ERR_FAILED;
+                    log_error("lyd_merge failed\n");
                 }
+
+                lyd_free_withsiblings(data);
             }
             else {
-                job.operational = instance[i].operational;
+                populate_job.operational = data;
             }
         }
 
-        if(instance[i].running) {
-            if(job.running) {
-                int rc = lyd_insert_sibling(&job.running, instance[i].running);
+        //also load as dev
+        data = datastore_load_external(filename, true);
+        if(data == 0) {
+            log_add_verbose(2, "datastore_load_external() could not load %s\n", filename);
+        }
+        else {
+            log_add_verbose(1, "loaded into dev %s (%s)\n", filename, data->schema->module->name);
+            if(populate_job.dev) {
+                int rc = lyd_merge(populate_job.dev, data, 0);
                 if(rc != 0) {
-                    log_error("lyd_insert_sibling");
-                    return NTS_ERR_FAILED;
+                    log_error("lyd_merge failed\n");
                 }
+
+                lyd_free_withsiblings(data);
             }
             else {
-                job.running = instance[i].running;
+                populate_job.dev = data;
             }
         }
     }
 
-    //late-resolve
-    log_message(1, LOG_COLOR_BOLD_YELLOW"schema_populate() starting late-resolve process...\n"LOG_COLOR_RESET);
-    if(job.late_resolve_count) {
-        int rc = schema_populate_late_resolve(&job);
-        if(rc != NTS_ERR_OK) {
-            log_error("schema_populate_late_resolve failed");
-            return rc;
+    if(framework_config.datastore_populate.random_generation_enabled) {
+        //get all xpaths
+        char **xpaths = 0;
+        int xpaths_count = datastore_schema_get_xpaths(&xpaths);
+        if(xpaths_count < 0) {
+            log_error("datastore_schema_get_xpaths failed\n");
+            return NTS_ERR_FAILED;
         }
-    }
-    
-    //validate data and remove invalid nodes
-    log_message(1, LOG_COLOR_BOLD_YELLOW"schema_populate() validating\n"LOG_COLOR_RESET);
-    int rc = schema_populate_validate(instance, instance_count);
-    if(rc != NTS_ERR_OK) {
-        log_error("schema_populate_commit_to_datastore failed");
-        return rc;
-    }
-
-    //commit to datastore
-    log_message(1, LOG_COLOR_BOLD_YELLOW"schema_populate() commiting to datastore\n"LOG_COLOR_RESET);
-    rc = schema_populate_commit_to_datastore(&job);
-    if(rc != NTS_ERR_OK) {
-        log_error("schema_populate_commit_to_datastore failed");
-        return rc;
-    }
-
-    //cleanup
-    log_message(1, LOG_COLOR_BOLD_YELLOW"schema_populate() cleaning up... "LOG_COLOR_RESET);
-    for(int i = 0; i < instance_count; i++) {
-        log_message(1, "%d ", i);
-
-        free(instance[i].modules);
-        free(instance[i].xpath);
 
-        free(xpaths[i]);
-    }
-    free(xpaths);
-    free(job.late_resolve_instance);
-    free(job.late_resolve_schema);
-    free(job.late_resolve_parent_o);
-    free(job.late_resolve_parent_r);
-
-    lyd_free_withsiblings(job.operational);
-    lyd_free_withsiblings(job.running);
-        
-    log_message(1, "\n");
-    log_message(1, LOG_COLOR_BOLD_GREEN"schema_populate() finished\n"LOG_COLOR_RESET);
-    
-    return NTS_ERR_OK;
-}
+        //exclude pre-populated modules; also modules excluded by config are not outputted by datastore_schema_get_xpaths
+        struct lyd_node *elem;
+        LY_TREE_FOR(populate_job.dev, elem) {
+            for(int i = 0; i < xpaths_count; i++) {
+                if(strstr(xpaths[i], elem->schema->module->name) == (xpaths[i] + 1)) {  //xpaths[i] is "/module:container"
+                    log_add_verbose(1, "excluding "LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" as being pre-populated...\n", xpaths[i]);
+                    free(xpaths[i]);
+
+                    xpaths_count--;
+                    for(int j = i; j < xpaths_count; j++) {
+                        xpaths[j] = xpaths[j + 1];
+                    }
 
-static int schema_populate_late_resolve(populate_job_t *job) {
-    assert(job);
+                    break;
+                }
+            }
+        }
 
-    job->late_resolving = true;
-    for(int i = 0; i < job->late_resolve_count; i++) {
-        log_message(1, LOG_COLOR_BOLD_YELLOW"late-populating "LOG_COLOR_RESET": ");
-        int rc = schema_populate_add_leaf(job, job->late_resolve_instance[i], job->late_resolve_schema[i], job->late_resolve_parent_o[i], job->late_resolve_parent_r[i]);
-        if(rc != NTS_ERR_OK) {
-            log_error("schema_populate_add_leaf failed on late-resolve");
-            return rc;
+        populate_instance_t *instance = (populate_instance_t *)malloc(sizeof(populate_instance_t) * xpaths_count);
+        if(!instance) {
+            log_error("bad malloc\n");
+            for(int i = 0; i < xpaths_count; i++) {
+                free(xpaths[i]);
+            }
+            free(xpaths);
+            return NTS_ERR_FAILED;
         }
-    }
-    job->late_resolving = false;
 
-    return NTS_ERR_OK;
-}
+        //RANDOM generate everything
+        for(int i = 0; i < xpaths_count; i++) {
+            log_add_verbose(1, "generating "LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" data...\n", xpaths[i]);
 
-static int schema_populate_validate(populate_instance_t *instance, int count) {
-    assert_session();
-    assert(instance);
+            struct lys_node *schema_node = (struct lys_node *)ly_ctx_get_node(session_context, 0, xpaths[i], 0);
+            if(schema_node == 0) {
+                log_error("ly_ctx_get_node failed for %s\n", xpaths[i]);
+                return NTS_ERR_FAILED;
+            }
 
-    int rc = 0;
-    int commit_ok = NTS_ERR_OK;
+            if(!schema_node->module->implemented) {
+                log_add_verbose(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
+                log_error("module is not implemented for %s\n", xpaths[i]);
+                return NTS_ERR_FAILED;
+            }
 
-    for(int i = 0; i < count; i++) {
-        if(instance[i].operational) {
-            log_message(2, "available modules:");
-            for(int j = 0; j < instance[i].mod_count; j++) {
-                log_message(2, " %s", instance[i].modules[j]->name);
+            if((schema_node->flags & LYS_STATUS_DEPRC) != 0) {
+                log_add_verbose(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
+                log_error("module is deprecated for %s\n", xpaths[i]);
+                return NTS_ERR_FAILED;
             }
-            log_message(2, "\n");
-            log_message(1, "validating OPERATIONAL for [%d] : %s... ", i, instance[i].xpath);
-
-            int solved_instance_errors = 1;
-            int solved_errors = 0;
-            bool success = false;
-            while(instance[i].operational && solved_instance_errors) {
-                solved_instance_errors = 0;
-                rc = lyd_validate_modules(&instance[i].operational, instance[i].modules, instance[i].mod_count, LYD_OPT_DATA, 0);
-                if(rc == 0) {
-                    log_message(1, LOG_COLOR_BOLD_GREEN"success (%d)\n"LOG_COLOR_RESET, solved_errors);
-                    success = true;
-                    break;
-                }
-                else {
-                    log_message(2, "\n");
-
-                    struct ly_err_item *err = ly_err_first(session_context);
-                    while(err) {
-                        if((err->vecode == LYVE_NOWHEN) || (err->vecode == LYVE_NOMUST) || (err->vecode == LYVE_NOCONSTR) || (err->vecode == LYVE_NOLEAFREF) || (err->vecode == LYVE_NOMIN) || (err->vecode == LYVE_INVAL)) {
-                            struct ly_set *set = lyd_find_path(instance[i].operational, err->path);
-                            if(set && set->number) {
-                                log_message(2, "operational error code %d on path %s with msg %s\n", err->vecode, err->path, err->msg);
-                                log_message(2, LOG_COLOR_BOLD_RED"  [WHEN-DELETE O]"LOG_COLOR_RESET" %s ... ", err->path);
-
-                                bool mandatory = false;
-                                if((set->set.d[0]->schema->flags & LYS_MAND_TRUE) != 0) {
-                                    mandatory = true;
-                                }
-
-                                if((set->set.d[0]->schema->parent) && (set->set.d[0]->schema->parent->nodetype == LYS_CASE)) {
-                                    if((set->set.d[0]->schema->parent->flags & LYS_MAND_TRUE) != 0) {
-                                        mandatory = true;
-                                    }
-                                }
-
-                                if((set->set.d[0]->dflt != 0) || (lys_is_key((const struct lys_node_leaf *)set->set.d[0]->schema, 0)) || (mandatory) || (err->vecode == LYVE_NOMIN)) {
-                                    //delete whole parent
-                                    log_message(2, "deleted parent : %s\n", lyd_path(set->set.d[0]->parent));
-                                    struct lyd_node *p = set->set.d[0]->parent;
-                                    lyd_free_withsiblings(set->set.d[0]);
-                                    lyd_free(p);
-                                    if(p == instance[i].operational) {
-                                        log_message(1, "instance became empty "LOG_COLOR_BOLD_GREEN"success\n"LOG_COLOR_RESET);
-                                        success = true;
-                                        instance[i].operational = 0;
-                                        break;
-                                    }
-                                }
-                                else {
-                                    //delete THIS node only
-                                    lyd_free(set->set.d[0]);
-                                    log_message(2, "deleted\n");
-                                    if(set->set.d[0] == instance[i].operational) {
-                                        log_message(1, "instance became empty "LOG_COLOR_BOLD_GREEN"success\n"LOG_COLOR_RESET);
-                                        success = true;
-                                        instance[i].operational = 0;
-                                        break;
-                                    }
-                                }
-                                solved_instance_errors++;
-
-                                ly_set_free(set);
-                            }
-                        }
-                        else if((err->vecode != 0) && (err->vecode != 29)) {
-                            log_message(2, "operational error code %d on path %s with msg %s\n", err->vecode, err->path, err->msg);
-                        }
-
-                        err = err->next;
-                    }
-                    ly_err_clean(session_context, 0);
-                }
 
-                solved_errors += solved_instance_errors;
+            //populate current instance vals
+            instance[i].init = 0;
+            instance[i].xpath = strdup(xpaths[i]);
+            instance[i].modules = 0;
+            instance[i].mod_count = 0;
+            instance[i].operational = 0;
+            instance[i].running = 0;
+            instance[i].dev = 0;
+            
+            //do the actual population
+            int rc = populate_recursive(&populate_job, &instance[i], schema_node, 0, 0, 0, 0);
+            if(rc != NTS_ERR_OK) {
+                log_error("populate_recursive failed instance %d with xpath %s\n", i, instance[i].xpath);
+                return rc;
             }
+        }
 
-            if(!success) {
-                if(!solved_errors) {
-                    log_message(1, LOG_COLOR_BOLD_YELLOW"failed"LOG_COLOR_RESET"\n%s\n", ly_errmsg(session_context));
+        //link everything so we would be able to find everything in late-resolve
+        log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"datastore_populate_data() done generating, now linking... (%d root nodes)\n"LOG_COLOR_RESET, xpaths_count);
+        for(int i = 0; i < xpaths_count; i++) {
+            if(instance[i].dev) {
+                if(populate_job.dev) {
+                    int rc = lyd_insert_sibling(&populate_job.dev, instance[i].dev);
+                    if(rc != 0) {
+                        log_error("lyd_insert_sibling\n");
+                        return NTS_ERR_FAILED;
+                    }
                 }
                 else {
-                    log_message(1, LOG_COLOR_BOLD_YELLOW"partially solved (%d)"LOG_COLOR_RESET"\n", solved_errors);
+                    populate_job.dev = instance[i].dev;
                 }
             }
-        }
 
-        if(instance[i].running) {
-            log_message(1, "validating RUNNING... for [%d] : %s... ", i, instance[i].xpath);
-
-            int solved_instance_errors = 1;
-            int solved_errors = 0;
-            bool success = false;
-            while(instance[i].running && solved_instance_errors) {
-                solved_instance_errors = 0;
-                rc = lyd_validate_modules(&instance[i].running, instance[i].modules, instance[i].mod_count, LYD_OPT_CONFIG, 0);
-                if(rc == 0) {
-                    log_message(1, LOG_COLOR_BOLD_GREEN"success (%d)\n"LOG_COLOR_RESET, solved_errors);
-                    success = true;
-                    break;
+            if(instance[i].operational) {
+                if(populate_job.operational) {
+                    int rc = lyd_insert_sibling(&populate_job.operational, instance[i].operational);
+                    if(rc != 0) {
+                        log_error("lyd_insert_sibling\n");
+                        return NTS_ERR_FAILED;
+                    }
                 }
                 else {
-                    log_message(2, "\n");
-
-                    struct ly_err_item *err = ly_err_first(session_context);
-                    while(err) {
-                        if((err->vecode == LYVE_NOWHEN) || (err->vecode == LYVE_NOMUST) || (err->vecode == LYVE_NOCONSTR) || (err->vecode == LYVE_NOLEAFREF) || (err->vecode == LYVE_NOMIN) || (err->vecode == LYVE_INVAL)) {
-                            struct ly_set *set = lyd_find_path(instance[i].running, err->path);
-                            if(set && set->number) {
-                                log_message(2, "running error code %d on path %s with msg %s\n", err->vecode, err->path, err->msg);
-                                log_message(2, LOG_COLOR_BOLD_RED"  [WHEN-DELETE R]"LOG_COLOR_RESET" %s ... ", err->path);
-
-                                bool mandatory = false;
-                                if((set->set.d[0]->schema->flags & LYS_MAND_TRUE) != 0) {
-                                    mandatory = true;
-                                }
-
-                                if((set->set.d[0]->schema->parent) && (set->set.d[0]->schema->parent->nodetype == LYS_CASE)) {
-                                    if((set->set.d[0]->schema->parent->flags & LYS_MAND_TRUE) != 0) {
-                                        mandatory = true;
-                                    }
-                                }
-
-                                if((set->set.d[0]->dflt != 0) || (lys_is_key((const struct lys_node_leaf *)set->set.d[0]->schema, 0)) || (mandatory) || (err->vecode == LYVE_NOMIN))  {
-                                    //delete whole parent
-                                    log_message(2, "deleted parent : %s\n", lyd_path(set->set.d[0]->parent));
-                                    struct lyd_node *p = set->set.d[0]->parent;
-                                    lyd_free_withsiblings(set->set.d[0]);
-                                    lyd_free(p);
-
-                                    if(p == instance[i].running) {
-                                        log_message(1, "instance became empty "LOG_COLOR_BOLD_GREEN"success\n"LOG_COLOR_RESET);
-                                        success = true;
-                                        instance[i].running = 0;
-                                        break;
-                                    }
-                                }
-                                else {
-                                    //delete THIS node only
-                                    lyd_free(set->set.d[0]);
-                                    log_message(2, "deleted\n");
-                                    if(set->set.d[0] == instance[i].running) {
-                                        log_message(1, "instance became empty "LOG_COLOR_BOLD_GREEN"success\n"LOG_COLOR_RESET);
-                                        success = true;
-                                        instance[i].running = 0;
-                                        break;
-                                    }
-                                }
-                                solved_instance_errors++;
-
-                                ly_set_free(set);
-                            }
-                        }
-                        else if((err->vecode != 0) && (err->vecode != 29)) {
-                            log_message(2, "running error code %d on path %s with msg %s\n", err->vecode, err->path, err->msg);
-                        }
-
-                        err = err->next;
-                    }
-                    ly_err_clean(session_context, 0);
+                    populate_job.operational = instance[i].operational;
                 }
-
-                solved_errors += solved_instance_errors;
             }
 
-            if(!success) {
-                if(!solved_errors) {
-                    log_message(1, LOG_COLOR_BOLD_YELLOW"failed"LOG_COLOR_RESET"\n%s\n", ly_errmsg(session_context));
+            if(instance[i].running) {
+                if(populate_job.running) {
+                    int rc = lyd_insert_sibling(&populate_job.running, instance[i].running);
+                    if(rc != 0) {
+                        log_error("lyd_insert_sibling\n");
+                        return NTS_ERR_FAILED;
+                    }
                 }
                 else {
-                    log_message(1, LOG_COLOR_BOLD_YELLOW"partially solved (%d)"LOG_COLOR_RESET"\n", solved_errors);
+                    populate_job.running = instance[i].running;
                 }
             }
         }
-    }
 
-    return commit_ok;
-}
+        //late-resolve
+        log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"datastore_populate_data() starting late-resolve process...\n"LOG_COLOR_RESET);
+        if(populate_job.late_resolve_count) {
+            int rc = populate_late_resolve(&populate_job);
+            if(rc != NTS_ERR_OK) {
+                log_error("populate_late_resolve failed\n");
+                return rc;
+            }
+        }
+        
+        //validate data and remove invalid nodes
+        log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"datastore_populate_data() validating\n"LOG_COLOR_RESET);
+        int rc = populate_validate(instance, xpaths_count);
+        if(rc != NTS_ERR_OK) {
+            log_error("populate_validate failed\n");
+            return rc;
+        }
+
+        //cleanup
+        log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"datastore_populate_data() cleanup\n"LOG_COLOR_RESET);
+        for(int i = 0; i < xpaths_count; i++) {
+            log_add(1, "%d ", i);
 
-static int schema_populate_commit_to_datastore(populate_job_t *job) {
-    assert_session();
-    assert(job);
+            free(instance[i].modules);
+            free(instance[i].xpath);
 
-    int rc = 0;
-    int commit_ok = 0;
+            free(xpaths[i]);
+        }
+        log_add(1, "\n");
+
+        free(xpaths);
+        free(populate_job.late_resolve_instance);
+        free(populate_job.late_resolve_schema);
+        free(populate_job.late_resolve_parent_d);
+        free(populate_job.late_resolve_parent_o);
+        free(populate_job.late_resolve_parent_r);
+
+        populate_job.late_resolving = false;
+        populate_job.late_resolve_instance = 0;
+        populate_job.late_resolve_schema = 0;
+        populate_job.late_resolve_parent_d = 0;
+        populate_job.late_resolve_parent_o = 0;
+        populate_job.late_resolve_parent_r = 0;
+        populate_job.late_resolve_count = 0;
+    }
 
-    if(job->operational) {
-        rc = SR_ERR_OK;
-        log_message(1, "editing batch for OPERATIONAL... ");
-        rc = sr_edit_batch(session_operational, job->operational, "merge");
+    if(populate_job.running) {
+        log_add_verbose(1, "editing batch for RUNNING... ");
+        int rc = sr_edit_batch(session_running, populate_job.running, "replace");
+        // lyd_free_withsiblings(populate_job.running); //checkAL
         if (rc != SR_ERR_OK) {
-            log_message(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
-            commit_ok = NTS_ERR_FAILED;
+            log_add(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
+            return NTS_ERR_FAILED;
         }
         else {
-            log_message(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
+            log_add(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
         }
-
-        rc = SR_ERR_OK;
-        log_message(1, "appling changes to OPERATIONAL... ");
-        rc = sr_apply_changes(session_operational, 0, 0);
+    }
+    
+    if(populate_job.operational) {
+        log_add_verbose(1, "editing batch for OPERATIONAL... ");
+        int rc = sr_edit_batch(session_operational, populate_job.operational, "replace");
+        // lyd_free_withsiblings(populate_job.operational); //checkAL
         if (rc != SR_ERR_OK) {
-            sr_discard_changes(session_operational);
-            commit_ok = NTS_ERR_FAILED;
-            log_message(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
+            log_add(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
+            return NTS_ERR_FAILED;
         }
         else {
-            log_message(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
+            log_add(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
         }
     }
 
-    if(job->running) {
-        // or you can do it like this, but will replace the WHOLE datastore
-        // rc = SR_ERR_OK;
-        // log_message(1, "editing batch for RUNNING...");
-        // rc = sr_replace_config(session_running, 0, job->running, 0, 0);
-        // if (rc != SR_ERR_OK) {
-        //     log_message(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
-        //     commit_ok = NTS_ERR_FAILED;
-        // }
-        // else {
-        //     log_message(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
-        // }
-
-        rc = SR_ERR_OK;
-        log_message(1, "editing batch for RUNNING...");
-        rc = sr_edit_batch(session_running, job->running, "merge");
+
+    log_add_verbose(1, "appling changes to RUNNING... ");
+    int rc = sr_apply_changes(session_running, 0, 0);
+    if (rc != SR_ERR_OK) {
+        sr_discard_changes(session_running);
+        log_add(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
+        return NTS_ERR_FAILED;
+    }
+    else {
+        log_add(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
+    }
+
+    log_add_verbose(1, "appling changes to OPERATIONAL... ");
+    rc = sr_apply_changes(session_operational, 0, 0);
+    if (rc != SR_ERR_OK) {
+        log_add(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
+        return NTS_ERR_FAILED;
+    }
+    else {
+        log_add(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
+    }
+    
+    log_add_verbose(1, "populate finished...\n");
+    return NTS_ERR_OK;
+}
+
+int datastore_populate_update_operational(const char **xpath, int xpath_len) {
+
+    if(xpath_len == 0) {
+        return NTS_ERR_OK;
+    }
+
+    populate_instance_t *instance = 0;
+    int instance_count = 0;
+
+    for(int i = 0; i < xpath_len; i++) {
+        log_add_verbose(1, "generating "LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" operational data...\n", xpath[i]);
+
+        struct lyd_node *node_dev = datastore_operations_get_lyd_node(populate_job.dev, xpath[i]);
+        if(node_dev == 0) {
+            log_error("datastore_operations_get_lyd_node failed on dev\n");
+            return NTS_ERR_FAILED;
+        }
+
+        struct lyd_node *node_running = datastore_operations_get_lyd_node(populate_job.running, xpath[i]);
+        if(node_running == 0) {
+            log_error("datastore_operations_get_lyd_node failed on running\n");
+            return NTS_ERR_FAILED;
+        }
+
+        //operational node (container/list) does not exist yet
+        struct lyd_node *node_operational = lyd_new_path(populate_job.operational, 0, xpath[i], 0, 0, LYD_PATH_OPT_NOPARENTRET | LYD_PATH_OPT_UPDATE);
+        if(node_operational == 0) {
+            log_error("lyd_new_path failed on operational\n");
+            return NTS_ERR_FAILED;
+        }
+
+        struct lys_node *schema_node = node_dev->schema;
+
+        int cinst = instance_count;
+        instance_count++;
+        instance = (populate_instance_t *)realloc(instance, sizeof(populate_instance_t) * instance_count);
+        instance[cinst].init = true;
+        instance[cinst].xpath = strdup(xpath[i]);
+        instance[cinst].modules = 0;
+        instance[cinst].mod_count = 0;
+        instance[cinst].dev = node_dev;
+        instance[cinst].operational = node_operational;
+        instance[cinst].running = node_running;
+
+        int rc = populate_instance_add_module(&instance[cinst], schema_node->module);
+        if(rc != NTS_ERR_OK) {
+            log_error("instance_add_module failed\n");
+            return rc;
+        }
+
+        //populate-recursive pe toti childrenii, cu param only_operational == 1
+        struct lys_node *elem;
+        LY_TREE_FOR(schema_node->child, elem) {
+            int rc = populate_recursive(&populate_job, &instance[cinst], elem, node_dev, node_operational, node_running, 1);
+            if(rc != NTS_ERR_OK) {
+                log_error("populate_recursive failed with xpath %s\n", instance[cinst].xpath);
+                return rc;
+            }
+        }
+    }
+
+    //late resolve
+    log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"datastore_populate_update_operational() starting late-resolve process...\n"LOG_COLOR_RESET);
+    if(populate_job.late_resolve_count) {
+        int rc = populate_late_resolve(&populate_job);
+        if(rc != NTS_ERR_OK) {
+            log_error("populate_late_resolve failed\n");
+            return rc;
+        }
+    }
+
+    // //validate
+    // log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"datastore_populate_update_operational() validating\n"LOG_COLOR_RESET);
+
+    // //build validate_instance' populate_validate must have root-path instances
+    // populate_instance_t *validate_instance = 0;
+    // int validate_instance_count = 0;
+
+    // for(int i = 0; i < instance_count; i++) {
+    //     //get root path from instance[i].xpath
+    //     char *root_path = strdup(instance[i].xpath);
+    //     *strstr(root_path + 1, "/") = 0;
+        
+    //     int found = validate_instance_count;
+    //     for(int j = 0; j < validate_instance_count; j++) {
+    //         if(strcmp(root_path, validate_instance[j].xpath) == 0) {
+    //             found = j;
+    //             break;
+    //         }
+    //     }
+
+    //     //if not found
+    //     if(found == validate_instance_count) {
+    //         //add root path UNIQUE to validate_instance
+    //         validate_instance_count++;
+    //         validate_instance = (populate_instance_t *)realloc(validate_instance, sizeof(populate_instance_t) * validate_instance_count);
+
+    //         validate_instance[found].init = true;
+    //         validate_instance[found].xpath = strdup(root_path);
+    //         validate_instance[found].modules = 0;
+    //         validate_instance[found].mod_count = 0;
+    //         validate_instance[found].dev = datastore_operations_get_lyd_node(populate_job.dev, root_path);
+    //         validate_instance[found].operational = datastore_operations_get_lyd_node(populate_job.operational, root_path);
+    //         validate_instance[found].running = datastore_operations_get_lyd_node(populate_job.running, root_path);
+    //     }
+    //     free(root_path);
+
+    //     //add each instance[i].modules to validate_instance[].modules
+    //     for(int j = 0; j < instance[i].mod_count; j++) {
+    //         int rc = populate_instance_add_module(&validate_instance[found], instance[i].modules[j]);
+    //         if(rc != NTS_ERR_OK) {
+    //             log_error("instance_add_module failed\n");
+    //             return rc;
+    //         }
+    //     }
+    // }
+
+    // int rc = populate_validate(validate_instance, validate_instance_count);
+    // if(rc != NTS_ERR_OK) {
+    //     log_error("populate_validate failed\n");
+    //     return rc;
+    // }
+
+    //cleanup
+    log_add_verbose(1, LOG_COLOR_BOLD_YELLOW"datastore_populate_update_operational() cleanup\n"LOG_COLOR_RESET);
+    // for(int i = 0; i < validate_instance_count; i++) {
+    //     free(validate_instance[i].modules);
+    //     free(validate_instance[i].xpath);
+    // }
+    // free(validate_instance);
+
+    for(int i = 0; i < instance_count; i++) {
+        free(instance[i].modules);
+        free(instance[i].xpath);
+    }
+    free(instance);
+
+    free(populate_job.late_resolve_instance);
+    free(populate_job.late_resolve_schema);
+    free(populate_job.late_resolve_parent_d);
+    free(populate_job.late_resolve_parent_o);
+    free(populate_job.late_resolve_parent_r);
+
+    populate_job.late_resolving = false;
+    populate_job.late_resolve_instance = 0;
+    populate_job.late_resolve_schema = 0;
+    populate_job.late_resolve_parent_d = 0;
+    populate_job.late_resolve_parent_o = 0;
+    populate_job.late_resolve_parent_r = 0;
+    populate_job.late_resolve_count = 0;
+
+    //edit batch and apply pe operational
+    if(populate_job.operational) {
+        log_add_verbose(1, "editing batch for OPERATIONAL... ");
+        int rc = sr_edit_batch(session_operational, populate_job.operational, "replace");
+        // lyd_free_withsiblings(populate_job.running); //checkAL
         if (rc != SR_ERR_OK) {
-            log_message(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
-            commit_ok = NTS_ERR_FAILED;
+            log_add(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
+            return NTS_ERR_FAILED;
         }
         else {
-            log_message(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
+            log_add(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
         }
+    
 
-        rc = SR_ERR_OK;
-        log_message(1, "appling changes to RUNNING... ");
-        rc = sr_apply_changes(session_running, 0, 0);
+        //apply pe operational
+        log_add_verbose(1, "appling changes to OPERATIONAL... ");
+        rc = sr_apply_changes(session_operational, 0, 0);
         if (rc != SR_ERR_OK) {
-            sr_discard_changes(session_running);
-            commit_ok = NTS_ERR_FAILED;
-            log_message(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
+            log_add(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
+            return NTS_ERR_FAILED;
         }
         else {
-            log_message(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
+            log_add(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
         }
     }
+    
+    log_add_verbose(1, "datastore_populate_update_operational() finished...\n");
+
+    return NTS_ERR_OK;
+}
+
+int datastore_dynamic_operational_auto_callback(sr_session_ctx_t *session, const char *module_name, const char *xpath, sr_event_t event, uint32_t request_id, void *private_data) {
+    sr_change_iter_t *it = 0;
+    int rc = SR_ERR_OK;
+    sr_change_oper_t oper;
+    sr_val_t *old_value = 0;
+    sr_val_t *new_value = 0;
+
+    rc = sr_get_changes_iter(session, "//.", &it);
+    if(rc != SR_ERR_OK) {
+        log_error("sr_get_changes_iter failed\n");
+        return SR_ERR_VALIDATION_FAILED;
+    }
+
+    //event-ul este mereu DONE
+
+    char **add_item = 0;
+    int add_item_len = 0;
+
+    char *prev_xpath = strdup("x"); //a non empty value
+    while((rc = sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) {
+        if(oper == SR_OP_CREATED) {
+            if((new_value->type == SR_CONTAINER_T) || (new_value->type == SR_CONTAINER_PRESENCE_T) || (new_value->type == SR_LIST_T)) {
+                add_item = (char**)realloc(add_item, sizeof(char *) * (add_item_len + 1));
+                add_item[add_item_len] = strdup(new_value->xpath);
+                add_item_len++;
+            }
+            
+            datastore_operations_add_sr_val(populate_job.running, new_value);
+            datastore_operations_add_sr_val(populate_job.dev, new_value);
+        }
+        else if(oper == SR_OP_DELETED) {
+            if(strncmp(prev_xpath, old_value->xpath, strlen(prev_xpath)) != 0) {
+                if((old_value->type == SR_CONTAINER_T) || (old_value->type == SR_CONTAINER_PRESENCE_T) || (old_value->type == SR_LIST_T)) {
+                    datastore_operations_free_path(populate_job.running, old_value->xpath);
+                    datastore_operations_free_path(populate_job.dev, old_value->xpath);
+                    datastore_operations_free_path(populate_job.operational, old_value->xpath);
+                    free(prev_xpath);
+                    prev_xpath = strdup(old_value->xpath);
+                }
+                else {
+                    datastore_operations_free_path(populate_job.running, old_value->xpath);
+                    datastore_operations_free_path(populate_job.dev, old_value->xpath);
+                }
+            }
+        }
+        else if(oper == SR_OP_MODIFIED) {
+            datastore_operations_change_sr_val(populate_job.running, new_value);
+            datastore_operations_change_sr_val(populate_job.dev, new_value);
+        }
+
+
+        debug_print_sr_change(oper, old_value, new_value);
+        
+        sr_free_val(old_value);
+        sr_free_val(new_value);
+    }
+
+    free(prev_xpath);
+    sr_free_change_iter(it);
+
+    //add operational (and dev)
+    rc = datastore_populate_update_operational((const char **)add_item, add_item_len);
+    if(rc != NTS_ERR_OK) {
+        log_error("datastore_populate_update_operational error\n");
+    }
+    for(int i = 0; i < add_item_len; i++) {
+        free(add_item[i]);
+    }
+    free(add_item);
 
-    return commit_ok;
+    return SR_ERR_OK;
 }