diff --git a/.gitignore b/.gitignore
index 1b2cb35f..e9ed0e3e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,7 +8,6 @@ Makefile
apps/Makefile
apps/*/Makefile
docker/Makefile
-docker/*/Makefile
etc/Makefile
example/Makefile
lib/Makefile
@@ -37,8 +36,6 @@ docker/netconf/Dockerfile
etc/clixonrc
-example/*.conf
-
include/clixon_config.h
lib/src/build.c
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4d7ce430..c9a1e5ec 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,15 +5,18 @@
### Major New features
### API changes on existing features (you may need to change your code)
-* Limited support of RFC 7895 YANG Module Library to list modules:
- * That is, limited support of: ietf-yang-library.yang
- * For example: `exampleietf-restconf-monitoring2017-01-26...`
-* Notification event stream enhancements
- * Yang 1.1 notification support
- * Event stream discovery support according to RFC 5277 Sec 3.2.5.1
- * That is, support of ietf-restconf-monitoring.yang (mimics schema in 3.2.5.1)
- * Event stream discovery support according to RFC 8040 (restconf)
- * That is, support of ietf-netconf-notification.yang
+* YANG Module Library support
+ * According to RFC 7895 and implemented by ietf-yang-library.yang
+ * Supported: module, name, revision, namespace
+ * Not supported: notification, deviation, module-set-id, etc.
+ * Enabled by default, disable by resetting CLICON_MODULE_LIBRARY_RFC7895
+* Yang 1.1 notification support (RFC 7950: Sec 7.16)
+* Event stream discovery support according to RFC 5277 for netconf
+ * Implemented by ietf-netconf-notification.yang
+ * Disabled by default. Enable by setting CLICON_STREAM_DISCOVERY_RFC5277
+* Event stream discovery support according to RFC 8040 for restconf
+ * Implemented by ietf-restconf-monitoring.yang (mimics schema in 3.2.5.1)
+ * Disabled by default. Enable by setting CLICON_STREAM_DISCOVERY_RFC8040.
* clixon_restconf and clixon_netconf now take -D as command-line option instead of just -D
* This aligns to clixon_cli and clixon_backend
* Application command option -S to clixon_netconf is obsolete. Use `clixon_netconf -l s` instead.
diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c
index bede591f..189e2dc5 100644
--- a/apps/backend/backend_client.c
+++ b/apps/backend/backend_client.c
@@ -122,21 +122,6 @@ client_subscription_delete(struct client_entry *ce,
return 0;
}
-#ifdef notused /* xxx */
-static struct client_subscription *
-client_subscription_find(struct client_entry *ce,
- char *stream)
-{
- struct client_subscription *su = NULL;
-
- for (su = ce->ce_subscription; su; su = su->su_next)
- if (strcmp(su->su_stream, stream) == 0)
- break;
-
- return su;
-}
-#endif
-
static struct client_entry *
ce_find_bypid(struct client_entry *ce_list,
int pid)
@@ -261,146 +246,138 @@ from_client_get_config(clicon_handle h,
return retval;
}
-/*! Get streams state according to RFC 5277 and RCC 8040
+/*! Get streams state according to RFC 8040 or RFC5277 common function
+ * @param[in] h Clicon handle
+ * @param[in] yspec Yang spec
+ * @param[in] xpath Xpath selection, not used but may be to filter early
+ * @param[in] module Name of yang module
+ * @param[in] top Top symbol, ie netconf or restconf-state
+ * @param[in,out] xret Existing XML tree, merge x into this
* @retval -1 Error (fatal)
* @retval 0 OK
* @retval 1 Statedata callback failed
*/
static int
-client_get_streams(clicon_handle h,
- char *xpath,
- cxobj **xtop)
+client_get_streams(clicon_handle h,
+ yang_spec *yspec,
+ char *xpath,
+ char *module,
+ char *top,
+ cxobj **xret)
{
int retval = -1;
+ yang_stmt *ystream = NULL; /* yang stream module */
+ yang_stmt *yns = NULL; /* yang namespace */
cxobj *x = NULL;
- cxobj *xc;
- char *reason = NULL;
- yang_spec *yspec;
- cbuf *cb;
+ cbuf *cb = NULL;
- if ((yspec = clicon_dbspec_yang(h)) == NULL){
- clicon_err(OE_YANG, ENOENT, "No yang spec");
+ if ((ystream = yang_find((yang_node*)yspec, Y_MODULE, module)) == NULL){
+ clicon_err(OE_YANG, 0, "%s yang module not found", module);
goto done;
}
- if (*xtop==NULL){
- clicon_err(OE_CFG, ENOENT, "XML tree expected");
+ if ((yns = yang_find((yang_node*)ystream, Y_NAMESPACE, NULL)) == NULL){
+ clicon_err(OE_YANG, 0, "%s yang namespace not found", module);
goto done;
}
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, 0, "clicon buffer");
goto done;
}
- cprintf(cb,"");
- if (stream_get_xml(h, cb) < 0)
+ cprintf(cb,"<%s xmlns=\"%s\">", top, yns->ys_argument);
+ if (stream_get_xml(h, strcmp(top,"restconf-state")==0, cb) < 0)
goto done;
- cprintf(cb,"");
- cprintf(cb,"");
- if (stream_get_xml(h, cb) < 0)
- goto done;
- cprintf(cb,"");
+ cprintf(cb,"%s>", top);
- /* XXX. yspec */
- if (xml_parse_string(cbuf_get(cb), NULL, &x) < 0){
- if (netconf_operation_failed_xml(xtop, "protocol", clicon_err_reason)< 0)
+ if (xml_parse_string(cbuf_get(cb), yspec, &x) < 0){
+ if (netconf_operation_failed_xml(xret, "protocol", clicon_err_reason)< 0)
goto done;
retval = 1;
goto done;
}
- if (xml_merge(*xtop, x, yspec, &reason) < 0)
- goto done;
- if (reason){
- while ((xc = xml_child_i(*xtop, 0)) != NULL)
- xml_purge(xc);
- if (netconf_operation_failed_xml(xtop, "rpc", reason)< 0)
- goto done;
- retval = 1;
- goto done;
- }
- retval = 0;
+ retval = netconf_trymerge(x, yspec, xret);
done:
if (cb)
cbuf_free(cb);
- if (reason)
- free(reason);
if (x)
xml_free(x);
return retval;
}
/*! Get modules state according to RFC 7895
+ * @param[in] h Clicon handle
+ * @param[in] yspec Yang spec
+ * @param[in] xpath Xpath selection, not used but may be to filter early
+ * @param[in] module Name of yang module
+ * @param[in,out] xret Existing XML tree, merge x into this
* @retval -1 Error (fatal)
* @retval 0 OK
* @retval 1 Statedata callback failed
*/
static int
-client_get_modules(clicon_handle h,
- char *xpath,
- cxobj **xtop)
+client_get_modules(clicon_handle h,
+ yang_spec *yspec,
+ char *xpath,
+ char *module,
+ cxobj **xret)
{
int retval = -1;
cxobj *x = NULL;
- cxobj *xc;
- char *reason = NULL;
- yang_spec *yspec;
- cbuf *cb;
- yang_stmt *ymod = NULL;
- yang_stmt *yrev;
+ cbuf *cb = NULL;
+ yang_stmt *ylib = NULL; /* ietf-yang-library */
+ yang_stmt *yns = NULL; /* namespace */
+ yang_stmt *ymod; /* generic module */
+ yang_stmt *ys;
- if ((yspec = clicon_dbspec_yang(h)) == NULL){
- clicon_err(OE_YANG, ENOENT, "No yang spec");
+ if ((ylib = yang_find((yang_node*)yspec, Y_MODULE, module)) == NULL){
+ clicon_err(OE_YANG, 0, "%s not found", module);
goto done;
}
- if (*xtop==NULL){
- clicon_err(OE_CFG, ENOENT, "XML tree expected");
+ if ((yns = yang_find((yang_node*)ylib, Y_NAMESPACE, NULL)) == NULL){
+ clicon_err(OE_YANG, 0, "%s yang namespace not found", module);
goto done;
}
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, 0, "clicon buffer");
goto done;
}
- cprintf(cb,"");
+ cprintf(cb,"", yns->ys_argument);
cprintf(cb,"1"); /* NYI */
+ ymod = NULL;
while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) {
cprintf(cb,"");
cprintf(cb,"%s", ymod->ys_argument);
- if ((yrev = yang_find((yang_node*)ymod, Y_REVISION, NULL)) != NULL)
- cprintf(cb,"%s", yrev->ys_argument);
+ if ((ys = yang_find((yang_node*)ymod, Y_REVISION, NULL)) != NULL)
+ cprintf(cb,"%s", ys->ys_argument);
else
cprintf(cb,"");
+ if ((ys = yang_find((yang_node*)ymod, Y_NAMESPACE, NULL)) != NULL)
+ cprintf(cb,"%s", ys->ys_argument);
+ else
+ cprintf(cb,"");
cprintf(cb,"");
}
cprintf(cb,"");
- /* XXX. yspec */
- if (xml_parse_string(cbuf_get(cb), NULL, &x) < 0){
- if (netconf_operation_failed_xml(xtop, "protocol", clicon_err_reason)< 0)
+ if (xml_parse_string(cbuf_get(cb), yspec, &x) < 0){
+ if (netconf_operation_failed_xml(xret, "protocol", clicon_err_reason)< 0)
goto done;
retval = 1;
goto done;
}
- if (xml_merge(*xtop, x, yspec, &reason) < 0)
- goto done;
- if (reason){
- while ((xc = xml_child_i(*xtop, 0)) != NULL)
- xml_purge(xc);
- if (netconf_operation_failed_xml(xtop, "rpc", reason)< 0)
- goto done;
- retval = 1;
- goto done;
- }
- retval = 0;
+ retval = netconf_trymerge(x, yspec, xret);
done:
if (cb)
cbuf_free(cb);
- if (reason)
- free(reason);
if (x)
xml_free(x);
return retval;
}
/*! Get system state-data, including streams and plugins
+ * @param[in] h Clicon handle
+ * @param[in] xpath Xpath selection, not used but may be to filter early
+ * @param[in,out] xret Existing XML tree, merge x into this
* @retval -1 Error (fatal)
* @retval 0 OK
* @retval 1 Statedata callback failed
@@ -410,18 +387,27 @@ client_statedata(clicon_handle h,
char *xpath,
cxobj **xret)
{
- int retval = -1;
- cxobj **xvec = NULL;
- size_t xlen;
- int i;
-
- if ((retval = client_get_streams(h, xpath, xret)) != 0)
- goto done;
- if ((retval = client_get_modules(h, xpath, xret)) != 0)
- goto done;
- if ((retval = clixon_plugin_statedata(h, xpath, xret)) != 0)
+ int retval = -1;
+ cxobj **xvec = NULL;
+ size_t xlen;
+ int i;
+ yang_spec *yspec;
+
+ if ((yspec = clicon_dbspec_yang(h)) == NULL){
+ clicon_err(OE_YANG, ENOENT, "No yang spec");
+ goto done;
+ }
+ if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") &&
+ (retval = client_get_streams(h, yspec, xpath, "ietf-netconf-notification", "netconf", xret)) != 0)
+ goto done;
+ if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
+ (retval = client_get_streams(h, yspec, xpath, "ietf-restconf-monitoring", "restconf-state", xret)) != 0)
+ goto done;
+ if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895") &&
+ (retval = client_get_modules(h, yspec, xpath, "ietf-yang-library", xret)) != 0)
+ goto done;
+ if ((retval = clixon_plugin_statedata(h, yspec, xpath, xret)) != 0)
goto done;
-#if 1
/* Code complex to filter out anything that is outside of xpath */
if (xpath_vec(*xret, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done;
@@ -441,7 +427,6 @@ client_statedata(clicon_handle h,
/* reset flag */
if (xml_apply(*xret, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0)
goto done;
-#endif
retval = 0;
done:
if (xvec)
diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c
index 0873fc1c..6640dce3 100644
--- a/apps/backend/backend_main.c
+++ b/apps/backend/backend_main.c
@@ -773,12 +773,16 @@ main(int argc,
/* Read and parse application yang specification */
if (yang_spec_main(h) == NULL)
goto done;
- if (yang_spec_append(h, CLIXON_DATADIR, "ietf-restconf-monitoring", NULL)< 0)
- goto done;
- if (yang_spec_append(h, CLIXON_DATADIR, "ietf-netconf-notification", NULL)< 0)
- goto done;
- if (yang_spec_append(h, CLIXON_DATADIR, "ietf-yang-library", NULL)< 0)
- goto done;
+ /* Add system modules */
+ if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
+ yang_spec_append(h, CLIXON_DATADIR, "ietf-restconf-monitoring", NULL)< 0)
+ goto done;
+ if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") &&
+ yang_spec_append(h, CLIXON_DATADIR, "ietf-netconf-notification", NULL)< 0)
+ goto done;
+ if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895") &&
+ yang_spec_append(h, CLIXON_DATADIR, "ietf-yang-library", NULL)< 0)
+ goto done;
/* Set options: database dir and yangspec (could be hidden in connect?)*/
if (xmldb_setopt(h, "dbdir", clicon_xmldb_dir(h)) < 0)
goto done;
diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c
index 255b0f1d..e8ce2972 100644
--- a/apps/backend/backend_plugin.c
+++ b/apps/backend/backend_plugin.c
@@ -112,6 +112,7 @@ clixon_plugin_reset(clicon_handle h,
* This is internal system call, plugin is invoked (does not call) this function
* Backend plugins can register
* @param[in] h clicon handle
+ * @param[in] yspec Yang spec
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in,out] xtop State XML tree is merged with existing tree.
* @retval -1 Error
@@ -120,26 +121,17 @@ clixon_plugin_reset(clicon_handle h,
* @note xtop can be replaced
*/
int
-clixon_plugin_statedata(clicon_handle h,
- char *xpath,
- cxobj **xtop)
+clixon_plugin_statedata(clicon_handle h,
+ yang_spec *yspec,
+ char *xpath,
+ cxobj **xret)
{
- int retval = -1;
- cxobj *x = NULL;
- yang_spec *yspec;
- cxobj *xc;
+ int retval = -1;
+ int ret;
+ cxobj *x = NULL;
clixon_plugin *cp = NULL;
plgstatedata_t *fn; /* Plugin statedata fn */
- char *reason = NULL;
- if ((yspec = clicon_dbspec_yang(h)) == NULL){
- clicon_err(OE_YANG, ENOENT, "No yang spec");
- goto done;
- }
- if (*xtop==NULL){
- clicon_err(OE_CFG, ENOENT, "XML tree expected");
- goto done;
- }
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if ((fn = cp->cp_api.ca_statedata) == NULL)
continue;
@@ -149,27 +141,17 @@ clixon_plugin_statedata(clicon_handle h,
retval = 1;
goto done; /* Dont quit here on user callbacks */
}
- if (xml_merge(*xtop, x, yspec, &reason) < 0)
+ if ((ret = netconf_trymerge(x, yspec, xret)) != 0){
+ retval = ret;
goto done;
- if (reason){
- while ((xc = xml_child_i(*xtop, 0)) != NULL)
- xml_purge(xc);
- clicon_log(LOG_NOTICE, "%s: Plugin '%s' state callback failed",
- __FUNCTION__, cp->cp_name);
- if (netconf_operation_failed_xml(xtop, "rpc", reason)< 0)
- goto done;
- goto ok;
}
if (x){
xml_free(x);
x = NULL;
}
}
- ok:
retval = 0;
done:
- if (reason)
- free(reason);
if (x)
xml_free(x);
return retval;
diff --git a/apps/backend/backend_plugin.h b/apps/backend/backend_plugin.h
index 3dff37b2..a2736b19 100644
--- a/apps/backend/backend_plugin.h
+++ b/apps/backend/backend_plugin.h
@@ -71,7 +71,7 @@ int backend_plugin_initiate(clicon_handle h);
int clixon_plugin_reset(clicon_handle h, char *db);
-int clixon_plugin_statedata(clicon_handle h, char *xpath, cxobj **xtop);
+int clixon_plugin_statedata(clicon_handle h, yang_spec *yspec, char *xpath, cxobj **xtop);
transaction_data_t * transaction_new(void);
int transaction_free(transaction_data_t *);
diff --git a/apps/restconf/Makefile.in b/apps/restconf/Makefile.in
index 89aa84e0..32366f89 100644
--- a/apps/restconf/Makefile.in
+++ b/apps/restconf/Makefile.in
@@ -75,6 +75,7 @@ APPL = clixon_restconf
# Not accessible from plugin
APPSRC = restconf_main.c
APPSRC += restconf_methods.c
+APPSRC += restconf_stream.c
APPOBJ = $(APPSRC:.c=.o)
# Accessible from plugin
diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c
index be343612..9f1ac618 100644
--- a/apps/restconf/restconf_main.c
+++ b/apps/restconf/restconf_main.c
@@ -73,11 +73,12 @@
/* clicon */
#include
-#include /* Need to be after clixon_xml-h due to attribute format */
+#include /* Need to be after clixon_xml.h due to attribute format */
/* restconf */
#include "restconf_lib.h"
#include "restconf_methods.h"
+#include "restconf_stream.h"
/* Command line options to be passed to getopt(3) */
#define RESTCONF_OPTS "hD:f:l:p:y:a:u:"
@@ -90,6 +91,7 @@
#define RESTCONF_API "restconf"
#define RESTCONF_API_ROOT "/restconf"
+#define RESTCONF_STREAM_ROOT "/stream"
#define RESTCONF_LOGFILE "/www-data/clixon_restconf.log"
@@ -622,12 +624,16 @@ main(int argc,
if (yang_spec_main(h) == NULL)
goto done;
/* Add system modules */
- if (yang_spec_append(h, CLIXON_DATADIR, "ietf-restconf-monitoring", NULL)< 0)
- goto done;
- if (yang_spec_append(h, CLIXON_DATADIR, "ietf-netconf-notification", NULL)< 0)
- goto done;
- if (yang_spec_append(h, CLIXON_DATADIR, "ietf-yang-library", NULL)< 0)
- goto done;
+ if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
+ yang_spec_append(h, CLIXON_DATADIR, "ietf-restconf-monitoring", NULL)< 0)
+ goto done;
+ if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") &&
+ yang_spec_append(h, CLIXON_DATADIR, "ietf-netconf-notification", NULL)< 0)
+ goto done;
+ if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895") &&
+ yang_spec_append(h, CLIXON_DATADIR, "ietf-yang-library", NULL)< 0)
+ goto done;
+
/* Call start function in all plugins before we go interactive
Pass all args after the standard options to plugin_start
*/
@@ -660,9 +666,12 @@ main(int argc,
}
clicon_debug(1, "------------");
if ((path = FCGX_GetParam("REQUEST_URI", r->envp)) != NULL){
- clicon_debug(1, "path:%s", path);
+ clicon_debug(1, "path: %s", path);
if (strncmp(path, RESTCONF_API_ROOT, strlen(RESTCONF_API_ROOT)) == 0)
api_restconf(h, r); /* This is the function */
+ else if (strncmp(path, RESTCONF_STREAM_ROOT, strlen(RESTCONF_STREAM_ROOT)) == 0) {
+ api_stream(h, r);
+ }
else if (strncmp(path, RESTCONF_WELL_KNOWN, strlen(RESTCONF_WELL_KNOWN)) == 0) {
api_well_known(h, r); /* */
}
diff --git a/apps/restconf/restconf_stream.c b/apps/restconf/restconf_stream.c
new file mode 100644
index 00000000..5a99c702
--- /dev/null
+++ b/apps/restconf/restconf_stream.c
@@ -0,0 +1,85 @@
+/*
+ *
+ ***** BEGIN LICENSE BLOCK *****
+
+ Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
+
+ 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 *****
+
+ Restconf event stream implementation.
+ See RFC 8040 RESTCONF Protocol
+ Sections 3.8, 6, 9.3
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "clixon_config.h" /* generated by config & autoconf */
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+/* cligen */
+#include
+
+/* clicon */
+#include
+
+#include /* Need to be after clixon_xml-h due to attribute format */
+
+/* restconf */
+#include "restconf_lib.h"
+#include "restconf_stream.h"
+
+/*! Process a FastCGI request
+ * @param[in] r Fastcgi request handle
+ */
+int
+api_stream(clicon_handle h,
+ FCGX_Request *r)
+{
+ int retval = -1;
+
+ clicon_debug(1, "%s", __FUNCTION__);
+ retval = 0;
+ // done:
+ clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
+ return retval;
+}
diff --git a/apps/restconf/restconf_stream.h b/apps/restconf/restconf_stream.h
new file mode 100644
index 00000000..7fd5ac4a
--- /dev/null
+++ b/apps/restconf/restconf_stream.h
@@ -0,0 +1,44 @@
+/*
+ *
+ ***** BEGIN LICENSE BLOCK *****
+
+ Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
+
+ 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 *****
+
+ */
+
+#ifndef _RESTCONF_STREAM_H_
+#define _RESTCONF_STREAM_H_
+
+/*
+ * Prototypes
+ */
+int api_stream(clicon_handle h, FCGX_Request *r);
+
+#endif /* _RESTCONF_STREAM_H_ */
diff --git a/datastore/text/clixon_xmldb_text.c b/datastore/text/clixon_xmldb_text.c
index 7b7d52d8..894cf7c7 100644
--- a/datastore/text/clixon_xmldb_text.c
+++ b/datastore/text/clixon_xmldb_text.c
@@ -174,7 +174,6 @@ text_connect(void)
xh = (xmldb_handle)th;
done:
return xh;
-
}
/*! Disconnect from to a datastore plugin and deallocate handle
@@ -191,6 +190,7 @@ text_disconnect(xmldb_handle xh)
size_t klen;
int i;
+ clicon_debug(1, "%s", __FUNCTION__);
if (th){
if (th->th_dbdir)
free(th->th_dbdir);
diff --git a/lib/clixon/clixon_netconf_lib.h b/lib/clixon/clixon_netconf_lib.h
index f65bc9dc..063345e3 100644
--- a/lib/clixon/clixon_netconf_lib.h
+++ b/lib/clixon/clixon_netconf_lib.h
@@ -62,5 +62,6 @@ int netconf_operation_failed(cbuf *cb, char *type, char *message);
int netconf_operation_failed_xml(cxobj **xret, char *type, char *message);
int netconf_malformed_message(cbuf *cb, char *message);
int netconf_malformed_message_xml(cxobj **xret, char *message);
+int netconf_trymerge(cxobj *x, yang_spec *yspec, cxobj **xret);
#endif /* _CLIXON_NETCONF_LIB_H */
diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c
index a7cf2f9e..d59e88c9 100644
--- a/lib/src/clixon_netconf_lib.c
+++ b/lib/src/clixon_netconf_lib.c
@@ -60,6 +60,8 @@
#include "clixon_yang.h"
#include "clixon_log.h"
#include "clixon_xml.h"
+#include "clixon_options.h"
+#include "clixon_xml_map.h"
#include "clixon_netconf_lib.h"
/*! Create Netconf in-use error XML tree according to RFC 6241 Appendix A
@@ -934,3 +936,37 @@ netconf_malformed_message_xml(cxobj **xret,
done:
return retval;
}
+
+/*! Help function: merge - check yang - if error make netconf errmsg
+ * @param[in] x XML tree
+ * @param[in] yspec Yang spec
+ * @param[in,out] xret Existing XML tree, merge x into this
+ * @retval -1 Error (fatal)
+ * @retval 0 OK
+ * @retval 1 Statedata callback failed
+ */
+int
+netconf_trymerge(cxobj *x,
+ yang_spec *yspec,
+ cxobj **xret)
+{
+ int retval = -1;
+ char *reason = NULL;
+ cxobj *xc;
+
+ if (xml_merge(*xret, x, yspec, &reason) < 0)
+ goto done;
+ if (reason){
+ while ((xc = xml_child_i(*xret, 0)) != NULL)
+ xml_purge(xc);
+ if (netconf_operation_failed_xml(xret, "rpc", reason)< 0)
+ goto done;
+ retval = 1;
+ goto done;
+ }
+ retval = 0;
+ done:
+ if (reason)
+ free(reason);
+ return retval;
+}
diff --git a/lib/src/clixon_xml_db.c b/lib/src/clixon_xml_db.c
index e29c7c30..4dfe4f96 100644
--- a/lib/src/clixon_xml_db.c
+++ b/lib/src/clixon_xml_db.c
@@ -230,6 +230,7 @@ xmldb_disconnect(clicon_handle h)
xmldb_handle xh;
struct xmldb_api *xa;
+ clicon_debug(1, "%s", __FUNCTION__);
if ((xa = clicon_xmldb_api_get(h)) == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
goto done;
diff --git a/test/test_event.sh b/test/test_event.sh
index 789dd793..de7c0689 100755
--- a/test/test_event.sh
+++ b/test/test_event.sh
@@ -22,6 +22,9 @@ cat < $cfg
/usr/local/lib/$APPNAME/clispec
/usr/local/lib/$APPNAME/cli
$APPNAME
+ true
+ true
+ true
EOF
@@ -83,30 +86,37 @@ sleep 1
# get the stream list using netconf
new "netconf event stream discovery RFC5277 Sec 3.2.5"
-expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' 'NETCONFdefault NETCONF event streamfalseCLICONClicon logsfalse]]>]]>'
+expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' 'CLICONClicon logsfalseNETCONFdefault NETCONF event streamfalse]]>]]>'
new "netconf event stream discovery RFC8040 Sec 6.2"
-expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' 'NETCONFdefault NETCONF event streamfalseCLICONClicon logsfalse]]>]]>'
+expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' 'CLICONClicon logsfalsexmlhttps://example.com/stream/CLICONNETCONFdefault NETCONF event streamfalsexmlhttps://example.com/stream/NETCONF]]>]]>'
new "restconf event stream discovery RFC8040 Sec 6.2"
-expectfn "curl -s -X GET http://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/streams" 0 '{"streams": {"stream": \[{"name": "CLICON","description": "Clicon logs","replay-support": false},{ "name": "NETCONF","description": "default NETCONF event stream","replay-support": false}\]}}'
+expectfn "curl -s -X GET http://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/streams" 0 '{"streams": {"stream": \[{"name": "CLICON","description": "Clicon logs","replay-support": false,"access": \[{"encoding": "xml","location": "https://example.com/stream/CLICON"}\]},{ "name": "NETCONF","description": "default NETCONF event stream","replay-support": false,"access": \[{"encoding": "xml","location": "https://example.com/stream/NETCONF"}\]}\]}'
-#new "netconf subscription"
+new "restconf subscribe RFC8040 Sec 6.3, get location"
+expectfn "curl -s -X GET http://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/streams/stream=NETCONF/access=xml/location" 0 '{"location": "https://example.com/stream/NETCONF"}'
+
+new "restconf monitor event stream RFC8040 Sec 6.3"
+#expectfn "curl -s -X GET http://localhost/stream/NETCONF" 0 ''
+
+#new "netconf subscription" NOTYET
#expectwait "$clixon_netconf -qf $cfg -y $fyang" "ROUTING]]>]]>" "^]]>]]>Routing notification]]>]]>$" 30
new "Kill restconf daemon"
sudo pkill -u www-data clixon_restconf
new "Kill backend"
-# Check if still alive
-pid=`pgrep clixon_backend`
-if [ -z "$pid" ]; then
- err "backend already dead"
-fi
# kill backend
sudo clixon_backend -zf $cfg
if [ $? -ne 0 ]; then
err "kill backend"
fi
+# Check if still alive
+pid=`pgrep clixon_backend`
+if [ -n "$pid" ]; then
+ sudo kill $pid
+fi
+
rm -rf $dir
diff --git a/test/test_restconf.sh b/test/test_restconf.sh
index c82948ac..3e10acd6 100755
--- a/test/test_restconf.sh
+++ b/test/test_restconf.sh
@@ -25,6 +25,7 @@ cat < $cfg
1
/usr/local/var/$APPNAME
/usr/local/lib/xmldb/text.so
+ true
EOF
@@ -136,7 +137,7 @@ if [ -z "$match" ]; then
fi
new "restconf schema resource, RFC 8040 sec 3.7 according to RFC 7895"
-expecteq "$(curl -s -H 'Accept: application/yang-data+json' -G http://localhost/restconf/data/ietf-yang-library:modules-state/module=ietf-routing,2014-10-26/)" '{"module": [{"name": "ietf-routing","revision": "2014-10-26"}]}
+expecteq "$(curl -s -H 'Accept: application/yang-data+json' -G http://localhost/restconf/data/ietf-yang-library:modules-state/module=ietf-routing,2014-10-26/)" '{"module": [{"name": "ietf-routing","revision": "2014-10-26","namespace": "urn:ietf:params:xml:ns:yang:ietf-routing"}]}
'
new "restconf options. RFC 8040 4.1"
diff --git a/test/test_yang.sh b/test/test_yang.sh
index 94f56dc1..b70dc527 100755
--- a/test/test_yang.sh
+++ b/test/test_yang.sh
@@ -21,6 +21,7 @@ cat < $cfg
1
/usr/local/var/$APPNAME
/usr/local/lib/xmldb/text.so
+ true
EOF
@@ -118,7 +119,7 @@ new "cli not defined extension"
#expectfn "$clixon_cli -1f $cfg -y $fyangerr show version" 0 "Yang error: Extension ex:not-defined not found"
new "netconf schema resource, RFC 7895"
-expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' 'ietf-yang-library2016-06-21'
+expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' 'ietf-yang-types2013-07-15urn:ietf:params:xml:ns:yang:ietf-yang-types'
new "netconf edit config"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "125one]]>]]>" "^]]>]]>$"
diff --git a/yang/clixon-config@2018-04-30.yang b/yang/clixon-config@2018-04-30.yang
index c629a3c7..f0f7ce68 100644
--- a/yang/clixon-config@2018-04-30.yang
+++ b/yang/clixon-config@2018-04-30.yang
@@ -38,9 +38,9 @@ module clixon-config {
***** END LICENSE BLOCK *****";
- revision 2018-02-12 {
+ revision 2018-09-30 {
description
- "Added pretty print for datastore";
+ "Aligned to Clixon 3.8.0";
}
typedef startup_mode{
description
@@ -349,5 +349,26 @@ module clixon-config {
type string;
description "RFC8341 NACM external configuration file";
}
+ leaf CLICON_MODULE_LIBRARY_RFC7895 {
+ type boolean;
+ default false;
+ description "Enable RFC 7895 YANG Module library support as state
+ data. Ifenabled, module info will appear when doing
+ netconf get or restconf GET";
+ }
+ leaf CLICON_STREAM_DISCOVERY_RFC5277 {
+ type boolean;
+ default false;
+ description "Enable event stream discovery as described in RFC 5277
+ sections 3.2. If enabled, available streams will appear
+ when doing netconf get or restconf GET";
+ }
+ leaf CLICON_STREAM_DISCOVERY_RFC8040 {
+ type boolean;
+ default false;
+ description "Enable event stream discovery as described in RFC 5277
+ sections 3.2. If enabled, available streams will appear
+ when doing netconf get or restconf GET";
+ }
}
}
diff --git a/yang/ietf-netconf-notification@2008-07-01.yang b/yang/ietf-netconf-notification@2008-07-01.yang
index 1e98e455..0b78ac3b 100644
--- a/yang/ietf-netconf-notification@2008-07-01.yang
+++ b/yang/ietf-netconf-notification@2008-07-01.yang
@@ -1,4 +1,4 @@
-module ietf-restconf-monitoring {
+module ietf-netconf-notification {
namespace "urn:ietf:params:xml:ns:netconf:notification:1:0";
prefix "rcmon";