mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-09 12:39:21 +00:00
mgmt, lib: differentiate DELETE and REMOVE operations
Currently, there's a single operation type which doesn't return error if the object doesn't exists. To be compatible with NETCONF/RESTCONF, we should support differentiate between DELETE (fails when object doesn't exist) and REMOVE (doesn't fail if the object doesn't exist). Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
This commit is contained in:
parent
76e4eb84dd
commit
3c2598a26f
@ -1005,7 +1005,7 @@ configuration. Here’s the declaration of this structure (taken from the
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Operation to apply (either NB_OP_CREATE, NB_OP_MODIFY or
|
* Operation to apply (either NB_OP_CREATE, NB_OP_MODIFY or
|
||||||
* NB_OP_DELETE).
|
* NB_OP_DESTROY).
|
||||||
*/
|
*/
|
||||||
enum nb_operation operation;
|
enum nb_operation operation;
|
||||||
|
|
||||||
@ -1205,7 +1205,7 @@ This example shows how to create a list entry:
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.xpath = "./access-list",
|
.xpath = "./access-list",
|
||||||
.operation = acl ? NB_OP_MODIFY : NB_OP_DELETE,
|
.operation = acl ? NB_OP_MODIFY : NB_OP_DESTROY,
|
||||||
.value = acl,
|
.value = acl,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -1242,7 +1242,7 @@ When deleting a list entry, all non-key leaves can be ignored:
|
|||||||
struct cli_config_change changes[] = {
|
struct cli_config_change changes[] = {
|
||||||
{
|
{
|
||||||
.xpath = ".",
|
.xpath = ".",
|
||||||
.operation = NB_OP_DELETE,
|
.operation = NB_OP_DESTROY,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -55,8 +55,9 @@ message YangData {
|
|||||||
enum CfgDataReqType {
|
enum CfgDataReqType {
|
||||||
REQ_TYPE_NONE = 0;
|
REQ_TYPE_NONE = 0;
|
||||||
SET_DATA = 1;
|
SET_DATA = 1;
|
||||||
DELETE_DATA = 2;
|
REMOVE_DATA = 2;
|
||||||
CREATE_DATA = 3;
|
CREATE_DATA = 3;
|
||||||
|
DELETE_DATA = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message YangCfgDataReq {
|
message YangCfgDataReq {
|
||||||
|
@ -565,11 +565,25 @@ static int mgmt_be_update_setcfg_in_batch(struct mgmt_be_client *client_ctx,
|
|||||||
for (index = 0; index < num_req; index++) {
|
for (index = 0; index < num_req; index++) {
|
||||||
cfg_chg = &txn_req->req.set_cfg.cfg_changes[index];
|
cfg_chg = &txn_req->req.set_cfg.cfg_changes[index];
|
||||||
|
|
||||||
if (cfg_req[index]->req_type
|
/*
|
||||||
== MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA)
|
* Treat all operations as destroy or modify, because we don't
|
||||||
|
* need additional existence checks on the backend. Everything
|
||||||
|
* is already checked by mgmtd.
|
||||||
|
*/
|
||||||
|
switch (cfg_req[index]->req_type) {
|
||||||
|
case MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA:
|
||||||
|
case MGMTD__CFG_DATA_REQ_TYPE__REMOVE_DATA:
|
||||||
cfg_chg->operation = NB_OP_DESTROY;
|
cfg_chg->operation = NB_OP_DESTROY;
|
||||||
else
|
break;
|
||||||
|
case MGMTD__CFG_DATA_REQ_TYPE__SET_DATA:
|
||||||
|
case MGMTD__CFG_DATA_REQ_TYPE__CREATE_DATA:
|
||||||
cfg_chg->operation = NB_OP_MODIFY;
|
cfg_chg->operation = NB_OP_MODIFY;
|
||||||
|
break;
|
||||||
|
case MGMTD__CFG_DATA_REQ_TYPE__REQ_TYPE_NONE:
|
||||||
|
case _MGMTD__CFG_DATA_REQ_TYPE_IS_INT_SIZE:
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
strlcpy(cfg_chg->xpath, cfg_req[index]->data->xpath,
|
strlcpy(cfg_chg->xpath, cfg_req[index]->data->xpath,
|
||||||
sizeof(cfg_chg->xpath));
|
sizeof(cfg_chg->xpath));
|
||||||
|
@ -731,13 +731,14 @@ int nb_candidate_edit(struct nb_config *candidate,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NB_OP_DESTROY:
|
case NB_OP_DESTROY:
|
||||||
|
case NB_OP_DELETE:
|
||||||
dnode = yang_dnode_get(candidate->dnode, xpath_edit);
|
dnode = yang_dnode_get(candidate->dnode, xpath_edit);
|
||||||
if (!dnode)
|
if (!dnode) {
|
||||||
/*
|
if (operation == NB_OP_DELETE)
|
||||||
* Return a special error code so the caller can choose
|
return NB_ERR;
|
||||||
* whether to ignore it or not.
|
else
|
||||||
*/
|
return NB_OK;
|
||||||
return NB_ERR_NOT_FOUND;
|
}
|
||||||
/* destroy dependant */
|
/* destroy dependant */
|
||||||
if (nb_node->dep_cbs.get_dependant_xpath) {
|
if (nb_node->dep_cbs.get_dependant_xpath) {
|
||||||
nb_node->dep_cbs.get_dependant_xpath(dnode, dep_xpath);
|
nb_node->dep_cbs.get_dependant_xpath(dnode, dep_xpath);
|
||||||
@ -767,6 +768,8 @@ const char *nb_operation_name(enum nb_operation operation)
|
|||||||
return "modify";
|
return "modify";
|
||||||
case NB_OP_DESTROY:
|
case NB_OP_DESTROY:
|
||||||
return "destroy";
|
return "destroy";
|
||||||
|
case NB_OP_DELETE:
|
||||||
|
return "delete";
|
||||||
case NB_OP_MOVE:
|
case NB_OP_MOVE:
|
||||||
return "move";
|
return "move";
|
||||||
}
|
}
|
||||||
@ -777,7 +780,8 @@ const char *nb_operation_name(enum nb_operation operation)
|
|||||||
bool nb_is_operation_allowed(struct nb_node *nb_node, enum nb_operation oper)
|
bool nb_is_operation_allowed(struct nb_node *nb_node, enum nb_operation oper)
|
||||||
{
|
{
|
||||||
if (lysc_is_key(nb_node->snode)) {
|
if (lysc_is_key(nb_node->snode)) {
|
||||||
if (oper == NB_OP_MODIFY || oper == NB_OP_DESTROY)
|
if (oper == NB_OP_MODIFY || oper == NB_OP_DESTROY
|
||||||
|
|| oper == NB_OP_DELETE)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -842,7 +846,7 @@ void nb_candidate_edit_config_changes(
|
|||||||
ret = nb_candidate_edit(candidate_config, nb_node,
|
ret = nb_candidate_edit(candidate_config, nb_node,
|
||||||
change->operation, xpath, NULL, data);
|
change->operation, xpath, NULL, data);
|
||||||
yang_data_free(data);
|
yang_data_free(data);
|
||||||
if (ret != NB_OK && ret != NB_ERR_NOT_FOUND) {
|
if (ret != NB_OK) {
|
||||||
flog_warn(
|
flog_warn(
|
||||||
EC_LIB_NB_CANDIDATE_EDIT_ERROR,
|
EC_LIB_NB_CANDIDATE_EDIT_ERROR,
|
||||||
"%s: failed to edit candidate configuration: operation [%s] xpath [%s]",
|
"%s: failed to edit candidate configuration: operation [%s] xpath [%s]",
|
||||||
|
@ -722,6 +722,7 @@ enum nb_operation {
|
|||||||
NB_OP_CREATE,
|
NB_OP_CREATE,
|
||||||
NB_OP_MODIFY,
|
NB_OP_MODIFY,
|
||||||
NB_OP_DESTROY,
|
NB_OP_DESTROY,
|
||||||
|
NB_OP_DELETE,
|
||||||
NB_OP_MOVE,
|
NB_OP_MOVE,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -953,7 +954,6 @@ extern bool nb_is_operation_allowed(struct nb_node *nb_node,
|
|||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* - NB_OK on success.
|
* - NB_OK on success.
|
||||||
* - NB_ERR_NOT_FOUND when the element to be deleted was not found.
|
|
||||||
* - NB_ERR for other errors.
|
* - NB_ERR for other errors.
|
||||||
*/
|
*/
|
||||||
extern int nb_candidate_edit(struct nb_config *candidate,
|
extern int nb_candidate_edit(struct nb_config *candidate,
|
||||||
|
@ -32,7 +32,7 @@ extern struct nb_config *vty_shared_candidate_config;
|
|||||||
* XPath (absolute or relative) of the configuration option being edited.
|
* XPath (absolute or relative) of the configuration option being edited.
|
||||||
*
|
*
|
||||||
* operation
|
* operation
|
||||||
* Operation to apply (either NB_OP_CREATE, NB_OP_MODIFY or NB_OP_DELETE).
|
* Operation to apply (either NB_OP_CREATE, NB_OP_MODIFY or NB_OP_DESTROY).
|
||||||
*
|
*
|
||||||
* value
|
* value
|
||||||
* New value of the configuration option. Should be NULL for typeless YANG
|
* New value of the configuration option. Should be NULL for typeless YANG
|
||||||
|
@ -221,7 +221,7 @@ static int frr_sr_process_change(struct nb_config *candidate,
|
|||||||
|
|
||||||
ret = nb_candidate_edit(candidate, nb_node, nb_op, xpath, NULL, data);
|
ret = nb_candidate_edit(candidate, nb_node, nb_op, xpath, NULL, data);
|
||||||
yang_data_free(data);
|
yang_data_free(data);
|
||||||
if (ret != NB_OK && ret != NB_ERR_NOT_FOUND) {
|
if (ret != NB_OK) {
|
||||||
flog_warn(
|
flog_warn(
|
||||||
EC_LIB_NB_CANDIDATE_EDIT_ERROR,
|
EC_LIB_NB_CANDIDATE_EDIT_ERROR,
|
||||||
"%s: failed to edit candidate configuration: operation [%s] xpath [%s]",
|
"%s: failed to edit candidate configuration: operation [%s] xpath [%s]",
|
||||||
|
@ -3996,11 +3996,16 @@ int vty_mgmt_send_config_data(struct vty *vty, const char *xpath_base,
|
|||||||
mgmt_yang_cfg_data_req_init(&cfg_req[indx]);
|
mgmt_yang_cfg_data_req_init(&cfg_req[indx]);
|
||||||
cfg_req[indx].data = &cfg_data[indx];
|
cfg_req[indx].data = &cfg_data[indx];
|
||||||
switch (vty->cfg_changes[indx].operation) {
|
switch (vty->cfg_changes[indx].operation) {
|
||||||
case NB_OP_DESTROY:
|
case NB_OP_DELETE:
|
||||||
cfg_req[indx].req_type =
|
cfg_req[indx].req_type =
|
||||||
MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA;
|
MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NB_OP_DESTROY:
|
||||||
|
cfg_req[indx].req_type =
|
||||||
|
MGMTD__CFG_DATA_REQ_TYPE__REMOVE_DATA;
|
||||||
|
break;
|
||||||
|
|
||||||
case NB_OP_CREATE_EXCL:
|
case NB_OP_CREATE_EXCL:
|
||||||
cfg_req[indx].req_type =
|
cfg_req[indx].req_type =
|
||||||
MGMTD__CFG_DATA_REQ_TYPE__CREATE_DATA;
|
MGMTD__CFG_DATA_REQ_TYPE__CREATE_DATA;
|
||||||
|
@ -918,7 +918,7 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req,
|
|||||||
*/
|
*/
|
||||||
if (chg->cb.operation == NB_CB_DESTROY)
|
if (chg->cb.operation == NB_CB_DESTROY)
|
||||||
batch->cfg_data[batch->num_cfg_data].req_type =
|
batch->cfg_data[batch->num_cfg_data].req_type =
|
||||||
MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA;
|
MGMTD__CFG_DATA_REQ_TYPE__REMOVE_DATA;
|
||||||
else
|
else
|
||||||
batch->cfg_data[batch->num_cfg_data].req_type =
|
batch->cfg_data[batch->num_cfg_data].req_type =
|
||||||
MGMTD__CFG_DATA_REQ_TYPE__SET_DATA;
|
MGMTD__CFG_DATA_REQ_TYPE__SET_DATA;
|
||||||
@ -2052,6 +2052,9 @@ int mgmt_txn_send_set_config_req(uint64_t txn_id, uint64_t req_id,
|
|||||||
|
|
||||||
switch (cfg_req[indx]->req_type) {
|
switch (cfg_req[indx]->req_type) {
|
||||||
case MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA:
|
case MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA:
|
||||||
|
cfg_chg->operation = NB_OP_DELETE;
|
||||||
|
break;
|
||||||
|
case MGMTD__CFG_DATA_REQ_TYPE__REMOVE_DATA:
|
||||||
cfg_chg->operation = NB_OP_DESTROY;
|
cfg_chg->operation = NB_OP_DESTROY;
|
||||||
break;
|
break;
|
||||||
case MGMTD__CFG_DATA_REQ_TYPE__SET_DATA:
|
case MGMTD__CFG_DATA_REQ_TYPE__SET_DATA:
|
||||||
|
@ -185,6 +185,23 @@ DEFPY(mgmt_delete_config_data, mgmt_delete_config_data_cmd,
|
|||||||
"XPath expression specifying the YANG data path\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_DELETE;
|
||||||
|
vty->num_cfg_changes = 1;
|
||||||
|
|
||||||
|
vty_mgmt_send_config_data(vty, NULL, false);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(mgmt_remove_config_data, mgmt_remove_config_data_cmd,
|
||||||
|
"mgmt remove-config WORD$path",
|
||||||
|
MGMTD_STR
|
||||||
|
"Remove configuration data\n"
|
||||||
|
"XPath expression specifying the YANG data path\n")
|
||||||
|
{
|
||||||
|
|
||||||
strlcpy(vty->cfg_changes[0].xpath, path,
|
strlcpy(vty->cfg_changes[0].xpath, path,
|
||||||
sizeof(vty->cfg_changes[0].xpath));
|
sizeof(vty->cfg_changes[0].xpath));
|
||||||
vty->cfg_changes[0].value = NULL;
|
vty->cfg_changes[0].value = NULL;
|
||||||
@ -547,6 +564,7 @@ void mgmt_vty_init(void)
|
|||||||
install_element(CONFIG_NODE, &mgmt_create_config_data_cmd);
|
install_element(CONFIG_NODE, &mgmt_create_config_data_cmd);
|
||||||
install_element(CONFIG_NODE, &mgmt_set_config_data_cmd);
|
install_element(CONFIG_NODE, &mgmt_set_config_data_cmd);
|
||||||
install_element(CONFIG_NODE, &mgmt_delete_config_data_cmd);
|
install_element(CONFIG_NODE, &mgmt_delete_config_data_cmd);
|
||||||
|
install_element(CONFIG_NODE, &mgmt_remove_config_data_cmd);
|
||||||
install_element(CONFIG_NODE, &mgmt_load_config_cmd);
|
install_element(CONFIG_NODE, &mgmt_load_config_cmd);
|
||||||
install_element(CONFIG_NODE, &mgmt_save_config_cmd);
|
install_element(CONFIG_NODE, &mgmt_save_config_cmd);
|
||||||
install_element(CONFIG_NODE, &mgmt_rollback_cmd);
|
install_element(CONFIG_NODE, &mgmt_rollback_cmd);
|
||||||
|
Loading…
Reference in New Issue
Block a user