1 /*************************************************************************
3 * Copyright 2020 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 ***************************************************************************/
21 #include "utils/log_utils.h"
22 #include "utils/rand_utils.h"
23 #include "utils/type_utils.h"
27 #include "core/session.h"
28 #include "core/framework.h"
30 #include "core/datastore/schema.h"
32 static int schema_populate_late_resolve(populate_job_t *job);
33 static int schema_populate_validate(populate_instance_t *instance, int count);
34 static int schema_populate_commit_to_datastore(populate_job_t *job);
36 int schema_populate(void) {
39 log_message(1, LOG_COLOR_BOLD_YELLOW"schema_populate() begin\n"LOG_COLOR_RESET);
42 int instance_count = schema_get_xpaths(&xpaths);
43 if(instance_count < 0) {
44 log_error("schema_get_xpaths failed");
45 return NTS_ERR_FAILED;
51 job.late_resolve_count = 0;
52 job.late_resolve_instance = 0;
53 job.late_resolve_schema = 0;
54 job.late_resolve_parent_o = 0;
55 job.late_resolve_parent_r = 0;
56 job.late_resolving = false;
58 populate_instance_t *instance = (populate_instance_t *)malloc(sizeof(populate_instance_t) * instance_count);
60 log_error("bad malloc");
61 return NTS_ERR_FAILED;
65 for(int i = 0; i < instance_count; i++) {
66 log_message(1, "populating "LOG_COLOR_BOLD_YELLOW"%s"LOG_COLOR_RESET" with data...\n", xpaths[i]);
68 struct lys_node *schema_node = (struct lys_node *)ly_ctx_get_node(session_context, 0, xpaths[i], 0);
69 if(schema_node == 0) {
70 log_error("ly_ctx_get_node failed for %s", xpaths[i]);
71 return NTS_ERR_FAILED;
74 if(schema_node == 0) {
75 log_message(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
76 log_error("ly_ctx_get_node failed for %s", xpaths[i]);
77 return NTS_ERR_FAILED;
80 if(!schema_node->module->implemented) {
81 log_message(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
82 log_error("module is not implemented for %s", xpaths[i]);
83 return NTS_ERR_FAILED;
86 if((schema_node->flags & LYS_STATUS_DEPRC) != 0) {
87 log_message(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
88 log_error("module is deprecated for %s", xpaths[i]);
89 return NTS_ERR_FAILED;
92 //populate current instance vals
94 instance[i].xpath = strdup(xpaths[i]);
95 instance[i].modules = 0;
96 instance[i].mod_count = 0;
97 instance[i].operational = 0;
98 instance[i].running = 0;
100 //do the actual population
101 int rc = schema_populate_recursive(&job, &instance[i], schema_node, 0, 0);
102 if(rc != NTS_ERR_OK) {
103 log_error("schema_populate_recursive failed instance %d with xpath %s", i, instance[i].xpath);
108 //link everything so we would be able to find everything in late-resolve
109 log_message(1, LOG_COLOR_BOLD_YELLOW"schema_populate() done populating, now linking... (%d root nodes)\n"LOG_COLOR_RESET, instance_count);
110 for(int i = 0; i < instance_count; i++) {
112 if(instance[i].operational) {
113 if(job.operational) {
114 int rc = lyd_insert_sibling(&job.operational, instance[i].operational);
116 log_error("lyd_insert_sibling");
117 return NTS_ERR_FAILED;
121 job.operational = instance[i].operational;
125 if(instance[i].running) {
127 int rc = lyd_insert_sibling(&job.running, instance[i].running);
129 log_error("lyd_insert_sibling");
130 return NTS_ERR_FAILED;
134 job.running = instance[i].running;
140 log_message(1, LOG_COLOR_BOLD_YELLOW"schema_populate() starting late-resolve process...\n"LOG_COLOR_RESET);
141 if(job.late_resolve_count) {
142 int rc = schema_populate_late_resolve(&job);
143 if(rc != NTS_ERR_OK) {
144 log_error("schema_populate_late_resolve failed");
149 //validate data and remove invalid nodes
150 log_message(1, LOG_COLOR_BOLD_YELLOW"schema_populate() validating\n"LOG_COLOR_RESET);
151 int rc = schema_populate_validate(instance, instance_count);
152 if(rc != NTS_ERR_OK) {
153 log_error("schema_populate_commit_to_datastore failed");
157 //commit to datastore
158 log_message(1, LOG_COLOR_BOLD_YELLOW"schema_populate() commiting to datastore\n"LOG_COLOR_RESET);
159 rc = schema_populate_commit_to_datastore(&job);
160 if(rc != NTS_ERR_OK) {
161 log_error("schema_populate_commit_to_datastore failed");
166 log_message(1, LOG_COLOR_BOLD_YELLOW"schema_populate() cleaning up... "LOG_COLOR_RESET);
167 for(int i = 0; i < instance_count; i++) {
168 log_message(1, "%d ", i);
170 free(instance[i].modules);
171 free(instance[i].xpath);
176 free(job.late_resolve_instance);
177 free(job.late_resolve_schema);
178 free(job.late_resolve_parent_o);
179 free(job.late_resolve_parent_r);
181 lyd_free_withsiblings(job.operational);
182 lyd_free_withsiblings(job.running);
184 log_message(1, "\n");
185 log_message(1, LOG_COLOR_BOLD_GREEN"schema_populate() finished\n"LOG_COLOR_RESET);
190 static int schema_populate_late_resolve(populate_job_t *job) {
193 job->late_resolving = true;
194 for(int i = 0; i < job->late_resolve_count; i++) {
195 log_message(1, LOG_COLOR_BOLD_YELLOW"late-populating "LOG_COLOR_RESET": ");
196 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]);
197 if(rc != NTS_ERR_OK) {
198 log_error("schema_populate_add_leaf failed on late-resolve");
202 job->late_resolving = false;
207 static int schema_populate_validate(populate_instance_t *instance, int count) {
212 int commit_ok = NTS_ERR_OK;
214 for(int i = 0; i < count; i++) {
215 if(instance[i].operational) {
216 log_message(2, "available modules:");
217 for(int j = 0; j < instance[i].mod_count; j++) {
218 log_message(2, " %s", instance[i].modules[j]->name);
220 log_message(2, "\n");
221 log_message(1, "validating OPERATIONAL for [%d] : %s... ", i, instance[i].xpath);
223 int solved_instance_errors = 1;
224 int solved_errors = 0;
225 bool success = false;
226 while(instance[i].operational && solved_instance_errors) {
227 solved_instance_errors = 0;
228 rc = lyd_validate_modules(&instance[i].operational, instance[i].modules, instance[i].mod_count, LYD_OPT_DATA, 0);
230 log_message(1, LOG_COLOR_BOLD_GREEN"success (%d)\n"LOG_COLOR_RESET, solved_errors);
235 log_message(2, "\n");
237 struct ly_err_item *err = ly_err_first(session_context);
239 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)) {
240 struct ly_set *set = lyd_find_path(instance[i].operational, err->path);
241 if(set && set->number) {
242 log_message(2, "operational error code %d on path %s with msg %s\n", err->vecode, err->path, err->msg);
243 log_message(2, LOG_COLOR_BOLD_RED" [WHEN-DELETE O]"LOG_COLOR_RESET" %s ... ", err->path);
245 bool mandatory = false;
246 if((set->set.d[0]->schema->flags & LYS_MAND_TRUE) != 0) {
250 if((set->set.d[0]->schema->parent) && (set->set.d[0]->schema->parent->nodetype == LYS_CASE)) {
251 if((set->set.d[0]->schema->parent->flags & LYS_MAND_TRUE) != 0) {
256 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)) {
257 //delete whole parent
258 log_message(2, "deleted parent : %s\n", lyd_path(set->set.d[0]->parent));
259 struct lyd_node *p = set->set.d[0]->parent;
260 lyd_free_withsiblings(set->set.d[0]);
262 if(p == instance[i].operational) {
263 log_message(1, "instance became empty "LOG_COLOR_BOLD_GREEN"success\n"LOG_COLOR_RESET);
265 instance[i].operational = 0;
270 //delete THIS node only
271 lyd_free(set->set.d[0]);
272 log_message(2, "deleted\n");
273 if(set->set.d[0] == instance[i].operational) {
274 log_message(1, "instance became empty "LOG_COLOR_BOLD_GREEN"success\n"LOG_COLOR_RESET);
276 instance[i].operational = 0;
280 solved_instance_errors++;
285 else if((err->vecode != 0) && (err->vecode != 29)) {
286 log_message(2, "operational error code %d on path %s with msg %s\n", err->vecode, err->path, err->msg);
291 ly_err_clean(session_context, 0);
294 solved_errors += solved_instance_errors;
299 log_message(1, LOG_COLOR_BOLD_YELLOW"failed"LOG_COLOR_RESET"\n%s\n", ly_errmsg(session_context));
302 log_message(1, LOG_COLOR_BOLD_YELLOW"partially solved (%d)"LOG_COLOR_RESET"\n", solved_errors);
307 if(instance[i].running) {
308 log_message(1, "validating RUNNING... for [%d] : %s... ", i, instance[i].xpath);
310 int solved_instance_errors = 1;
311 int solved_errors = 0;
312 bool success = false;
313 while(instance[i].running && solved_instance_errors) {
314 solved_instance_errors = 0;
315 rc = lyd_validate_modules(&instance[i].running, instance[i].modules, instance[i].mod_count, LYD_OPT_CONFIG, 0);
317 log_message(1, LOG_COLOR_BOLD_GREEN"success (%d)\n"LOG_COLOR_RESET, solved_errors);
322 log_message(2, "\n");
324 struct ly_err_item *err = ly_err_first(session_context);
326 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)) {
327 struct ly_set *set = lyd_find_path(instance[i].running, err->path);
328 if(set && set->number) {
329 log_message(2, "running error code %d on path %s with msg %s\n", err->vecode, err->path, err->msg);
330 log_message(2, LOG_COLOR_BOLD_RED" [WHEN-DELETE R]"LOG_COLOR_RESET" %s ... ", err->path);
332 bool mandatory = false;
333 if((set->set.d[0]->schema->flags & LYS_MAND_TRUE) != 0) {
337 if((set->set.d[0]->schema->parent) && (set->set.d[0]->schema->parent->nodetype == LYS_CASE)) {
338 if((set->set.d[0]->schema->parent->flags & LYS_MAND_TRUE) != 0) {
343 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)) {
344 //delete whole parent
345 log_message(2, "deleted parent : %s\n", lyd_path(set->set.d[0]->parent));
346 struct lyd_node *p = set->set.d[0]->parent;
347 lyd_free_withsiblings(set->set.d[0]);
350 if(p == instance[i].running) {
351 log_message(1, "instance became empty "LOG_COLOR_BOLD_GREEN"success\n"LOG_COLOR_RESET);
353 instance[i].running = 0;
358 //delete THIS node only
359 lyd_free(set->set.d[0]);
360 log_message(2, "deleted\n");
361 if(set->set.d[0] == instance[i].running) {
362 log_message(1, "instance became empty "LOG_COLOR_BOLD_GREEN"success\n"LOG_COLOR_RESET);
364 instance[i].running = 0;
368 solved_instance_errors++;
373 else if((err->vecode != 0) && (err->vecode != 29)) {
374 log_message(2, "running error code %d on path %s with msg %s\n", err->vecode, err->path, err->msg);
379 ly_err_clean(session_context, 0);
382 solved_errors += solved_instance_errors;
387 log_message(1, LOG_COLOR_BOLD_YELLOW"failed"LOG_COLOR_RESET"\n%s\n", ly_errmsg(session_context));
390 log_message(1, LOG_COLOR_BOLD_YELLOW"partially solved (%d)"LOG_COLOR_RESET"\n", solved_errors);
399 static int schema_populate_commit_to_datastore(populate_job_t *job) {
406 if(job->operational) {
408 log_message(1, "editing batch for OPERATIONAL... ");
409 rc = sr_edit_batch(session_operational, job->operational, "merge");
410 if (rc != SR_ERR_OK) {
411 log_message(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
412 commit_ok = NTS_ERR_FAILED;
415 log_message(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
419 log_message(1, "appling changes to OPERATIONAL... ");
420 rc = sr_apply_changes(session_operational, 0, 0);
421 if (rc != SR_ERR_OK) {
422 sr_discard_changes(session_operational);
423 commit_ok = NTS_ERR_FAILED;
424 log_message(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
427 log_message(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
432 // or you can do it like this, but will replace the WHOLE datastore
434 // log_message(1, "editing batch for RUNNING...");
435 // rc = sr_replace_config(session_running, 0, job->running, 0, 0);
436 // if (rc != SR_ERR_OK) {
437 // log_message(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
438 // commit_ok = NTS_ERR_FAILED;
441 // log_message(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
445 log_message(1, "editing batch for RUNNING...");
446 rc = sr_edit_batch(session_running, job->running, "merge");
447 if (rc != SR_ERR_OK) {
448 log_message(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
449 commit_ok = NTS_ERR_FAILED;
452 log_message(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
456 log_message(1, "appling changes to RUNNING... ");
457 rc = sr_apply_changes(session_running, 0, 0);
458 if (rc != SR_ERR_OK) {
459 sr_discard_changes(session_running);
460 commit_ok = NTS_ERR_FAILED;
461 log_message(1, LOG_COLOR_BOLD_RED"failed\n"LOG_COLOR_RESET);
464 log_message(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);