Stream debug and tests
This commit is contained in:
parent
e4adec413a
commit
fa9b9c7e2e
8 changed files with 295 additions and 121 deletions
|
|
@ -83,29 +83,32 @@ ce_find_bypid(struct client_entry *ce_list,
|
|||
|
||||
/*! Stream callback for netconf stream notification (RFC 5277)
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] op 0:event, 1:rm
|
||||
* @param[in] event Event as XML
|
||||
* @param[in] arg Extra argument provided in stream_ss_add
|
||||
* @see stream_ss_add
|
||||
*/
|
||||
static int
|
||||
ce_event_cb(clicon_handle h,
|
||||
int op,
|
||||
cxobj *event,
|
||||
void *arg)
|
||||
{
|
||||
struct client_entry *ce = (struct client_entry *)arg;
|
||||
|
||||
if (send_msg_notify_xml(ce->ce_s, event) < 0){
|
||||
if (errno == ECONNRESET || errno == EPIPE){
|
||||
clicon_log(LOG_WARNING, "client %d reset", ce->ce_nr);
|
||||
#if 0
|
||||
/* We should remove here but removal is not possible
|
||||
from a client since backend_client is not linked.
|
||||
Maybe we should add it to the plugin, but it feels
|
||||
"safe" that you cant remove a client.
|
||||
Instead, the client is (hopefully) removed elsewhere?
|
||||
*/
|
||||
clicon_debug(1, "%s op:%d", __FUNCTION__, op);
|
||||
switch (op){
|
||||
case 1:
|
||||
/* Risk of recursion here */
|
||||
if (ce->ce_s)
|
||||
backend_client_rm(h, ce);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
if (send_msg_notify_xml(ce->ce_s, event) < 0){
|
||||
if (errno == ECONNRESET || errno == EPIPE){
|
||||
clicon_log(LOG_WARNING, "client %d reset", ce->ce_nr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -126,6 +129,7 @@ backend_client_rm(clicon_handle h,
|
|||
struct client_entry *c0;
|
||||
struct client_entry **ce_prev;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
c0 = backend_client_list(h);
|
||||
ce_prev = &c0; /* this points to stack and is not real backpointer */
|
||||
for (c = *ce_prev; c; c = c->ce_next){
|
||||
|
|
@ -842,20 +846,19 @@ from_client_create_subscription(clicon_handle h,
|
|||
if ((x = xpath_first(xe, "//stream")) != NULL)
|
||||
stream = xml_find_value(x, "body");
|
||||
if ((x = xpath_first(xe, "//stopTime")) != NULL){
|
||||
stoptime = xml_find_value(x, "body");
|
||||
if (str2time(stoptime, &stop) < 0){
|
||||
if ((stoptime = xml_find_value(x, "body")) != NULL &&
|
||||
str2time(stoptime, &stop) < 0){
|
||||
if (netconf_bad_element(cbret, "application", "<bad-element>stopTime</bad-element>", "Expected timestamp") < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
if ((x = xpath_first(xe, "//startTime")) != NULL){
|
||||
starttime = xml_find_value(x, "body");
|
||||
if (str2time(starttime, &start) < 0){
|
||||
if ((starttime = xml_find_value(x, "body")) != NULL &&
|
||||
str2time(starttime, &start) < 0){
|
||||
if (netconf_bad_element(cbret, "application", "<bad-element>startTime</bad-element>", "Expected timestamp") < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if ((xfilter = xpath_first(xe, "//filter")) != NULL){
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ usage(clicon_handle h,
|
|||
char *confpid = clicon_backend_pidfile(h);
|
||||
char *group = clicon_sock_group(h);
|
||||
|
||||
fprintf(stderr, "usage:%s\n"
|
||||
fprintf(stderr, "usage:%s <options>*\n"
|
||||
"where options are\n"
|
||||
"\t-h\t\tHelp\n"
|
||||
"\t-D <level>\tDebug level\n"
|
||||
|
|
@ -860,6 +860,8 @@ main(int argc,
|
|||
if (debug)
|
||||
clicon_option_dump(h, debug);
|
||||
|
||||
if (stream_timer_setup(0, h) < 0)
|
||||
goto done;
|
||||
if (event_loop() < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
|
|
|
|||
|
|
@ -90,8 +90,6 @@ where
|
|||
|
||||
You access the streams using curl, but they differ slightly in behaviour as described in the following two sections.
|
||||
|
||||
### Native event streams
|
||||
|
||||
Add the following to extend the nginx configuration file with the following statements:
|
||||
```
|
||||
location /streams {
|
||||
|
|
@ -111,11 +109,13 @@ where the first command retrieves only new notifications, and the second receive
|
|||
|
||||
### Nginx Nchan streams
|
||||
|
||||
As an alternative, Nginx/Nchan can be used for streams.
|
||||
Nginx uses pub/sub channels and can be configured in a variety of
|
||||
ways. The following uses a simple variant with one generic subscription
|
||||
channel (streams) and one publication channel (pub).
|
||||
|
||||
Configure clixon with `--enable-publish` which enables curl code for publishing streams to nchan.
|
||||
Set configure option CLICON_STREAM_PUB to, for example, http://localhost/pub to enable pushing notifications to nchan.
|
||||
|
||||
Download and install nchan, see (https://nchan.io/#install).
|
||||
|
||||
|
|
|
|||
|
|
@ -108,14 +108,12 @@ restconf_stream_cb(int s,
|
|||
clicon_debug(1, "%s msg_rcv error", __FUNCTION__);
|
||||
goto done;
|
||||
}
|
||||
clicon_debug(1, "%s msg: %s", __FUNCTION__, reply->op_body);
|
||||
clicon_debug(1, "%s msg: %s", __FUNCTION__, reply?reply->op_body:"null");
|
||||
/* handle close from remote end: this will exit the client */
|
||||
if (eof){
|
||||
clicon_debug(1, "%s eof", __FUNCTION__);
|
||||
clicon_err(OE_PROTO, ESHUTDOWN, "Socket unexpected close");
|
||||
close(s);
|
||||
errno = ESHUTDOWN;
|
||||
event_unreg_fd(s, restconf_stream_cb);
|
||||
FCGX_FPrintF(r->out, "SHUTDOWN\r\n");
|
||||
FCGX_FPrintF(r->out, "\r\n");
|
||||
FCGX_FFlush(r->out);
|
||||
|
|
@ -148,7 +146,6 @@ restconf_stream_cb(int s,
|
|||
FCGX_FPrintF(r->out, "data: %s\r\n", cbuf_get(cb));
|
||||
FCGX_FPrintF(r->out, "\r\n");
|
||||
FCGX_FFlush(r->out);
|
||||
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -186,8 +183,8 @@ restconf_stream(clicon_handle h,
|
|||
cg_var *cv;
|
||||
char *vname;
|
||||
|
||||
*sp = -1;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
*sp = -1;
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
|
|
@ -228,6 +225,7 @@ restconf_stream(clicon_handle h,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval: %d", __FUNCTION__, retval);
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (cb)
|
||||
|
|
@ -239,6 +237,19 @@ restconf_stream(clicon_handle h,
|
|||
#include "restconf_lib.h"
|
||||
#include "restconf_stream.h"
|
||||
|
||||
static int
|
||||
stream_checkuplink(int s,
|
||||
void *arg)
|
||||
{
|
||||
FCGX_Request *r = (FCGX_Request *)arg;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (FCGX_GetError(r->out) != 0){ /* break loop */
|
||||
clicon_debug(1, "%s FCGX_GetError upstream", __FUNCTION__);
|
||||
clicon_exit_set();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
stream_timeout(int s,
|
||||
void *arg)
|
||||
|
|
@ -248,8 +259,10 @@ stream_timeout(int s,
|
|||
FCGX_Request *r = (FCGX_Request *)arg;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (FCGX_GetError(r->out) != 0) /* break loop */
|
||||
if (FCGX_GetError(r->out) != 0){ /* break loop */
|
||||
clicon_debug(1, "%s FCGX_GetError upstream", __FUNCTION__);
|
||||
clicon_exit_set();
|
||||
}
|
||||
else{
|
||||
gettimeofday(&t, NULL);
|
||||
t1.tv_sec = 1; t1.tv_usec = 0;
|
||||
|
|
@ -355,10 +368,16 @@ api_stream(clicon_handle h,
|
|||
(void*)r,
|
||||
"stream socket") < 0)
|
||||
goto done;
|
||||
if (event_reg_fd(r->listen_sock,
|
||||
stream_checkuplink,
|
||||
(void*)r,
|
||||
"stream socket") < 0)
|
||||
goto done;
|
||||
/* Poll upstream errors */
|
||||
stream_timeout(0, (void*)r);
|
||||
/* Start loop */
|
||||
event_loop();
|
||||
close(s);
|
||||
event_unreg_fd(s, restconf_stream_cb);
|
||||
clicon_exit_reset();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue