YANG Action (RFC 7950 Section 7.15)
See [Support for "action" statement](https://github.com/clicon/clixon/issues/101)
This commit is contained in:
parent
87c65c3541
commit
bdb516fec9
16 changed files with 583 additions and 104 deletions
|
|
@ -77,6 +77,7 @@
|
|||
#include "clixon_netconf_lib.h"
|
||||
#include "clixon_xml_sort.h"
|
||||
#include "clixon_yang_type.h"
|
||||
#include "clixon_xml_map.h"
|
||||
#include "clixon_xml_bind.h"
|
||||
|
||||
/*
|
||||
|
|
@ -183,31 +184,33 @@ populate_self_parent(cxobj *xt,
|
|||
}
|
||||
if (xml2ns(xt, xml_prefix(xt), &ns) < 0)
|
||||
goto done;
|
||||
if ((y = yang_find_datanode(yparent, name)) == NULL){
|
||||
if (_yang_unknown_anydata){
|
||||
/* Add dummy Y_ANYDATA yang stmt, see ysp_add */
|
||||
if ((y = yang_anydata_add(yparent, name)) < 0)
|
||||
/* Special case since action is not a datanode */
|
||||
if ((y = yang_find(yparent, Y_ACTION, name)) == NULL)
|
||||
if ((y = yang_find_datanode(yparent, name)) == NULL){
|
||||
if (_yang_unknown_anydata){
|
||||
/* Add dummy Y_ANYDATA yang stmt, see ysp_add */
|
||||
if ((y = yang_anydata_add(yparent, name)) < 0)
|
||||
goto done;
|
||||
xml_spec_set(xt, y);
|
||||
retval = 2; /* treat as anydata */
|
||||
clicon_log(LOG_WARNING,
|
||||
"%s: %d: No YANG spec for %s, anydata used",
|
||||
__FUNCTION__, __LINE__, name);
|
||||
goto done;
|
||||
xml_spec_set(xt, y);
|
||||
retval = 2; /* treat as anydata */
|
||||
clicon_log(LOG_WARNING,
|
||||
"%s: %d: No YANG spec for %s, anydata used",
|
||||
__FUNCTION__, __LINE__, name);
|
||||
goto done;
|
||||
}
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "Failed to find YANG spec of XML node: %s", name);
|
||||
cprintf(cb, " with parent: %s", xml_name(xp));
|
||||
if (ns)
|
||||
cprintf(cb, " in namespace: %s", ns);
|
||||
if (xerr &&
|
||||
netconf_unknown_element_xml(xerr, "application", name, cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "Failed to find YANG spec of XML node: %s", name);
|
||||
cprintf(cb, " with parent: %s", xml_name(xp));
|
||||
if (ns)
|
||||
cprintf(cb, " in namespace: %s", ns);
|
||||
if (xerr &&
|
||||
netconf_unknown_element_xml(xerr, "application", name, cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
nsy = yang_find_mynamespace(y);
|
||||
if (ns == NULL || nsy == NULL){
|
||||
if (xerr &&
|
||||
|
|
@ -516,6 +519,92 @@ xml_bind_yang0(cxobj *xt,
|
|||
goto done;
|
||||
}
|
||||
|
||||
/*! RPC-specific
|
||||
*/
|
||||
static int
|
||||
xml_bind_yang_rpc_rpc(cxobj *x,
|
||||
yang_stmt *yrpc,
|
||||
char *rpcname,
|
||||
cxobj **xerr)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cb = NULL;
|
||||
char *name;
|
||||
cxobj *xc;
|
||||
yang_stmt *yi = NULL; /* input */
|
||||
int ret;
|
||||
|
||||
xml_spec_set(x, yrpc); /* required for validate */
|
||||
if ((yi = yang_find(yrpc, Y_INPUT, NULL)) == NULL){
|
||||
/* If no yang input spec but RPC has elements, return unknown element */
|
||||
if (xml_child_nr_type(x, CX_ELMNT) != 0){
|
||||
xc = xml_child_i_type(x, 0, CX_ELMNT); /* Pick first */
|
||||
name = xml_name(xc);
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "Unrecognized parameter: %s in rpc: %s", name, rpcname);
|
||||
if (xerr &&
|
||||
netconf_unknown_element_xml(xerr, "application", name, cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else{
|
||||
/* xml_bind_yang need to have parent with yang spec for
|
||||
* recursive population to work. Therefore, assign input yang
|
||||
* to rpc level although not 100% intuitive */
|
||||
xml_spec_set(x, yi);
|
||||
if ((ret = xml_bind_yang(x, YB_PARENT, NULL, xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
}
|
||||
retval = 1;
|
||||
done:
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Action-specific
|
||||
*
|
||||
* Find the innermost container or list containing an XML element that carries the name of the
|
||||
* defined action.
|
||||
* Only one action can be invoked in one rpc
|
||||
* XXX if not more action, consider folding into calling function
|
||||
*/
|
||||
static int
|
||||
xml_bind_yang_rpc_action(cxobj *xn,
|
||||
yang_stmt *yspec,
|
||||
cxobj **xerr)
|
||||
{
|
||||
int retval = -1;
|
||||
int ret;
|
||||
cxobj *xi;
|
||||
yang_stmt *yi;;
|
||||
|
||||
if ((ret = xml_bind_yang(xn, YB_MODULE, yspec, xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
/* Special case: bind "action" node to module for validate code to work */
|
||||
if ((xi = xml_child_i_type(xn, 0, CX_ELMNT)) != NULL &&
|
||||
(yi = xml_spec(xi))){
|
||||
xml_spec_set(xn, ys_module(yi));
|
||||
}
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Find yang spec association of XML node for incoming RPC starting with <rpc>
|
||||
*
|
||||
* Incoming RPC has an "input" structure that is not taken care of by xml_bind_yang
|
||||
|
|
@ -541,13 +630,11 @@ xml_bind_yang_rpc(cxobj *xrpc,
|
|||
int retval = -1;
|
||||
yang_stmt *yrpc = NULL; /* yang node */
|
||||
yang_stmt *ymod=NULL; /* yang module */
|
||||
yang_stmt *yi = NULL; /* input */
|
||||
cxobj *x;
|
||||
int ret;
|
||||
char *opname; /* top-level netconf operation */
|
||||
char *rpcname; /* RPC name */
|
||||
char *name;
|
||||
cbuf *cb = NULL;
|
||||
cxobj *xc;
|
||||
|
||||
opname = xml_name(xrpc);
|
||||
|
|
@ -607,6 +694,15 @@ xml_bind_yang_rpc(cxobj *xrpc,
|
|||
x = NULL;
|
||||
while ((x = xml_child_each(xrpc, x, CX_ELMNT)) != NULL) {
|
||||
rpcname = xml_name(x);
|
||||
if ((ret = xml_rpc_isaction(x)) < 0)
|
||||
goto done;
|
||||
if (ret == 1){
|
||||
if ((ret = xml_bind_yang_rpc_action(x, yspec, xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
goto ok;
|
||||
} /* if not action fall through */
|
||||
if (ys_module_by_xml(yspec, x, &ymod) < 0)
|
||||
goto done;
|
||||
if (ymod == NULL){
|
||||
|
|
@ -621,39 +717,14 @@ xml_bind_yang_rpc(cxobj *xrpc,
|
|||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
xml_spec_set(x, yrpc); /* required for validate */
|
||||
if ((yi = yang_find(yrpc, Y_INPUT, NULL)) == NULL){
|
||||
/* If no yang input spec but RPC has elements, return unknown element */
|
||||
if (xml_child_nr_type(x, CX_ELMNT) != 0){
|
||||
xc = xml_child_i_type(x, 0, CX_ELMNT); /* Pick first */
|
||||
name = xml_name(xc);
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "Unrecognized parameter: %s in rpc: %s", name, rpcname);
|
||||
if (xerr &&
|
||||
netconf_unknown_element_xml(xerr, "application", name, cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else{
|
||||
/* xml_bind_yang need to have parent with yang spec for
|
||||
* recursive population to work. Therefore, assign input yang
|
||||
* to rpc level although not 100% intuitive */
|
||||
xml_spec_set(x, yi);
|
||||
if ((ret = xml_bind_yang(x, YB_PARENT, NULL, xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
}
|
||||
if ((ret = xml_bind_yang_rpc_rpc(x, yrpc, rpcname, xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
}
|
||||
ok:
|
||||
retval = 1;
|
||||
done:
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue