Added option to treat unknown XML (wrt YANG) as anydata.
This commit is contained in:
parent
12d1b67250
commit
dafc6d10e0
15 changed files with 80 additions and 8 deletions
|
|
@ -50,6 +50,8 @@ Expected: May 2020
|
||||||
|
|
||||||
### Minor changes
|
### Minor changes
|
||||||
|
|
||||||
|
* Added option `CLICON_YANG_UNKNOWN_ANYDATA` to treat unknown XML (wrt YANG) as anydata.
|
||||||
|
* This is to be (very) forgiving but you need to accept eg unsynchronized YANG and XML
|
||||||
* Compile-time option: `USE_CLIGEN44` for running clixon-45 with cligen-44.
|
* Compile-time option: `USE_CLIGEN44` for running clixon-45 with cligen-44.
|
||||||
* Temporary fix since cligen-45 have some non-backward compatible behaviour.
|
* Temporary fix since cligen-45 have some non-backward compatible behaviour.
|
||||||
* Optimizations
|
* Optimizations
|
||||||
|
|
|
||||||
|
|
@ -523,7 +523,6 @@ main(int argc,
|
||||||
usage(h, argv[0]);
|
usage(h, argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* External NACM file? */
|
/* External NACM file? */
|
||||||
nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE");
|
nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE");
|
||||||
if (nacm_mode && strcmp(nacm_mode, "external") == 0)
|
if (nacm_mode && strcmp(nacm_mode, "external") == 0)
|
||||||
|
|
@ -692,6 +691,9 @@ main(int argc,
|
||||||
clicon_configfile(h));
|
clicon_configfile(h));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
/* Treat unknown XML as anydata */
|
||||||
|
if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
|
||||||
|
xml_bind_yang_unknown_anydata(1);
|
||||||
|
|
||||||
/* Publish stream on pubsub channels.
|
/* Publish stream on pubsub channels.
|
||||||
* CLICON_STREAM_PUB should be set to URL to where streams are published
|
* CLICON_STREAM_PUB should be set to URL to where streams are published
|
||||||
|
|
|
||||||
|
|
@ -515,6 +515,10 @@ main(int argc, char **argv)
|
||||||
if (netconf_module_features(h) < 0)
|
if (netconf_module_features(h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
/* Treat unknwon XML as anydata */
|
||||||
|
if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
|
||||||
|
xml_bind_yang_unknown_anydata(1);
|
||||||
|
|
||||||
/* Create top-level and store as option */
|
/* Create top-level and store as option */
|
||||||
if ((yspec = yspec_new()) == NULL)
|
if ((yspec = yspec_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -715,6 +715,9 @@ main(int argc,
|
||||||
if ((yspec = yspec_new()) == NULL)
|
if ((yspec = yspec_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_dbspec_yang_set(h, yspec);
|
clicon_dbspec_yang_set(h, yspec);
|
||||||
|
/* Treat unknown XML as anydata */
|
||||||
|
if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
|
||||||
|
xml_bind_yang_unknown_anydata(1);
|
||||||
|
|
||||||
/* Load restconf plugins before yangs are loaded (eg extension callbacks) */
|
/* Load restconf plugins before yangs are loaded (eg extension callbacks) */
|
||||||
if ((dir = clicon_restconf_dir(h)) != NULL)
|
if ((dir = clicon_restconf_dir(h)) != NULL)
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
|
int xml_bind_yang_unknown_anydata(int bool);
|
||||||
int xml_bind_yang_rpc(cxobj *xrpc, yang_stmt *yspec, cxobj **xerr);
|
int xml_bind_yang_rpc(cxobj *xrpc, yang_stmt *yspec, cxobj **xerr);
|
||||||
int xml_bind_yang_rpc_reply(cxobj *xrpc, char *name, yang_stmt *yspec, cxobj **xerr);
|
int xml_bind_yang_rpc_reply(cxobj *xrpc, char *name, yang_stmt *yspec, cxobj **xerr);
|
||||||
int xml_bind_yang0(cxobj *xt, yang_bind yb, yang_stmt *yspec, cxobj **xerr);
|
int xml_bind_yang0(cxobj *xt, yang_bind yb, yang_stmt *yspec, cxobj **xerr);
|
||||||
|
|
|
||||||
|
|
@ -555,7 +555,7 @@ clicon_option_int_set(clicon_handle h,
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_option_bool(clicon_handle h,
|
clicon_option_bool(clicon_handle h,
|
||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
|
|
@ -563,7 +563,9 @@ clicon_option_bool(clicon_handle h,
|
||||||
return 0;
|
return 0;
|
||||||
if (strcmp(s,"true")==0)
|
if (strcmp(s,"true")==0)
|
||||||
return 1;
|
return 1;
|
||||||
return 0; /* Hopefully false, but anything else than "true" */
|
if (strcmp(s,"1")==0)
|
||||||
|
return 1;
|
||||||
|
return 0; /* Hopefully false, but anything else than "true" or "one" */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Set option given as bool
|
/*! Set option given as bool
|
||||||
|
|
@ -578,8 +580,14 @@ clicon_option_bool_set(clicon_handle h,
|
||||||
{
|
{
|
||||||
char s[64];
|
char s[64];
|
||||||
|
|
||||||
if (snprintf(s, sizeof(s)-1, "%u", val) < 0)
|
if (val != 0 && val != 1){
|
||||||
|
clicon_err(OE_CFG, EINVAL, "val is %d, 0 or 1 expected", val);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
if (snprintf(s, sizeof(s)-1, "%s", val?"true":"false") < 0){
|
||||||
|
clicon_err(OE_CFG, errno, "snprintf");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return clicon_option_str_set(h, name, s);
|
return clicon_option_str_set(h, name, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1091,15 +1091,17 @@ xml_yang_validate_all(clicon_handle h,
|
||||||
and !Node has a config sub-statement and it is false */
|
and !Node has a config sub-statement and it is false */
|
||||||
ys=xml_spec(xt);
|
ys=xml_spec(xt);
|
||||||
if (ys==NULL){
|
if (ys==NULL){
|
||||||
|
if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
|
||||||
|
goto ok;
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (xml2ns(xt, xml_prefix(xt), &namespace) < 0)
|
|
||||||
goto done;
|
|
||||||
cprintf(cb, "Failed to find YANG spec of XML node: %s", xml_name(xt));
|
cprintf(cb, "Failed to find YANG spec of XML node: %s", xml_name(xt));
|
||||||
if ((xp = xml_parent(xt)) != NULL)
|
if ((xp = xml_parent(xt)) != NULL)
|
||||||
cprintf(cb, " with parent: %s", xml_name(xp));
|
cprintf(cb, " with parent: %s", xml_name(xp));
|
||||||
|
if (xml2ns(xt, xml_prefix(xt), &namespace) < 0)
|
||||||
|
goto done;
|
||||||
if (namespace)
|
if (namespace)
|
||||||
cprintf(cb, " in namespace: %s", namespace);
|
cprintf(cb, " in namespace: %s", namespace);
|
||||||
if (netconf_unknown_element_xml(xret, "application", xml_name(xt), cbuf_get(cb)) < 0)
|
if (netconf_unknown_element_xml(xret, "application", xml_name(xt), cbuf_get(cb)) < 0)
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,21 @@
|
||||||
#include "clixon_yang_type.h"
|
#include "clixon_yang_type.h"
|
||||||
#include "clixon_xml_bind.h"
|
#include "clixon_xml_bind.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables
|
||||||
|
*/
|
||||||
|
static int _yang_unknown_anydata = 0;
|
||||||
|
|
||||||
|
/*! Kludge to equate unknown XML with anydata
|
||||||
|
* The problem with this is that its global and shuld be bound to a handle
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_bind_yang_unknown_anydata(int bool)
|
||||||
|
{
|
||||||
|
_yang_unknown_anydata = bool;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*! After yang binding, bodies of containers and lists are stripped from XML bodies
|
/*! After yang binding, bodies of containers and lists are stripped from XML bodies
|
||||||
* May apply to other nodes?
|
* May apply to other nodes?
|
||||||
*/
|
*/
|
||||||
|
|
@ -156,6 +171,10 @@ populate_self_parent(cxobj *xt,
|
||||||
if (xml2ns(xt, xml_prefix(xt), &ns) < 0)
|
if (xml2ns(xt, xml_prefix(xt), &ns) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((y = yang_find_datanode(yparent, name)) == NULL){
|
if ((y = yang_find_datanode(yparent, name)) == NULL){
|
||||||
|
if (_yang_unknown_anydata){
|
||||||
|
retval = 2; /* treat as anydata */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -244,6 +263,10 @@ populate_self_top(cxobj *xt,
|
||||||
if (xml2ns(xt, xml_prefix(xt), &ns) < 0)
|
if (xml2ns(xt, xml_prefix(xt), &ns) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((y = yang_find_schemanode(ymod, name)) == NULL){ /* also rpc */
|
if ((y = yang_find_schemanode(ymod, name)) == NULL){ /* also rpc */
|
||||||
|
if (_yang_unknown_anydata){
|
||||||
|
retval = 2; /* treat as anydata */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,9 @@ fi
|
||||||
# Backend user
|
# Backend user
|
||||||
BUSER=clicon
|
BUSER=clicon
|
||||||
|
|
||||||
|
# If set, unknown XML is treated as ANYDATA
|
||||||
|
: ${YANG_UNKNOWN_ANYDATA:=false}
|
||||||
|
|
||||||
# Follow the binary programs that can be parametrized (eg with valgrind)
|
# Follow the binary programs that can be parametrized (eg with valgrind)
|
||||||
|
|
||||||
: ${clixon_cli:=clixon_cli}
|
: ${clixon_cli:=clixon_cli}
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,9 @@ new "copy startup->candidate"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><copy-config><target><candidate/></target><source><startup/></source></copy-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><copy-config><target><candidate/></target><source><startup/></source></copy-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "copy startup->running not allowed"
|
new "copy startup->running not allowed"
|
||||||
|
if ! $YANG_UNKNOWN_ANYDATA ; then
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><copy-config><target><running/></target><source><startup/></source></copy-config></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>running</bad-element></error-info><error-severity>error</error-severity><error-message>Failed to find YANG spec of XML node: running with parent: target in namespace: urn:ietf:params:xml:ns:netconf:base:1.0</error-message></rpc-error></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><copy-config><target><running/></target><source><startup/></source></copy-config></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>running</bad-element></error-info><error-severity>error</error-severity><error-message>Failed to find YANG spec of XML node: running with parent: target in namespace: urn:ietf:params:xml:ns:netconf:base:1.0</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||||
|
fi
|
||||||
|
|
||||||
# Here running is empty
|
# Here running is empty
|
||||||
new "Check running empty"
|
new "Check running empty"
|
||||||
|
|
|
||||||
|
|
@ -282,8 +282,10 @@ new "restconf delete identity"
|
||||||
expectpart "$(curl -s -i -X DELETE http://localhost/restconf/data/example:crypto)" 0 "HTTP/1.1 204 No Content"
|
expectpart "$(curl -s -i -X DELETE http://localhost/restconf/data/example:crypto)" 0 "HTTP/1.1 204 No Content"
|
||||||
|
|
||||||
# 2. set identity in other module with restconf , read it with restconf and netconf
|
# 2. set identity in other module with restconf , read it with restconf and netconf
|
||||||
|
if ! $YANG_UNKNOWN_ANYDATA ; then
|
||||||
new "restconf add POST instead of PUT (should fail)"
|
new "restconf add POST instead of PUT (should fail)"
|
||||||
expectpart "$(curl -s -i -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/example:crypto -d '{"example:crypto":"example-des:des3"}')" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"bad-element","error-info":{"bad-element":"crypto"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: crypto with parent: crypto in namespace: urn:example:my-crypto"}}}'
|
expectpart "$(curl -s -i -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/example:crypto -d '{"example:crypto":"example-des:des3"}')" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"bad-element","error-info":{"bad-element":"crypto"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: crypto with parent: crypto in namespace: urn:example:my-crypto"}}}'
|
||||||
|
fi
|
||||||
|
|
||||||
# Alternative error:
|
# Alternative error:
|
||||||
#'{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"crypto"},"error-severity":"error","error-message":"Leaf contains sub-element"}}}'
|
#'{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"crypto"},"error-severity":"error","error-message":"Leaf contains sub-element"}}}'
|
||||||
|
|
|
||||||
|
|
@ -237,8 +237,10 @@ new "restconf rpc using POST json"
|
||||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":42}}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"clixon-example:output":{"x":"42","y":"42"}}
|
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":42}}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"clixon-example:output":{"x":"42","y":"42"}}
|
||||||
'
|
'
|
||||||
|
|
||||||
|
if ! $YANG_UNKNOWN_ANYDATA ; then
|
||||||
new "restconf rpc using POST json wrong"
|
new "restconf rpc using POST json wrong"
|
||||||
expectpart "$(curl -si -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"bad-element","error-info":{"bad-element":"wrongelement"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: wrongelement with parent: example in namespace: urn:example:clixon"}}}'
|
expectpart "$(curl -si -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"bad-element","error-info":{"bad-element":"wrongelement"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: wrongelement with parent: example in namespace: urn:example:clixon"}}}'
|
||||||
|
fi
|
||||||
|
|
||||||
new "restconf rpc non-existing rpc without namespace"
|
new "restconf rpc non-existing rpc without namespace"
|
||||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations/kalle)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"kalle"},"error-severity":"error","error-message":"RPC not defined"}}'
|
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations/kalle)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"kalle"},"error-severity":"error","error-message":"RPC not defined"}}'
|
||||||
|
|
|
||||||
|
|
@ -122,8 +122,10 @@ fi
|
||||||
new "restconf omit mandatory"
|
new "restconf omit mandatory"
|
||||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":null}' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"x"},"error-severity":"error","error-message":"Mandatory variable"}}}
'
|
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":null}' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"x"},"error-severity":"error","error-message":"Mandatory variable"}}}
'
|
||||||
|
|
||||||
new "restconf add extra"
|
new "restconf add extra w/o yang: should fail"
|
||||||
|
if ! $YANG_UNKNOWN_ANYDATA ; then
|
||||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"0","extra":"0"}}' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"bad-element","error-info":{"bad-element":"extra"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: extra with parent: example in namespace: urn:example:clixon"}}}'
|
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"0","extra":"0"}}' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"bad-element","error-info":{"bad-element":"extra"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: extra with parent: example in namespace: urn:example:clixon"}}}'
|
||||||
|
fi
|
||||||
|
|
||||||
new "restconf wrong method"
|
new "restconf wrong method"
|
||||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"0"}}' http://localhost/restconf/operations/clixon-example:wrong)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"wrong"},"error-severity":"error","error-message":"RPC not defined"}}}
'
|
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"0"}}' http://localhost/restconf/operations/clixon-example:wrong)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"wrong"},"error-severity":"error","error-message":"RPC not defined"}}}
'
|
||||||
|
|
@ -137,8 +139,10 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netco
|
||||||
new "netconf edit-config ok"
|
new "netconf edit-config ok"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><target><candidate/></target><config/></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><target><candidate/></target><config/></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
if ! $YANG_UNKNOWN_ANYDATA ; then
|
||||||
new "netconf edit-config extra arg should fail"
|
new "netconf edit-config extra arg should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><target><candidate/></target><extra/><config/></edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>extra</bad-element></error-info><error-severity>error</error-severity><error-message>Failed to find YANG spec of XML node: extra with parent: edit-config in namespace: urn:ietf:params:xml:ns:netconf:base:1.0</error-message></rpc-error></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><target><candidate/></target><extra/><config/></edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>extra</bad-element></error-info><error-severity>error</error-severity><error-message>Failed to find YANG spec of XML node: extra with parent: edit-config in namespace: urn:ietf:params:xml:ns:netconf:base:1.0</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||||
|
fi
|
||||||
|
|
||||||
new "netconf edit-config empty target should fail"
|
new "netconf edit-config empty target should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><target/><config/></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>data-missing</error-tag><error-app-tag>missing-choice</error-app-tag><error-info><missing-choice>config-target</missing-choice></error-info><error-severity>error</error-severity></rpc-error></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><target/><config/></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>data-missing</error-tag><error-app-tag>missing-choice</error-app-tag><error-info><missing-choice>config-target</missing-choice></error-info><error-severity>error</error-severity></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@
|
||||||
#include "clixon/clixon.h"
|
#include "clixon/clixon.h"
|
||||||
|
|
||||||
/* Command line options passed to getopt(3) */
|
/* Command line options passed to getopt(3) */
|
||||||
#define UTIL_XML_OPTS "hD:f:Jjl:pvoy:Y:t:T:"
|
#define UTIL_XML_OPTS "hD:f:Jjl:pvoy:Y:t:T:u"
|
||||||
|
|
||||||
static int
|
static int
|
||||||
validate_tree(clicon_handle h,
|
validate_tree(clicon_handle h,
|
||||||
|
|
@ -125,6 +125,7 @@ usage(char *argv0)
|
||||||
"\t-Y <dir> \tYang dirs (can be several)\n"
|
"\t-Y <dir> \tYang dirs (can be several)\n"
|
||||||
"\t-t <file>\tXML top input file (where base tree is pasted to)\n"
|
"\t-t <file>\tXML top input file (where base tree is pasted to)\n"
|
||||||
"\t-T <path>\tXPath to where in top input file base should be pasted\n"
|
"\t-T <path>\tXPath to where in top input file base should be pasted\n"
|
||||||
|
"\t-u \t\tTreat unknown XML as anydata\n"
|
||||||
,
|
,
|
||||||
argv0);
|
argv0);
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
@ -221,6 +222,11 @@ main(int argc,
|
||||||
case 'T': /* top file xpath */
|
case 'T': /* top file xpath */
|
||||||
top_path = optarg;
|
top_path = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'u':
|
||||||
|
if (clicon_option_bool_set(h, "CLICON_YANG_UNKNOWN_ANYDATA", 1) < 0)
|
||||||
|
goto done;
|
||||||
|
xml_bind_yang_unknown_anydata(1);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -314,6 +314,14 @@ module clixon-config {
|
||||||
Some yang specs seem not to fulfil this. However, if you reset this, there may
|
Some yang specs seem not to fulfil this. However, if you reset this, there may
|
||||||
be follow-up errors due to code that assumes a configuration list has keys";
|
be follow-up errors due to code that assumes a configuration list has keys";
|
||||||
}
|
}
|
||||||
|
leaf CLICON_YANG_UNKNOWN_ANYDATA{
|
||||||
|
type boolean;
|
||||||
|
default false;
|
||||||
|
description
|
||||||
|
"Treat unknown XML/JSON nodes as anydata.
|
||||||
|
This does not apply to namespaces, which means a top-level node: xxx:yyy
|
||||||
|
is accepted only if yyy is unknown, not xxx";
|
||||||
|
}
|
||||||
leaf CLICON_BACKEND_DIR {
|
leaf CLICON_BACKEND_DIR {
|
||||||
type string;
|
type string;
|
||||||
description
|
description
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue