Merge pull request #3442 from opensourcerouting/confirmed-commits

lib: add support for confirmed commits
This commit is contained in:
Donald Sharp 2018-12-09 09:35:49 -05:00 committed by GitHub
commit 64b81b3a64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 115 additions and 18 deletions

View File

@ -653,7 +653,7 @@ struct thread_master *frr_init(void)
lib_error_init(); lib_error_init();
yang_init(); yang_init();
nb_init(di->yang_modules, di->n_yang_modules); nb_init(master, di->yang_modules, di->n_yang_modules);
return master; return master;
} }

View File

@ -1539,7 +1539,8 @@ static void nb_load_callbacks(const struct frr_yang_module_info *module)
} }
} }
void nb_init(const struct frr_yang_module_info *modules[], size_t nmodules) void nb_init(struct thread_master *tm,
const struct frr_yang_module_info *modules[], size_t nmodules)
{ {
unsigned int errors = 0; unsigned int errors = 0;
@ -1574,7 +1575,7 @@ void nb_init(const struct frr_yang_module_info *modules[], size_t nmodules)
running_config = nb_config_new(NULL); running_config = nb_config_new(NULL);
/* Initialize the northbound CLI. */ /* Initialize the northbound CLI. */
nb_cli_init(); nb_cli_init(tm);
} }
void nb_terminate(void) void nb_terminate(void)

View File

@ -20,6 +20,7 @@
#ifndef _FRR_NORTHBOUND_H_ #ifndef _FRR_NORTHBOUND_H_
#define _FRR_NORTHBOUND_H_ #define _FRR_NORTHBOUND_H_
#include "thread.h"
#include "hook.h" #include "hook.h"
#include "linklist.h" #include "linklist.h"
#include "openbsd-tree.h" #include "openbsd-tree.h"
@ -825,7 +826,7 @@ extern const char *nb_client_name(enum nb_client client);
* nmodules * nmodules
* Size of the modules array. * Size of the modules array.
*/ */
extern void nb_init(const struct frr_yang_module_info *modules[], extern void nb_init(struct thread_master *tm, const struct frr_yang_module_info *modules[],
size_t nmodules); size_t nmodules);
/* /*

View File

@ -36,6 +36,7 @@
int debug_northbound; int debug_northbound;
struct nb_config *vty_shared_candidate_config; struct nb_config *vty_shared_candidate_config;
static struct thread_master *master;
static void vty_show_libyang_errors(struct vty *vty, struct ly_ctx *ly_ctx) static void vty_show_libyang_errors(struct vty *vty, struct ly_ctx *ly_ctx)
{ {
@ -213,16 +214,80 @@ int nb_cli_rpc(const char *xpath, struct list *input, struct list *output)
} }
} }
static int nb_cli_commit(struct vty *vty, bool force, char *comment) void nb_cli_confirmed_commit_clean(struct vty *vty)
{
THREAD_TIMER_OFF(vty->t_confirmed_commit_timeout);
nb_config_free(vty->confirmed_commit_rollback);
vty->confirmed_commit_rollback = NULL;
}
int nb_cli_confirmed_commit_rollback(struct vty *vty)
{ {
uint32_t transaction_id; uint32_t transaction_id;
int ret; int ret;
/* Perform the rollback. */
ret = nb_candidate_commit(
vty->confirmed_commit_rollback, NB_CLIENT_CLI, true,
"Rollback to previous configuration - confirmed commit has timed out",
&transaction_id);
if (ret == NB_OK)
vty_out(vty,
"Rollback performed successfully (Transaction ID #%u).\n",
transaction_id);
else
vty_out(vty, "Failed to rollback to previous configuration.\n");
return ret;
}
static int nb_cli_confirmed_commit_timeout(struct thread *thread)
{
struct vty *vty = THREAD_ARG(thread);
/* XXX: broadcast this message to all logged-in users? */
vty_out(vty,
"\nConfirmed commit has timed out, rolling back to previous configuration.\n\n");
nb_cli_confirmed_commit_rollback(vty);
nb_cli_confirmed_commit_clean(vty);
return 0;
}
static int nb_cli_commit(struct vty *vty, bool force,
unsigned int confirmed_timeout, char *comment)
{
uint32_t transaction_id;
int ret;
/* Check if there's a pending confirmed commit. */
if (vty->t_confirmed_commit_timeout) {
if (confirmed_timeout) {
/* Reset timeout if "commit confirmed" is used again. */
vty_out(vty,
"%% Resetting confirmed-commit timeout to %u minute(s)\n\n",
confirmed_timeout);
THREAD_TIMER_OFF(vty->t_confirmed_commit_timeout);
thread_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");
nb_cli_confirmed_commit_clean(vty);
}
return CMD_SUCCESS;
}
if (vty_exclusive_lock != NULL && vty_exclusive_lock != vty) { if (vty_exclusive_lock != NULL && vty_exclusive_lock != vty) {
vty_out(vty, "%% Configuration is locked by another VTY.\n\n"); vty_out(vty, "%% Configuration is locked by another VTY.\n\n");
return CMD_WARNING; return CMD_WARNING;
} }
/* "force" parameter. */
if (!force && nb_candidate_needs_update(vty->candidate_config)) { if (!force && nb_candidate_needs_update(vty->candidate_config)) {
vty_out(vty, vty_out(vty,
"%% Candidate configuration needs to be updated before commit.\n\n"); "%% Candidate configuration needs to be updated before commit.\n\n");
@ -231,6 +296,16 @@ static int nb_cli_commit(struct vty *vty, bool force, char *comment)
return CMD_WARNING; return CMD_WARNING;
} }
/* "confirm" parameter. */
if (confirmed_timeout) {
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);
}
ret = nb_candidate_commit(vty->candidate_config, NB_CLIENT_CLI, true, ret = nb_candidate_commit(vty->candidate_config, NB_CLIENT_CLI, true,
comment, &transaction_id); comment, &transaction_id);
@ -534,18 +609,22 @@ DEFUN (config_private,
DEFPY (config_commit, DEFPY (config_commit,
config_commit_cmd, config_commit_cmd,
"commit [force$force]", "commit [{force$force|confirmed (1-60)}]",
"Commit changes into the running configuration\n" "Commit changes into the running configuration\n"
"Force commit even if the candidate is outdated\n") "Force commit even if the candidate is outdated\n"
"Rollback this commit unless there is a confirming commit\n"
"Timeout in minutes for the commit to be confirmed\n")
{ {
return nb_cli_commit(vty, !!force, NULL); return nb_cli_commit(vty, !!force, confirmed, NULL);
} }
DEFPY (config_commit_comment, DEFPY (config_commit_comment,
config_commit_comment_cmd, config_commit_comment_cmd,
"commit [force$force] comment LINE...", "commit [{force$force|confirmed (1-60)}] comment LINE...",
"Commit changes into the running configuration\n" "Commit changes into the running configuration\n"
"Force commit even if the candidate is outdated\n" "Force commit even if the candidate is outdated\n"
"Rollback this commit unless there is a confirming commit\n"
"Timeout in minutes for the commit to be confirmed\n"
"Assign a comment to this commit\n" "Assign a comment to this commit\n"
"Comment for this commit (Max 80 characters)\n") "Comment for this commit (Max 80 characters)\n")
{ {
@ -555,7 +634,7 @@ DEFPY (config_commit_comment,
argv_find(argv, argc, "LINE", &idx); argv_find(argv, argc, "LINE", &idx);
comment = argv_concat(argv, argc, idx); comment = argv_concat(argv, argc, idx);
ret = nb_cli_commit(vty, !!force, comment); ret = nb_cli_commit(vty, !!force, confirmed, comment);
XFREE(MTYPE_TMP, comment); XFREE(MTYPE_TMP, comment);
return ret; return ret;
@ -1543,8 +1622,10 @@ static const struct cmd_variable_handler yang_var_handlers[] = {
.completions = yang_translator_autocomplete}, .completions = yang_translator_autocomplete},
{.completions = NULL}}; {.completions = NULL}};
void nb_cli_init(void) void nb_cli_init(struct thread_master *tm)
{ {
master = tm;
/* Initialize the shared candidate configuration. */ /* Initialize the shared candidate configuration. */
vty_shared_candidate_config = nb_config_new(NULL); vty_shared_candidate_config = nb_config_new(NULL);

View File

@ -105,8 +105,10 @@ extern void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *dnode,
bool show_defaults); bool show_defaults);
/* Prototypes of internal functions. */ /* Prototypes of internal functions. */
extern void nb_cli_confirmed_commit_clean(struct vty *vty);
extern int nb_cli_confirmed_commit_rollback(struct vty *vty);
extern void nb_cli_install_default(int node); extern void nb_cli_install_default(int node);
extern void nb_cli_init(void); extern void nb_cli_init(struct thread_master *tm);
extern void nb_cli_terminate(void); extern void nb_cli_terminate(void);
#endif /* _FRR_NORTHBOUND_CLI_H_ */ #endif /* _FRR_NORTHBOUND_CLI_H_ */

View File

@ -2714,6 +2714,14 @@ int vty_config_enter(struct vty *vty, bool private_config, bool exclusive)
void vty_config_exit(struct vty *vty) void vty_config_exit(struct vty *vty)
{ {
/* Check if there's a pending confirmed commit. */
if (vty->t_confirmed_commit_timeout) {
vty_out(vty,
"WARNING: exiting with a pending confirmed commit. Rolling back to previous configuration.\n\n");
nb_cli_confirmed_commit_rollback(vty);
nb_cli_confirmed_commit_clean(vty);
}
vty_config_exclusive_unlock(vty); vty_config_exclusive_unlock(vty);
if (vty->candidate_config) { if (vty->candidate_config) {

View File

@ -126,6 +126,10 @@ struct vty {
/* Base candidate configuration. */ /* Base candidate configuration. */
struct nb_config *candidate_config_base; struct nb_config *candidate_config_base;
/* Confirmed-commit timeout and rollback configuration. */
struct thread *t_confirmed_commit_timeout;
struct nb_config *confirmed_commit_rollback;
/* qobj object ID (replacement for "index") */ /* qobj object ID (replacement for "index") */
uint64_t qobj_index; uint64_t qobj_index;

View File

@ -1384,10 +1384,10 @@ static void bgp_startup(void)
LOG_DAEMON); LOG_DAEMON);
zprivs_preinit(&bgpd_privs); zprivs_preinit(&bgpd_privs);
zprivs_init(&bgpd_privs); zprivs_init(&bgpd_privs);
yang_init();
nb_init(NULL, 0);
master = thread_master_create(NULL); master = thread_master_create(NULL);
yang_init();
nb_init(master, NULL, 0);
bgp_master_init(master); bgp_master_init(master);
bgp_option_set(BGP_OPT_NO_LISTEN); bgp_option_set(BGP_OPT_NO_LISTEN);
vrf_init(NULL, NULL, NULL, NULL, NULL); vrf_init(NULL, NULL, NULL, NULL, NULL);

View File

@ -156,7 +156,7 @@ int main(int argc, char **argv)
vty_init(master); vty_init(master);
memory_init(); memory_init();
yang_init(); yang_init();
nb_init(NULL, 0); nb_init(master, NULL, 0);
/* OSPF vty inits. */ /* OSPF vty inits. */
test_vty_init(); test_vty_init();

View File

@ -84,7 +84,7 @@ int main(int argc, char **argv)
vty_init(master); vty_init(master);
memory_init(); memory_init();
yang_init(); yang_init();
nb_init(NULL, 0); nb_init(master, NULL, 0);
test_init(argc, argv); test_init(argc, argv);

View File

@ -143,7 +143,7 @@ static void test_init(void)
cmd_init(1); cmd_init(1);
yang_init(); yang_init();
nb_init(NULL, 0); nb_init(master, NULL, 0);
install_node(&bgp_node, NULL); install_node(&bgp_node, NULL);
install_node(&rip_node, NULL); install_node(&rip_node, NULL);

View File

@ -449,7 +449,7 @@ int main(int argc, char **argv)
vty_init(master); vty_init(master);
memory_init(); memory_init();
yang_init(); yang_init();
nb_init(modules, array_size(modules)); nb_init(master, modules, array_size(modules));
/* Create artificial data. */ /* Create artificial data. */
create_data(num_vrfs, num_interfaces, num_routes); create_data(num_vrfs, num_interfaces, num_routes);