Stricter incoming RPC sanity checking, error messages may have changed
This commit is contained in:
parent
f9998c441c
commit
ac5637a46a
30 changed files with 163 additions and 99 deletions
|
|
@ -24,12 +24,19 @@
|
||||||
## 4.5.0
|
## 4.5.0
|
||||||
Expected: May 2020
|
Expected: May 2020
|
||||||
|
|
||||||
|
### API changes on existing protocol/config features (You may have have to change how you use Clixon)
|
||||||
|
|
||||||
|
* Stricter incoming RPC sanity checking, error messages may have changed.
|
||||||
|
|
||||||
### C-API changes on existing features (you may need to change your plugin C-code)
|
### C-API changes on existing features (you may need to change your plugin C-code)
|
||||||
|
|
||||||
* CLI
|
* CLI
|
||||||
* `clicon_parse()`: Changed signature due to new cligen error and result handling:
|
* `clicon_parse()`: Changed signature due to new cligen error and result handling:
|
||||||
* Removed: `cli_nomatch()`
|
* Removed: `cli_nomatch()`
|
||||||
|
|
||||||
|
### Minor changes
|
||||||
|
|
||||||
|
|
||||||
## 4.4.0
|
## 4.4.0
|
||||||
5 April 2020
|
5 April 2020
|
||||||
|
|
||||||
|
|
@ -115,8 +122,6 @@ features include optimized search functions and a repair callback.
|
||||||
|
|
||||||
### Minor changes
|
### Minor changes
|
||||||
|
|
||||||
* Added a compile-time option `MOVE_TRANS_END` which changes the semantics of the transaction_end callback. Instead of being called after a transaction, it is called prior to the target database is installed. This is to ensure that the source and target databases are same as for other transaction callbacks.
|
|
||||||
|
|
||||||
* Moved hello example to [clixon-examples](https://github.com/clicon/clixon-examples)
|
* Moved hello example to [clixon-examples](https://github.com/clicon/clixon-examples)
|
||||||
* Sanity check of mandatory key statement for Yang LISTs.
|
* Sanity check of mandatory key statement for Yang LISTs.
|
||||||
* If fails, exit with error message, eg: `Yang error: Sanity check failed: LIST vsDataContainer lacks key statement which MUST be present (See RFC 7950 Sec 7.8.2)`
|
* If fails, exit with error message, eg: `Yang error: Sanity check failed: LIST vsDataContainer lacks key statement which MUST be present (See RFC 7950 Sec 7.8.2)`
|
||||||
|
|
|
||||||
|
|
@ -1570,12 +1570,16 @@ from_client_msg(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Decode msg from client -> xml top (ct) and session id */
|
/* Decode msg from client -> xml top (ct) and session id */
|
||||||
if (clicon_msg_decode(msg, yspec, &id, &xt) < 0){
|
if ((ret = clicon_msg_decode(msg, yspec, &id, &xt, &xret)) < 0){
|
||||||
if (netconf_malformed_message(cbret, "XML parse error") < 0)
|
if (netconf_malformed_message(cbret, "XML parse error") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto reply;
|
goto reply;
|
||||||
}
|
}
|
||||||
|
if (ret == 0){
|
||||||
|
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
|
||||||
|
goto done;
|
||||||
|
goto reply;
|
||||||
|
}
|
||||||
if ((x = xpath_first(xt, NULL, "/rpc")) == NULL){
|
if ((x = xpath_first(xt, NULL, "/rpc")) == NULL){
|
||||||
if ((x = xpath_first(xt, NULL, "/hello")) != NULL){
|
if ((x = xpath_first(xt, NULL, "/hello")) != NULL){
|
||||||
if ((ret = from_client_hello(h, x, ce, cbret)) <0)
|
if ((ret = from_client_hello(h, x, ce, cbret)) <0)
|
||||||
|
|
@ -1589,12 +1593,6 @@ from_client_msg(clicon_handle h,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ce->ce_id = id;
|
ce->ce_id = id;
|
||||||
/* Populate incoming XML tree with yang -
|
|
||||||
* should really have been dealt with by decode above
|
|
||||||
* but it still is needed - test_cli debug test fails
|
|
||||||
*/
|
|
||||||
if (xml_bind_yang_rpc(x, yspec, NULL) < 0)
|
|
||||||
goto done;
|
|
||||||
if ((ret = xml_yang_validate_rpc(h, x, &xret)) < 0)
|
if ((ret = xml_yang_validate_rpc(h, x, &xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
|
|
|
||||||
|
|
@ -509,8 +509,6 @@ from_validate_common(clicon_handle h,
|
||||||
* @retval -1 Error - or validation failed
|
* @retval -1 Error - or validation failed
|
||||||
* @retval 0 Validation failed (with cbret set)
|
* @retval 0 Validation failed (with cbret set)
|
||||||
* @retval 1 Validation OK
|
* @retval 1 Validation OK
|
||||||
* @note Need to differentiate between error and validation fail
|
|
||||||
* (only done for validate_common)
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
candidate_commit(clicon_handle h,
|
candidate_commit(clicon_handle h,
|
||||||
|
|
|
||||||
|
|
@ -978,6 +978,7 @@ cli_notification_cb(int s,
|
||||||
cxobj *xe;
|
cxobj *xe;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
enum format_enum format = (enum format_enum)arg;
|
enum format_enum format = (enum format_enum)arg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* get msg (this is the reason this function is called) */
|
/* get msg (this is the reason this function is called) */
|
||||||
if (clicon_msg_rcv(s, &reply, &eof) < 0)
|
if (clicon_msg_rcv(s, &reply, &eof) < 0)
|
||||||
|
|
@ -989,8 +990,13 @@ cli_notification_cb(int s,
|
||||||
event_unreg_fd(s, cli_notification_cb);
|
event_unreg_fd(s, cli_notification_cb);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (clicon_msg_decode(reply, NULL, NULL, &xt) < 0) /* XXX pass yang_spec */
|
/* XXX pass yang_spec and use xerr*/
|
||||||
|
if ((ret = clicon_msg_decode(reply, NULL, NULL, &xt, NULL)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (ret == 0){ /* will not happen since no yspec ^*/
|
||||||
|
clicon_err(OE_NETCONF, EFAULT, "Notification malformed");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
if ((xe = xpath_first(xt, NULL, "//event")) != NULL){
|
if ((xe = xpath_first(xt, NULL, "//event")) != NULL){
|
||||||
x = NULL;
|
x = NULL;
|
||||||
while ((x = xml_child_each(xe, x, -1)) != NULL) {
|
while ((x = xml_child_each(xe, x, -1)) != NULL) {
|
||||||
|
|
|
||||||
|
|
@ -425,6 +425,8 @@ netconf_notification_cb(int s,
|
||||||
clicon_handle h = (clicon_handle)arg;
|
clicon_handle h = (clicon_handle)arg;
|
||||||
yang_stmt *yspec = NULL;
|
yang_stmt *yspec = NULL;
|
||||||
cvec *nsc = NULL;
|
cvec *nsc = NULL;
|
||||||
|
int ret;
|
||||||
|
cxobj *xerr = NULL;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
/* get msg (this is the reason this function is called) */
|
/* get msg (this is the reason this function is called) */
|
||||||
|
|
@ -439,9 +441,12 @@ netconf_notification_cb(int s,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
yspec = clicon_dbspec_yang(h);
|
yspec = clicon_dbspec_yang(h);
|
||||||
if (clicon_msg_decode(reply, yspec, NULL, &xt) < 0)
|
if ((ret = clicon_msg_decode(reply, yspec, NULL, &xt, &xerr)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (ret == 0){ /* XXX use xerr */
|
||||||
|
clicon_err(OE_NETCONF, EFAULT, "Notification malformed");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
if ((nsc = xml_nsctx_init(NULL, NOTIFICATION_RFC5277_NAMESPACE)) == NULL)
|
if ((nsc = xml_nsctx_init(NULL, NOTIFICATION_RFC5277_NAMESPACE)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xn = xpath_first(xt, nsc, "notification")) == NULL)
|
if ((xn = xpath_first(xt, nsc, "notification")) == NULL)
|
||||||
|
|
@ -467,6 +472,8 @@ netconf_notification_cb(int s,
|
||||||
xml_nsctx_free(nsc);
|
xml_nsctx_free(nsc);
|
||||||
if (xt != NULL)
|
if (xt != NULL)
|
||||||
xml_free(xt);
|
xml_free(xt);
|
||||||
|
if (xerr != NULL)
|
||||||
|
xml_free(xerr);
|
||||||
if (reply)
|
if (reply)
|
||||||
free(reply);
|
free(reply);
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
||||||
|
|
@ -847,8 +847,17 @@ api_operations_post(clicon_handle h,
|
||||||
clicon_log_xml(LOG_DEBUG, xtop, "%s 5. Translate input args:", __FUNCTION__);
|
clicon_log_xml(LOG_DEBUG, xtop, "%s 5. Translate input args:", __FUNCTION__);
|
||||||
#endif
|
#endif
|
||||||
/* 6. Validate outgoing RPC and fill in defaults */
|
/* 6. Validate outgoing RPC and fill in defaults */
|
||||||
if (xml_bind_yang_rpc(xtop, yspec, NULL) < 0) /* */
|
if ((ret = xml_bind_yang_rpc(xtop, yspec, &xret)) < 0) /* */
|
||||||
goto done;
|
goto done;
|
||||||
|
if (ret == 0){
|
||||||
|
if ((xe = xpath_first(xret, NULL, "rpc-error")) == NULL){
|
||||||
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
if (api_return_err(h, r, xe, pretty, media_out, 0) < 0)
|
||||||
|
goto done;
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
if ((ret = xml_yang_validate_rpc(h, xtop, &xret)) < 0)
|
if ((ret = xml_yang_validate_rpc(h, xtop, &xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,7 @@ restconf_stream_cb(int s,
|
||||||
cxobj *xn; /* notification xml */
|
cxobj *xn; /* notification xml */
|
||||||
cbuf *cb = NULL;
|
cbuf *cb = NULL;
|
||||||
int pretty = 0; /* XXX should be via arg */
|
int pretty = 0; /* XXX should be via arg */
|
||||||
|
int ret;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
/* get msg (this is the reason this function is called) */
|
/* get msg (this is the reason this function is called) */
|
||||||
|
|
@ -180,8 +181,12 @@ restconf_stream_cb(int s,
|
||||||
clicon_exit_set();
|
clicon_exit_set();
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (clicon_msg_decode(reply, NULL, NULL, &xtop) < 0) /* XXX pass yang_spec */
|
if ((ret = clicon_msg_decode(reply, NULL, NULL, &xtop, NULL)) < 0) /* XXX pass yang_spec */
|
||||||
goto done;
|
goto done;
|
||||||
|
if (ret == 0){
|
||||||
|
clicon_err(OE_XML, EFAULT, "Invalid notification");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
/* create event */
|
/* create event */
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||||
|
|
|
||||||
|
|
@ -98,10 +98,3 @@
|
||||||
*/
|
*/
|
||||||
#define STATE_ORDERED_BY_SYSTEM
|
#define STATE_ORDERED_BY_SYSTEM
|
||||||
|
|
||||||
/*! Separate list merge into two separate rounds,
|
|
||||||
* First round search for duplicates where objects are saved, and a second round where
|
|
||||||
* actual merge is done. If in same round, in extreme cases that later
|
|
||||||
* searches are among earlier objects already added
|
|
||||||
* clixon-4.4
|
|
||||||
*/
|
|
||||||
#define XML_MERGE_TWO_ROUNDS
|
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@
|
||||||
#include <clixon/clixon_regex.h>
|
#include <clixon/clixon_regex.h>
|
||||||
#include <clixon/clixon_path.h>
|
#include <clixon/clixon_path.h>
|
||||||
#include <clixon/clixon_xml_map.h>
|
#include <clixon/clixon_xml_map.h>
|
||||||
|
#include <clixon/clixon_xml_bind.h>
|
||||||
#include <clixon/clixon_xml_io.h>
|
#include <clixon/clixon_xml_io.h>
|
||||||
#include <clixon/clixon_validate.h>
|
#include <clixon/clixon_validate.h>
|
||||||
#include <clixon/clixon_datastore.h>
|
#include <clixon/clixon_datastore.h>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
Copyright (C) 2017-2019 Olof Hagsand
|
||||||
|
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ struct clicon_msg *clicon_msg_encode(uint32_t id, char *format, ...) __attribute
|
||||||
#else
|
#else
|
||||||
struct clicon_msg *clicon_msg_encode(uint32_t id, char *format, ...);
|
struct clicon_msg *clicon_msg_encode(uint32_t id, char *format, ...);
|
||||||
#endif
|
#endif
|
||||||
int clicon_msg_decode(struct clicon_msg *msg, yang_stmt *yspec, uint32_t *id, cxobj **xml);
|
int clicon_msg_decode(struct clicon_msg *msg, yang_stmt *yspec, uint32_t *id, cxobj **xml, cxobj **xerr);
|
||||||
|
|
||||||
int clicon_connect_unix(clicon_handle h, char *sockpath);
|
int clicon_connect_unix(clicon_handle h, char *sockpath);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
|
||||||
|
Copyright (C) 2017-2019 Olof Hagsand
|
||||||
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC
|
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
@ -102,6 +103,7 @@ int clicon_str2int(const map_str2int *mstab, char *str);
|
||||||
int clicon_str2int_search(const map_str2int *mstab, char *str, int upper);
|
int clicon_str2int_search(const map_str2int *mstab, char *str, int upper);
|
||||||
int nodeid_split(char *nodeid, char **prefix, char **id);
|
int nodeid_split(char *nodeid, char **prefix, char **id);
|
||||||
char *clixon_trim(char *str);
|
char *clixon_trim(char *str);
|
||||||
|
char *clixon_trim2(char *str, char *trims);
|
||||||
int clicon_strcmp(char *s1, char *s2);
|
int clicon_strcmp(char *s1, char *s2);
|
||||||
|
|
||||||
#ifndef HAVE_STRNDUP
|
#ifndef HAVE_STRNDUP
|
||||||
|
|
|
||||||
|
|
@ -120,10 +120,8 @@ enum yang_bind{
|
||||||
YB_NONE=0, /* Dont do Yang binding */
|
YB_NONE=0, /* Dont do Yang binding */
|
||||||
YB_MODULE, /* Search for matching yang binding among top-level symbols of Yang modules */
|
YB_MODULE, /* Search for matching yang binding among top-level symbols of Yang modules */
|
||||||
YB_PARENT, /* Assume yang binding of existing parent and match its children by name */
|
YB_PARENT, /* Assume yang binding of existing parent and match its children by name */
|
||||||
|
YB_RPC, /* Assume top-level xml is an netconf RPC message (or hello) */
|
||||||
|
|
||||||
#ifdef NYI
|
|
||||||
YB_RPC, /* Assume top-level xml is an netconf RPC message */
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
typedef enum yang_bind yang_bind;
|
typedef enum yang_bind yang_bind;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ INCLUDES = -I. @INCLUDES@ -I$(top_srcdir)/lib/clixon -I$(top_srcdir)/include -I$
|
||||||
SRC = clixon_sig.c clixon_uid.c clixon_log.c clixon_err.c clixon_event.c \
|
SRC = clixon_sig.c clixon_uid.c clixon_log.c clixon_err.c clixon_event.c \
|
||||||
clixon_string.c clixon_regex.c clixon_handle.c clixon_file.c \
|
clixon_string.c clixon_regex.c clixon_handle.c clixon_file.c \
|
||||||
clixon_xml.c clixon_xml_io.c clixon_xml_sort.c clixon_xml_map.c clixon_xml_vec.c \
|
clixon_xml.c clixon_xml_io.c clixon_xml_sort.c clixon_xml_map.c clixon_xml_vec.c \
|
||||||
clixon_json.c \
|
clixon_xml_bind.c clixon_json.c \
|
||||||
clixon_yang.c clixon_yang_type.c clixon_yang_module.c clixon_yang_parse_lib.c \
|
clixon_yang.c clixon_yang_type.c clixon_yang_module.c clixon_yang_parse_lib.c \
|
||||||
clixon_yang_cardinality.c clixon_xml_changelog.c clixon_xml_nsctx.c \
|
clixon_yang_cardinality.c clixon_xml_changelog.c clixon_xml_nsctx.c \
|
||||||
clixon_path.c clixon_validate.c \
|
clixon_path.c clixon_validate.c \
|
||||||
|
|
|
||||||
|
|
@ -362,6 +362,10 @@ text_modify(clicon_handle h,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (x1bstr){
|
if (x1bstr){
|
||||||
|
/* XXX: Do the type lookup here inline instead, there are more
|
||||||
|
* cases where we check for types, eg where we now call clixon_trim2
|
||||||
|
* AND in nacm path where we need proper namespace contexts.
|
||||||
|
*/
|
||||||
if (check_identityref(x1, x0, x0p, x1bstr, y0) < 0)
|
if (check_identityref(x1, x0, x0p, x1bstr, y0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((x0b = xml_body_get(x0)) != NULL){
|
if ((x0b = xml_body_get(x0)) != NULL){
|
||||||
|
|
@ -496,7 +500,7 @@ text_modify(clicon_handle h,
|
||||||
if (xml_copy(x1, x0) < 0)
|
if (xml_copy(x1, x0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
}
|
} /* anyxml, anydata */
|
||||||
if (x0==NULL){
|
if (x0==NULL){
|
||||||
if (op==OP_MERGE && !permit && xnacm){
|
if (op==OP_MERGE && !permit && xnacm){
|
||||||
if ((ret = nacm_datanode_write(NULL, x1, NACM_CREATE, username, xnacm, cbret)) < 0)
|
if ((ret = nacm_datanode_write(NULL, x1, NACM_CREATE, username, xnacm, cbret)) < 0)
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,10 @@
|
||||||
* quoted-string = (DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)
|
* quoted-string = (DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)
|
||||||
* positive-integer-value = (non-zero-digit DIGIT*)
|
* positive-integer-value = (non-zero-digit DIGIT*)
|
||||||
* identifier = (ALPHA | "_")(ALPHA | DIGIT | "_" | "-" | ".")*
|
* identifier = (ALPHA | "_")(ALPHA | DIGIT | "_" | "-" | ".")*
|
||||||
|
*
|
||||||
|
* RFC 8341: All the same rules as an instance-identifier apply, except that predicates
|
||||||
|
* for keys are optional. If a key predicate is missing, then the
|
||||||
|
* node-instance-identifier represents all possible server instances for that key.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
%start start
|
%start start
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@
|
||||||
#include "clixon_yang_type.h"
|
#include "clixon_yang_type.h"
|
||||||
#include "clixon_yang_module.h"
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_xml_sort.h"
|
#include "clixon_xml_sort.h"
|
||||||
|
#include "clixon_xml_bind.h"
|
||||||
#include "clixon_xml_map.h"
|
#include "clixon_xml_map.h"
|
||||||
#include "clixon_xml_nsctx.h" /* namespace context */
|
#include "clixon_xml_nsctx.h" /* namespace context */
|
||||||
#include "clixon_netconf_lib.h"
|
#include "clixon_netconf_lib.h"
|
||||||
|
|
@ -1249,6 +1250,12 @@ _json_parse(char *str,
|
||||||
break;
|
break;
|
||||||
case YB_NONE:
|
case YB_NONE:
|
||||||
break;
|
break;
|
||||||
|
case YB_RPC:
|
||||||
|
if ((ret = xml_bind_yang_rpc(x, yspec, xerr)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
failed++;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
/* Now find leafs with identityrefs (+transitive) and translate
|
/* Now find leafs with identityrefs (+transitive) and translate
|
||||||
* prefixes in values to XML namespaces */
|
* prefixes in values to XML namespaces */
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2020 Olof Hagsand
|
Copyright (C) 2017-2019 Olof Hagsand
|
||||||
|
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
|
@ -351,13 +352,13 @@ nacm_rule_datanode(cxobj *xt,
|
||||||
|
|
||||||
/* 6b) Either (1) the rule does not have a "rule-type" defined or
|
/* 6b) Either (1) the rule does not have a "rule-type" defined or
|
||||||
(2) the "rule-type" is "data-node" and the "path" matches the
|
(2) the "rule-type" is "data-node" and the "path" matches the
|
||||||
requested data node, action node, or notification node. A
|
requested data node, action node, or notification node. */
|
||||||
path is considered to match if the requested node is the node
|
|
||||||
specified by the path or is a descendant node of the path.*/
|
|
||||||
if ((path = xml_find_body(xrule, "path")) == NULL){
|
if ((path = xml_find_body(xrule, "path")) == NULL){
|
||||||
if (xml_find_body(xrule, "rpc-name") ||xml_find_body(xrule, "notification-name"))
|
if (xml_find_body(xrule, "rpc-name") ||xml_find_body(xrule, "notification-name"))
|
||||||
goto nomatch;
|
goto nomatch;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
path = clixon_trim2(path, " \t\n");
|
||||||
access_operations = xml_find_body(xrule, "access-operations");
|
access_operations = xml_find_body(xrule, "access-operations");
|
||||||
switch (access){
|
switch (access){
|
||||||
case NACM_READ:
|
case NACM_READ:
|
||||||
|
|
@ -387,10 +388,17 @@ nacm_rule_datanode(cxobj *xt,
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Here module is matched, now check for path if any NYI */
|
/* Here module is matched, now check for path if any NYI
|
||||||
|
* A path is considered to match if the requested node is the node
|
||||||
|
* specified by the path or is a descendant node of the path */
|
||||||
if (path){
|
if (path){
|
||||||
|
#if 0
|
||||||
|
if ((ret = clixon_xml_find_instance_id(xt, yt, xvec, xlen, "%s", path)) == NULL)
|
||||||
|
goto nomatch;
|
||||||
|
#else
|
||||||
if ((xpath = xpath_first(xt, nsc, "%s", path)) == NULL)
|
if ((xpath = xpath_first(xt, nsc, "%s", path)) == NULL)
|
||||||
goto nomatch;
|
goto nomatch;
|
||||||
|
#endif
|
||||||
/* The requested node xr is the node specified by the path or is a
|
/* The requested node xr is the node specified by the path or is a
|
||||||
* descendant node of the path:
|
* descendant node of the path:
|
||||||
* xmatch is one of xvec[] or an ancestor of the xvec[] nodes.
|
* xmatch is one of xvec[] or an ancestor of the xvec[] nodes.
|
||||||
|
|
|
||||||
|
|
@ -1321,8 +1321,8 @@ api_path_resolve(clixon_path *cplist,
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @retval 0 Fail
|
* @retval 0 Fail
|
||||||
* @retval 1 OK
|
* @retval 1 OK
|
||||||
* @note: The spec says: prefixes depend on the XML context in which the value occurs. However,
|
* @note: The spec says: prefixes depend on the XML context in which the value occurs.
|
||||||
* canonical prefixes/namespaces are used based on loaded yang modules.
|
* However, canonical prefixes/namespaces are used based on loaded yang modules.
|
||||||
* This means that prefix=NULL is not allowed.
|
* This means that prefix=NULL is not allowed.
|
||||||
* Reasons for fail (retval = 0) are:
|
* Reasons for fail (retval = 0) are:
|
||||||
* - No prefix of identifier (keynames may omit prefix)
|
* - No prefix of identifier (keynames may omit prefix)
|
||||||
|
|
@ -1564,7 +1564,8 @@ clixon_xml_find_api_path(cxobj *xt,
|
||||||
|
|
||||||
/*! Given (instance-id) path and XML tree, return matching xml node vector using stdarg
|
/*! Given (instance-id) path and XML tree, return matching xml node vector using stdarg
|
||||||
*
|
*
|
||||||
* Instance-identifier is a subset of XML XPaths and defined in Yang, used in NACM for example.
|
* Instance-identifier is a subset of XML XPaths and defined in Yang, used in NACM for
|
||||||
|
* example.
|
||||||
* @param[in] xt Top xml-tree where to search
|
* @param[in] xt Top xml-tree where to search
|
||||||
* @param[in] yt Yang statement of top symbol (can be yang-spec if top-level)
|
* @param[in] yt Yang statement of top symbol (can be yang-spec if top-level)
|
||||||
* @param[out] xvec Vector of xml-trees. Vector must be free():d after use
|
* @param[out] xvec Vector of xml-trees. Vector must be free():d after use
|
||||||
|
|
@ -1588,6 +1589,7 @@ clixon_xml_find_api_path(cxobj *xt,
|
||||||
* }
|
* }
|
||||||
* clixon_xvec_free(xvec);
|
* clixon_xvec_free(xvec);
|
||||||
* @endcode
|
* @endcode
|
||||||
|
* @note canonical namespace contexts are used, seexpath2canonical
|
||||||
* @see clixon_xml_find_api_path for RESTCONF api-paths
|
* @see clixon_xml_find_api_path for RESTCONF api-paths
|
||||||
* @see RFC7950 Sec 9.13
|
* @see RFC7950 Sec 9.13
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
/* cligen */
|
/* cligen */
|
||||||
#include <cligen/cligen.h>
|
#include <cligen/cligen.h>
|
||||||
|
|
@ -170,15 +171,21 @@ clicon_msg_encode(uint32_t id,
|
||||||
* @param[in] yspec Yang specification, (can be NULL)
|
* @param[in] yspec Yang specification, (can be NULL)
|
||||||
* @param[out] id Session id
|
* @param[out] id Session id
|
||||||
* @param[out] xml XML parse tree
|
* @param[out] xml XML parse tree
|
||||||
|
* @param[out] xerr Reason for failure (yang assignment not made) if retval =0
|
||||||
|
* @retval 1 Parse OK and all yang assignment made
|
||||||
|
* @retval 0 Parse OK but yang assigment not made (or only partial)
|
||||||
|
* @retval -1 Error with clicon_err called. Includes parse error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_msg_decode(struct clicon_msg *msg,
|
clicon_msg_decode(struct clicon_msg *msg,
|
||||||
yang_stmt *yspec,
|
yang_stmt *yspec,
|
||||||
uint32_t *id,
|
uint32_t *id,
|
||||||
cxobj **xml)
|
cxobj **xml,
|
||||||
|
cxobj **xerr)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *xmlstr;
|
char *xmlstr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* hdr */
|
/* hdr */
|
||||||
if (id)
|
if (id)
|
||||||
|
|
@ -186,11 +193,16 @@ clicon_msg_decode(struct clicon_msg *msg,
|
||||||
/* body */
|
/* body */
|
||||||
xmlstr = msg->op_body;
|
xmlstr = msg->op_body;
|
||||||
clicon_debug(1, "%s %s", __FUNCTION__, xmlstr);
|
clicon_debug(1, "%s %s", __FUNCTION__, xmlstr);
|
||||||
if (clixon_xml_parse_string(xmlstr, yspec?YB_MODULE:YB_NONE, yspec, xml, NULL) < 0)
|
if ((ret = clixon_xml_parse_string(xmlstr, yspec?YB_RPC:YB_NONE, yspec, xml, xerr)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
if (ret == 0)
|
||||||
|
goto fail;
|
||||||
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
fail:
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Open local connection using unix domain sockets
|
/*! Open local connection using unix domain sockets
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@
|
||||||
#include "clixon_stream.h"
|
#include "clixon_stream.h"
|
||||||
#include "clixon_err_string.h"
|
#include "clixon_err_string.h"
|
||||||
#include "clixon_xml_nsctx.h"
|
#include "clixon_xml_nsctx.h"
|
||||||
#include "clixon_xml_map.h"
|
#include "clixon_xml_bind.h"
|
||||||
#include "clixon_xml_sort.h"
|
#include "clixon_xml_sort.h"
|
||||||
#include "clixon_xml_io.h"
|
#include "clixon_xml_io.h"
|
||||||
#include "clixon_netconf_lib.h"
|
#include "clixon_netconf_lib.h"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
|
||||||
|
Copyright (C) 2017-2019 Olof Hagsand
|
||||||
|
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
|
@ -692,6 +694,29 @@ clixon_trim(char *str)
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Trim blanks from front and end of a string, return new string
|
||||||
|
* @param[in] str
|
||||||
|
* @param[in] trims Characters to trim: a vector of characters
|
||||||
|
* @retval s Pointer into existing str after trimming blanks
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
clixon_trim2(char *str,
|
||||||
|
char *trims)
|
||||||
|
{
|
||||||
|
char *s = str;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
while (strlen(s) && index(trims, s[0])) /* trim from front */
|
||||||
|
s++;
|
||||||
|
for (i=strlen(s)-1; i>=0; i--){ /* trim from rear */
|
||||||
|
if (index(trims, s[i]))
|
||||||
|
s[i] = '\0';
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
/*! check string equals (NULL is equal)
|
/*! check string equals (NULL is equal)
|
||||||
* @param[in] s1 String 1
|
* @param[in] s1 String 1
|
||||||
* @param[in] s2 String 2
|
* @param[in] s2 String 2
|
||||||
|
|
|
||||||
|
|
@ -1090,14 +1090,10 @@ xml_yang_validate_all(clicon_handle h,
|
||||||
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 (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)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
else
|
|
||||||
if (netconf_unknown_element_xml(xret, "application", xml_name(xt), cbuf_get(cb)) < 0)
|
|
||||||
goto done;
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (yang_config(ys) != 0){
|
if (yang_config(ys) != 0){
|
||||||
|
|
|
||||||
|
|
@ -66,9 +66,9 @@
|
||||||
#include "clixon_log.h"
|
#include "clixon_log.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
#include "clixon_options.h" /* xml_bind_yang */
|
#include "clixon_options.h"
|
||||||
#include "clixon_yang_module.h"
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_xml_map.h" /* xml_bind_yang */
|
#include "clixon_xml_bind.h"
|
||||||
#include "clixon_xml_vec.h"
|
#include "clixon_xml_vec.h"
|
||||||
#include "clixon_xml_sort.h"
|
#include "clixon_xml_sort.h"
|
||||||
#include "clixon_xml_nsctx.h"
|
#include "clixon_xml_nsctx.h"
|
||||||
|
|
@ -455,7 +455,13 @@ _xml_parse(const char *str,
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
failed++;
|
failed++;
|
||||||
break;
|
break;
|
||||||
}
|
case YB_RPC:
|
||||||
|
if ((ret = xml_bind_yang_rpc(x, yspec, xerr)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
failed++;
|
||||||
|
break;
|
||||||
|
} /* switch */
|
||||||
}
|
}
|
||||||
if (failed)
|
if (failed)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -601,7 +607,7 @@ clixon_xml_parse_file(int fd,
|
||||||
* @param[in] yb How to bind yang to XML top-level when parsing
|
* @param[in] yb How to bind yang to XML top-level when parsing
|
||||||
* @param[in] yspec Yang specification, or NULL
|
* @param[in] yspec Yang specification, or NULL
|
||||||
* @param[in,out] xt Pointer to XML parse tree. If empty will be created.
|
* @param[in,out] xt Pointer to XML parse tree. If empty will be created.
|
||||||
* @param[out] xerr Reason for failure (yang assignment not made)
|
* @param[out] xerr Reason for failure (yang assignment not made) if retval = 0
|
||||||
* @retval 1 Parse OK and all yang assignment made
|
* @retval 1 Parse OK and all yang assignment made
|
||||||
* @retval 0 Parse OK but yang assigment not made (or only partial)
|
* @retval 0 Parse OK but yang assigment not made (or only partial)
|
||||||
* @retval -1 Error with clicon_err called. Includes parse error
|
* @retval -1 Error with clicon_err called. Includes parse error
|
||||||
|
|
|
||||||
|
|
@ -1304,14 +1304,12 @@ xml_merge1(cxobj *x0, /* the target */
|
||||||
char *x1bstr; /* mod body string */
|
char *x1bstr; /* mod body string */
|
||||||
yang_stmt *yc; /* yang child */
|
yang_stmt *yc; /* yang child */
|
||||||
cbuf *cbr = NULL; /* Reason buffer */
|
cbuf *cbr = NULL; /* Reason buffer */
|
||||||
#ifdef XML_MERGE_TWO_ROUNDS
|
|
||||||
int i;
|
int i;
|
||||||
struct {
|
struct {
|
||||||
cxobj *w_x0c;
|
cxobj *w_x0c;
|
||||||
cxobj *w_x1c;
|
cxobj *w_x1c;
|
||||||
yang_stmt *w_yc;
|
yang_stmt *w_yc;
|
||||||
} *second_wave = NULL;
|
} *second_wave = NULL;
|
||||||
#endif
|
|
||||||
|
|
||||||
assert(x1 && xml_type(x1) == CX_ELMNT);
|
assert(x1 && xml_type(x1) == CX_ELMNT);
|
||||||
assert(y0);
|
assert(y0);
|
||||||
|
|
@ -1347,13 +1345,11 @@ xml_merge1(cxobj *x0, /* the target */
|
||||||
}
|
}
|
||||||
if (assign_namespaces(x1, x0, x0p) < 0)
|
if (assign_namespaces(x1, x0, x0p) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
#ifdef XML_MERGE_TWO_ROUNDS
|
|
||||||
if ((second_wave = calloc(xml_child_nr(x1), sizeof(*second_wave))) == NULL){
|
if ((second_wave = calloc(xml_child_nr(x1), sizeof(*second_wave))) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "calloc");
|
clicon_err(OE_UNIX, errno, "calloc");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
i = 0;
|
i = 0;
|
||||||
#endif
|
|
||||||
/* Loop through children of the modification tree */
|
/* Loop through children of the modification tree */
|
||||||
x1c = NULL;
|
x1c = NULL;
|
||||||
while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) {
|
while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) {
|
||||||
|
|
@ -1377,7 +1373,6 @@ xml_merge1(cxobj *x0, /* the target */
|
||||||
x0c = NULL;
|
x0c = NULL;
|
||||||
if (yc && match_base_child(x0, x1c, yc, &x0c) < 0)
|
if (yc && match_base_child(x0, x1c, yc, &x0c) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
#ifdef XML_MERGE_TWO_ROUNDS
|
|
||||||
/* Save x0c, x1c, yc and merge in second wave, so that x1c entries "interfer"
|
/* Save x0c, x1c, yc and merge in second wave, so that x1c entries "interfer"
|
||||||
* with itself, ie that later searches are among earlier objects already added
|
* with itself, ie that later searches are among earlier objects already added
|
||||||
* to x0 */
|
* to x0 */
|
||||||
|
|
@ -1385,14 +1380,7 @@ xml_merge1(cxobj *x0, /* the target */
|
||||||
second_wave[i].w_x1c = x1c;
|
second_wave[i].w_x1c = x1c;
|
||||||
second_wave[i].w_yc = yc;
|
second_wave[i].w_yc = yc;
|
||||||
i++;
|
i++;
|
||||||
#else
|
|
||||||
if (xml_merge1(x0c, yc, x0, x1c, reason) < 0)
|
|
||||||
goto done;
|
|
||||||
if (*reason != NULL)
|
|
||||||
goto ok;
|
|
||||||
#endif
|
|
||||||
} /* while */
|
} /* while */
|
||||||
#ifdef XML_MERGE_TWO_ROUNDS
|
|
||||||
/* Second run where actual merging is done
|
/* Second run where actual merging is done
|
||||||
* Loop through children of the modification tree */
|
* Loop through children of the modification tree */
|
||||||
x1c = NULL;
|
x1c = NULL;
|
||||||
|
|
@ -1408,7 +1396,6 @@ xml_merge1(cxobj *x0, /* the target */
|
||||||
goto ok;
|
goto ok;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if (xml_parent(x0) == NULL &&
|
if (xml_parent(x0) == NULL &&
|
||||||
xml_insert(x0p, x0, INS_LAST, NULL, NULL) < 0)
|
xml_insert(x0p, x0, INS_LAST, NULL, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1416,10 +1403,8 @@ xml_merge1(cxobj *x0, /* the target */
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
#ifdef XML_MERGE_TWO_ROUNDS
|
|
||||||
if (second_wave)
|
if (second_wave)
|
||||||
free(second_wave);
|
free(second_wave);
|
||||||
#endif
|
|
||||||
if (cbr)
|
if (cbr)
|
||||||
cbuf_free(cbr);
|
cbuf_free(cbr);
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
||||||
|
|
@ -660,7 +660,8 @@ cv_validate1(clicon_handle h,
|
||||||
if (strcmp(restype, "enumeration") == 0){
|
if (strcmp(restype, "enumeration") == 0){
|
||||||
found = 0;
|
found = 0;
|
||||||
yi = NULL;
|
yi = NULL;
|
||||||
if (str != NULL)
|
if (str != NULL) {
|
||||||
|
str = clixon_trim2(str, " \t\n"); /* May be misplaced, strip earlier? */
|
||||||
while ((yi = yn_each(yrestype, yi)) != NULL){
|
while ((yi = yn_each(yrestype, yi)) != NULL){
|
||||||
if (yang_keyword_get(yi) != Y_ENUM)
|
if (yang_keyword_get(yi) != Y_ENUM)
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -669,6 +670,7 @@ cv_validate1(clicon_handle h,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!found){
|
if (!found){
|
||||||
if (reason)
|
if (reason)
|
||||||
*reason = cligen_reason("'%s' does not match enumeration", str);
|
*reason = cligen_reason("'%s' does not match enumeration", str);
|
||||||
|
|
@ -680,7 +682,7 @@ cv_validate1(clicon_handle h,
|
||||||
* of the names of the bits that are set. A zero-length string thus
|
* of the names of the bits that are set. A zero-length string thus
|
||||||
* represents a value where no bits are set.
|
* represents a value where no bits are set.
|
||||||
*/
|
*/
|
||||||
|
str = clixon_trim2(str, " \t\n"); /* May be misplaced, strip earlier? */
|
||||||
nvec = 0;
|
nvec = 0;
|
||||||
if ((vec = clicon_strsep(str, " \t", &nvec)) == NULL)
|
if ((vec = clicon_strsep(str, " \t", &nvec)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -283,7 +283,7 @@ expectpart "$(curl -s -i -X DELETE http://localhost/restconf/data/example:crypt
|
||||||
|
|
||||||
# 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
|
||||||
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":"Missing matching yang node"}}}'
|
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"}}}'
|
||||||
|
|
||||||
# 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"}}}'
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,6 @@
|
||||||
# @see test_nacm.sh is slightly modified - this follows the RFC more closely
|
# @see test_nacm.sh is slightly modified - this follows the RFC more closely
|
||||||
# See RFC 8341 A.1 and A.2
|
# See RFC 8341 A.1 and A.2
|
||||||
# Note: use clixon-example instead of ietf-netconf-monitoring since the latter is
|
# Note: use clixon-example instead of ietf-netconf-monitoring since the latter is
|
||||||
# Tests for
|
|
||||||
# deny-ncm: This rule prevents the "guest" group from reading any
|
|
||||||
# monitoring information in the "clixon-example" YANG
|
|
||||||
# module.
|
|
||||||
# permit-ncm: This rule allows the "limited" group to read the
|
|
||||||
# "clixon-example" YANG module.
|
|
||||||
# permit-exec: This rule allows the "limited" group to invoke any
|
|
||||||
# protocol operation supported by the server.
|
|
||||||
# permit-all: This rule allows the "admin" group complete access to
|
|
||||||
# all content in the server. No subsequent rule will match for the
|
|
||||||
# "admin" group because of this module rule
|
|
||||||
|
|
||||||
# Magic line must be first in script (see README.md)
|
# Magic line must be first in script (see README.md)
|
||||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
|
|
|
||||||
|
|
@ -123,9 +123,10 @@ new "restconf empty rpc, default media type should fail (JSON)"
|
||||||
expectpart "$(curl -si -X POST -H "Accept: application/yang-data+json" -d {\"clixon-example:input\":null} http://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 415 Unsupported Media Type'
|
expectpart "$(curl -si -X POST -H "Accept: application/yang-data+json" -d {\"clixon-example:input\":null} http://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 415 Unsupported Media Type'
|
||||||
|
|
||||||
new "restconf empty rpc with extra args (should fail)"
|
new "restconf empty rpc with extra args (should fail)"
|
||||||
expectpart "$(curl -si -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-example:input\":{\"extra\":null}} http://localhost/restconf/operations/clixon-example:empty)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"extra"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: extra with parent: empty in namespace: urn:example:clixon"}}}
'
|
expectpart "$(curl -si -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-example:input\":{\"extra\":null}} http://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"extra"},"error-severity":"error","error-message":"Unrecognized parameter: extra in rpc: empty"}}}'
|
||||||
|
|
||||||
new "restconf debug rpc"
|
# Irritiating to get debugs on the terminal
|
||||||
|
#new "restconf debug rpc"
|
||||||
#expectpart "$(curl -si -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-lib:input\":{\"level\":0}} http://localhost/restconf/operations/clixon-lib:debug)" 0 "HTTP/1.1 204 No Content"
|
#expectpart "$(curl -si -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-lib:input\":{\"level\":0}} http://localhost/restconf/operations/clixon-lib:debug)" 0 "HTTP/1.1 204 No Content"
|
||||||
|
|
||||||
new "restconf get empty config + state json"
|
new "restconf get empty config + state json"
|
||||||
|
|
@ -243,19 +244,19 @@ expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"
|
||||||
'
|
'
|
||||||
|
|
||||||
new "restconf rpc using POST json wrong"
|
new "restconf rpc using POST json wrong"
|
||||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-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"}}}'
|
||||||
|
|
||||||
new "restconf rpc non-existing rpc without namespace"
|
new "restconf rpc non-existing rpc without namespace"
|
||||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations/kalle)" 0 '{"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"}}'
|
||||||
|
|
||||||
new "restconf rpc non-existing rpc"
|
new "restconf rpc non-existing rpc"
|
||||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations/clixon-example:kalle)" 0 '{"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/clixon-example: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"}}'
|
||||||
|
|
||||||
new "restconf rpc missing name"
|
new "restconf rpc missing name"
|
||||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"Operation name expected"}}}
'
|
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations)" 0 'HTTP/1.1 412 Precondition Failed' '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"Operation name expected"}}}'
|
||||||
|
|
||||||
new "restconf rpc missing input"
|
new "restconf rpc missing input"
|
||||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"restconf RPC does not have input statement"}}}
'
|
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"restconf RPC does not have input statement"}}}'
|
||||||
|
|
||||||
new "restconf rpc using POST xml"
|
new "restconf rpc using POST xml"
|
||||||
ret=$(curl -s -X POST -H "Content-Type: application/yang-data+json" -H "Accept: application/yang-data+xml" -d '{"clixon-example:input":{"x":42}}' http://localhost/restconf/operations/clixon-example:example)
|
ret=$(curl -s -X POST -H "Content-Type: application/yang-data+json" -H "Accept: application/yang-data+xml" -d '{"clixon-example:input":{"x":42}}' http://localhost/restconf/operations/clixon-example:example)
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ if [ -z "$match" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "restconf empty rpc with input x"
|
new "restconf empty rpc with input x"
|
||||||
expectpart "$(curl -iss -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":0}}' http://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"x"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: x with parent: empty in namespace: urn:example:clixon"}}}
'
|
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":0}}' http://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"x"},"error-severity":"error","error-message":"Unrecognized parameter: x in rpc: empty"}}}'
|
||||||
|
|
||||||
# cornercase: optional has yang input/output sections but test without body
|
# cornercase: optional has yang input/output sections but test without body
|
||||||
new "restconf optional rpc with null input and output"
|
new "restconf optional rpc with null input and output"
|
||||||
|
|
@ -129,7 +129,7 @@ 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"
|
||||||
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":"unknown-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"}}}'
|
||||||
|
|
||||||
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"}}}
'
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue