static void test_df4(void **state) { struct state *st = (*state); const char *xml1 = "<df xmlns=\"urn:libyang:tests:defaults\">" "<b1_2>x</b1_2><foo>42</foo><b1_1>42</b1_1>" "</df><hidden xmlns=\"urn:libyang:tests:defaults\">" "<foo>42</foo><baz>42</baz></hidden>"; const char *xml2 = "<df xmlns=\"urn:libyang:tests:defaults\" " "xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">" "<b2>1</b2><foo ncwd:default=\"true\">42</foo>" "</df><hidden xmlns=\"urn:libyang:tests:defaults\" " "xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">" "<foo ncwd:default=\"true\">42</foo><baz ncwd:default=\"true\">42</baz></hidden>"; const char *xml3 = "<df xmlns=\"urn:libyang:tests:defaults\" " "xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">" "<s2a>1</s2a><foo ncwd:default=\"true\">42</foo>" "</df><hidden xmlns=\"urn:libyang:tests:defaults\" " "xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">" "<foo ncwd:default=\"true\">42</foo><baz ncwd:default=\"true\">42</baz></hidden>"; st->dt = lyd_new(NULL, st->mod, "df"); assert_ptr_not_equal(st->dt, NULL); /* select2 - s2a */ assert_ptr_not_equal(lyd_new_leaf(st->dt, NULL, "s2a", "1"), NULL); assert_int_equal(lyd_validate(&(st->dt), LYD_OPT_CONFIG), 0); assert_int_equal(lyd_wd_add(NULL, &(st->dt), LYD_OPT_CONFIG | LYD_WD_ALL_TAG), 0); assert_int_equal(lyd_print_mem(&(st->xml), st->dt, LYD_XML, LYP_WITHSIBLINGS), 0); assert_ptr_not_equal(st->xml, NULL); assert_string_equal(st->xml, xml3); assert_int_equal(lyd_wd_cleanup(&(st->dt), 0), 0); free(st->xml); st->xml = NULL; /* select2 - s2b - b2 */ assert_ptr_not_equal(lyd_new_leaf(st->dt, NULL, "b2", "1"), NULL); assert_int_equal(lyd_validate(&(st->dt), LYD_OPT_CONFIG), 0); assert_int_equal(lyd_wd_add(NULL, &(st->dt), LYD_OPT_CONFIG | LYD_WD_ALL_TAG), 0); assert_int_equal(lyd_print_mem(&(st->xml), st->dt, LYD_XML, LYP_WITHSIBLINGS), 0); assert_ptr_not_equal(st->xml, NULL); assert_string_equal(st->xml, xml2); assert_int_equal(lyd_wd_cleanup(&(st->dt), 0), 0); free(st->xml); st->xml = NULL; /* select2 - s2b - b1 */ assert_ptr_not_equal(lyd_new_leaf(st->dt, NULL, "b1_2", "x"), NULL); assert_int_equal(lyd_validate(&(st->dt), LYD_OPT_CONFIG), 0); assert_int_equal(lyd_wd_add(NULL, &(st->dt), LYD_OPT_CONFIG | LYD_WD_ALL), 0); assert_int_equal(lyd_print_mem(&(st->xml), st->dt, LYD_XML, LYP_WITHSIBLINGS), 0); assert_ptr_not_equal(st->xml, NULL); assert_string_equal(st->xml, xml1); }
static void test_df3(void **state) { struct state *st = (*state); struct lyd_node *node; const char *xml1 = "<df xmlns=\"urn:libyang:tests:defaults\">" "<a1>1</a1>" "<foo>42</foo><b1_1>42</b1_1>" "</df><hidden xmlns=\"urn:libyang:tests:defaults\">" "<foo>42</foo><baz>42</baz></hidden>"; const char *xml2 = "<df xmlns=\"urn:libyang:tests:defaults\" " "xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">" "<c><x ncwd:default=\"true\">42</x></c>" "<foo ncwd:default=\"true\">42</foo><b1_1 ncwd:default=\"true\">42</b1_1>" "</df><hidden xmlns=\"urn:libyang:tests:defaults\" " "xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">" "<foo ncwd:default=\"true\">42</foo><baz ncwd:default=\"true\">42</baz></hidden>"; st->dt = lyd_new(NULL, st->mod, "df"); assert_ptr_not_equal(st->dt, NULL); /* select - c */ assert_ptr_not_equal((node = lyd_new(st->dt, NULL, "c")), NULL); assert_int_equal(lyd_validate(&(st->dt), LYD_OPT_CONFIG), 0); assert_int_equal(lyd_wd_add(NULL, &(st->dt), LYD_OPT_CONFIG | LYD_WD_ALL_TAG), 0); assert_int_equal(lyd_print_mem(&(st->xml), st->dt, LYD_XML, LYP_WITHSIBLINGS), 0); assert_ptr_not_equal(st->xml, NULL); assert_string_equal(st->xml, xml2); assert_int_equal(lyd_wd_cleanup(&(st->dt), 0), 0); free(st->xml); st->xml = NULL; /* select - a */ assert_ptr_not_equal(lyd_new_leaf(st->dt, NULL, "a1", "1"), NULL); assert_int_equal(lyd_validate(&(st->dt), LYD_OPT_CONFIG), 0); assert_int_equal(lyd_wd_add(NULL, &(st->dt), LYD_OPT_CONFIG | LYD_WD_ALL), 0); assert_int_equal(lyd_print_mem(&(st->xml), st->dt, LYD_XML, LYP_WITHSIBLINGS), 0); assert_ptr_not_equal(st->xml, NULL); assert_string_equal(st->xml, xml1); }
/** * @brief Import content of the specified datastore for the given module from a file * referenced by the descriptor 'fd_in' */ static int srcfg_import_datastore(struct ly_ctx *ly_ctx, int fd_in, const char *module_name, srcfg_datastore_t datastore, LYD_FORMAT format, bool permanent) { int rc = SR_ERR_INTERNAL; unsigned i = 0; struct lyd_node *new_data_tree = NULL; struct lyd_node *current_data_tree = NULL; struct lyd_difflist *diff = NULL; char *first_xpath = NULL, *second_xpath = NULL; char *input_data = NULL; int ret = 0; struct stat info; CHECK_NULL_ARG2(ly_ctx, module_name); /* parse input data */ ret = fstat(fd_in, &info); CHECK_NOT_MINUS1_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, cleanup, "Unable to obtain input file info: %s.", sr_strerror_safe(errno)); ly_errno = LY_SUCCESS; if (S_ISREG(info.st_mode)) { /* load (using mmap) and parse the input data in one step */ new_data_tree = lyd_parse_fd(ly_ctx, fd_in, format, LYD_OPT_STRICT | LYD_OPT_CONFIG); } else { /* most likely STDIN */ /* load input data into the memory first */ ret = srcfg_read_file_content(fd_in, &input_data); CHECK_RC_MSG_GOTO(ret, cleanup, "Unable to read the input data."); /* parse the input data stored inside memory buffer */ new_data_tree = lyd_parse_mem(ly_ctx, input_data, format, LYD_OPT_STRICT | LYD_OPT_CONFIG); } if (NULL == new_data_tree && LY_SUCCESS != ly_errno) { SR_LOG_ERR("Unable to parse the input data: %s", ly_errmsg()); goto cleanup; } /* validate input data */ if (NULL != new_data_tree) { ret = lyd_validate(&new_data_tree, LYD_OPT_STRICT | LYD_OPT_CONFIG | LYD_WD_IMPL_TAG); CHECK_ZERO_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, cleanup, "Input data are not valid: %s", ly_errmsg()); } /* remove default nodes */ lyd_wd_cleanup(&new_data_tree, 0); /* get data tree of currently stored configuration */ rc = srcfg_get_module_data(ly_ctx, module_name, ¤t_data_tree); if (SR_ERR_OK != rc) { goto cleanup; } /* get the list of changes made by the user */ diff = lyd_diff(current_data_tree, new_data_tree, 0); if (NULL == diff) { SR_LOG_ERR("Unable to get the list of changes: %s", ly_errmsg()); goto cleanup; } /* iterate over the list of differences and for each issue corresponding Sysrepo command(s) */ while (diff->type && LYD_DIFF_END != diff->type[i]) { if (NULL != diff->first[i]) { first_xpath = lyd_path(diff->first[i]); if (NULL == first_xpath) { SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg()); goto cleanup; } } if (NULL != diff->second[i]) { second_xpath = lyd_path(diff->second[i]); if (NULL == second_xpath) { free(first_xpath); first_xpath = NULL; SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg()); goto cleanup; } } switch (diff->type[i]) { case LYD_DIFF_DELETED: SR_LOG_DBG("<LYD_DIFF_DELETED> node: %s", first_xpath); rc = srcfg_convert_lydiff_deleted(first_xpath); break; case LYD_DIFF_CHANGED: SR_LOG_DBG("<LYD_DIFF_CHANGED> orig: %s, new: %s", first_xpath, second_xpath); rc = srcfg_convert_lydiff_changed(first_xpath, diff->second[i]); break; case LYD_DIFF_MOVEDAFTER1: SR_LOG_DBG("<LYD_DIFF_MOVEDAFTER1> moved: %s, after: %s", first_xpath, second_xpath); rc = srcfg_convert_lydiff_movedafter(first_xpath, second_xpath); break; case LYD_DIFF_CREATED: SR_LOG_DBG("<LYD_DIFF_CREATED> parent: %s, new node: %s", first_xpath, second_xpath); rc = srcfg_convert_lydiff_created(diff->second[i]); break; case LYD_DIFF_MOVEDAFTER2: SR_LOG_DBG("<LYD_DIFF_MOVEDAFTER2> after: %s, this new node was inserted: %s", first_xpath, second_xpath); rc = srcfg_convert_lydiff_movedafter(second_xpath, first_xpath); break; default: assert(0 && "not reachable"); } free(first_xpath); free(second_xpath); first_xpath = second_xpath = NULL; if (SR_ERR_OK != rc) { goto cleanup; } ++i; } if (0 == i) { SR_LOG_DBG_MSG("No changes were made."); } else { /* commit the changes */ rc = sr_commit(srcfg_session); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_commit: %s.", sr_strerror(rc)); goto cleanup; } if (SRCFG_STORE_RUNNING == datastore && permanent) { /* copy running datastore data into the startup datastore */ rc = sr_copy_config(srcfg_session, module_name, SR_DS_RUNNING, SR_DS_STARTUP); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_copy_config: %s.", sr_strerror(rc)); goto cleanup; } } } rc = SR_ERR_OK; cleanup: if (NULL != diff) { lyd_free_diff(diff); } if (NULL != current_data_tree) { lyd_free_withsiblings(current_data_tree); } if (NULL != new_data_tree) { lyd_free_withsiblings(new_data_tree); } if (input_data) { free(input_data); } return rc; }
/** * @brief Get complete libyang data tree of a specified module from sysrepo. */ static int srcfg_get_module_data(struct ly_ctx *ly_ctx, const char *module_name, struct lyd_node **data_tree) { int rc = SR_ERR_OK, ret = 0; sr_val_t *value = NULL; sr_val_iter_t *iter = NULL; struct lyd_node *node = NULL; const struct lys_node *schema = NULL; char query[PATH_MAX] = { 0, }; char *string_val = NULL; snprintf(query, PATH_MAX, "/%s:*//.", module_name); rc = sr_get_items_iter(srcfg_session, query, &iter); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error by sr_get_items_iter: %s", sr_strerror(rc)); goto cleanup; } *data_tree = NULL; ly_errno = LY_SUCCESS; ly_diminish_errors = true; while (SR_ERR_OK == (rc = sr_get_item_next(srcfg_session, iter, &value))) { ly_diminish_errors = false; if (NULL == value) { goto next; } /* get node schema */ schema = ly_ctx_get_node2(ly_ctx, NULL, value->xpath, 0); if (!schema) { SR_LOG_ERR("Error by ly_ctx_get_node2: %s", ly_errmsg()); goto fail; } /* skip default values */ if (schema->nodetype == LYS_LEAF && value->dflt) { goto next; } /* skip non-presence containers */ if (value->type == SR_CONTAINER_T) { goto next; } /* convert value to string */ rc = sr_val_to_str(value, schema, &string_val); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error by sr_val_to_str: %s", sr_strerror(rc)); goto fail; } /* add node to data tree */ ly_errno = LY_SUCCESS; node = lyd_new_path(*data_tree, ly_ctx, value->xpath, string_val, LYD_PATH_OPT_UPDATE); if (!node && LY_SUCCESS != ly_errno) { SR_LOG_ERR("Error by lyd_new_path: %s", ly_errmsg()); goto fail; } if (NULL == *data_tree) { *data_tree = node; } next: /* cleanup before next iteration */ if (NULL != string_val) { free(string_val); string_val = NULL; } if (NULL != value) { sr_free_val(value); value = NULL; } ly_diminish_errors = true; } ly_diminish_errors = false; if (SR_ERR_NOT_FOUND == rc) { rc = SR_ERR_OK; } if (SR_ERR_OK == rc) { if (NULL != *data_tree) { /* validate returned data, but most importantly resolve leafrefs */ ret = lyd_validate(data_tree, LYD_OPT_STRICT | LYD_OPT_CONFIG | LYD_WD_IMPL_TAG); CHECK_ZERO_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, fail, "Received data tree from sysrepo is not valid: %s", ly_errmsg()); /* remove default nodes added by validation */ lyd_wd_cleanup(data_tree, 0); } goto cleanup; } fail: rc = SR_ERR_INTERNAL; if (NULL != *data_tree) { lyd_free_withsiblings(*data_tree); *data_tree = NULL; } cleanup: if (NULL != string_val) { free(string_val); } if (NULL != value) { sr_free_val(value); } if (NULL != iter) { sr_free_val_iter(iter); } return rc; }