Conformance to RFC-8040 operations where prefix was used instead of module name.
* Proper specification for an operation is POST /restconf/operations/<module_name>:<rpc_procedure> HTTP/1.1 * See https://github.com/clicon/clixon/issues/31, https://github.com/clicon/clixon/pull/32 and https://github.com/clicon/clixon/issues/30 * Thanks David Cornejo and Dmitry Vakhrushev of Netgate for pointing this out
This commit is contained in:
parent
fd19640579
commit
719ea93398
5 changed files with 87 additions and 25 deletions
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
## 3.7.0 (Upcoming)
|
## 3.7.0 (Upcoming)
|
||||||
### Major changes:
|
### Major changes:
|
||||||
|
* Conformance for RFC-8040 operations where prefix was used instead of module name.
|
||||||
|
* Proper specification for an operation is POST /restconf/operations/<module_name>:<rpc_procedure> HTTP/1.1
|
||||||
|
* See https://github.com/clicon/clixon/issues/31, https://github.com/clicon/clixon/pull/32 and https://github.com/clicon/clixon/issues/30
|
||||||
|
* Thanks David Cornejo and Dmitry Vakhrushev of Netgate for pointing this out.
|
||||||
* Support for YANG identity and identityref according to RFC 7950 Sec 7.18 and 9.10
|
* Support for YANG identity and identityref according to RFC 7950 Sec 7.18 and 9.10
|
||||||
* Previous support did no validation of values.
|
* Previous support did no validation of values.
|
||||||
* Validation of types and CLI expansion
|
* Validation of types and CLI expansion
|
||||||
|
|
|
||||||
|
|
@ -925,8 +925,7 @@ api_operations_get(clicon_handle h,
|
||||||
yang_spec *yspec;
|
yang_spec *yspec;
|
||||||
yang_stmt *ym;
|
yang_stmt *ym;
|
||||||
yang_stmt *yc;
|
yang_stmt *yc;
|
||||||
yang_stmt *yprefix;
|
char *modname;
|
||||||
char *prefix;
|
|
||||||
cbuf *cbx = NULL;
|
cbuf *cbx = NULL;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
|
|
||||||
|
|
@ -937,15 +936,12 @@ api_operations_get(clicon_handle h,
|
||||||
cprintf(cbx, "<operations>");
|
cprintf(cbx, "<operations>");
|
||||||
ym = NULL;
|
ym = NULL;
|
||||||
while ((ym = yn_each((yang_node*)yspec, ym)) != NULL) {
|
while ((ym = yn_each((yang_node*)yspec, ym)) != NULL) {
|
||||||
if ((yprefix = yang_find((yang_node*)ym, Y_PREFIX, NULL)) != NULL)
|
modname = ym->ys_argument;
|
||||||
prefix = yprefix->ys_argument;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
yc = NULL;
|
yc = NULL;
|
||||||
while ((yc = yn_each((yang_node*)ym, yc)) != NULL) {
|
while ((yc = yn_each((yang_node*)ym, yc)) != NULL) {
|
||||||
if (yc->ys_keyword != Y_RPC)
|
if (yc->ys_keyword != Y_RPC)
|
||||||
continue;
|
continue;
|
||||||
cprintf(cbx, "<%s:%s />", prefix, yc->ys_argument);
|
cprintf(cbx, "<%s:%s />", modname, yc->ys_argument);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cprintf(cbx, "</operations>");
|
cprintf(cbx, "</operations>");
|
||||||
|
|
@ -1030,6 +1026,9 @@ api_operations_post(clicon_handle h,
|
||||||
char *username;
|
char *username;
|
||||||
cbuf *cbret = NULL;
|
cbuf *cbret = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
char *prefix = NULL;
|
||||||
|
char *id = NULL;
|
||||||
|
yang_stmt *ys = NULL;
|
||||||
|
|
||||||
clicon_debug(1, "%s json:\"%s\" path:\"%s\"", __FUNCTION__, data, path);
|
clicon_debug(1, "%s json:\"%s\" path:\"%s\"", __FUNCTION__, data, path);
|
||||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||||
|
|
@ -1047,8 +1046,22 @@ api_operations_post(clicon_handle h,
|
||||||
}
|
}
|
||||||
clicon_debug(1, "%s oppath: %s", __FUNCTION__, oppath);
|
clicon_debug(1, "%s oppath: %s", __FUNCTION__, oppath);
|
||||||
|
|
||||||
/* Find yang rpc statement, return yang rpc statement if found */
|
/* Find yang rpc statement, return yang rpc statement if found
|
||||||
if (yang_abs_schema_nodeid(yspec, oppath, Y_RPC, &yrpc) < 0){
|
* POST {+restconf}/operations/<operation>
|
||||||
|
*
|
||||||
|
* The <operation> field identifies the module name and rpc identifier
|
||||||
|
* string for the desired operation.
|
||||||
|
*/
|
||||||
|
if (yang_nodeid_split(oppath+1, &prefix, &id) < 0) /* +1 skip / */
|
||||||
|
goto done;
|
||||||
|
if ((ys = yang_find((yang_node*)yspec, Y_MODULE, prefix)) == NULL){
|
||||||
|
if (netconf_operation_failed_xml(&xerr, "protocol", "yang module not found") < 0)
|
||||||
|
goto done;
|
||||||
|
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||||
|
goto done;
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
if ((yrpc = yang_find((yang_node*)ys, Y_RPC, id)) == NULL){
|
||||||
if (netconf_operation_failed_xml(&xerr, "protocol", "yang node not found") < 0)
|
if (netconf_operation_failed_xml(&xerr, "protocol", "yang node not found") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||||
|
|
@ -1229,6 +1242,10 @@ api_operations_post(clicon_handle h,
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||||
|
if (prefix)
|
||||||
|
free(prefix);
|
||||||
|
if (id)
|
||||||
|
free(id);
|
||||||
if (xdata)
|
if (xdata)
|
||||||
xml_free(xdata);
|
xml_free(xdata);
|
||||||
if (xtop)
|
if (xtop)
|
||||||
|
|
|
||||||
|
|
@ -246,6 +246,7 @@ yang_stmt *yn_each(yang_node *yn, yang_stmt *ys);
|
||||||
char *yang_key2str(int keyword);
|
char *yang_key2str(int keyword);
|
||||||
char *yarg_prefix(yang_stmt *ys);
|
char *yarg_prefix(yang_stmt *ys);
|
||||||
char *yarg_id(yang_stmt *ys);
|
char *yarg_id(yang_stmt *ys);
|
||||||
|
int yang_nodeid_split(char *nodeid, char **prefix, char **id);
|
||||||
yang_stmt *ys_module(yang_stmt *ys);
|
yang_stmt *ys_module(yang_stmt *ys);
|
||||||
yang_spec *ys_spec(yang_stmt *ys);
|
yang_spec *ys_spec(yang_stmt *ys);
|
||||||
yang_stmt *yang_find_module_by_prefix(yang_stmt *ys, char *prefix);
|
yang_stmt *yang_find_module_by_prefix(yang_stmt *ys, char *prefix);
|
||||||
|
|
|
||||||
|
|
@ -611,8 +611,8 @@ yang_find_schemanode(yang_node *yn,
|
||||||
/*! Find first matching data node in all (sub)modules in a yang spec
|
/*! Find first matching data node in all (sub)modules in a yang spec
|
||||||
*
|
*
|
||||||
* @param[in] ysp Yang specification
|
* @param[in] ysp Yang specification
|
||||||
* @param[in] argument if NULL, match any(first) argument. XXX is that really a case?
|
* @param[in] argument Name of node. If NULL match first
|
||||||
* @param[in] schemanode If set look for schema nodes, otherwise only data nodes
|
* @param[in] class See yang_class for class of yang nodes
|
||||||
* A yang specification has modules as children which in turn can have
|
* A yang specification has modules as children which in turn can have
|
||||||
* syntax-nodes as children. This function goes through all the modules to
|
* syntax-nodes as children. This function goes through all the modules to
|
||||||
* look for nodes. Note that if a child to a module is a choice,
|
* look for nodes. Note that if a child to a module is a choice,
|
||||||
|
|
@ -803,7 +803,7 @@ yarg_id(yang_stmt *ys)
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Assume argument is id on the type: <[prefix:]id>, return 'prefix'
|
/*! Assume argument is id on the type: <[prefix:]id>, return 'prefix'
|
||||||
* @param[in] ys A yang statement
|
* @param[in] ys A yang statement
|
||||||
* @retval NULL No prefix
|
* @retval NULL No prefix
|
||||||
* @retval prefix Malloced string that needs to be freed by caller.
|
* @retval prefix Malloced string that needs to be freed by caller.
|
||||||
|
|
@ -822,6 +822,46 @@ yarg_prefix(yang_stmt *ys)
|
||||||
return prefix;
|
return prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Split yang node identifier into prefix and identifer.
|
||||||
|
* @param[in] node-id
|
||||||
|
* @param[out] prefix Malloced string. May be NULL.
|
||||||
|
* @param[out] id Malloced identifier.
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
* @note caller need to free id and prefix after use
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
yang_nodeid_split(char *nodeid,
|
||||||
|
char **prefix,
|
||||||
|
char **id)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
if ((str = strchr(nodeid, ':')) == NULL){
|
||||||
|
if ((*id = strdup(nodeid)) == NULL){
|
||||||
|
clicon_err(OE_YANG, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if ((*prefix = strdup(nodeid)) == NULL){
|
||||||
|
clicon_err(OE_YANG, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
(*prefix)[str-nodeid] = '\0';
|
||||||
|
str++;
|
||||||
|
if ((*id = strdup(str)) == NULL){
|
||||||
|
clicon_err(OE_YANG, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Given a yang statement and a prefix, return yang module to that prefix
|
/*! Given a yang statement and a prefix, return yang module to that prefix
|
||||||
* Note, not the other module but the proxy import statement only
|
* Note, not the other module but the proxy import statement only
|
||||||
* @param[in] ys A yang statement
|
* @param[in] ys A yang statement
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ new "kill old restconf daemon"
|
||||||
sudo pkill -u www-data clixon_restconf
|
sudo pkill -u www-data clixon_restconf
|
||||||
|
|
||||||
new "start restconf daemon"
|
new "start restconf daemon"
|
||||||
sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg -y $fyang # -D
|
sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg -y $fyang -D
|
||||||
|
|
||||||
sleep 1
|
sleep 1
|
||||||
|
|
||||||
|
|
@ -113,12 +113,12 @@ expecteq "$(curl -s -H 'Accept: application/yang-data+xml' -G http://localhost/r
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "restconf get restconf/operations. RFC8040 3.3.2 (json)"
|
new2 "restconf get restconf/operations. RFC8040 3.3.2 (json)"
|
||||||
expecteq "$(curl -sG http://localhost/restconf/operations)" '{"operations": {"ex:empty": null,"ex:input": null,"ex:output": null,"ex:client-rpc": null,"rt:fib-route": null,"rt:route-count": null}}
|
expecteq "$(curl -sG http://localhost/restconf/operations)" '{"operations": {"example:empty": null,"example:input": null,"example:output": null,"example:client-rpc": null,"ietf-routing:fib-route": null,"ietf-routing:route-count": null}}
|
||||||
'
|
'
|
||||||
|
|
||||||
new "restconf get restconf/operations. RFC8040 3.3.2 (xml)"
|
new "restconf get restconf/operations. RFC8040 3.3.2 (xml)"
|
||||||
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/operations)
|
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/operations)
|
||||||
expect="<operations><ex:empty/><ex:input/><ex:output/><ex:client-rpc/><rt:fib-route/><rt:route-count/></operations>"
|
expect="<operations><example:empty/><example:input/><example:output/><example:client-rpc/><ietf-routing:fib-route/><ietf-routing:route-count/></operations>"
|
||||||
match=`echo $ret | grep -EZo "$expect"`
|
match=`echo $ret | grep -EZo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
err "$expect" "$ret"
|
err "$expect" "$ret"
|
||||||
|
|
@ -143,7 +143,7 @@ expectfn "curl -s -I http://localhost/restconf/data" 0 "HTTP/1.1 200 OK"
|
||||||
#Content-Type: application/yang-data+json"
|
#Content-Type: application/yang-data+json"
|
||||||
|
|
||||||
new2 "restconf empty rpc"
|
new2 "restconf empty rpc"
|
||||||
expecteq "$(curl -s -X POST -d {\"input\":{\"name\":\"\"}} http://localhost/restconf/operations/ex:empty)" ""
|
expecteq "$(curl -s -X POST -d {\"input\":{\"name\":\"\"}} http://localhost/restconf/operations/example:empty)" ""
|
||||||
|
|
||||||
new2 "restconf get empty config + state json"
|
new2 "restconf get empty config + state json"
|
||||||
expecteq "$(curl -sSG http://localhost/restconf/data)" '{"data": {"interfaces-state": {"interface": [{"name": "eth0","type": "ex:eth","if-index": 42}]}}}
|
expecteq "$(curl -sSG http://localhost/restconf/data)" '{"data": {"interfaces-state": {"interface": [{"name": "eth0","type": "ex:eth","if-index": 42}]}}}
|
||||||
|
|
@ -246,29 +246,29 @@ expecteq "$(curl -s -G http://localhost/restconf/data)" '{"data": {"interfaces":
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "restconf rpc using POST json"
|
new2 "restconf rpc using POST json"
|
||||||
expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/rt:fib-route)" '{"output": {"route": {"address-family": "ipv4","next-hop": {"next-hop-list": "2.3.4.5"}}}}
|
expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"output": {"route": {"address-family": "ipv4","next-hop": {"next-hop-list": "2.3.4.5"}}}}
|
||||||
'
|
'
|
||||||
|
|
||||||
# Cant get this to work due to quoting
|
# Cant get this to work due to quoting
|
||||||
#new2 "restconf rpc using POST wrong JSON"
|
#new2 "restconf rpc using POST wrong JSON"
|
||||||
#expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":ipv4}}' http://localhost/restconf/operations/rt:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": " on line 1: syntax error at or before: i"}}}}
'
|
#expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":ipv4}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": " on line 1: syntax error at or before: i"}}}}
'
|
||||||
|
|
||||||
new2 "restconf rpc using POST json w/o mandatory element"
|
new2 "restconf rpc using POST json w/o mandatory element"
|
||||||
expecteq "$(curl -s -X POST -d '{"input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/rt:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "Missing mandatory variable: routing-instance-name"}}}}
'
|
expecteq "$(curl -s -X POST -d '{"input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "Missing mandatory variable: routing-instance-name"}}}}
'
|
||||||
new2 "restconf rpc non-existing rpc w/o namespace"
|
new2 "restconf rpc non-existing rpc w/o namespace"
|
||||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/kalle)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang node not found"}}}}
'
|
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/kalle)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang node not found"}}}}
'
|
||||||
|
|
||||||
new2 "restconf rpc non-existing rpc"
|
new2 "restconf rpc non-existing rpc"
|
||||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/ex:kalle)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang node not found"}}}}
'
|
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/example:kalle)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang node not found"}}}}
'
|
||||||
|
|
||||||
new2 "restconf rpc missing name"
|
new2 "restconf rpc missing name"
|
||||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "Operation name expected"}}}}
'
|
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "Operation name expected"}}}}
'
|
||||||
|
|
||||||
new2 "restconf rpc missing input"
|
new2 "restconf rpc missing input"
|
||||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/rt:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "Missing mandatory variable: routing-instance-name"}}}}
'
|
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "Missing mandatory variable: routing-instance-name"}}}}
'
|
||||||
|
|
||||||
new "restconf rpc using POST xml"
|
new "restconf rpc using POST xml"
|
||||||
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/rt:fib-route)
|
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)
|
||||||
expect="<output><route><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop></route></output>"
|
expect="<output><route><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop></route></output>"
|
||||||
match=`echo $ret | grep -EZo "$expect"`
|
match=`echo $ret | grep -EZo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
|
|
@ -276,10 +276,10 @@ if [ -z "$match" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new2 "restconf rpc using wrong prefix"
|
new2 "restconf rpc using wrong prefix"
|
||||||
expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/wrong:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang node not found"}}}}
'
|
expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/wrong:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang module not found"}}}}
'
|
||||||
|
|
||||||
new "restconf local client rpc using POST xml"
|
new "restconf local client rpc using POST xml"
|
||||||
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"input":{"request":"example"}}' http://localhost/restconf/operations/ex:client-rpc)
|
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"input":{"request":"example"}}' http://localhost/restconf/operations/example:client-rpc)
|
||||||
expect="<output><result>ok</result></output>"
|
expect="<output><result>ok</result></output>"
|
||||||
match=`echo $ret | grep -EZo "$expect"`
|
match=`echo $ret | grep -EZo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
|
|
@ -287,7 +287,7 @@ if [ -z "$match" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# XXX cant get -H to work
|
# XXX cant get -H to work
|
||||||
#expecteq 'curl -s -X POST -H "Accept: application/yang-data+xml" -d {"input":{"routing-instance-name":"ipv4"}} http://localhost/restconf/operations/rt:fib-route' '<output><route><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop></route></output>'
|
#expecteq 'curl -s -X POST -H "Accept: application/yang-data+xml" -d {"input":{"routing-instance-name":"ipv4"}} http://localhost/restconf/operations/ietf-routing:fib-route' '<output><route><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop></route></output>'
|
||||||
|
|
||||||
# Cant get shell macros to work, inline matching from lib.sh
|
# Cant get shell macros to work, inline matching from lib.sh
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue