X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=ntsimulator%2Fntsim-ng%2Fcore%2Fdatastore%2Fpopulate_recursive.c;fp=ntsimulator%2Fntsim-ng%2Fcore%2Fdatastore%2Fpopulate_recursive.c;h=98f6d5d89f408d79be247818d9720f577c8fe7d0;hb=caec2fcb18e829420672509fe5e356b48d0c3840;hp=0000000000000000000000000000000000000000;hpb=f379349d310d61b27d2c0bf7334d2268cc8f42e2;p=sim%2Fo1-interface.git diff --git a/ntsimulator/ntsim-ng/core/datastore/populate_recursive.c b/ntsimulator/ntsim-ng/core/datastore/populate_recursive.c new file mode 100644 index 0000000..98f6d5d --- /dev/null +++ b/ntsimulator/ntsim-ng/core/datastore/populate_recursive.c @@ -0,0 +1,482 @@ +/************************************************************************* +* +* 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. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +***************************************************************************/ +#define _GNU_SOURCE + +#include "populate.h" +#include "populate_internal.h" +#include "utils/log_utils.h" +#include "utils/rand_utils.h" +#include "utils/type_utils.h" + +#include "core/datastore/schema.h" +#include "core/framework.h" +#include "core/session.h" + +#include +#include + +#include +#include + + +int populate_recursive(populate_job_t *job, populate_instance_t *instance, struct lys_node *schema, struct lyd_node *parent_d, struct lyd_node *parent_o, struct lyd_node *parent_r, int operational_only) { + assert(schema); + + char *resolved_schema_path = lys_path(schema, LYS_PATH_FIRST_PREFIX); + bool element_operational = ((schema->flags & LYS_CONFIG_W) == 0); + + populate_recursive_rerun_switch: + switch(schema->nodetype) { + //for container, just add it to the xpath, and iterate it's childeren to further traverse the tree + case LYS_CONTAINER: { + //don't add if populating only operational + if(operational_only && !element_operational) { + return NTS_ERR_OK; + } + + //add container + + struct lyd_node *new_parent_d = parent_d; + struct lyd_node *new_parent_o = parent_o; + struct lyd_node *new_parent_r = parent_r; + + new_parent_d = lyd_new(parent_d, schema->module, schema->name); + if(!new_parent_d) { + log_error("error creating container dev -> %s\n", schema->name); + log_error("ly_error: %s\n", ly_errmsg(session_context)); + return NTS_ERR_FAILED; + } + + new_parent_o = lyd_new(parent_o, schema->module, schema->name); + if(!new_parent_o) { + log_error("error creating container operational -> %s\n", schema->name); + log_error("ly_error: %s\n", ly_errmsg(session_context)); + return NTS_ERR_FAILED; + } + + if(!element_operational) { + new_parent_r = lyd_new(parent_r, schema->module, schema->name); + if(!new_parent_r) { + log_error("error creating container running -> %s\n", schema->name); + log_error("ly_error: %s\n", ly_errmsg(session_context)); + return NTS_ERR_FAILED; + } + } + + if(!instance->init) { + instance->init = true; + instance->dev = new_parent_d; + instance->operational = new_parent_o; + instance->running = new_parent_r; + } + + char *xpath = lyd_path(new_parent_d); + log_add_verbose(1, LOG_COLOR_BOLD_MAGENTA"[%15s] "LOG_COLOR_BOLD_YELLOW"[%c%c]"LOG_COLOR_RESET" %s\n", "CONTAINER", element_operational ? 'O' : 'R', populate_info_get_mandatory(schema), xpath); + free(xpath); + + int rc = populate_instance_add_module(instance, schema->module); + if(rc != NTS_ERR_OK) { + log_error("instance_add_module failed\n"); + return rc; + } + + struct lys_node *child = 0; + LY_TREE_FOR(schema->child, child) { + int rc = populate_recursive(job, instance, child, new_parent_d, new_parent_o, new_parent_r, operational_only); + if(rc != NTS_ERR_OK) { + log_error("populate_recursive failed\n"); + return rc; + } + } + } break; + + //choice does not appear into the data path. get all the avalable choices, and choose a random one + case LYS_CHOICE: { + int choice_no = 0; + struct lys_node_case *choice = (struct lys_node_case *)schema->child; + while(choice) { + choice_no++; + choice = (struct lys_node_case *)choice->next; + } + + //select a random choice + choice_no = rand_uint16() % choice_no; + + int i = 0; + choice = (struct lys_node_case *)schema->child; + while(i < choice_no) { + i++; + choice = (struct lys_node_case *)choice->next; + } + + //after the choice was made, rerun the adding without other tree-searching (will run into a CASE) + schema = (struct lys_node *)choice; + goto populate_recursive_rerun_switch; + } break; + + //the actual "case" is this node's child, so we skip directly to that + case LYS_CASE: + //case contains mandatory + if(schema->child) { + schema = schema->child; + goto populate_recursive_rerun_switch; + } + else { + //blank case + return NTS_ERR_OK; + } + break; + + //populate a list + case LYS_LIST: { + //don't add if populating only operational + if(operational_only && !element_operational) { + return NTS_ERR_OK; + } + + //get min-max for current list + struct lys_node_list *list = (struct lys_node_list *)schema; + int min_added = list->min ? list->min : 1; + int max_added = list->max ? list->max : 65536; + + int populating_times = populate_instance_get_count(resolved_schema_path); + if(populating_times != 0) { + if(min_added < populating_times) { + min_added = populating_times; + } + if(min_added > max_added) { + min_added = max_added; + log_error("min-elements exceeds max-elements for path %s. truncated to %d\n", resolved_schema_path, max_added); + } + log_add_verbose(2, "populating %d times list '%s'\n", min_added, resolved_schema_path); + + //populate node with the intended number of values + while(min_added) { + //add list + + struct lyd_node *new_parent_d = parent_d; + struct lyd_node *new_parent_o = parent_o; + struct lyd_node *new_parent_r = parent_r; + + new_parent_d = lyd_new(parent_d, schema->module, schema->name); + if(!new_parent_d) { + log_error("error creating list dev -> %s\n", schema->name); + log_error("ly_error: %s\n", ly_errmsg(session_context)); + return NTS_ERR_FAILED; + } + + + new_parent_o = lyd_new(parent_o, schema->module, schema->name); + if(!new_parent_o) { + log_error("error creating list operational -> %s\n", schema->name); + log_error("ly_error: %s\n", ly_errmsg(session_context)); + return NTS_ERR_FAILED; + } + + if(!element_operational) { + new_parent_r = lyd_new(parent_r, schema->module, schema->name); + if(!new_parent_r) { + log_error("error creating container running -> %s\n", schema->name); + log_error("ly_error: %s\n", ly_errmsg(session_context)); + return NTS_ERR_FAILED; + } + } + + if(!instance->init) { + instance->init = true; + instance->dev = new_parent_d; + instance->operational = new_parent_o; + instance->running = new_parent_r; + } + + char *xpath = lyd_path(new_parent_d); + log_add_verbose(1, LOG_COLOR_BOLD_MAGENTA"[%15s] "LOG_COLOR_BOLD_YELLOW"[%c%c]"LOG_COLOR_RESET" %s\n", "LIST", element_operational ? 'O' : 'R', populate_info_get_mandatory(schema), xpath); + free(xpath); + + int rc = populate_instance_add_module(instance, schema->module); + if(rc != NTS_ERR_OK) { + log_error("instance_add_module failed\n"); + return rc; + } + + //populate all list elements below in the tree + struct lys_node *child = 0; + LY_TREE_FOR(schema->child, child) { + int rc = populate_recursive(job, instance, child, new_parent_d, new_parent_o, new_parent_r, operational_only); + if(rc != NTS_ERR_OK) { + log_error("populate_recursive failed\n"); + return rc; + } + } + + min_added--; + } + } + else { + log_add_verbose(2, "not populating list '%s'\n", resolved_schema_path); + } + } break; + + //populate the leaf + case LYS_LEAF: { + //don't add if populating only operational + if(operational_only && !element_operational) { + return NTS_ERR_OK; + } + + if(populate_add_leaf(job, instance, schema, parent_d, parent_o, parent_r) != NTS_ERR_OK) { + return NTS_ERR_FAILED; + } + } break; + + //leaflist is treated the same as a LEAF, but with min/max characteristics of a LIST + case LYS_LEAFLIST: { + //don't add if populating only operational + if(operational_only && !element_operational) { + return NTS_ERR_OK; + } + + //get min-max for the current leaflist + struct lys_node_leaflist *list = (struct lys_node_leaflist *)schema; + int min_added = list->min ? list->min : 1; + int max_added = list->max ? list->max : 65536; + + int populating_times = populate_instance_get_count(resolved_schema_path); + if(populating_times != 0) { + if(min_added < populating_times) { + min_added = populating_times; + } + if(min_added > max_added) { + min_added = max_added; + log_error("min-elements exceeds max-elements for path %s truncated to %d\n", resolved_schema_path, max_added); + } + log_add_verbose(2, "populating %d times leaflist '%s'\n", min_added, resolved_schema_path); + + //add the leafs + while(min_added) { + if(populate_add_leaf(job, instance, schema, parent_d, parent_o, parent_r) != NTS_ERR_OK) { + return NTS_ERR_FAILED; + } + min_added--; + } + } + else { + log_add_verbose(2, "not populating leaflist '%s'\n", resolved_schema_path); + } + } break; + + case LYS_ACTION: + case LYS_INPUT: + case LYS_OUTPUT: + case LYS_NOTIF: + //don't do anything, since we don't want to add this or go further down the tree when we meet them + break; + + //other node types (grouping, uses, augment, etc just traverse) + default: + log_add_verbose(1, "[%15s] %s\n", typeutils_yang_nodetype_to_str(schema->nodetype), resolved_schema_path); + + //traverse the tree down for any other node types, without adding anything to the path + struct lys_node *child = 0; + LY_TREE_FOR(schema->child, child) { + int rc = populate_recursive(job, instance, child, parent_d, parent_o, parent_r, operational_only); + if(rc != NTS_ERR_OK) { + return rc; + } + } + break; + } + + free(resolved_schema_path); + + return NTS_ERR_OK; +} + +int populate_add_leaf(populate_job_t *job, populate_instance_t *instance, struct lys_node *schema, struct lyd_node *parent_d, struct lyd_node *parent_o, struct lyd_node *parent_r) { + assert_session(); + assert(job); + assert(schema); + assert(parent_d); + + int rc = populate_instance_add_module(instance, schema->module); + if(rc != NTS_ERR_OK) { + log_error("bad schema_instance_add module\n"); + return rc; + } + + struct lys_type *type = &((struct lys_node_leaf *)schema)->type; + + char *data_xpath = lyd_path(parent_d); + data_xpath = (char *)realloc(data_xpath, sizeof(char) * (strlen(data_xpath) + 1 + strlen(schema->name) + 1)); + if(!data_xpath) { + log_error("lyd_path failed\n"); + return NTS_ERR_FAILED; + } + strcat(data_xpath, "/"); + strcat(data_xpath, schema->name); + + bool leaf_operational = ((schema->flags & LYS_CONFIG_W) == 0); + log_add_verbose(1, LOG_COLOR_BOLD_MAGENTA"[%15s] "LOG_COLOR_BOLD_YELLOW"[%c%c]"LOG_COLOR_RESET" %s <-- ", typeutils_yang_type_to_str(type->base), leaf_operational ? 'O' : 'R', populate_info_get_mandatory(schema), data_xpath); + free(data_xpath); + + + char *resolved_schema_path = lys_path(schema, LYS_PATH_FIRST_PREFIX); + char *value = populate_get_restrict_schema(resolved_schema_path); + free(resolved_schema_path); + + populate_add_leaf_rerun_switch: + switch(type->base) { + case LY_TYPE_UNION: + if((type->info.uni.count == 0) && (type->der != 0)) { + type = &type->der->type; + } + + type = &type->info.uni.types[0]; + goto populate_add_leaf_rerun_switch; + break; + + case LY_TYPE_INST: { + struct lyd_node *parent = parent_o; + while(parent->parent) { + parent = parent->parent; + } + + if(value == 0) { + value = lyd_path(parent); + } + + goto populate_add_leaf_actual_add; + } break; + + case LY_TYPE_EMPTY: + if(rand_bool()) { //if present, add it + log_add(1, LOG_COLOR_CYAN"present"LOG_COLOR_RESET"\n"); + goto populate_add_leaf_actual_add; + } + else { + log_add(1, LOG_COLOR_CYAN"empty"LOG_COLOR_RESET"\n"); + return NTS_ERR_OK; + } + break; + + case LY_TYPE_LEAFREF: { + if(value == 0) { + int index = 0; + struct lyd_node *new_node = 0; + while((new_node == 0) && (index < POPULATE_LEAFREF_TEST_ENTRIES_TOTAL)) { + new_node = lyd_new_leaf(parent_d, schema->module, schema->name, populate_leafref_test_val(index)); + index++; + } + + if(new_node == 0) { + log_error("error on lyd_new_leaf schema %s. didn't work with any temp val\n", schema->name); + return NTS_ERR_FAILED; + } + + //based on the new_node's path, try to find elements of relative path for the leafref + struct ly_set *set = lyd_find_path(new_node, type->info.lref.path); + lyd_free(new_node); + + if(set && set->number) { + //choose a random schema and get its value + static int set_number = 0; + set_number++; + if(set_number >= set->number) { + set_number = 0; + } + asprintf(&value, "%s", ((struct lyd_node_leaf_list *)set->set.d[set_number])->value_str); + if(!value) { + log_error("bad asprintf\n"); + return NTS_ERR_FAILED; + } + + int rc = populate_instance_add_module(instance, set->set.d[set_number]->schema->module); + if(rc != NTS_ERR_OK) { + log_error("bad schema_instance_add module\n"); + return rc; + } + + ly_set_free(set); + + goto populate_add_leaf_actual_add; + } + else { + //adding to late-resolve list, as we don't have any nodes in the leafref path + int rc = populate_late_resolve_add_leaf(job, instance, schema, parent_d, parent_o, parent_r); + if(rc != NTS_ERR_OK) { + return rc; + } + + if(!job->late_resolving) { + log_add(1, LOG_COLOR_BOLD_YELLOW"added to late-resolve list...\n"LOG_COLOR_RESET); + } + else { + log_add(1, LOG_COLOR_BOLD_YELLOW"REadded to late-resolve list...\n"LOG_COLOR_RESET); + } + + return NTS_ERR_OK; + } + } + } break; + + default: + if(value == 0) { + value = rand_get_populate_value(type); + } + goto populate_add_leaf_actual_add; + break; + } + + populate_add_leaf_actual_add: { + //add schema to dev + struct lyd_node *new_node = lyd_new_leaf(parent_d, schema->module, schema->name, value); + if(new_node == 0) { + log_error("error on lyd_new_leaf dev: %s\n", ly_errmsg(session_context)); + return NTS_ERR_FAILED; + } + + //print out the value + if(value) { + log_add(1, LOG_COLOR_CYAN"'%s'"LOG_COLOR_RESET"\n", value); + } + else { + log_add(1, "\n"); + } + + //if it fits the case, add it also to running + if(leaf_operational || (lys_is_key((const struct lys_node_leaf *)schema, 0) != 0)) { + //add schema to operational + struct lyd_node *new_node = lyd_new_leaf(parent_o, schema->module, schema->name, value); + if(new_node == 0) { + log_error("error on lyd_new_leaf operational: %s\n", ly_errmsg(session_context)); + return NTS_ERR_FAILED; + } + } + + if(!leaf_operational) { + struct lyd_node *new_node = lyd_new_leaf(parent_r, schema->module, schema->name, value); + if(new_node == 0) { + log_error("error on lyd_new_leaf running: %s\n", ly_errmsg(session_context)); + return NTS_ERR_FAILED; + } + } + + free(value); + } + + return NTS_ERR_OK; +}