* xml-stats moved from clixon-config.yang as state data to an rpc datastatsin clixon-lib.yang
* Two new plugin callbacks added * ca_daemon: Called just after a server has "daemonized", ie put in background. * ca_trans_commit_done: Called when all plugin commits have been done.
This commit is contained in:
parent
65806f1ef2
commit
1c99bd6a9b
20 changed files with 290 additions and 112 deletions
|
|
@ -31,10 +31,14 @@ Expected: May 2020
|
|||
|
||||
### API changes on existing protocol/config features (You may have have to change how you use Clixon)
|
||||
|
||||
* xml-stats moved from clixon-config.yang as state data to an rpc `datastats`in clixon-lib.yang
|
||||
* 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)
|
||||
|
||||
* Two new plugin callbacks added
|
||||
* ca_daemon: Called just after a server has "daemonized", ie put in background.
|
||||
* ca_trans_commit_done: Called when all plugin commits have been done.
|
||||
* Length of xml vector in many structs changed from `size_t` to `int`since it is a vector size, not byte size. This includes `transaction_data_t`
|
||||
* `xml_merge()` changed to use 3-value return: 1:OK, 0:Yang failed, -1: Error
|
||||
* `clixon_netconf_error(category, xerr, msg, arg)` removed first argument -> `clixon_netconf_error(xerr, msg, arg)`
|
||||
|
|
|
|||
|
|
@ -276,60 +276,19 @@ clixon_stats_get_db(clicon_handle h,
|
|||
db_elmnt *de = NULL;
|
||||
|
||||
/* This is the db cache */
|
||||
if ((de = clicon_db_elmnt_get(h, dbname)) != NULL)
|
||||
xt = de->de_xml;
|
||||
xml_stats(xt, &nr, &sz);
|
||||
if ((de = clicon_db_elmnt_get(h, dbname)) == NULL ||
|
||||
(xt = de->de_xml) == NULL){
|
||||
cprintf(cb, "<datastore><name>%s</name><nr>0</nr><size>0</size></datastore>", dbname);
|
||||
}
|
||||
else{
|
||||
if (xml_stats(xt, &nr, &sz) < 0)
|
||||
goto done;
|
||||
cprintf(cb, "<datastore><name>%s</name><nr>%" PRIu64 "</nr>"
|
||||
"<size>%" PRIu64 "</size></datastore>",
|
||||
dbname, nr, sz);
|
||||
retval = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Get clixon stats
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[in] xpath XML Xpath
|
||||
* @param[in] nsc XML Namespace context for xpath
|
||||
* @param[in,out] xret Existing XML tree, merge x into this
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
clixon_stats_get(clicon_handle h,
|
||||
yang_stmt *yspec,
|
||||
char *xpath,
|
||||
cvec *nsc,
|
||||
cxobj **xret)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cb = NULL;
|
||||
uint64_t nr;
|
||||
int ret;
|
||||
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "<clixon-stats xmlns=\"%s\">", CLIXON_CONF_NS);
|
||||
nr=0;
|
||||
xml_stats_global(&nr);
|
||||
cprintf(cb, "<global><xmlnr>%" PRIu64 "</xmlnr></global>", nr);
|
||||
clixon_stats_get_db(h, "running", cb);
|
||||
clixon_stats_get_db(h, "candidate", cb);
|
||||
clixon_stats_get_db(h, "startup", cb);
|
||||
cprintf(cb, "</clixon-stats>");
|
||||
if ((ret = clixon_xml_parse_string(cbuf_get(cb), YB_MODULE, yspec, xret, NULL)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
clicon_err(OE_XML, EINVAL, "Internal error");
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -408,11 +367,6 @@ client_statedata(clicon_handle h,
|
|||
if (ret == 0)
|
||||
goto fail;
|
||||
}
|
||||
/* Clixon-config has a state data, if yang is present */
|
||||
if (yang_find(yspec, Y_MODULE, "clixon-config") != NULL){
|
||||
if (clixon_stats_get(h, yspec, xpath, nsc, xret) < 0)
|
||||
goto done;
|
||||
}
|
||||
if ((ret = clixon_plugin_statedata(h, yspec, nsc, xpath, xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
|
|
@ -1441,6 +1395,41 @@ from_client_ping(clicon_handle h,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Check liveness of backend daemon, just send a reply
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] xe Request: <rpc><xn></rpc>
|
||||
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
|
||||
* @param[in] arg client-entry
|
||||
* @param[in] regarg User argument given at rpc_callback_register()
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
from_client_datastats(clicon_handle h,
|
||||
cxobj *xe,
|
||||
cbuf *cbret,
|
||||
void *arg,
|
||||
void *regarg)
|
||||
{
|
||||
int retval = -1;
|
||||
uint64_t nr;
|
||||
|
||||
cprintf(cbret, "<rpc-reply>");
|
||||
nr=0;
|
||||
xml_stats_global(&nr);
|
||||
cprintf(cbret, "<global><xmlnr>%" PRIu64 "</xmlnr></global>", nr);
|
||||
if (clixon_stats_get_db(h, "running", cbret) < 0)
|
||||
goto done;
|
||||
if (clixon_stats_get_db(h, "candidate", cbret) < 0)
|
||||
goto done;
|
||||
if (clixon_stats_get_db(h, "startup", cbret) < 0)
|
||||
goto done;
|
||||
cprintf(cbret, "</rpc-reply>");
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Verify nacm user with peer uid credentials
|
||||
* @param[in] mode Peer credential mode: none, exact or except
|
||||
* @param[in] peername Peer username if any
|
||||
|
|
@ -1797,10 +1786,13 @@ backend_rpc_init(clicon_handle h)
|
|||
goto done;
|
||||
/* Clixon RPC */
|
||||
if (rpc_callback_register(h, from_client_debug, NULL,
|
||||
"http://clicon.org/lib", "debug") < 0)
|
||||
CLIXON_LIB_NS, "debug") < 0)
|
||||
goto done;
|
||||
if (rpc_callback_register(h, from_client_ping, NULL,
|
||||
"http://clicon.org/lib", "ping") < 0)
|
||||
CLIXON_LIB_NS, "ping") < 0)
|
||||
goto done;
|
||||
if (rpc_callback_register(h, from_client_datastats, NULL,
|
||||
CLIXON_LIB_NS, "datastats") < 0)
|
||||
goto done;
|
||||
retval =0;
|
||||
done:
|
||||
|
|
|
|||
|
|
@ -349,6 +349,9 @@ startup_commit(clicon_handle h,
|
|||
/* 8. Call plugin transaction commit callbacks */
|
||||
if (plugin_transaction_commit(h, td) < 0)
|
||||
goto done;
|
||||
/* After commit, make a post-commit call (sure that all plugins have committed) */
|
||||
if (plugin_transaction_commit_done(h, td) < 0)
|
||||
goto done;
|
||||
/* Clear cached trees from default values and marking */
|
||||
if (xmldb_get0_clear(h, td->td_target) < 0)
|
||||
goto done;
|
||||
|
|
@ -538,6 +541,9 @@ candidate_commit(clicon_handle h,
|
|||
/* 7. Call plugin transaction commit callbacks */
|
||||
if (plugin_transaction_commit(h, td) < 0)
|
||||
goto done;
|
||||
/* After commit, make a post-commit call (sure that all plugins have committed) */
|
||||
if (plugin_transaction_commit_done(h, td) < 0)
|
||||
goto done;
|
||||
|
||||
/* Clear cached trees from default values and marking */
|
||||
if (xmldb_get0_clear(h, td->td_target) < 0)
|
||||
|
|
|
|||
|
|
@ -885,6 +885,10 @@ main(int argc,
|
|||
}
|
||||
|
||||
}
|
||||
/* Call plugin callbacks when in background and before dropped privileges */
|
||||
if (clixon_plugin_daemon(h) < 0)
|
||||
goto done;
|
||||
|
||||
/* Write pid-file */
|
||||
if ((pid = pidfile_write(pidfile)) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -92,6 +92,32 @@ clixon_plugin_reset(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Request plugins to reset system state
|
||||
* The system 'state' should be the same as the contents of running_db
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] db Name of database
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
clixon_plugin_daemon(clicon_handle h)
|
||||
{
|
||||
clixon_plugin *cp = NULL;
|
||||
plgdaemon_t *daemonfn; /* Plugin auth */
|
||||
int retval = 1;
|
||||
|
||||
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||
if ((daemonfn = cp->cp_api.ca_daemon) == NULL)
|
||||
continue;
|
||||
if ((retval = daemonfn(h)) < 0) {
|
||||
clicon_debug(1, "plugin_daemon() failed");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Go through all backend statedata callbacks and collect state data
|
||||
* This is internal system call, plugin is invoked (does not call) this function
|
||||
* Backend plugins can register
|
||||
|
|
@ -345,6 +371,36 @@ plugin_transaction_commit(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Call transaction_commit_done callbacks in all backend plugins
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] td Transaction data
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error: one of the plugin callbacks returned error
|
||||
* @note no revert is done
|
||||
*/
|
||||
int
|
||||
plugin_transaction_commit_done(clicon_handle h,
|
||||
transaction_data_t *td)
|
||||
{
|
||||
int retval = 0;
|
||||
clixon_plugin *cp = NULL;
|
||||
trans_cb_t *fn;
|
||||
int i=0;
|
||||
|
||||
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||
i++;
|
||||
if ((fn = cp->cp_api.ca_trans_commit_done) == NULL)
|
||||
continue;
|
||||
if ((retval = fn(h, (transaction_data)td)) < 0){
|
||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' trans_commit_done callback does not make clicon_err call on error",
|
||||
__FUNCTION__, cp->cp_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Call transaction_end() in all plugins after a successful commit.
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] td Transaction data
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
*
|
||||
***** 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(Netgate)
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
|
|
@ -69,6 +71,8 @@ typedef struct {
|
|||
*/
|
||||
int clixon_plugin_reset(clicon_handle h, char *db);
|
||||
|
||||
int clixon_plugin_daemon(clicon_handle h);
|
||||
|
||||
int clixon_plugin_statedata(clicon_handle h, yang_stmt *yspec, cvec *nsc,
|
||||
char *xpath, cxobj **xtop);
|
||||
transaction_data_t * transaction_new(void);
|
||||
|
|
@ -78,6 +82,7 @@ int plugin_transaction_begin(clicon_handle h, transaction_data_t *td);
|
|||
int plugin_transaction_validate(clicon_handle h, transaction_data_t *td);
|
||||
int plugin_transaction_complete(clicon_handle h, transaction_data_t *td);
|
||||
int plugin_transaction_commit(clicon_handle h, transaction_data_t *td);
|
||||
int plugin_transaction_commit_done(clicon_handle h, transaction_data_t *td);
|
||||
int plugin_transaction_end(clicon_handle h, transaction_data_t *td);
|
||||
int plugin_transaction_abort(clicon_handle h, transaction_data_t *td);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ module clixon-example {
|
|||
import iana-if-type {
|
||||
prefix ianaift;
|
||||
}
|
||||
|
||||
/* Example interface type for tests, local callbacks, etc */
|
||||
identity eth {
|
||||
base if:interface-type;
|
||||
|
|
@ -33,7 +34,20 @@ module clixon-example {
|
|||
identity loopback {
|
||||
base if:interface-type;
|
||||
}
|
||||
/* Translation function example - See also example_cli */
|
||||
/* Generic config data */
|
||||
container table{
|
||||
list parameter{
|
||||
key name;
|
||||
leaf name{
|
||||
type string;
|
||||
}
|
||||
leaf value{
|
||||
type string;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Translation function example - See also example_cli
|
||||
* XXX use table ^instead */
|
||||
container translate{
|
||||
description "dont have lists directly under top since restconf cant address list directly";
|
||||
list translate{
|
||||
|
|
|
|||
|
|
@ -46,8 +46,10 @@
|
|||
/*! Clixon configuration namespace
|
||||
* Probably should be defined somewhere else or extracted from yang
|
||||
* @see clixon-config.yang
|
||||
* @see clixon-lib.yang
|
||||
*/
|
||||
#define CLIXON_CONF_NS "http://clicon.org/config"
|
||||
#define CLIXON_LIB_NS "http://clicon.org/lib"
|
||||
|
||||
/*
|
||||
* Types
|
||||
|
|
|
|||
|
|
@ -105,6 +105,12 @@ typedef int (*clicon_upgrade_cb)(
|
|||
*/
|
||||
typedef int (plgstart_t)(clicon_handle); /* Plugin start */
|
||||
|
||||
/* Called just after a server has "daemonized", ie put in background.
|
||||
* Backend: If daemon privileges are dropped this callback is called *before* privileges are dropped.
|
||||
* If daemon is started in foreground (-F) it is still called.
|
||||
*/
|
||||
typedef int (plgdaemon_t)(clicon_handle); /* Plugin daemonized */
|
||||
|
||||
/* Called just before plugin unloaded.
|
||||
*/
|
||||
typedef int (plgexit_t)(clicon_handle); /* Plugin exit */
|
||||
|
|
@ -211,12 +217,14 @@ struct clixon_plugin_api{
|
|||
struct { /* netconf-specific */
|
||||
} cau_netconf;
|
||||
struct { /* backend-specific */
|
||||
plgdaemon_t *cb_daemon; /* Plugin daemonized */
|
||||
plgreset_t *cb_reset; /* Reset system status */
|
||||
plgstatedata_t *cb_statedata; /* Get state data from plugin (backend only) */
|
||||
trans_cb_t *cb_trans_begin; /* Transaction start */
|
||||
trans_cb_t *cb_trans_validate; /* Transaction validation */
|
||||
trans_cb_t *cb_trans_complete; /* Transaction validation complete */
|
||||
trans_cb_t *cb_trans_commit; /* Transaction commit */
|
||||
trans_cb_t *cb_trans_commit_done; /* Transaction when commit done */
|
||||
trans_cb_t *cb_trans_revert; /* Transaction revert */
|
||||
trans_cb_t *cb_trans_end; /* Transaction completed */
|
||||
trans_cb_t *cb_trans_abort; /* Transaction aborted */
|
||||
|
|
@ -229,12 +237,14 @@ struct clixon_plugin_api{
|
|||
#define ca_suspend u.cau_cli.ci_suspend
|
||||
#define ca_interrupt u.cau_cli.ci_interrupt
|
||||
#define ca_auth u.cau_restconf.cr_auth
|
||||
#define ca_daemon u.cau_backend.cb_daemon
|
||||
#define ca_reset u.cau_backend.cb_reset
|
||||
#define ca_statedata u.cau_backend.cb_statedata
|
||||
#define ca_trans_begin u.cau_backend.cb_trans_begin
|
||||
#define ca_trans_validate u.cau_backend.cb_trans_validate
|
||||
#define ca_trans_complete u.cau_backend.cb_trans_complete
|
||||
#define ca_trans_commit u.cau_backend.cb_trans_commit
|
||||
#define ca_trans_commit_done u.cau_backend.cb_trans_commit_done
|
||||
#define ca_trans_revert u.cau_backend.cb_trans_revert
|
||||
#define ca_trans_end u.cau_backend.cb_trans_end
|
||||
#define ca_trans_abort u.cau_backend.cb_trans_abort
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ typedef struct clixon_xml_vec clixon_xvec; /* struct defined in clicon_xml_vec.c
|
|||
*/
|
||||
char *xml_type2str(enum cxobj_type type);
|
||||
int xml_stats_global(uint64_t *nr);
|
||||
size_t xml_stats(cxobj *xt, uint64_t *nrp, size_t *szp);
|
||||
int xml_stats(cxobj *xt, uint64_t *nrp, size_t *szp);
|
||||
char *xml_name(cxobj *xn);
|
||||
int xml_name_set(cxobj *xn, char *name);
|
||||
char *xml_prefix(cxobj *xn);
|
||||
|
|
|
|||
|
|
@ -471,7 +471,7 @@ clixon_plugin_extension(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Call plugingeneral-purpose datastore upgrade in all plugins
|
||||
/*! Call plugin general-purpose datastore upgrade in all plugins
|
||||
*
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] db Name of datastore, eg "running", "startup" or "tmp"
|
||||
|
|
|
|||
|
|
@ -1011,7 +1011,10 @@ clicon_rpc_debug(clicon_handle h,
|
|||
goto done;
|
||||
username = clicon_username_get(h);
|
||||
if ((msg = clicon_msg_encode(session_id,
|
||||
"<rpc username=\"%s\"><debug xmlns=\"http://clicon.org/lib\"><level>%d</level></debug></rpc>", username?username:"", level)) == NULL)
|
||||
"<rpc username=\"%s\"><debug xmlns=\"%s\"><level>%d</level></debug></rpc>",
|
||||
username?username:"",
|
||||
CLIXON_LIB_NS,
|
||||
level)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -284,18 +284,24 @@ xml_stats_one(cxobj *x,
|
|||
}
|
||||
|
||||
/*! Return statistics of an XML tree recursively
|
||||
* @param[in] x XML object
|
||||
* @param[in] xt XML object
|
||||
* @param[out] szp Size of this XML obj recursively
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
size_t
|
||||
int
|
||||
xml_stats(cxobj *xt,
|
||||
uint64_t *nrp,
|
||||
size_t *szp)
|
||||
{
|
||||
int retval = -1;
|
||||
size_t sz = 0;
|
||||
cxobj *xc;
|
||||
|
||||
if (xt == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "xml node is NULL");
|
||||
goto done;
|
||||
}
|
||||
*nrp += 1;
|
||||
xml_stats_one(xt, &sz);
|
||||
if (szp)
|
||||
|
|
@ -308,7 +314,9 @@ xml_stats(cxobj *xt,
|
|||
*szp += sz;
|
||||
}
|
||||
clicon_debug(1, "%s %zu", __FUNCTION__, *szp);
|
||||
return 0;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -157,8 +157,7 @@ if [ $RC -ne 0 ]; then
|
|||
fi
|
||||
|
||||
new "auth get"
|
||||
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data)" 0 '{"data":{"clixon-example:state":{"op":["41","42","43"]}}}
|
||||
'
|
||||
expectpart "$(curl -u andy:bar -siS -X GET http://localhost/restconf/data)" 0 'HTTP/1.1 200 OK' '{"data":{"clixon-example:state":{"op":\["41","42","43"\]}'
|
||||
|
||||
new "Set x to 0"
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"nacm-example:x": 0}' http://localhost/restconf/data/nacm-example:x)" 0 ""
|
||||
|
|
|
|||
|
|
@ -77,12 +77,11 @@ expecteq "$(curl -s -H 'Accept: application/yang-data+xml' -G http://localhost/r
|
|||
|
||||
# Should be alphabetically ordered
|
||||
new "restconf get restconf/operations. RFC8040 3.3.2 (json)"
|
||||
expecteq "$(curl -sG http://localhost/restconf/operations)" 0 '{"operations":{"clixon-example:client-rpc":[null],"clixon-example:empty":[null],"clixon-example:optional":[null],"clixon-example:example":[null],"clixon-lib:debug":[null],"clixon-lib:ping":[null],"ietf-netconf:get-config":[null],"ietf-netconf:edit-config":[null],"ietf-netconf:copy-config":[null],"ietf-netconf:delete-config":[null],"ietf-netconf:lock":[null],"ietf-netconf:unlock":[null],"ietf-netconf:get":[null],"ietf-netconf:close-session":[null],"ietf-netconf:kill-session":[null],"ietf-netconf:commit":[null],"ietf-netconf:discard-changes":[null],"ietf-netconf:validate":[null],"clixon-rfc5277:create-subscription":[null]}}
|
||||
'
|
||||
expectpart "$(curl -siG http://localhost/restconf/operations)" 0 'HTTP/1.1 200 OK' '{"operations":{"clixon-example:client-rpc":\[null\],"clixon-example:empty":\[null\],"clixon-example:optional":\[null\],"clixon-example:example":\[null\],"clixon-lib:debug":\[null\],"clixon-lib:ping":\[null\],"clixon-lib:datastats":\[null\],"ietf-netconf:get-config":\[null\],"ietf-netconf:edit-config":\[null\],"ietf-netconf:copy-config":\[null\],"ietf-netconf:delete-config":\[null\],"ietf-netconf:lock":\[null\],"ietf-netconf:unlock":\[null\],"ietf-netconf:get":\[null\],"ietf-netconf:close-session":\[null\],"ietf-netconf:kill-session":\[null\],"ietf-netconf:commit":\[null\],"ietf-netconf:discard-changes":\[null\],"ietf-netconf:validate":\[null\],"clixon-rfc5277:create-subscription":\[null\]}}'
|
||||
|
||||
new "restconf get restconf/operations. RFC8040 3.3.2 (xml)"
|
||||
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/operations)
|
||||
expect='<operations><client-rpc xmlns="urn:example:clixon"/><empty xmlns="urn:example:clixon"/><optional xmlns="urn:example:clixon"/><example xmlns="urn:example:clixon"/><debug xmlns="http://clicon.org/lib"/><ping xmlns="http://clicon.org/lib"/><get-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><copy-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><delete-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><lock xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><unlock xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><get xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><close-session xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><kill-session xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><commit xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><discard-changes xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><validate xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"/></operations>'
|
||||
expect='<operations><client-rpc xmlns="urn:example:clixon"/><empty xmlns="urn:example:clixon"/><optional xmlns="urn:example:clixon"/><example xmlns="urn:example:clixon"/><debug xmlns="http://clicon.org/lib"/><ping xmlns="http://clicon.org/lib"/><datastats xmlns="http://clicon.org/lib"/><get-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><copy-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><delete-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><lock xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><unlock xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><get xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><close-session xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><kill-session xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><commit xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><discard-changes xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><validate xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"/></operations>'
|
||||
match=`echo $ret | grep --null -Eo "$expect"`
|
||||
if [ -z "$match" ]; then
|
||||
err "$expect" "$ret"
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+xml' http://loca
|
|||
# This just catches the header and the jukebox module, the RFC has foo and bar which
|
||||
# seems wrong to recreate
|
||||
new "B.1.2. Retrieve the Server Module Information"
|
||||
expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-yang-library:modules-state)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+json" '{"ietf-yang-library:modules-state":{"module-set-id":"0","module":\[{"name":"clixon-lib","revision":"2019-08-13","namespace":"http://clicon.org/lib","conformance-type":"implement"},{"name":"clixon-rfc5277","revision":"2008-07-01","namespace":"urn:ietf:params:xml:ns:netmod:notification","conformance-type":"implement"},{"name":"example-events","revision":"","namespace":"urn:example:events","conformance-type":"implement"},{"name":"example-jukebox","revision":"2016-08-15","namespace":"http://example.com/ns/example-jukebox","conformance-type":"implement"},{"name":"example-system","revision":"","namespace":"http://example.com/ns/example-system","conformance-type":"implement"},{"name":"ietf-inet-types","revision":"2013-07-15","namespace":"urn:ietf:params:xml:ns:yang:ietf-inet-types","conformance-type":"implement"},'
|
||||
expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-yang-library:modules-state)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+json" '{"ietf-yang-library:modules-state":{"module-set-id":"0","module":\[{"name":"clixon-lib","revision":"2020-04-23","namespace":"http://clicon.org/lib","conformance-type":"implement"},{"name":"clixon-rfc5277","revision":"2008-07-01","namespace":"urn:ietf:params:xml:ns:netmod:notification","conformance-type":"implement"},{"name":"example-events","revision":"","namespace":"urn:example:events","conformance-type":"implement"},{"name":"example-jukebox","revision":"2016-08-15","namespace":"http://example.com/ns/example-jukebox","conformance-type":"implement"},{"name":"example-system","revision":"","namespace":"http://example.com/ns/example-system","conformance-type":"implement"},{"name":"ietf-inet-types","revision":"2013-07-15","namespace":"urn:ietf:params:xml:ns:yang:ietf-inet-types","conformance-type":"implement"},'
|
||||
|
||||
new "B.1.3. Retrieve the Server Capability Information"
|
||||
expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/capabilities)" 0 "HTTP/1.1 200 OK" "Content-Type: application/yang-data+xml" 'Cache-Control: no-cache' '<capabilities xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring"><capability>urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=explicit</capability><capability>urn:ietf:params:restconf:capability:depth</capability>
|
||||
|
|
|
|||
|
|
@ -205,16 +205,16 @@ expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<
|
|||
|
||||
# Now same with restconf
|
||||
new "restconf edit main"
|
||||
expectpart "$(curl -s -i -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data -d '{"main:main":{"x":"foo","ext":"foo"}}')" 0 'HTTP/1.1 201 Created'
|
||||
expectpart "$(curl -si -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data -d '{"main:main":{"x":"foo","ext":"foo"}}')" 0 'HTTP/1.1 201 Created'
|
||||
|
||||
new "restconf edit sub1"
|
||||
expectpart "$(curl -s -i -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data -d '{"main:sub1":{"x":"foo","ext1":"foo"}}')" 0 'HTTP/1.1 201 Created'
|
||||
expectpart "$(curl -si -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data -d '{"main:sub1":{"x":"foo","ext1":"foo"}}')" 0 'HTTP/1.1 201 Created'
|
||||
|
||||
new "restconf edit sub2"
|
||||
expectpart "$(curl -s -i -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data -d '{"main:sub2":{"x":"foo","ext2":"foo"}}')" 0 'HTTP/1.1 201 Created'
|
||||
expectpart "$(curl -si -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data -d '{"main:sub2":{"x":"foo","ext2":"foo"}}')" 0 'HTTP/1.1 201 Created'
|
||||
|
||||
new "restconf check main/sub1/sub2 contents"
|
||||
expectpart "$(curl -s -X GET http://localhost/restconf/data)" 0 '{"data":{"main:main":{"ext":"foo","x":"foo"},"main:sub1":{"ext1":"foo","x":"foo"},"main:sub2":{"ext2":"foo","x":"foo"}}}'
|
||||
expectpart "$(curl -si -X GET http://localhost/restconf/data?content=config)" 0 'HTTP/1.1 200 OK' '{"data":{"main:main":{"ext":"foo","x":"foo"},"main:sub1":{"ext1":"foo","x":"foo"},"main:sub2":{"ext2":"foo","x":"foo"}}}'
|
||||
|
||||
new "Kill restconf daemon"
|
||||
stop_restconf
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
#
|
||||
# ***** 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(Netgate)#
|
||||
# This file is part of CLIXON
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
@ -42,7 +43,7 @@ datarootdir = @datarootdir@
|
|||
YANG_INSTALLDIR = @YANG_INSTALLDIR@
|
||||
|
||||
YANGSPECS = clixon-config@2020-02-22.yang
|
||||
YANGSPECS += clixon-lib@2019-08-13.yang
|
||||
YANGSPECS += clixon-lib@2020-04-23.yang
|
||||
YANGSPECS += clixon-rfc5277@2008-07-01.yang
|
||||
YANGSPECS += clixon-xml-changelog@2019-03-21.yang
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ module clixon-config {
|
|||
|
||||
***** END LICENSE BLOCK *****";
|
||||
|
||||
/* Deleted: clixon-stats state for clixon XML and memory statistics. (moved to clixon-lib)
|
||||
*/
|
||||
revision 2020-02-22 {
|
||||
description
|
||||
"Added: search index extension,
|
||||
|
|
@ -718,33 +720,4 @@ module clixon-config {
|
|||
|
||||
}
|
||||
}
|
||||
container clixon-stats{
|
||||
config false;
|
||||
description "Clixon backend statistics.";
|
||||
container global{
|
||||
description "Clixon global statistics";
|
||||
leaf xmlnr{
|
||||
description "Number of XML objects. That is number of residing xml/json objects
|
||||
in the internal 'cxobj' representation.";
|
||||
type uint64;
|
||||
}
|
||||
}
|
||||
list datastore{
|
||||
description "Datastore statistics";
|
||||
key "name";
|
||||
leaf name{
|
||||
description "name of datastore (eg running).";
|
||||
type string;
|
||||
}
|
||||
leaf nr{
|
||||
description "Number of XML objects. That is number of residing xml/json objects
|
||||
in the internal 'cxobj' representation.";
|
||||
type uint64;
|
||||
}
|
||||
leaf size{
|
||||
description "Size in bytes of internal datastore cache of datastore tree.";
|
||||
type uint64;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
102
yang/clixon/clixon-lib@2020-04-23.yang
Normal file
102
yang/clixon/clixon-lib@2020-04-23.yang
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
module clixon-lib {
|
||||
yang-version 1.1;
|
||||
namespace "http://clicon.org/lib";
|
||||
prefix cl;
|
||||
|
||||
organization
|
||||
"Clicon / Clixon";
|
||||
|
||||
contact
|
||||
"Olof Hagsand <olof@hagsand.se>";
|
||||
|
||||
description
|
||||
"Clixon Netconf extensions for communication between clients and backend.
|
||||
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
Copyright (C) 2009-2019 Olof Hagsand
|
||||
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)
|
||||
|
||||
This file is part of CLIXON
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the \"License\");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an \"AS IS\" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the \"GPL\"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****";
|
||||
|
||||
revision 2020-04-23 {
|
||||
description
|
||||
"Added: clixon-stats state for clixon XML and memory statistics.";
|
||||
}
|
||||
revision 2019-08-13 {
|
||||
description
|
||||
"No changes (reverted change)";
|
||||
}
|
||||
revision 2019-06-05 {
|
||||
description
|
||||
"ping rpc added for liveness";
|
||||
}
|
||||
revision 2019-01-02 {
|
||||
description
|
||||
"Released in Clixon 3.9";
|
||||
}
|
||||
rpc debug {
|
||||
description "Set debug level of backend.";
|
||||
input {
|
||||
leaf level {
|
||||
type uint32;
|
||||
}
|
||||
}
|
||||
}
|
||||
rpc ping {
|
||||
description "Check aliveness of backend daemon.";
|
||||
}
|
||||
rpc datastats {
|
||||
description "Clixon XML statistics.";
|
||||
output {
|
||||
container global{
|
||||
description "Clixon global statistics";
|
||||
leaf xmlnr{
|
||||
description "Number of XML objects. That is number of residing xml/json objects
|
||||
in the internal 'cxobj' representation.";
|
||||
type uint64;
|
||||
}
|
||||
}
|
||||
list datastore{
|
||||
description "Datastore statistics";
|
||||
key "name";
|
||||
leaf name{
|
||||
description "name of datastore (eg running).";
|
||||
type string;
|
||||
}
|
||||
leaf nr{
|
||||
description "Number of XML objects. That is number of residing xml/json objects
|
||||
in the internal 'cxobj' representation.";
|
||||
type uint64;
|
||||
}
|
||||
leaf size{
|
||||
description "Size in bytes of internal datastore cache of datastore tree.";
|
||||
type uint64;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue