mirror_frr/mgmtd/mgmt_vty.c
Christian Hopps d1e85e3600 mgmtd: Enroll Staticd as a backend client for MGMTD
This commmit introduces Staticd as a backend client for the MGMTd
framework. All the static commands will be diverted to the MGMT
daemon and will use the transactional model to make changes to the
internal state. Similar mechanism can be used by other daemons to use
the MGMT framework in the future.

This commit includes the following functionalities in the changeset:
1. Diverts all the staticd (config only) commands to MGMTd.
2. Enrolls staticd as a backend client to use the MGMT framework.
3. Modify the staticd NB config handlers so that they can be compiled
   into a library and loaded in the MGMTd process context.

Co-authored-by: Pushpasis Sarkar <pushpasis@gmail.com>
Co-authored-by: Abhinay Ramesh <rabhinay@vmware.com>
Co-authored-by: Ujwal P <ujwalp@vmware.com>
Signed-off-by: Yash Ranjan <ranjany@vmware.com>
2023-03-21 22:09:07 -04:00

486 lines
12 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* MGMTD VTY Interface
*
* Copyright (C) 2021 Vmware, Inc.
* Pushpasis Sarkar <spushpasis@vmware.com>
*/
#include <zebra.h>
#include "command.h"
#include "json.h"
#include "mgmtd/mgmt.h"
#include "mgmtd/mgmt_be_server.h"
#include "mgmtd/mgmt_be_adapter.h"
#include "mgmtd/mgmt_fe_server.h"
#include "mgmtd/mgmt_fe_adapter.h"
#include "mgmtd/mgmt_ds.h"
#include "mgmtd/mgmt_history.h"
#include "mgmtd/mgmt_vty_clippy.c"
DEFPY(show_mgmt_be_adapter,
show_mgmt_be_adapter_cmd,
"show mgmt backend-adapter all",
SHOW_STR
MGMTD_STR
MGMTD_BE_ADAPTER_STR
"Display all Backend Adapters\n")
{
mgmt_be_adapter_status_write(vty);
return CMD_SUCCESS;
}
DEFPY(show_mgmt_be_xpath_reg,
show_mgmt_be_xpath_reg_cmd,
"show mgmt backend-yang-xpath-registry",
SHOW_STR
MGMTD_STR
"Backend Adapter YANG Xpath Registry\n")
{
mgmt_be_xpath_register_write(vty);
return CMD_SUCCESS;
}
DEFPY(show_mgmt_fe_adapter, show_mgmt_fe_adapter_cmd,
"show mgmt frontend-adapter all [detail$detail]",
SHOW_STR
MGMTD_STR
MGMTD_FE_ADAPTER_STR
"Display all Frontend Adapters\n"
"Display more details\n")
{
mgmt_fe_adapter_status_write(vty, !!detail);
return CMD_SUCCESS;
}
DEFPY_HIDDEN(mgmt_performance_measurement,
mgmt_performance_measurement_cmd,
"[no] mgmt performance-measurement",
NO_STR
MGMTD_STR
"Enable performance measurement\n")
{
if (no)
mgmt_fe_adapter_perf_measurement(vty, false);
else
mgmt_fe_adapter_perf_measurement(vty, true);
return CMD_SUCCESS;
}
DEFPY(mgmt_reset_performance_stats,
mgmt_reset_performance_stats_cmd,
"mgmt reset-statistics",
MGMTD_STR
"Reset the Performance measurement statistics\n")
{
mgmt_fe_adapter_reset_perf_stats(vty);
return CMD_SUCCESS;
}
DEFPY(show_mgmt_txn,
show_mgmt_txn_cmd,
"show mgmt transaction all",
SHOW_STR
MGMTD_STR
MGMTD_TXN_STR
"Display all Transactions\n")
{
mgmt_txn_status_write(vty);
return CMD_SUCCESS;
}
DEFPY(show_mgmt_ds,
show_mgmt_ds_cmd,
"show mgmt datastore [all|candidate|operational|running]$dsname",
SHOW_STR
MGMTD_STR
MGMTD_DS_STR
"All datastores (default)\n"
"Candidate datastore\n"
"Operational datastore\n"
"Running datastore\n")
{
struct mgmt_ds_ctx *ds_ctx;
if (!dsname || dsname[0] == 'a') {
mgmt_ds_status_write(vty);
return CMD_SUCCESS;
}
ds_ctx = mgmt_ds_get_ctx_by_id(mm, mgmt_ds_name2id(dsname));
if (!ds_ctx) {
vty_out(vty, "ERROR: Could not access %s datastore!\n", dsname);
return CMD_ERR_NO_MATCH;
}
mgmt_ds_status_write_one(vty, ds_ctx);
return CMD_SUCCESS;
}
DEFPY(mgmt_commit,
mgmt_commit_cmd,
"mgmt commit <check|apply|abort>$type",
MGMTD_STR
"Commit action\n"
"Validate the set of config commands\n"
"Validate and apply the set of config commands\n"
"Abort and drop the set of config commands recently added\n")
{
bool validate_only = type[0] == 'c';
bool abort = type[1] == 'b';
if (vty_mgmt_send_commit_config(vty, validate_only, abort) != 0)
return CMD_WARNING_CONFIG_FAILED;
return CMD_SUCCESS;
}
DEFPY(mgmt_set_config_data, mgmt_set_config_data_cmd,
"mgmt set-config WORD$path VALUE",
MGMTD_STR
"Set configuration data\n"
"XPath expression specifying the YANG data path\n"
"Value of the data to set\n")
{
strlcpy(vty->cfg_changes[0].xpath, path,
sizeof(vty->cfg_changes[0].xpath));
vty->cfg_changes[0].value = value;
vty->cfg_changes[0].operation = NB_OP_CREATE;
vty->num_cfg_changes = 1;
vty->no_implicit_commit = true;
vty_mgmt_send_config_data(vty);
vty->no_implicit_commit = false;
return CMD_SUCCESS;
}
DEFPY(mgmt_delete_config_data, mgmt_delete_config_data_cmd,
"mgmt delete-config WORD$path",
MGMTD_STR
"Delete configuration data\n"
"XPath expression specifying the YANG data path\n")
{
strlcpy(vty->cfg_changes[0].xpath, path,
sizeof(vty->cfg_changes[0].xpath));
vty->cfg_changes[0].value = NULL;
vty->cfg_changes[0].operation = NB_OP_DESTROY;
vty->num_cfg_changes = 1;
vty->no_implicit_commit = true;
vty_mgmt_send_config_data(vty);
vty->no_implicit_commit = false;
return CMD_SUCCESS;
}
DEFPY(show_mgmt_get_config, show_mgmt_get_config_cmd,
"show mgmt get-config [candidate|operational|running]$dsname WORD$path",
SHOW_STR MGMTD_STR
"Get configuration data from a specific configuration datastore\n"
"Candidate datastore (default)\n"
"Operational datastore\n"
"Running datastore\n"
"XPath expression specifying the YANG data path\n")
{
const char *xpath_list[VTY_MAXCFGCHANGES] = {0};
Mgmtd__DatastoreId datastore = MGMTD_DS_CANDIDATE;
if (dsname)
datastore = mgmt_ds_name2id(dsname);
xpath_list[0] = path;
vty_mgmt_send_get_config(vty, datastore, xpath_list, 1);
return CMD_SUCCESS;
}
DEFPY(show_mgmt_get_data, show_mgmt_get_data_cmd,
"show mgmt get-data [candidate|operational|running]$dsname WORD$path",
SHOW_STR MGMTD_STR
"Get data from a specific datastore\n"
"Candidate datastore\n"
"Operational datastore (default)\n"
"Running datastore\n"
"XPath expression specifying the YANG data path\n")
{
const char *xpath_list[VTY_MAXCFGCHANGES] = {0};
Mgmtd__DatastoreId datastore = MGMTD_DS_OPERATIONAL;
if (dsname)
datastore = mgmt_ds_name2id(dsname);
xpath_list[0] = path;
vty_mgmt_send_get_data(vty, datastore, xpath_list, 1);
return CMD_SUCCESS;
}
DEFPY(show_mgmt_dump_data,
show_mgmt_dump_data_cmd,
"show mgmt datastore-contents [candidate|operational|running]$dsname [xpath WORD$path] [file WORD$filepath] <json|xml>$fmt",
SHOW_STR
MGMTD_STR
"Get Datastore contents from a specific datastore\n"
"Candidate datastore (default)\n"
"Operational datastore\n"
"Running datastore\n"
"XPath expression specifying the YANG data path\n"
"XPath string\n"
"Dump the contents to a file\n"
"Full path of the file\n"
"json output\n"
"xml output\n")
{
struct mgmt_ds_ctx *ds_ctx;
Mgmtd__DatastoreId datastore = MGMTD_DS_CANDIDATE;
LYD_FORMAT format = fmt[0] == 'j' ? LYD_JSON : LYD_XML;
FILE *f = NULL;
if (datastore)
datastore = mgmt_ds_name2id(dsname);
ds_ctx = mgmt_ds_get_ctx_by_id(mm, datastore);
if (!ds_ctx) {
vty_out(vty, "ERROR: Could not access datastore!\n");
return CMD_ERR_NO_MATCH;
}
if (filepath) {
f = fopen(filepath, "w");
if (!f) {
vty_out(vty,
"Could not open file pointed by filepath %s\n",
filepath);
return CMD_SUCCESS;
}
}
mgmt_ds_dump_tree(vty, ds_ctx, path, f, format);
if (f)
fclose(f);
return CMD_SUCCESS;
}
DEFPY(show_mgmt_map_xpath,
show_mgmt_map_xpath_cmd,
"show mgmt yang-xpath-subscription WORD$path",
SHOW_STR
MGMTD_STR
"Get YANG Backend Subscription\n"
"XPath expression specifying the YANG data path\n")
{
mgmt_be_xpath_subscr_info_write(vty, path);
return CMD_SUCCESS;
}
DEFPY(mgmt_load_config,
mgmt_load_config_cmd,
"mgmt load-config WORD$filepath <merge|replace>$type",
MGMTD_STR
"Load configuration onto Candidate Datastore\n"
"Full path of the file\n"
"Merge configuration with contents of Candidate Datastore\n"
"Replace the existing contents of Candidate datastore\n")
{
bool merge = type[0] == 'm' ? true : false;
struct mgmt_ds_ctx *ds_ctx;
int ret;
if (access(filepath, F_OK) == -1) {
vty_out(vty, "ERROR: File %s : %s\n", filepath,
strerror(errno));
return CMD_ERR_NO_FILE;
}
ds_ctx = mgmt_ds_get_ctx_by_id(mm, MGMTD_DS_CANDIDATE);
if (!ds_ctx) {
vty_out(vty, "ERROR: Could not access Candidate datastore!\n");
return CMD_ERR_NO_MATCH;
}
ret = mgmt_ds_load_config_from_file(ds_ctx, filepath, merge);
if (ret != 0)
vty_out(vty, "Error with parsing the file with error code %d\n",
ret);
return CMD_SUCCESS;
}
DEFPY(mgmt_save_config,
mgmt_save_config_cmd,
"mgmt save-config <candidate|running>$dsname WORD$filepath",
MGMTD_STR
"Save configuration from datastore\n"
"Candidate datastore\n"
"Running datastore\n"
"Full path of the file\n")
{
Mgmtd__DatastoreId datastore = mgmt_ds_name2id(dsname);
struct mgmt_ds_ctx *ds_ctx;
FILE *f;
ds_ctx = mgmt_ds_get_ctx_by_id(mm, datastore);
if (!ds_ctx) {
vty_out(vty, "ERROR: Could not access the '%s' datastore!\n",
dsname);
return CMD_ERR_NO_MATCH;
}
if (!filepath) {
vty_out(vty, "ERROR: No file path mentioned!\n");
return CMD_ERR_NO_MATCH;
}
f = fopen(filepath, "w");
if (!f) {
vty_out(vty, "Could not open file pointed by filepath %s\n",
filepath);
return CMD_SUCCESS;
}
mgmt_ds_dump_tree(vty, ds_ctx, "/", f, LYD_JSON);
fclose(f);
return CMD_SUCCESS;
}
DEFPY(show_mgmt_cmt_hist,
show_mgmt_cmt_hist_cmd,
"show mgmt commit-history",
SHOW_STR
MGMTD_STR
"Show commit history\n")
{
show_mgmt_cmt_history(vty);
return CMD_SUCCESS;
}
DEFPY(mgmt_rollback,
mgmt_rollback_cmd,
"mgmt rollback <commit-id WORD$commit | last [(1-10)]$last>",
MGMTD_STR
"Rollback commits\n"
"Rollback to commit ID\n"
"Commit-ID\n"
"Rollbak n commits\n"
"Number of commits\n")
{
if (commit)
mgmt_history_rollback_by_id(vty, commit);
else
mgmt_history_rollback_n(vty, last);
return CMD_SUCCESS;
}
static int config_write_mgmt_debug(struct vty *vty);
static struct cmd_node debug_node = {
.name = "debug",
.node = DEBUG_NODE,
.prompt = "",
.config_write = config_write_mgmt_debug,
};
static int config_write_mgmt_debug(struct vty *vty)
{
int n = mgmt_debug_be + mgmt_debug_fe + mgmt_debug_ds + mgmt_debug_txn;
if (!n)
return 0;
if (n == 4) {
vty_out(vty, "debug mgmt all\n");
return 0;
}
vty_out(vty, "debug mgmt");
if (mgmt_debug_be)
vty_out(vty, " backend");
if (mgmt_debug_ds)
vty_out(vty, " datastore");
if (mgmt_debug_fe)
vty_out(vty, " frontend");
if (mgmt_debug_txn)
vty_out(vty, " transaction");
vty_out(vty, "\n");
return 0;
}
DEFPY(debug_mgmt,
debug_mgmt_cmd,
"[no$no] debug mgmt <all$all|{backend$be|datastore$ds|frontend$fe|transaction$txn}>",
NO_STR
DEBUG_STR
MGMTD_STR
"All debug\n"
"Back-end debug\n"
"Datastore debug\n"
"Front-end debug\n"
"Transaction debug\n")
{
bool set = !no;
if (all)
be = fe = ds = txn = set ? all : NULL;
if (be)
mgmt_debug_be = set;
if (ds)
mgmt_debug_ds = set;
if (fe)
mgmt_debug_fe = set;
if (txn)
mgmt_debug_txn = set;
return CMD_SUCCESS;
}
void mgmt_vty_init(void)
{
/*
* Initialize command handling from VTYSH connection.
* Call command initialization routines defined by
* backend components that are moved to new MGMTD infra
* here one by one.
*/
#if HAVE_STATICD
extern void static_vty_init(void);
static_vty_init();
#endif
install_node(&debug_node);
install_element(VIEW_NODE, &show_mgmt_be_adapter_cmd);
install_element(VIEW_NODE, &show_mgmt_be_xpath_reg_cmd);
install_element(VIEW_NODE, &show_mgmt_fe_adapter_cmd);
install_element(VIEW_NODE, &show_mgmt_txn_cmd);
install_element(VIEW_NODE, &show_mgmt_ds_cmd);
install_element(VIEW_NODE, &show_mgmt_get_config_cmd);
install_element(VIEW_NODE, &show_mgmt_get_data_cmd);
install_element(VIEW_NODE, &show_mgmt_dump_data_cmd);
install_element(VIEW_NODE, &show_mgmt_map_xpath_cmd);
install_element(VIEW_NODE, &show_mgmt_cmt_hist_cmd);
install_element(CONFIG_NODE, &mgmt_commit_cmd);
install_element(CONFIG_NODE, &mgmt_set_config_data_cmd);
install_element(CONFIG_NODE, &mgmt_delete_config_data_cmd);
install_element(CONFIG_NODE, &mgmt_load_config_cmd);
install_element(CONFIG_NODE, &mgmt_save_config_cmd);
install_element(CONFIG_NODE, &mgmt_rollback_cmd);
install_element(VIEW_NODE, &debug_mgmt_cmd);
install_element(CONFIG_NODE, &debug_mgmt_cmd);
/* Enable view */
install_element(ENABLE_NODE, &mgmt_performance_measurement_cmd);
install_element(ENABLE_NODE, &mgmt_reset_performance_stats_cmd);
/*
* TODO: Register and handlers for auto-completion here.
*/
}