]> git.proxmox.com Git - mirror_frr.git/blobdiff - lib/northbound_cli.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / lib / northbound_cli.c
index e0dcdb490fcf2c12f732663fa50d2a49e8dfc959..e9c89d202906dfac18c38d70b086cb7c6adee212 100644 (file)
@@ -1,20 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Copyright (C) 2018  NetDEF, Inc.
  *                     Renato Westphal
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include <zebra.h>
@@ -42,7 +29,7 @@ struct debug nb_dbg_events = {0, "Northbound events"};
 struct debug nb_dbg_libyang = {0, "libyang debugging"};
 
 struct nb_config *vty_shared_candidate_config;
-static struct thread_master *master;
+static struct event_loop *master;
 
 static void vty_show_nb_errors(struct vty *vty, int error, const char *errmsg)
 {
@@ -59,7 +46,7 @@ static int nb_cli_classic_commit(struct vty *vty)
 
        context.client = NB_CLIENT_CLI;
        context.user = vty;
-       ret = nb_candidate_commit(&context, vty->candidate_config, true, NULL,
+       ret = nb_candidate_commit(context, vty->candidate_config, true, NULL,
                                  NULL, errmsg, sizeof(errmsg));
        switch (ret) {
        case NB_OK:
@@ -133,7 +120,7 @@ static int nb_cli_schedule_command(struct vty *vty)
 void nb_cli_enqueue_change(struct vty *vty, const char *xpath,
                           enum nb_operation operation, const char *value)
 {
-       struct vty_cfg_change *change;
+       struct nb_cfg_change *change;
 
        if (vty->num_cfg_changes == VTY_MAXCFGCHANGES) {
                /* Not expected to happen. */
@@ -154,79 +141,21 @@ static int nb_cli_apply_changes_internal(struct vty *vty,
                                         bool clear_pending)
 {
        bool error = false;
-
-       if (xpath_base == NULL)
-               xpath_base = "";
+       char buf[BUFSIZ];
 
        VTY_CHECK_XPATH;
 
-       /* Edit candidate configuration. */
-       for (size_t i = 0; i < vty->num_cfg_changes; i++) {
-               struct vty_cfg_change *change = &vty->cfg_changes[i];
-               struct nb_node *nb_node;
-               char xpath[XPATH_MAXLEN];
-               struct yang_data *data;
-               int ret;
-
-               /* Handle relative XPaths. */
-               memset(xpath, 0, sizeof(xpath));
-               if (vty->xpath_index > 0
-                   && (xpath_base[0] == '.' || change->xpath[0] == '.'))
-                       strlcpy(xpath, VTY_CURR_XPATH, sizeof(xpath));
-               if (xpath_base[0]) {
-                       if (xpath_base[0] == '.')
-                               strlcat(xpath, xpath_base + 1, sizeof(xpath));
-                       else
-                               strlcat(xpath, xpath_base, sizeof(xpath));
-               }
-               if (change->xpath[0] == '.')
-                       strlcat(xpath, change->xpath + 1, sizeof(xpath));
-               else
-                       strlcpy(xpath, change->xpath, sizeof(xpath));
-
-               /* Find the northbound node associated to the data path. */
-               nb_node = nb_node_find(xpath);
-               if (!nb_node) {
-                       flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH,
-                                 "%s: unknown data path: %s", __func__, xpath);
-                       error = true;
-                       continue;
-               }
-
-               /* If the value is not set, get the default if it exists. */
-               if (change->value == NULL)
-                       change->value = yang_snode_get_default(nb_node->snode);
-               data = yang_data_new(xpath, change->value);
-
-               /*
-                * Ignore "not found" errors when editing the candidate
-                * configuration.
-                */
-               ret = nb_candidate_edit(vty->candidate_config, nb_node,
-                                       change->operation, xpath, NULL, data);
-               yang_data_free(data);
-               if (ret != NB_OK && ret != NB_ERR_NOT_FOUND) {
-                       flog_warn(
-                               EC_LIB_NB_CANDIDATE_EDIT_ERROR,
-                               "%s: failed to edit candidate configuration: operation [%s] xpath [%s]",
-                               __func__, nb_operation_name(change->operation),
-                               xpath);
-                       error = true;
-                       continue;
-               }
-       }
-
+       nb_candidate_edit_config_changes(
+               vty->candidate_config, vty->cfg_changes, vty->num_cfg_changes,
+               xpath_base, VTY_CURR_XPATH, vty->xpath_index, buf, sizeof(buf),
+               &error);
        if (error) {
-               char buf[BUFSIZ];
-
                /*
                 * Failure to edit the candidate configuration should never
                 * happen in practice, unless there's a bug in the code. When
                 * that happens, log the error but otherwise ignore it.
                 */
-               vty_out(vty, "%% Failed to edit configuration.\n\n");
-               vty_out(vty, "%s",
-                       yang_print_errors(ly_native_ctx, buf, sizeof(buf)));
+               vty_out(vty, "%s", buf);
        }
 
        /*
@@ -254,6 +183,8 @@ static int nb_cli_apply_changes_internal(struct vty *vty,
 int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...)
 {
        char xpath_base[XPATH_MAXLEN] = {};
+       bool implicit_commit;
+       int ret;
 
        /* Parse the base XPath format string. */
        if (xpath_base_fmt) {
@@ -263,6 +194,20 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...)
                vsnprintf(xpath_base, sizeof(xpath_base), xpath_base_fmt, ap);
                va_end(ap);
        }
+
+       if (vty_mgmt_should_process_cli_apply_changes(vty)) {
+               VTY_CHECK_XPATH;
+
+               if (vty->type == VTY_FILE)
+                       return CMD_SUCCESS;
+
+               implicit_commit = vty_needs_implicit_commit(vty);
+               ret = vty_mgmt_send_config_data(vty);
+               if (ret >= 0 && !implicit_commit)
+                       vty->mgmt_num_pending_setcfg++;
+               return ret;
+       }
+
        return nb_cli_apply_changes_internal(vty, xpath_base, false);
 }
 
@@ -270,6 +215,8 @@ int nb_cli_apply_changes_clear_pending(struct vty *vty,
                                       const char *xpath_base_fmt, ...)
 {
        char xpath_base[XPATH_MAXLEN] = {};
+       bool implicit_commit;
+       int ret;
 
        /* Parse the base XPath format string. */
        if (xpath_base_fmt) {
@@ -279,6 +226,17 @@ int nb_cli_apply_changes_clear_pending(struct vty *vty,
                vsnprintf(xpath_base, sizeof(xpath_base), xpath_base_fmt, ap);
                va_end(ap);
        }
+
+       if (vty_mgmt_should_process_cli_apply_changes(vty)) {
+               VTY_CHECK_XPATH;
+
+               implicit_commit = vty_needs_implicit_commit(vty);
+               ret = vty_mgmt_send_config_data(vty);
+               if (ret >= 0 && !implicit_commit)
+                       vty->mgmt_num_pending_setcfg++;
+               return ret;
+       }
+
        return nb_cli_apply_changes_internal(vty, xpath_base, true);
 }
 
@@ -310,7 +268,7 @@ int nb_cli_rpc(struct vty *vty, const char *xpath, struct list *input,
 
 void nb_cli_confirmed_commit_clean(struct vty *vty)
 {
-       thread_cancel(&vty->t_confirmed_commit_timeout);
+       event_cancel(&vty->t_confirmed_commit_timeout);
        nb_config_free(vty->confirmed_commit_rollback);
        vty->confirmed_commit_rollback = NULL;
 }
@@ -326,7 +284,7 @@ int nb_cli_confirmed_commit_rollback(struct vty *vty)
        context.client = NB_CLIENT_CLI;
        context.user = vty;
        ret = nb_candidate_commit(
-               &context, vty->confirmed_commit_rollback, true,
+               context, vty->confirmed_commit_rollback, true,
                "Rollback to previous configuration - confirmed commit has timed out",
                &transaction_id, errmsg, sizeof(errmsg));
        if (ret == NB_OK) {
@@ -345,9 +303,9 @@ int nb_cli_confirmed_commit_rollback(struct vty *vty)
        return ret;
 }
 
-static void nb_cli_confirmed_commit_timeout(struct thread *thread)
+static void nb_cli_confirmed_commit_timeout(struct event *thread)
 {
-       struct vty *vty = THREAD_ARG(thread);
+       struct vty *vty = EVENT_ARG(thread);
 
        /* XXX: broadcast this message to all logged-in users? */
        vty_out(vty,
@@ -373,11 +331,10 @@ static int nb_cli_commit(struct vty *vty, bool force,
                                "%% Resetting confirmed-commit timeout to %u minute(s)\n\n",
                                confirmed_timeout);
 
-                       thread_cancel(&vty->t_confirmed_commit_timeout);
-                       thread_add_timer(master,
-                                        nb_cli_confirmed_commit_timeout, vty,
-                                        confirmed_timeout * 60,
-                                        &vty->t_confirmed_commit_timeout);
+                       event_cancel(&vty->t_confirmed_commit_timeout);
+                       event_add_timer(master, nb_cli_confirmed_commit_timeout,
+                                       vty, confirmed_timeout * 60,
+                                       &vty->t_confirmed_commit_timeout);
                } else {
                        /* Accept commit confirmation. */
                        vty_out(vty, "%% Commit complete.\n\n");
@@ -400,16 +357,15 @@ static int nb_cli_commit(struct vty *vty, bool force,
                vty->confirmed_commit_rollback = nb_config_dup(running_config);
 
                vty->t_confirmed_commit_timeout = NULL;
-               thread_add_timer(master, nb_cli_confirmed_commit_timeout, vty,
-                                confirmed_timeout * 60,
-                                &vty->t_confirmed_commit_timeout);
+               event_add_timer(master, nb_cli_confirmed_commit_timeout, vty,
+                               confirmed_timeout * 60,
+                               &vty->t_confirmed_commit_timeout);
        }
 
        context.client = NB_CLIENT_CLI;
        context.user = vty;
-       ret = nb_candidate_commit(&context, vty->candidate_config, true,
-                                 comment, &transaction_id, errmsg,
-                                 sizeof(errmsg));
+       ret = nb_candidate_commit(context, vty->candidate_config, true, comment,
+                                 &transaction_id, errmsg, sizeof(errmsg));
 
        /* Map northbound return code to CLI return code. */
        switch (ret) {
@@ -1481,6 +1437,7 @@ DEFPY (show_yang_operational_data,
        struct lyd_node *dnode;
        char *strp;
        uint32_t print_options = LYD_PRINT_WITHSIBLINGS;
+       int ret;
 
        if (xml)
                format = LYD_XML;
@@ -1501,10 +1458,15 @@ DEFPY (show_yang_operational_data,
 
        /* Obtain data. */
        dnode = yang_dnode_new(ly_ctx, false);
-       if (nb_oper_data_iterate(xpath, translator, 0, nb_cli_oper_data_cb,
-                                dnode)
-           != NB_OK) {
-               vty_out(vty, "%% Failed to fetch operational data.\n");
+       ret = nb_oper_data_iterate(xpath, translator, 0, nb_cli_oper_data_cb,
+                                  dnode);
+       if (ret != NB_OK) {
+               if (format == LYD_JSON)
+                       vty_out(vty, "{}\n");
+               else {
+                       /* embed ly_last_errmsg() when we get newer libyang */
+                       vty_out(vty, "<!-- Not found -->\n");
+               }
                yang_dnode_free(dnode);
                return CMD_WARNING;
        }
@@ -1730,7 +1692,7 @@ static int nb_cli_rollback_configuration(struct vty *vty,
 
        context.client = NB_CLIENT_CLI;
        context.user = vty;
-       ret = nb_candidate_commit(&context, candidate, true, comment, NULL,
+       ret = nb_candidate_commit(context, candidate, true, comment, NULL,
                                  errmsg, sizeof(errmsg));
        nb_config_free(candidate);
        switch (ret) {
@@ -1923,7 +1885,7 @@ static const struct cmd_variable_handler yang_var_handlers[] = {
         .completions = yang_translator_autocomplete},
        {.completions = NULL}};
 
-void nb_cli_init(struct thread_master *tm)
+void nb_cli_init(struct event_loop *tm)
 {
        master = tm;