* New clixon-lib@2020-12-30.yang revision
* Added callback to process-control RPC feature in clixon-lib.yang to manage processes
* Changed behavior of starting restconf internally using `CLICON_BACKEND_RESTCONF_PROCESS` monitoring changes in enable flag, not only the RPC.
* Changed: RPC process-control output parameter status to pid
This commit is contained in:
Olof hagsand 2021-01-01 17:26:49 +01:00
parent 7459925bd0
commit cf63d0f761
21 changed files with 741 additions and 280 deletions

View file

@ -39,11 +39,23 @@ Developers may need to change their code
Users may have to change how they access the system
* New clixon-lib@2020-12-30.yang revision
* Changed: RPC process-control output parameter status to pid
* New clixon-config@2020-12-30.yang revision
* Removed obsolete RESTCONF and SSL options
* Changed namespace of clixon-restconf@2020-10-30.yang from https://clicon.org/restconf ->http://clicon.org/restconf ->
* CLIspec dbxml API: Ability to specify deletion of _any_ vs _specific_ entry.
* In a cli_del() call, the cvv arg list either exactly matches the api-format-path in which case _any_ deletion is specified, otherwise, if there is an extra element in the cvv list, that is used for a specific delete.
### Minor changes
* Added callback to process-control RPC feature in clixon-lib.yang to manage processes
* WHen an RPC comes in, be able to look at configuration
* Changed behavior of starting restconf internally using `CLICON_BACKEND_RESTCONF_PROCESS` monitoring changes in enable flag, not only the RPC. The semantics is as follows:
* on RPC start, if enable is true, start the service, if false, error or ignore it
* on RPC stop, stop the service
* on backend start make the state as configured
* on enable change, make the state as configured
* Limited fuzz by AFL committed,
* see [fuzz/README.md](fuzz/README.md) for details

View file

@ -1,6 +1,6 @@
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)
Copyright (C) 2020-2021 Olof Hagsand and Rubicon Communications, LLC (Netgate)
CLIXON is dual license.

View file

@ -1580,23 +1580,18 @@ from_client_process_control(clicon_handle h,
cxobj *x;
char *name = NULL;
char *operation = NULL;
int status = 0;
uint32_t pid = 0;
clicon_debug(1, "%s", __FUNCTION__);
if ((x = xml_find_type(xe, NULL, "name", CX_ELMNT)) != NULL)
name = xml_body(x);
if ((x = xml_find_type(xe, NULL, "operation", CX_ELMNT)) != NULL)
operation = xml_body(x);
/* Make the actual process operation */
if (clixon_process_operation(h, name, operation, &status) < 0)
/* Make the actual process operation (with wrap function enabled) */
if (clixon_process_operation(h, name, operation, 1, &pid) < 0)
goto done;
if (strcmp(operation, "status") == 0)
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><status xmlns=\"%s\">%s</status></rpc-reply>",
NETCONF_BASE_NAMESPACE,
CLIXON_LIB_NS,
status?"true":"false");
else
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><ok/></rpc-reply>", NETCONF_BASE_NAMESPACE);
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><pid xmlns=\"%s\">%u</pid></rpc-reply>",
NETCONF_BASE_NAMESPACE, CLIXON_LIB_NS, pid);
retval = 0;
done:
return retval;
@ -1633,7 +1628,6 @@ from_client_hello(clicon_handle h,
return retval;
}
/*! An internal clicon message has arrived from a client. Receive and dispatch.
* @param[in] h Clicon handle
* @param[in] s Socket where message arrived. read from this.

View file

@ -60,6 +60,7 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#include <libgen.h>
#include <assert.h>
/* cligen */
#include <cligen/cligen.h>
@ -67,7 +68,7 @@
/* clicon */
#include <clixon/clixon.h>
#include "clixon_backend_handle.h"
#include "clixon_backend_transaction.h"
#include "backend_socket.h"
#include "backend_client.h"
#include "backend_plugin.h"
@ -178,50 +179,6 @@ backend_server_socket(clicon_handle h)
return ss;
}
/*! Enable process-control of restconf daemon, ie start/stop restconf
* @param[in] h Clicon handle
* @note Could also look in clixon-restconf and start process if enable is true, but that needs to
* be in start callback using a pseudo plugin.
*/
static int
backend_restconf_process_control(clicon_handle h)
{
int retval = -1;
char **argv = NULL;
int i;
int nr;
char dbgstr[8];
char wwwstr[64];
nr = 4;
if (clicon_debug_get() != 0)
nr += 2;
if ((argv = calloc(nr, sizeof(char *))) == NULL){
clicon_err(OE_UNIX, errno, "calloc");
goto done;
}
i = 0;
snprintf(wwwstr, sizeof(wwwstr)-1, "%s/clixon_restconf", clicon_option_str(h, "CLICON_WWWDIR"));
argv[i++] = wwwstr;
argv[i++] = "-f";
argv[i++] = clicon_option_str(h, "CLICON_CONFIGFILE");
if (clicon_debug_get() != 0){
argv[i++] = "-D";
snprintf(dbgstr, sizeof(dbgstr)-1, "%d", clicon_debug_get());
argv[i++] = dbgstr;
}
argv[i++] = NULL;
if (clixon_process_register(h, "restconf",
NULL /* XXX network namespace */,
argv, nr) < 0)
goto done;
if (argv != NULL)
free(argv);
retval = 0;
done:
return retval;
}
/*! Load external NACM file
*/
static int
@ -431,6 +388,140 @@ ret2status(int ret,
return retval;
}
/*---------------------------------------------------------------------
* Restconf process pseudo plugin
*/
#define RESTCONF_PROCESS "restconf"
/*! Process rpc callback function
* - if RPC op is start, if enable is true, start the service, if false, error or ignore it
* - if RPC op is stop, stop the service
* These rules give that if RPC op is start and enable is false -> change op to none
*/
int
restconf_rpc_wrapper(clicon_handle h,
process_entry_t *pe,
char **operation)
{
int retval = -1;
cxobj *xt = NULL;
clicon_debug(1, "%s", __FUNCTION__);
if (strcmp(*operation, "stop") == 0){
/* if RPC op is stop, stop the service */
}
else if (strcmp(*operation, "start") == 0){
/* RPC op is start & enable is true, then start the service,
& enable is false, error or ignore it */
if (xmldb_get(h, "running", NULL, "/restconf", &xt) < 0)
goto done;
if (xt != NULL &&
xpath_first(xt, NULL, "/restconf[enable='false']") != NULL) {
*operation = "none";
}
}
retval = 0;
done:
if (xt)
xml_free(xt);
return retval;
}
/*! Enable process-control of restconf daemon, ie start/stop restconf by registering restconf process
* @param[in] h Clicon handle
* @note Could also look in clixon-restconf and start process if enable is true, but that needs to
* be in start callback using a pseudo plugin.
*/
static int
restconf_pseudo_process_control(clicon_handle h)
{
int retval = -1;
char **argv = NULL;
int i;
int nr;
char dbgstr[8];
char wwwstr[64];
nr = 4;
if (clicon_debug_get() != 0)
nr += 2;
if ((argv = calloc(nr, sizeof(char *))) == NULL){
clicon_err(OE_UNIX, errno, "calloc");
goto done;
}
i = 0;
snprintf(wwwstr, sizeof(wwwstr)-1, "%s/clixon_restconf", clicon_option_str(h, "CLICON_WWWDIR"));
argv[i++] = wwwstr;
argv[i++] = "-f";
argv[i++] = clicon_option_str(h, "CLICON_CONFIGFILE");
if (clicon_debug_get() != 0){
argv[i++] = "-D";
snprintf(dbgstr, sizeof(dbgstr)-1, "%d", clicon_debug_get());
argv[i++] = dbgstr;
}
argv[i++] = NULL;
assert(i==nr);
if (clixon_process_register(h, RESTCONF_PROCESS,
NULL /* XXX network namespace */,
restconf_rpc_wrapper,
argv, nr) < 0)
goto done;
if (argv != NULL)
free(argv);
retval = 0;
done:
return retval;
}
/*! Restconf pseduo-plugin process commit
*/
static int
restconf_pseudo_process_commit(clicon_handle h,
transaction_data td)
{
int retval = -1;
cxobj *xtarget;
cxobj *cx;
int enabled = 0;
clicon_debug(1, "%s", __FUNCTION__);
xtarget = transaction_target(td);
if (xpath_first(xtarget, NULL, "/restconf[enable='true']") != NULL)
enabled++;
if ((cx = xpath_first(xtarget, NULL, "/restconf/enable")) != NULL &&
xml_flag(cx, XML_FLAG_CHANGE|XML_FLAG_ADD)){
if (clixon_process_operation(h, RESTCONF_PROCESS,
enabled?"start":"stop", 0, NULL) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
/*! Register start/stop restconf RPC and create pseudo-plugin to monitor enable flag
* @param[in] h Clixon handle
*/
static int
restconf_pseudo_process_reg(clicon_handle h,
yang_stmt *yspec)
{
int retval = -1;
clixon_plugin *cp = NULL;
if (clixon_pseudo_plugin(h, "restconf pseudo plugin", &cp) < 0)
goto done;
cp->cp_api.ca_trans_commit = restconf_pseudo_process_commit;
/* Register generic process-control of restconf daemon, ie start/stop restconf */
if (restconf_pseudo_process_control(h) < 0)
goto done;
retval = 0;
done:
return retval;
}
/*! usage
*/
static void
@ -789,12 +880,6 @@ main(int argc,
clicon_option_str(h, "CLICON_BACKEND_REGEXP")) < 0)
goto done;
/* Enable process-control of restconf daemon, ie start/stop restconf */
if (clicon_option_bool(h, "CLICON_BACKEND_RESTCONF_PROCESS")){
if (backend_restconf_process_control(h) < 0)
goto done;
}
/* Load Yang modules
* 1. Load a yang module as a specific absolute filename */
if ((str = clicon_yang_main_file(h)) != NULL)
@ -815,7 +900,7 @@ main(int argc,
/* Load yang module library, RFC7895 */
if (yang_modules_init(h) < 0)
goto done;
/* Add netconf yang spec, used by netconf client and as internal protocol
/* Add generic yang specs, used by netconf client and as internal protocol
*/
if (netconf_module_load(h) < 0)
goto done;
@ -834,6 +919,11 @@ main(int argc,
if (clicon_option_bool(h, "CLICON_XMLDB_MODSTATE") &&
yang_spec_parse_module(h, "ietf-yang-library", NULL, yspec)< 0)
goto done;
/* Check restconf start/stop from backend */
if (clicon_option_bool(h, "CLICON_BACKEND_RESTCONF_PROCESS")){
if (restconf_pseudo_process_reg(h, yspec) < 0)
goto done;
}
/* Here all modules are loaded
* Compute and set canonical namespace context
*/

View file

@ -1121,9 +1121,6 @@ restconf_config(clicon_handle h,
/* Add netconf yang spec, used as internal protocol */
if (netconf_module_load(h) < 0)
goto done;
/* Clixon restconf daemon config */
if (yang_spec_parse_module(h, "clixon-restconf", NULL, yspec)< 0)
goto done;
/* Add system modules */
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
@ -1171,7 +1168,7 @@ restconf_config(clicon_handle h,
clicon_session_id_set(h, id);
break;
}
if ((nsc = xml_nsctx_init(NULL, "https://clicon.org/restconf")) == NULL)
if ((nsc = xml_nsctx_init(NULL, CLIXON_RESTCONF_NS)) == NULL)
goto done;
if ((pw = getpwuid(getuid())) == NULL){
clicon_err(OE_UNIX, errno, "getpwuid");

View file

@ -52,6 +52,7 @@
*/
#define CLIXON_CONF_NS "http://clicon.org/config"
#define CLIXON_LIB_NS "http://clicon.org/lib"
#define CLIXON_RESTCONF_NS "http://clicon.org/restconf"
/*
* Types

View file

@ -38,14 +38,22 @@
#ifndef _CLIXON_PROC_H_
#define _CLIXON_PROC_H_
/*
* Types
*/
typedef struct process_entry_t process_entry_t;
/* Process RPC callback function */
typedef int (proc_cb_t)(clicon_handle h, process_entry_t *pe, char **operation);
/*
* Prototypes
*/
int clixon_proc_run(char **argv, void (outcb)(char *), int doerr);
int clixon_proc_background(char **argv, char *netns, pid_t *pid);
int clixon_proc_background(char **argv, const char *netns, pid_t *pid);
int clixon_proc_daemon(char **argv, pid_t *pid);
int clixon_process_register(clicon_handle h, const char *name, const char *netns, char **argv, int argc);
int clixon_process_register(clicon_handle h, const char *name, const char *netns, proc_cb_t *callback, char **argv, int argc);
int clixon_process_delete_all(clicon_handle h);
int clixon_process_operation(clicon_handle h, char *name, char *op, int *status);
int clixon_process_operation(clicon_handle h, const char *name, char *op, const int wrapit, uint32_t *pid);
#endif /* _CLIXON_PROC_H_ */

View file

@ -902,7 +902,7 @@ xmldb_get(clicon_handle h,
* @note Use of 1 for OK
* @code
* cxobj *xt;
* if (xmldb_get0(xh, "running", YB_MODULE, nsc, "/interface[name="eth"]", 0, &xt, NULL) < 0)
* if (xmldb_get0(h, "running", YB_MODULE, nsc, "/interface[name="eth"]", 0, &xt, NULL) < 0)
* err;
* ...
* xmldb_get0_clear(h, xt); # Clear tree from default values and flags
@ -910,6 +910,19 @@ xmldb_get(clicon_handle h,
* @endcode
* @see xml_nsctx_node to get a XML namespace context from XML tree
* @see xmldb_get for a copy version (old-style)
* @note An annoying issue is one with default values and xpath miss:
* Assume a yang spec:
* module m {
* container c {
* leaf x {
* default 0;
* And a db content:
* <c><x>1</x></c>
* With the following call:
* xmldb_get0(h, "running", NULL, NULL, "/c[x=0]", 1, &xt, NULL)
* which result in a miss (there is no c with x=0), but when the returned xt is printed
* (the existing tree is discarded), the default (empty) xml tree is:
* <c><x>0</x></c>
*/
int
xmldb_get0(clicon_handle h,

View file

@ -1356,7 +1356,7 @@ netconf_module_features(clicon_handle h)
return retval;
}
/*! Load ietf netconf yang module and set enabled features
/*! Load generic yang specs, ie ietf netconf yang module and set enabled features
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
@ -1379,6 +1379,9 @@ netconf_module_load(clicon_handle h)
if (clicon_option_bool(h, "CLICON_XML_CHANGELOG"))
if (yang_spec_parse_module(h, "clixon-xml-changelog", NULL, yspec)< 0)
goto done;
/* Load restconf yang. Note this is also a part of clixon-config */
if (yang_spec_parse_module(h, "clixon-restconf", NULL, yspec)< 0)
goto done;
retval = 0;
done:
return retval;

View file

@ -317,6 +317,12 @@ done:
* @param[out] cpp Clixon plugin structure (direct pointer)
* @retval 0 OK, with cpp set
* @retval -1 Error
* @code
* clixon_plugin *cp = NULL;
* if (clixon_pseudo_plugin(h, "pseudo plugin", &cp) < 0)
* err;
* cp->cp_api.ca_extension = my_ext_cb;
* @endcode
*/
int
clixon_pseudo_plugin(clicon_handle h,

View file

@ -76,6 +76,19 @@
#include "clixon_queue.h"
#include "clixon_proc.h"
/*
* Types
*/
/* Process entry list */
struct process_entry_t {
qelem_t pe_qelem; /* List header */
char *pe_name; /* Name of process used for internal use */
char *pe_netns; /* Network namespace */
char **pe_argv; /* argv with command as element 0 and NULL-terminated */
pid_t pe_pid; /* Running process id (state) or 0 if dead */
proc_cb_t *pe_callback; /* Wrapper function */
};
/*
* Child process ID
* XXX Really shouldn't be a global variable
@ -209,7 +222,7 @@ clixon_proc_run(char **argv,
*/
int
clixon_proc_background(char **argv,
char *netns,
const char *netns,
pid_t *pid0)
{
int retval = -1;
@ -273,7 +286,6 @@ clixon_proc_background(char **argv,
}
}
#endif /* HAVE_SETNS */
clicon_debug(1, "%s argv0:%s", __FUNCTION__, argv[0]);
if (execv(argv[0], argv) < 0) {
clicon_err(OE_UNIX, errno, "execv");
exit(1);
@ -289,7 +301,7 @@ clixon_proc_background(char **argv,
*pid0 = child;
retval = 0;
quit:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clicon_debug(1, "%s retval:%d child:%u", __FUNCTION__, retval, child);
return retval;
}
@ -373,13 +385,6 @@ clixon_proc_daemon(char **argv,
/*
* Types
*/
typedef struct {
qelem_t pe_qelem; /* List header */
char *pe_name; /* Name of process used for internal use */
char *pe_netns; /* Network namespace */
char **pe_argv; /* argv with command as element 0 and NULL-terminated */
pid_t pe_pid;
} process_entry_t;
/* List of process callback entries */
static process_entry_t *proc_entry_list = NULL;
@ -398,6 +403,7 @@ int
clixon_process_register(clicon_handle h,
const char *name,
const char *netns,
proc_cb_t *callback,
char **argv,
int argc)
{
@ -436,6 +442,7 @@ clixon_process_register(clicon_handle h,
clicon_err(OE_UNIX, errno, "strdup");
}
}
pe->pe_callback = callback;
ADDQ(pe, proc_entry_list);
retval = 0;
done:
@ -469,7 +476,7 @@ clixon_process_delete_all(clicon_handle h)
}
static int
proc_op_run(process_entry_t *pe,
proc_op_run(pid_t pid0,
int *runp)
{
int retval = -1;
@ -477,7 +484,7 @@ proc_op_run(process_entry_t *pe,
pid_t pid;
run = 0;
if ((pid = pe->pe_pid) != 0){ /* if 0 stopped */
if ((pid = pid0) != 0){ /* if 0 stopped */
/* Check if lives */
run = 1;
if ((kill(pid, 0)) < 0){
@ -497,42 +504,26 @@ proc_op_run(process_entry_t *pe,
return retval;
}
/*! Upgrade specific module identified by namespace, search matching callbacks
/*! Perform process operation
*
* @param[in] h clicon handle
* @param[in] name Name of process
* @param[in] op start, stop.
* @param[out] status true if process is running / false if not running on entry
* @retval -1 Error
* @retval 0 OK
* @see upgrade_callback_reg_fn which registers the callbacks
*/
int
clixon_process_operation(clicon_handle h,
char *name,
char *op,
int *status)
static int
clixon_process_operation_one(const char *op,
const char *netns,
char **argv,
pid_t *pidp)
{
int retval = -1;
process_entry_t *pe;
int run;
int run = 0;
clicon_debug(1, "%s name:%s op:%s", __FUNCTION__, name, op);
if (proc_entry_list == NULL)
goto ok;
pe = proc_entry_list;
do {
if (strcmp(pe->pe_name, name) == 0){
/* Check if running */
if (proc_op_run(pe, &run) < 0)
if (proc_op_run(*pidp, &run) < 0)
goto done;
if (status) /* Store as output parameter */
*status = run;
if (strcmp(op, "stop") == 0 ||
strcmp(op, "restart") == 0){
if (run)
pidfile_zapold(pe->pe_pid); /* Ensures its dead */
pe->pe_pid = 0; /* mark as dead */
pidfile_zapold(*pidp); /* Ensures its dead */
*pidp = 0; /* mark as dead */
run = 0;
}
if (strcmp(op, "start") == 0 ||
@ -541,13 +532,54 @@ clixon_process_operation(clicon_handle h,
; /* Already runs */
}
else{
if (clixon_proc_background(pe->pe_argv, pe->pe_netns, &pe->pe_pid) < 0)
if (clixon_proc_background(argv, netns, pidp) < 0)
goto done;
}
}
else if (strcmp(op, "status") == 0){
; /* status already set */
}
retval = 0;
done:
return retval;
}
/*! Find process operation entry given name and op and perform operation if found
*
* @param[in] h clicon handle
* @param[in] name Name of process
* @param[in] op start, stop.
* @param[in] wrapit If set, call potential callback, if false, dont call it
* @param[out] status true if process is running / false if not running on entry
* @retval -1 Error
* @retval 0 OK
* @see upgrade_callback_reg_fn which registers the callbacks
*/
int
clixon_process_operation(clicon_handle h,
const char *name,
char *op,
int wrapit,
uint32_t *pid)
{
int retval = -1;
process_entry_t *pe;
clicon_debug(1, "%s name:%s op:%s", __FUNCTION__, name, op);
if (proc_entry_list == NULL)
goto ok;
pe = proc_entry_list;
do {
if (strcmp(pe->pe_name, name) == 0){
/* Call wrapper function that eg changes op based on config */
if (wrapit && pe->pe_callback != NULL)
if (pe->pe_callback(h, pe, &op) < 0)
goto done;
if (clixon_process_operation_one(op, pe->pe_netns, pe->pe_argv, &pe->pe_pid) < 0)
goto done;
if (pid)
*pid = pe->pe_pid;
break; /* hit break here */
}
pe = NEXTQ(process_entry_t *, pe);

View file

@ -28,8 +28,8 @@ memonce(){
'backend')
valgrindtest=2 # This means backend valgrind test
: ${DEMWAIT:=10} # valgrind backend needs some time to get up
clixon_backend="/usr/bin/valgrind --num-callers=50 --leak-check=full --show-leak-kinds=all --suppressions=./valgrind-clixon.supp --track-fds=yes --trace-children=yes --log-file=$valgrindfile clixon_backend"
# trace-children=no for test_restconf_rpc.sh
clixon_backend="/usr/bin/valgrind --num-callers=50 --leak-check=full --show-leak-kinds=all --suppressions=./valgrind-clixon.supp --track-fds=yes --trace-children=no --log-file=$valgrindfile clixon_backend"
;;
'restconf')
valgrindtest=3 # This means backend valgrind test

View file

@ -74,7 +74,7 @@ state='{"clixon-example:state":{"op":\["41","42","43"\]}'
if $IPv6; then
# For backend config, create 4 sockets, all combinations IPv4/IPv6 + http/https
RESTCONFIG=$(cat <<EOF
<restconf xmlns="https://clicon.org/restconf">
<restconf xmlns="http://clicon.org/restconf">
<enable>true</enable>
<auth-type>password</auth-type>
<server-cert-path>$srvcert</server-cert-path>
@ -90,7 +90,7 @@ EOF
else
# For backend config, create 4 sockets, all combinations IPv4/IPv6 + http/https
RESTCONFIG=$(cat <<EOF
<restconf xmlns="https://clicon.org/restconf">
<restconf xmlns="http://clicon.org/restconf">
<enable>true</enable>
<auth-type>password</auth-type>
<server-cert-path>$srvcert</server-cert-path>
@ -142,10 +142,12 @@ testrun()
new "kill old restconf daemon"
stop_restconf_pre
new "start restconf daemon ZZZ"
new "start restconf daemon"
echo "cfg:$cfg"
start_restconf -f $cfg
fi
new "wait restconf"
wait_restconf
@ -186,7 +188,7 @@ testrun()
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $proto://$addr/restconf/data/ietf-yang-library:modules-state/module=ietf-interfaces,2018-02-20)" 0 'HTTP/1.1 200 OK' '{"ietf-yang-library:module":\[{"name":"ietf-interfaces","revision":"2018-02-20","namespace":"urn:ietf:params:xml:ns:yang:ietf-interfaces","conformance-type":"implement"}\]}'
new "restconf schema resource, mod-state top-level"
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $proto://$addr/restconf/data/ietf-yang-library:modules-state)" 0 'HTTP/1.1 200 OK' '{"ietf-yang-library:modules-state":{"module-set-id":"0","module":\[{"name":"clixon-example","revision":"2020-12-01","namespace":"urn:example:clixon","conformance-type":"implement"},{"name":"clixon-lib","revision":"2020-12-08","'
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $proto://$addr/restconf/data/ietf-yang-library:modules-state)" 0 'HTTP/1.1 200 OK' '{"ietf-yang-library:modules-state":{"module-set-id":"0","module":\[{"name":"clixon-example","revision":"2020-12-01","namespace":"urn:example:clixon","conformance-type":"implement"},{"name":"clixon-lib","revision":"2020-12-30","'
new "restconf options. RFC 8040 4.1"
expectpart "$(curl $CURLOPTS -X OPTIONS $proto://$addr/restconf/data)" 0 "HTTP/1.1 200 OK" "Allow: OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE"
@ -390,7 +392,7 @@ for proto in $protos; do
addrs="$addrs \[::1\]"
fi
for addr in $addrs; do
new "restconf test: proto:$proto addr:$addr config:$config"
new "restconf test: proto:$proto addr:$addr"
testrun $proto $addr
done
done

View file

@ -102,7 +102,7 @@ expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPR
# 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 $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://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-12-08","namespace":"http://clicon.org/lib","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"}'
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://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-12-30","namespace":"http://clicon.org/lib","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"}'
new "B.1.3. Retrieve the Server Capability Information"
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPROTO://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>

View file

@ -1,6 +1,12 @@
#!/usr/bin/env bash
# Restconf direct start/stop using RPC (as alternative to systemd or other)
# Also try ip netns
# Restconf direct start/stop using RPC and config enable flag (as alternative to systemd or other)
# According tot he following behaviour:
# - on RPC start, if enable is true, start the service, if false, error or ignore it
# - on RPC stop, stop the service
# - on backend start make the state as configured
# - on enable change, make the state as configured
# - No restconf config means enable: false (extra rule)
# Also work-in-progress network namespaces, ip netns
# Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
@ -8,17 +14,12 @@ s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
APPNAME=example
cfg=$dir/conf.xml
# Cant get it to work in the general case, single tests work fine
# More specifically, if mem.sh background netconf, netconf crashes which is valgrindtest 1
if [ $valgrindtest -eq 1 ]; then
echo "...skipped "
return 0 # skip
fi
startupdb=$dir/startup_db
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_FEATURE>ietf-netconf:startup</CLICON_FEATURE>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR>
@ -31,7 +32,7 @@ cat <<EOF > $cfg
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
<CLICON_MODULE_LIBRARY_RFC7895>true</CLICON_MODULE_LIBRARY_RFC7895>
<!-- start restconf from backend -->
<CLICON_BACKEND_RESTCONF_PROCESS>true</CLICON_BACKEND_RESTCONF_PROCESS>
@ -39,6 +40,72 @@ cat <<EOF > $cfg
</clixon-config>
EOF
# Subroutine send a process control RPC and tricks to echo process-id returned
# Args:
# 1: operation
# 2: expectret 0: means expect pi 0 as return, else something else
testrpc()
{
operation=$1
expectret=$2
new "send rpc $operation"
ret=$($clixon_netconf -qf $cfg<<EOF
<rpc $DEFAULTNS>
<process-control xmlns="http://clicon.org/lib">
<name>restconf</name>
<operation>$operation</operation>
</process-control>
</rpc>]]>]]>
EOF
)
expect1="<rpc-reply $DEFAULTNS><pid xmlns=\"http://clicon.org/lib\">"
match=$(echo "$ret" | grep --null -Go "$expect1")
if [ -z "$match" ]; then
err "$expect1" "$ret"
fi
expect2="</pid></rpc-reply>]]>]]>"
match=$(echo "$ret" | grep --null -Go "$expect2")
if [ -z "$match" ]; then
err "$expect2" "$ret"
fi
new "check rpc $operation get pid"
pid=$(echo "$ret" | awk -F'[<>]' '{print $5}')
if [ -z "$pid" ]; then
err "Running process" "$ret"
fi
new "check restconf retvalue"
if [ $expectret -eq 0 ]; then
if [ $pid -ne 0 ]; then
err "No process" "$pid"
fi
else
if [ $pid -eq 0 ]; then
err "Running process"
fi
fi
>&2 echo "pid:$pid" # debug
echo $pid # cant use return that only uses 0-255
}
new "ENABLE true"
# First basic operation with restconf enable is true
cat<<EOF > $startupdb
<config>
<restconf xmlns="http://clicon.org/restconf">
<enable>true</enable>
</restconf>
</config>
EOF
new "kill old restconf"
stop_restconf_pre
new "test params: -f $cfg"
if [ $BE -ne 0 ]; then
new "kill old backend"
@ -46,92 +113,82 @@ if [ $BE -ne 0 ]; then
if [ $? -ne 0 ]; then
err
fi
new "start backend -s init -f $cfg"
start_backend -s init -f $cfg
new "waiting"
new "start backend -s startup -f $cfg"
start_backend -s startup -f $cfg
new "wait backend"
wait_backend
fi
new "kill old restconf"
stop_restconf_pre
# Get pid of running process and check return xml
new "Get rpc status"
pid0=$(testrpc status 1)
if [ $? -ne 0 ]; then exit -1; fi
new "1)check no restconf"
ps=$(ps aux|grep "$WWWDIR/clixon_restconf" | grep -v grep)
if [ -n "$ps" ]; then
err "No restconf running" "$ps"
fi
new "check restconf process running using ps pid0:$pid0"
ps=$(ps -hp $pid0)
new "2)check status off"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>status</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><status xmlns=\"http://clicon.org/lib\">false</status></rpc-reply>]]>]]>"
new "start restconf"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>start</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>"
new "3)check restconf on"
if [ $valgrindtest -eq 0 ]; then # Cant get pgrep to work properly
sleep $DEMWAIT # Slows the tests down considerably, but needed in eg docker test
fi
ps=$(ps aux|grep "$WWWDIR/clixon_restconf -f $cfg" | grep -v grep)
if [ -z "$ps" ]; then
err "restconf running"
fi
new "4)check status on"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>status</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><status xmlns=\"http://clicon.org/lib\">true</status></rpc-reply>]]>]]>"
new "stop restconf"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>stop</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>"
new "start restconf again"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>start</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>"
new "5)check restconf on"
if [ $valgrindtest -eq 0 ]; then # Cant get pgrep to work properly
sleep $DEMWAIT # Slows the tests down considerably, but needed in eg docker test
fi
ps=$(ps aux|grep "$WWWDIR/clixon_restconf -f $cfg" | grep -v grep)
if [ -z "$ps" ]; then
err "A restconf running"
fi
new "stop restconf RPC"
pid1=$(testrpc stop 0)
if [ $? -ne 0 ]; then exit -1; fi
new "Get rpc status stopped"
pid2=$(testrpc status 0)
if [ $? -ne 0 ]; then exit -1; fi
new "Start rpc again"
pid3=$(testrpc start 1)
if [ $? -ne 0 ]; then exit -1; fi
new "check restconf process running using ps"
ps=$(ps -hp $pid3)
if [ -z "$ps" ]; then
err "A restconf running"
fi
if [ $pid0 -eq $pid3 ]; then
err "A different pid" "$pid3"
fi
new "kill restconf"
stop_restconf_pre
new "6)check no restconf"
ps=$(ps aux|grep "$WWWDIR/clixon_restconf" | grep -v grep)
if [ -n "$ps" ]; then
err "No restconf running" "$ps"
new "start restconf RPC"
pid4=$(testrpc start 1)
if [ $? -ne 0 ]; then exit -1; fi
new "check status RPC on"
pid5=$(testrpc status 1)
if [ $? -ne 0 ]; then exit -1; fi
new "restart restconf RPC"
pid6=$(testrpc restart 1)
if [ $? -ne 0 ]; then exit -1; fi
new "Get restconf status rpc"
pid7=$(testrpc status 1)
if [ $? -ne 0 ]; then exit -1; fi
if [ $pid5 -eq $pid7 ]; then
err "A different pid" "$pid7"
fi
new "restart restconf"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>restart</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>"
new "7)check status on"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>status</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><status xmlns=\"http://clicon.org/lib\">true</status></rpc-reply>]]>]]>"
if [ $valgrindtest -eq 0 ]; then # Cant get pgrep to work properly
sleep $DEMWAIT # Slows the tests down considerably, but needed in eg docker test
fi
pid0=$(pgrep clixon_restconf)
new "restart restconf"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>restart</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>"
new "8)check status on"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>status</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><status xmlns=\"http://clicon.org/lib\">true</status></rpc-reply>]]>]]>"
if [ $valgrindtest -eq 0 ]; then # Cant get pgrep to work properly
new "9)check new pid"
sleep $DEMWAIT # Slows the tests down considerably, but needed in eg docker test
pid1=$(pgrep clixon_restconf)
if [ -z "$pid0" -o -z "$pid1" ]; then
err "Pids expected" "pid0:$pid0 = pid1:$pid1"
fi
if [ $pid0 -eq $pid1 ]; then
err "Different pids" "pid0:$pid0 = pid1:$pid1"
fi
fi
#if [ $valgrindtest -eq 0 ]; then # Cant get pgrep to work properly
# new "check new pid"
# sleep $DEMWAIT # Slows the tests down considerably, but needed in eg docker test
# pid1=$(pgrep clixon_restconf)
# if [ -z "$pid0" -o -z "$pid1" ]; then
# err "Pids expected" "pid0:$pid0 = pid1:$pid1"
# fi
# if [ $pid0 -eq $pid1 ]; then#
# err "Different pids" "pid0:$pid0 = pid1:$pid1"
# fi
#fi
if [ $BE -ne 0 ]; then
new "Kill backend"
@ -142,19 +199,70 @@ if [ $BE -ne 0 ]; then
fi
# kill backend
stop_backend -f $cfg
# XXX Cant get this to work in docker/alpine
if false; then
new "10)check no restconf"
sleep $DEMWAIT
ps=$(ps aux|grep "$WWWDIR/clixon_restconf" | grep -v grep)
if [ -n "$ps" ]; then
err "No restconf running" "$ps"
fi
fi
fi
if false; then # Work in progress
# So far, no restconf config enable flag has been true. Now change enable flag.
new "ENABLE false"
# Second basic operation with restconf enable is false
cat<<EOF > $startupdb
<config>
<restconf xmlns="http://clicon.org/restconf">
<enable>false</enable>
</restconf>
</config>
EOF
new "kill old restconf"
stop_restconf_pre
new "test params: -f $cfg"
if [ $BE -ne 0 ]; then
new "kill old backend"
sudo clixon_backend -z -f $cfg
if [ $? -ne 0 ]; then
err
fi
new "start backend -s startup -f $cfg"
start_backend -s startup -f $cfg
new "waiting"
wait_backend
fi
new "check status RPC off"
pid=$(testrpc status 0)
if [ $? -ne 0 ]; then exit -1; fi
new "start restconf RPC"
pid=$(testrpc start 0)
if [ $? -ne 0 ]; then exit -1; fi
new "check status RPC off"
pid=$(testrpc status 0)
if [ $? -ne 0 ]; then exit -1; fi
new "Enable restconf"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><edit-config><default-operation>merge</default-operation><target><candidate/></target><config><restconf xmlns=\"http://clicon.org/restconf\"><enable>true</enable></restconf></config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
new "netconf commit"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
new "check status RPC on"
pid=$(testrpc status 1)
if [ $? -ne 0 ]; then exit -1; fi
new "Disable restconf"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><edit-config><default-operation>merge</default-operation><target><candidate/></target><config><restconf xmlns=\"http://clicon.org/restconf\"><enable>false</enable></restconf></config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
new "netconf commit"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
new "check status RPC off"
pid=$(testrpc status 0)
if [ $? -ne 0 ]; then exit -1; fi
if false; then # Work in progress - namespace
#-------------------------------
# Now in a separate network namespace
new "restconf rpc in network namespace"
@ -207,3 +315,4 @@ sudo ip netns delete $netns
fi # namespaces
rm -rf $dir

View file

@ -301,7 +301,7 @@ cat <<EOF > $dir/startup_db
</config>
EOF
MODSTATE1='<modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"><module-set-id>0</module-set-id><module><name>clixon-lib</name><revision>2020-12-08</revision><namespace>http://clicon.org/lib</namespace></module>'
MODSTATE1='<modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"><module-set-id>0</module-set-id><module><name>clixon-lib</name><revision>2020-12-30</revision><namespace>http://clicon.org/lib</namespace></module>'
MODSTATE2='<module><name>interfaces</name><revision>2018-02-20</revision><namespace>urn:example:interfaces</namespace></module>'

View file

@ -42,8 +42,8 @@ datarootdir = @datarootdir@
# See also OPT_YANG_INSTALLDIR for the standard yang files
YANG_INSTALLDIR = @YANG_INSTALLDIR@
YANGSPECS = clixon-config@2020-11-03.yang
YANGSPECS += clixon-lib@2020-12-08.yang
YANGSPECS = clixon-config@2020-12-30.yang
YANGSPECS += clixon-lib@2020-12-30.yang
YANGSPECS += clixon-rfc5277@2008-07-01.yang
YANGSPECS += clixon-xml-changelog@2019-03-21.yang
YANGSPECS += clixon-restconf@2020-10-30.yang

View file

@ -1 +1 @@
clixon-config@2020-10-01.yang
clixon-config@2020-12-30.yang

View file

@ -3,6 +3,9 @@ module clixon-config {
namespace "http://clicon.org/config";
prefix cc;
import clixon-restconf {
prefix clrc;
}
organization
"Clicon / Clixon";
@ -40,9 +43,33 @@ module clixon-config {
***** END LICENSE BLOCK *****";
revision 2020-12-30 {
description
"Removed obsolete options:
CLICON_RESTCONF_IPV4_ADDR
CLICON_RESTCONF_IPV6_ADDR
CLICON_RESTCONF_HTTP_PORT
CLICON_RESTCONF_HTTPS_PORT
CLICON_SSL_SERVER_CERT
CLICON_SSL_SERVER_KEY
CLICON_SSL_CA_CERT";
}
revision 2020-11-03 {
description
"Added CLICON_BACKEND_RESTCONF_PROCESS
Copied to clixon-restconf.yang and marked as obsolete:
CLICON_RESTCONF_IPV4_ADDR
CLICON_RESTCONF_IPV6_ADDR
CLICON_RESTCONF_HTTP_PORT
CLICON_RESTCONF_HTTPS_PORT
CLICON_SSL_SERVER_CERT
CLICON_SSL_SERVER_KEY
CLICON_SSL_CA_CERT
Removed obsolete option CLICON_TRANSACTION_MOD";
}
revision 2020-10-01 {
description
"Added: CLICON_CONFIGDIR";
"Added: CLICON_CONFIGDIR.";
}
revision 2020-08-17 {
description
@ -264,8 +291,22 @@ module clixon-config {
}
}
}
typedef socket_address_family {
description "Address family for internal socket";
type enumeration{
enum UNIX {
description "Unix domain socket";
}
enum IPv4 {
description "IPv4";
}
}
}
container clixon-config {
container restconf {
uses clrc:clixon-restconf;
}
leaf-list CLICON_FEATURE {
description
"Supported features as used by YANG feature/if-feature
@ -392,7 +433,8 @@ module clixon-config {
default "/www-data/fastcgi_restconf.sock";
description
"FastCGI unix socket. Should be specified in webserver
Eg in nginx: fastcgi_pass unix:/www-data/clicon_restconf.sock";
Eg in nginx: fastcgi_pass unix:/www-data/clicon_restconf.sock
Only if with-restconf=fcgi, NOT evhtp";
}
leaf CLICON_RESTCONF_PRETTY {
type boolean;
@ -407,58 +449,6 @@ module clixon-config {
Setting this value to false makes restconf return not pretty-printed
which may be desirable for performance or tests";
}
leaf CLICON_RESTCONF_IPV4_ADDR {
type string;
default "0.0.0.0";
description
"RESTCONF IPv4 socket binding address.
Applies to native http by config option --with-restconf=evhtp.";
}
leaf CLICON_RESTCONF_IPV6_ADDR {
type string;
default "::";
description
"RESTCONF IPv6 socket binding address.
Applies to native http by config option --with-restconf=evhtp.";
}
leaf CLICON_RESTCONF_HTTP_PORT {
type uint16;
default 80;
description
"RESTCONF socket binding port, non-ssl
In the restconf daemon, it can be overriden by -P <port>
Applies to native http only by config option --with-restconf=evhtp.";
}
leaf CLICON_RESTCONF_HTTPS_PORT {
type uint16;
default 443;
description
"RESTCONF socket binding port, ssl
In the restconf daemon, this is the port chosen if -s is given.
Note it can be overriden by -P <port>
Applies to native http by config option --with-restconf=evhtp.";
}
leaf CLICON_SSL_SERVER_CERT {
type string;
default "/etc/ssl/certs/clixon-server-crt.pem";
description
"SSL server cert for restconf https.
Applies to native http only by config option --with-restconf=evhtp.";
}
leaf CLICON_SSL_SERVER_KEY {
type string;
default "/etc/ssl/private/clixon-server-key.pem";
description
"SSL server private key for restconf https.
Applies to native http only by config option --with-restconf=evhtp.";
}
leaf CLICON_SSL_CA_CERT {
type string;
default "/etc/ssl/certs/clixon-ca_crt.pem";
description
"SSL CA cert for client authentication.
Applies to native http only by config option --with-restconf=evhtp.";
}
leaf CLICON_CLI_DIR {
type string;
description
@ -624,15 +614,15 @@ module clixon-config {
from a spec, such as in the autocli.";
}
leaf CLICON_SOCK_FAMILY {
type string;
default "UNIX";
type socket_address_family;
default UNIX;
description
"Address family for communicating with clixon_backend
(UNIX|IPv4). IPv6 not yet implemented.
"Address family for communicating with clixon_backend with one of:
Note IPv6 not implemented.
Note that UNIX socket makes credential check as follows:
(1) client needs rw access to the socket
(2) NACM credentials can be checked according to CLICON_NACM_CREDENTIALS
Warning: IPv4 and IPv6 sockets have no credential mechanism.
Warning: Only UNIX (not IPv4) sockets have credential mechanism.
";
}
leaf CLICON_SOCK {
@ -681,6 +671,20 @@ module clixon-config {
mandatory true;
description "Process-id file of backend daemon";
}
leaf CLICON_BACKEND_RESTCONF_PROCESS {
type boolean;
default false;
description
"If set, enable process-control of restconf daemon, ie start/stop restconf
daemon internally from backend daemon.
It uses clixon-restconf.yang for config and clixon-lib.yang for RPC
Process control of restconf daemon is as follows:
- on RPC start, if enable is true, start the service, if false, error or ignore it
- on RPC stop, stop the service
- on backend start make the state as configured
- on enable change, make the state as configured
Disable if you start the restconf daemon by other means.";
}
leaf CLICON_AUTOCOMMIT {
type int32;
default 0;

View file

@ -0,0 +1,183 @@
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-12-30 {
description
"Changed: RPC process-control output parameter status to pid";
}
revision 2020-12-08 {
description
"Added: autocli-op extension.
rpc process-control for process/daemon management
Released in clixon 4.9";
}
revision 2020-04-23 {
description
"Added: stats RPC for clixon XML and memory statistics.
Added: restart-plugin RPC for restarting individual plugins without restarting backend.";
}
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";
}
typedef service-operation {
type enumeration {
enum start {
description
"Start if not already running";
}
enum stop {
description
"Stop if running";
}
enum restart {
description
"Stop if running, then start";
}
enum status {
description
"Check status";
}
}
description
"Common operations that can be performed on a service";
}
extension autocli-op {
description
"Takes an argument an operation defing how to modify the clispec at
this point in the YANG tree for the automated generated CLI.
Note that this extension is only used in clixon_cli.
Operations is expected to be extended, but the following operations are defined:
- hide This command is active but not shown by ? or TAB";
argument cliop;
}
rpc debug {
description "Set debug level of backend.";
input {
leaf level {
type uint32;
}
}
}
rpc ping {
description "Check aliveness of backend daemon.";
}
rpc stats {
description "Clixon XML statistics.";
output {
container global{
description "Clixon global statistics";
leaf xmlnr{
description "Number of XML objects: 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;
}
}
}
}
rpc restart-plugin {
description "Restart specific backend plugins.";
input {
leaf-list plugin {
description "Name of plugin to restart";
type string;
}
}
}
rpc process-control {
description
"Control a specific process or daemon: start/stop, etc.
This is for direct managing of a porcess by the backend.
Alternatively one can manage a daemon via systemd, containerd, kubernetes, etc.";
input {
leaf name {
description "Name of process";
type string;
mandatory true;
}
leaf operation {
type service-operation;
mandatory true;
description
"One of the strings 'start', 'stop', 'restart', or 'status'.";
}
}
output {
leaf pid {
description "Process-id of running process if operation is start,
restart or status. 0 if not running.
This is for two reasons:
- to check process running for status
- get the actual pid for targeting the actual process";
type uint32;
}
}
}
}

View file

@ -1,6 +1,6 @@
module clixon-restconf {
yang-version 1.1;
namespace "https://clicon.org/restconf";
namespace "http://clicon.org/restconf";
prefix "clrc";
import ietf-inet-types {
@ -124,6 +124,13 @@ module clixon-restconf {
}
}
container restconf {
description
"This presence is strictly not necessary since the enable flag
in clixon-restconf is the flag bearing the actual semantics.
However, removing the presence leads to default config in all
clixon installations, even those which do not use backend-started restconf.
One could see this as mostly cosmetically annoying.
Alternative would be to make the inclusion of this yang conditional.";
presence "Enables RESTCONF";
uses clixon-restconf;
}