19f6ee97d044cd7e12e256066bd19e2da16ee57d
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / datastore / populate.c
1 /*************************************************************************
2 *
3 * Copyright 2020 highstreet technologies GmbH and others
4 *
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
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
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 ***************************************************************************/
17
18 #define _GNU_SOURCE
19
20 #include "populate.h"
21 #include "utils/log_utils.h"
22 #include "utils/rand_utils.h"
23 #include "utils/type_utils.h"
24 #include <stdio.h>
25 #include <assert.h>
26
27 #include "core/session.h"
28 #include "core/framework.h"
29
30 #include "core/datastore/schema.h"
31
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);
35
36 int schema_populate(void) {
37     assert_session();
38
39     log_message(1, LOG_COLOR_BOLD_YELLOW"schema_populate() begin\n"LOG_COLOR_RESET);
40
41     char **xpaths = 0;
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;
46     }
47
48     populate_job_t job;
49     job.operational = 0;
50     job.running = 0;
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;
57
58     populate_instance_t *instance = (populate_instance_t *)malloc(sizeof(populate_instance_t) * instance_count);
59     if(!instance) {
60         log_error("bad malloc");
61         return NTS_ERR_FAILED;
62     }
63     
64     //populate everything
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]);
67
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;
72         }
73
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;
78         }
79
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;
84         }
85
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;
90         }
91
92         //populate current instance vals
93         instance[i].init = 0;
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;
99         
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);
104             return rc;
105         }
106     }
107
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++) {
111
112         if(instance[i].operational) {
113             if(job.operational) {
114                 int rc = lyd_insert_sibling(&job.operational, instance[i].operational);
115                 if(rc != 0) {
116                     log_error("lyd_insert_sibling");
117                     return NTS_ERR_FAILED;
118                 }
119             }
120             else {
121                 job.operational = instance[i].operational;
122             }
123         }
124
125         if(instance[i].running) {
126             if(job.running) {
127                 int rc = lyd_insert_sibling(&job.running, instance[i].running);
128                 if(rc != 0) {
129                     log_error("lyd_insert_sibling");
130                     return NTS_ERR_FAILED;
131                 }
132             }
133             else {
134                 job.running = instance[i].running;
135             }
136         }
137     }
138
139     //late-resolve
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");
145             return rc;
146         }
147     }
148     
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");
154         return rc;
155     }
156
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");
162         return rc;
163     }
164
165     //cleanup
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);
169
170         free(instance[i].modules);
171         free(instance[i].xpath);
172
173         free(xpaths[i]);
174     }
175     free(xpaths);
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);
180
181     lyd_free_withsiblings(job.operational);
182     lyd_free_withsiblings(job.running);
183         
184     log_message(1, "\n");
185     log_message(1, LOG_COLOR_BOLD_GREEN"schema_populate() finished\n"LOG_COLOR_RESET);
186     
187     return NTS_ERR_OK;
188 }
189
190 static int schema_populate_late_resolve(populate_job_t *job) {
191     assert(job);
192
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");
199             return rc;
200         }
201     }
202     job->late_resolving = false;
203
204     return NTS_ERR_OK;
205 }
206
207 static int schema_populate_validate(populate_instance_t *instance, int count) {
208     assert_session();
209     assert(instance);
210
211     int rc = 0;
212     int commit_ok = NTS_ERR_OK;
213
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);
219             }
220             log_message(2, "\n");
221             log_message(1, "validating OPERATIONAL for [%d] : %s... ", i, instance[i].xpath);
222
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);
229                 if(rc == 0) {
230                     log_message(1, LOG_COLOR_BOLD_GREEN"success (%d)\n"LOG_COLOR_RESET, solved_errors);
231                     success = true;
232                     break;
233                 }
234                 else {
235                     log_message(2, "\n");
236
237                     struct ly_err_item *err = ly_err_first(session_context);
238                     while(err) {
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);
244
245                                 bool mandatory = false;
246                                 if((set->set.d[0]->schema->flags & LYS_MAND_TRUE) != 0) {
247                                     mandatory = true;
248                                 }
249
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) {
252                                         mandatory = true;
253                                     }
254                                 }
255
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]);
261                                     lyd_free(p);
262                                     if(p == instance[i].operational) {
263                                         log_message(1, "instance became empty "LOG_COLOR_BOLD_GREEN"success\n"LOG_COLOR_RESET);
264                                         success = true;
265                                         instance[i].operational = 0;
266                                         break;
267                                     }
268                                 }
269                                 else {
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);
275                                         success = true;
276                                         instance[i].operational = 0;
277                                         break;
278                                     }
279                                 }
280                                 solved_instance_errors++;
281
282                                 ly_set_free(set);
283                             }
284                         }
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);
287                         }
288
289                         err = err->next;
290                     }
291                     ly_err_clean(session_context, 0);
292                 }
293
294                 solved_errors += solved_instance_errors;
295             }
296
297             if(!success) {
298                 if(!solved_errors) {
299                     log_message(1, LOG_COLOR_BOLD_YELLOW"failed"LOG_COLOR_RESET"\n%s\n", ly_errmsg(session_context));
300                 }
301                 else {
302                     log_message(1, LOG_COLOR_BOLD_YELLOW"partially solved (%d)"LOG_COLOR_RESET"\n", solved_errors);
303                 }
304             }
305         }
306
307         if(instance[i].running) {
308             log_message(1, "validating RUNNING... for [%d] : %s... ", i, instance[i].xpath);
309
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);
316                 if(rc == 0) {
317                     log_message(1, LOG_COLOR_BOLD_GREEN"success (%d)\n"LOG_COLOR_RESET, solved_errors);
318                     success = true;
319                     break;
320                 }
321                 else {
322                     log_message(2, "\n");
323
324                     struct ly_err_item *err = ly_err_first(session_context);
325                     while(err) {
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);
331
332                                 bool mandatory = false;
333                                 if((set->set.d[0]->schema->flags & LYS_MAND_TRUE) != 0) {
334                                     mandatory = true;
335                                 }
336
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) {
339                                         mandatory = true;
340                                     }
341                                 }
342
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]);
348                                     lyd_free(p);
349
350                                     if(p == instance[i].running) {
351                                         log_message(1, "instance became empty "LOG_COLOR_BOLD_GREEN"success\n"LOG_COLOR_RESET);
352                                         success = true;
353                                         instance[i].running = 0;
354                                         break;
355                                     }
356                                 }
357                                 else {
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);
363                                         success = true;
364                                         instance[i].running = 0;
365                                         break;
366                                     }
367                                 }
368                                 solved_instance_errors++;
369
370                                 ly_set_free(set);
371                             }
372                         }
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);
375                         }
376
377                         err = err->next;
378                     }
379                     ly_err_clean(session_context, 0);
380                 }
381
382                 solved_errors += solved_instance_errors;
383             }
384
385             if(!success) {
386                 if(!solved_errors) {
387                     log_message(1, LOG_COLOR_BOLD_YELLOW"failed"LOG_COLOR_RESET"\n%s\n", ly_errmsg(session_context));
388                 }
389                 else {
390                     log_message(1, LOG_COLOR_BOLD_YELLOW"partially solved (%d)"LOG_COLOR_RESET"\n", solved_errors);
391                 }
392             }
393         }
394     }
395
396     return commit_ok;
397 }
398
399 static int schema_populate_commit_to_datastore(populate_job_t *job) {
400     assert_session();
401     assert(job);
402
403     int rc = 0;
404     int commit_ok = 0;
405
406     if(job->operational) {
407         rc = SR_ERR_OK;
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;
413         }
414         else {
415             log_message(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
416         }
417
418         rc = SR_ERR_OK;
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);
425         }
426         else {
427             log_message(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
428         }
429     }
430
431     if(job->running) {
432         // or you can do it like this, but will replace the WHOLE datastore
433         // rc = SR_ERR_OK;
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;
439         // }
440         // else {
441         //     log_message(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
442         // }
443
444         rc = SR_ERR_OK;
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;
450         }
451         else {
452             log_message(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
453         }
454
455         rc = SR_ERR_OK;
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);
462         }
463         else {
464             log_message(1, LOG_COLOR_BOLD_GREEN"done\n"LOG_COLOR_RESET);
465         }
466     }
467
468     return commit_ok;
469 }