1 /*************************************************************************
3 * Copyright 2021 highstreet technologies GmbH and others
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
20 #include "populate_internal.h"
21 #include "utils/log_utils.h"
22 #include "utils/rand_utils.h"
23 #include "utils/type_utils.h"
25 #include "core/datastore/schema.h"
26 #include "core/framework.h"
27 #include "core/session.h"
30 #include <libyang/libyang.h>
36 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) {
39 char *resolved_schema_path = lys_path(schema, LYS_PATH_FIRST_PREFIX);
40 bool element_operational = ((schema->flags & LYS_CONFIG_W) == 0);
42 populate_recursive_rerun_switch:
43 switch(schema->nodetype) {
44 //for container, just add it to the xpath, and iterate it's childeren to further traverse the tree
46 //don't add if populating only operational
47 if(operational_only && !element_operational) {
53 struct lyd_node *new_parent_d = parent_d;
54 struct lyd_node *new_parent_o = parent_o;
55 struct lyd_node *new_parent_r = parent_r;
57 new_parent_d = lyd_new(parent_d, schema->module, schema->name);
59 log_error("error creating container dev -> %s\n", schema->name);
60 log_error("ly_error: %s\n", ly_errmsg(session_context));
61 return NTS_ERR_FAILED;
64 new_parent_o = lyd_new(parent_o, schema->module, schema->name);
66 log_error("error creating container operational -> %s\n", schema->name);
67 log_error("ly_error: %s\n", ly_errmsg(session_context));
68 return NTS_ERR_FAILED;
71 if(!element_operational) {
72 new_parent_r = lyd_new(parent_r, schema->module, schema->name);
74 log_error("error creating container running -> %s\n", schema->name);
75 log_error("ly_error: %s\n", ly_errmsg(session_context));
76 return NTS_ERR_FAILED;
81 instance->init = true;
82 instance->dev = new_parent_d;
83 instance->operational = new_parent_o;
84 instance->running = new_parent_r;
87 char *xpath = lyd_path(new_parent_d);
88 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);
91 int rc = populate_instance_add_module(instance, schema->module);
92 if(rc != NTS_ERR_OK) {
93 log_error("instance_add_module failed\n");
97 struct lys_node *child = 0;
98 LY_TREE_FOR(schema->child, child) {
99 int rc = populate_recursive(job, instance, child, new_parent_d, new_parent_o, new_parent_r, operational_only);
100 if(rc != NTS_ERR_OK) {
101 log_error("populate_recursive failed\n");
107 //choice does not appear into the data path. get all the avalable choices, and choose a random one
110 struct lys_node_case *choice = (struct lys_node_case *)schema->child;
113 choice = (struct lys_node_case *)choice->next;
116 //select a random choice
117 choice_no = rand_uint16() % choice_no;
120 choice = (struct lys_node_case *)schema->child;
121 while(i < choice_no) {
123 choice = (struct lys_node_case *)choice->next;
126 //after the choice was made, rerun the adding without other tree-searching (will run into a CASE)
127 schema = (struct lys_node *)choice;
128 goto populate_recursive_rerun_switch;
131 //the actual "case" is this node's child, so we skip directly to that
133 //case contains mandatory
135 schema = schema->child;
136 goto populate_recursive_rerun_switch;
146 //don't add if populating only operational
147 if(operational_only && !element_operational) {
151 //get min-max for current list
152 struct lys_node_list *list = (struct lys_node_list *)schema;
153 int min_added = list->min ? list->min : 1;
154 int max_added = list->max ? list->max : 65536;
156 int populating_times = populate_instance_get_count(resolved_schema_path);
157 if(populating_times != 0) {
158 if(min_added < populating_times) {
159 min_added = populating_times;
161 if(min_added > max_added) {
162 min_added = max_added;
163 log_error("min-elements exceeds max-elements for path %s. truncated to %d\n", resolved_schema_path, max_added);
165 log_add_verbose(2, "populating %d times list '%s'\n", min_added, resolved_schema_path);
167 //populate node with the intended number of values
171 struct lyd_node *new_parent_d = parent_d;
172 struct lyd_node *new_parent_o = parent_o;
173 struct lyd_node *new_parent_r = parent_r;
175 new_parent_d = lyd_new(parent_d, schema->module, schema->name);
177 log_error("error creating list dev -> %s\n", schema->name);
178 log_error("ly_error: %s\n", ly_errmsg(session_context));
179 return NTS_ERR_FAILED;
183 new_parent_o = lyd_new(parent_o, schema->module, schema->name);
185 log_error("error creating list operational -> %s\n", schema->name);
186 log_error("ly_error: %s\n", ly_errmsg(session_context));
187 return NTS_ERR_FAILED;
190 if(!element_operational) {
191 new_parent_r = lyd_new(parent_r, schema->module, schema->name);
193 log_error("error creating container running -> %s\n", schema->name);
194 log_error("ly_error: %s\n", ly_errmsg(session_context));
195 return NTS_ERR_FAILED;
199 if(!instance->init) {
200 instance->init = true;
201 instance->dev = new_parent_d;
202 instance->operational = new_parent_o;
203 instance->running = new_parent_r;
206 char *xpath = lyd_path(new_parent_d);
207 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);
210 int rc = populate_instance_add_module(instance, schema->module);
211 if(rc != NTS_ERR_OK) {
212 log_error("instance_add_module failed\n");
216 //populate all list elements below in the tree
217 struct lys_node *child = 0;
218 LY_TREE_FOR(schema->child, child) {
219 int rc = populate_recursive(job, instance, child, new_parent_d, new_parent_o, new_parent_r, operational_only);
220 if(rc != NTS_ERR_OK) {
221 log_error("populate_recursive failed\n");
230 log_add_verbose(2, "not populating list '%s'\n", resolved_schema_path);
236 //don't add if populating only operational
237 if(operational_only && !element_operational) {
241 if(populate_add_leaf(job, instance, schema, parent_d, parent_o, parent_r) != NTS_ERR_OK) {
242 return NTS_ERR_FAILED;
246 //leaflist is treated the same as a LEAF, but with min/max characteristics of a LIST
248 //don't add if populating only operational
249 if(operational_only && !element_operational) {
253 //get min-max for the current leaflist
254 struct lys_node_leaflist *list = (struct lys_node_leaflist *)schema;
255 int min_added = list->min ? list->min : 1;
256 int max_added = list->max ? list->max : 65536;
258 int populating_times = populate_instance_get_count(resolved_schema_path);
259 if(populating_times != 0) {
260 if(min_added < populating_times) {
261 min_added = populating_times;
263 if(min_added > max_added) {
264 min_added = max_added;
265 log_error("min-elements exceeds max-elements for path %s truncated to %d\n", resolved_schema_path, max_added);
267 log_add_verbose(2, "populating %d times leaflist '%s'\n", min_added, resolved_schema_path);
271 if(populate_add_leaf(job, instance, schema, parent_d, parent_o, parent_r) != NTS_ERR_OK) {
272 return NTS_ERR_FAILED;
278 log_add_verbose(2, "not populating leaflist '%s'\n", resolved_schema_path);
286 //don't do anything, since we don't want to add this or go further down the tree when we meet them
289 //other node types (grouping, uses, augment, etc just traverse)
291 log_add_verbose(1, "[%15s] %s\n", typeutils_yang_nodetype_to_str(schema->nodetype), resolved_schema_path);
293 //traverse the tree down for any other node types, without adding anything to the path
294 struct lys_node *child = 0;
295 LY_TREE_FOR(schema->child, child) {
296 int rc = populate_recursive(job, instance, child, parent_d, parent_o, parent_r, operational_only);
297 if(rc != NTS_ERR_OK) {
304 free(resolved_schema_path);
309 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) {
315 int rc = populate_instance_add_module(instance, schema->module);
316 if(rc != NTS_ERR_OK) {
317 log_error("bad schema_instance_add module\n");
321 struct lys_type *type = &((struct lys_node_leaf *)schema)->type;
323 char *data_xpath = lyd_path(parent_d);
324 data_xpath = (char *)realloc(data_xpath, sizeof(char) * (strlen(data_xpath) + 1 + strlen(schema->name) + 1));
326 log_error("lyd_path failed\n");
327 return NTS_ERR_FAILED;
329 strcat(data_xpath, "/");
330 strcat(data_xpath, schema->name);
332 bool leaf_operational = ((schema->flags & LYS_CONFIG_W) == 0);
333 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);
337 char *resolved_schema_path = lys_path(schema, LYS_PATH_FIRST_PREFIX);
338 char *value = populate_get_restrict_schema(resolved_schema_path);
339 free(resolved_schema_path);
341 populate_add_leaf_rerun_switch:
344 if((type->info.uni.count == 0) && (type->der != 0)) {
345 type = &type->der->type;
348 type = &type->info.uni.types[0];
349 goto populate_add_leaf_rerun_switch;
353 struct lyd_node *parent = parent_o;
354 while(parent->parent) {
355 parent = parent->parent;
359 value = lyd_path(parent);
362 goto populate_add_leaf_actual_add;
366 if(rand_bool()) { //if present, add it
367 log_add(1, LOG_COLOR_CYAN"present"LOG_COLOR_RESET"\n");
368 goto populate_add_leaf_actual_add;
371 log_add(1, LOG_COLOR_CYAN"empty"LOG_COLOR_RESET"\n");
376 case LY_TYPE_LEAFREF: {
379 struct lyd_node *new_node = 0;
380 while((new_node == 0) && (index < POPULATE_LEAFREF_TEST_ENTRIES_TOTAL)) {
381 new_node = lyd_new_leaf(parent_d, schema->module, schema->name, populate_leafref_test_val(index));
386 log_error("error on lyd_new_leaf schema %s. didn't work with any temp val\n", schema->name);
387 return NTS_ERR_FAILED;
390 //based on the new_node's path, try to find elements of relative path for the leafref
391 struct ly_set *set = lyd_find_path(new_node, type->info.lref.path);
394 if(set && set->number) {
395 //choose a random schema and get its value
396 static int set_number = 0;
398 if(set_number >= set->number) {
401 asprintf(&value, "%s", ((struct lyd_node_leaf_list *)set->set.d[set_number])->value_str);
403 log_error("bad asprintf\n");
404 return NTS_ERR_FAILED;
407 int rc = populate_instance_add_module(instance, set->set.d[set_number]->schema->module);
408 if(rc != NTS_ERR_OK) {
409 log_error("bad schema_instance_add module\n");
415 goto populate_add_leaf_actual_add;
418 //adding to late-resolve list, as we don't have any nodes in the leafref path
419 int rc = populate_late_resolve_add_leaf(job, instance, schema, parent_d, parent_o, parent_r);
420 if(rc != NTS_ERR_OK) {
424 if(!job->late_resolving) {
425 log_add(1, LOG_COLOR_BOLD_YELLOW"added to late-resolve list...\n"LOG_COLOR_RESET);
428 log_add(1, LOG_COLOR_BOLD_YELLOW"REadded to late-resolve list...\n"LOG_COLOR_RESET);
438 value = rand_get_populate_value(type);
440 goto populate_add_leaf_actual_add;
444 populate_add_leaf_actual_add: {
446 struct lyd_node *new_node = lyd_new_leaf(parent_d, schema->module, schema->name, value);
448 log_error("error on lyd_new_leaf dev: %s\n", ly_errmsg(session_context));
449 return NTS_ERR_FAILED;
452 //print out the value
454 log_add(1, LOG_COLOR_CYAN"'%s'"LOG_COLOR_RESET"\n", value);
460 //if it fits the case, add it also to running
461 if(leaf_operational || (lys_is_key((const struct lys_node_leaf *)schema, 0) != 0)) {
462 //add schema to operational
463 struct lyd_node *new_node = lyd_new_leaf(parent_o, schema->module, schema->name, value);
465 log_error("error on lyd_new_leaf operational: %s\n", ly_errmsg(session_context));
466 return NTS_ERR_FAILED;
470 if(!leaf_operational) {
471 struct lyd_node *new_node = lyd_new_leaf(parent_r, schema->module, schema->name, value);
473 log_error("error on lyd_new_leaf running: %s\n", ly_errmsg(session_context));
474 return NTS_ERR_FAILED;