- Better restconf debug: when restconf debug flag set in datastore, ensure the process is started with -D set

- Fixed native http support for base container
- Changed test certs and restconf scripts to functions
This commit is contained in:
Olof hagsand 2021-04-08 22:40:41 +02:00
parent 244060fddc
commit 15d01c58d8
49 changed files with 539 additions and 103 deletions

View file

@ -61,6 +61,44 @@
#define RESTCONF_PROCESS "restconf"
/*! Set current debug flag when starting process using -D <dbg>
*
* process argv list including -D is set on start. But the debug flags may change and this is a way
* to set it dynamically, ie at the time the process is started, not when the backend is started.
* @param[in] h Clixon backend
* @param[in] dbg Debug string , eg "0" or "1"
*/
static int
restconf_pseudo_set_debug(clicon_handle h,
char *dbg)
{
int retval = -1;
char **argv;
int argc;
int i;
if (dbg == NULL)
goto ok;
if (clixon_process_argv_get(h, RESTCONF_PROCESS, &argv, &argc) < 0)
goto done;
for (i=0; i<argc; i++){
if (argv[i] == NULL)
break;
if (strcmp(argv[i], "-D") == 0 && argc > i+1 && argv[i+1]){
free(argv[i+1]);
if ((argv[i+1] = strdup(dbg)) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto done;
}
break;
}
}
ok:
retval = 0;
done:
return retval;
}
/*! 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
@ -73,6 +111,7 @@ restconf_rpc_wrapper(clicon_handle h,
{
int retval = -1;
cxobj *xt = NULL;
cxobj *xb;
clicon_debug(1, "%s", __FUNCTION__);
switch (*operation){
@ -88,6 +127,17 @@ restconf_rpc_wrapper(clicon_handle h,
xpath_first(xt, NULL, "/restconf[enable='false']") != NULL) {
*operation = PROC_OP_NONE;
}
else{
/* Get debug flag of restconf config, set the restconf start -D daemon flag according
* to it. The restconf daemon cannoit read its debug flag from config initially,
* but in this way it is set directly in its input args.
* Its a trick.
*/
if ((xb = xpath_first(xt, NULL, "/restconf/debug")) != NULL){
if (restconf_pseudo_set_debug(h, xml_body(xb)) < 0)
goto done;
}
}
break;
default:
break;
@ -103,6 +153,8 @@ restconf_rpc_wrapper(clicon_handle h,
* @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.
* - Debug flag inheritance only works if backend is started with debug. If debug is set later
* this is ignored.
*/
static int
restconf_pseudo_process_control(clicon_handle h)
@ -112,11 +164,8 @@ restconf_pseudo_process_control(clicon_handle h)
int i;
int nr;
cbuf *cb = NULL;
cbuf *cbdbg = NULL;
nr = 4;
if (clicon_debug_get() != 0)
nr += 2;
nr = 6;
if ((argv = calloc(nr, sizeof(char *))) == NULL){
clicon_err(OE_UNIX, errno, "calloc");
goto done;
@ -133,15 +182,8 @@ restconf_pseudo_process_control(clicon_handle h)
/* Add debug if backend has debug.
* There is also a debug flag in clixon-restconf.yang but it kicks in after it starts
*/
if (clicon_debug_get() != 0){
argv[i++] = "-D";
if ((cbdbg = cbuf_new()) == NULL){ /* Cant use cb since it would overwrite it */
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
cprintf(cbdbg, "%d", clicon_debug_get());
argv[i++] = cbuf_get(cbdbg);
}
argv[i++] = "-D";
argv[i++] = "0";
argv[i++] = NULL;
assert(i==nr);
if (clixon_process_register(h, RESTCONF_PROCESS,
@ -156,8 +198,6 @@ restconf_pseudo_process_control(clicon_handle h)
done:
if (cb)
cbuf_free(cb);
if (cbdbg)
cbuf_free(cbdbg);
return retval;
}
@ -200,14 +240,26 @@ restconf_pseudo_process_commit(clicon_handle h,
cxobj *xtarget;
cxobj *cx;
int enabled = 0;
cxobj *xb;
clicon_debug(1, "%s", __FUNCTION__);
xtarget = transaction_target(td);
if (xpath_first(xtarget, NULL, "/restconf[enable='true']") != NULL)
enabled++;
/* Get debug flag of restconf config, set the restconf start -D daemon flag according
* to it. The restconf daemon cannoit read its debug flag from config initially,
* but in this way it is set directly in its input args.
* Its a trick.
*/
if ((xb = xpath_first(xtarget, NULL, "/restconf/debug")) != NULL){
if (restconf_pseudo_set_debug(h, xml_body(xb)) < 0)
goto done;
}
/* Toggle start/stop if enable flag changed */
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?PROC_OP_START:PROC_OP_STOP, 0) < 0)
goto done;

View file

@ -181,8 +181,8 @@
/* See see listen(5) */
#define SOCKET_LISTEN_BACKLOG 8
/* Cert verify depth */
#define VERIFY_DEPTH 1
/* Cert verify depth: dont know what to set here? */
#define VERIFY_DEPTH 5
/* Forward */
static int restconf_connection(int s, void* arg);

View file

@ -47,14 +47,13 @@ RUN apk add --update libevent cmake libevent-dev
# clone libevhtp
WORKDIR /clixon
RUN git clone https://github.com/clicon/libevhtp.git
WORKDIR /clixon/libevhtp/build
RUN cmake -DEVHTP_DISABLE_REGEX=ON -DEVHTP_DISABLE_EVTHR=ON ..
RUN make
RUN make install
RUN git clone https://github.com/clicon/clixon-libevhtp.git
WORKDIR /clixon/clixon-libevhtp
RUN ./configure
# NOTE: Patch include queue.h to use the queue.h included in the evhtp release instead
RUN (cd /usr/local/include/evhtp/; sed -i -e 's/<sys\/queue.h>/<evhtp\/sys\/queue.h>/' evhtp.h)
RUN make
RUN mkdir /usr/local/include
RUN make install
RUN mkdir /clixon/build
WORKDIR /clixon
@ -77,7 +76,7 @@ COPY clixon .
RUN adduser -D -H www-data
# Configure, build and install clixon
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-wwwuser=www-data --enable-optyangs --with-restconf=evhtp
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-wwwuser=www-data --enable-optyangs --with-restconf=native
RUN make
RUN make install

View file

@ -4,7 +4,7 @@ This directory contains code for building and pushing the clixon base docker
container. By default it is pushed to docker hub clixon/clixon, but you can change
the IMAGE in Makefile.in and push it to another name.
This clixon base container uses libevhtp, native http.
This clixon base container uses native http.
The clixon docker base image can be used to build clixon
applications. It has the whole code for a clixon release which it

View file

@ -100,7 +100,7 @@ RUN install *.sh /clixon/build/bin/test
# Copy startscript
WORKDIR /clixon
COPY startsystem_evhtp.sh startsystem.sh
COPY startsystem_native.sh startsystem.sh
RUN install startsystem.sh /clixon/build/bin/
#

View file

@ -62,6 +62,7 @@ int clixon_proc_socket(char **argv, pid_t *pid, int *sock);
int clixon_proc_socket_close(pid_t pid, int sock);
int clixon_proc_background(char **argv, const char *netns, pid_t *pid);
proc_operation clixon_process_op_str2int(char *opstr);
int clixon_process_argv_get(clicon_handle h, const char *name, char ***argv, int *argc);
int clixon_process_register(clicon_handle h, const char *name, const char *descr, 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, const char *name, proc_operation op, const int wrapit);

View file

@ -34,6 +34,20 @@
***** END LICENSE BLOCK *****
* Processes daemons
* States of processes:
A description of process states.
It starts in a STOPPED state. On operation "start" or "restart" it gets a pid and goes into RUNNING:
STOPPED --(re)start--> RUNNING
In RUNNING several things can happen:
- It is killed externally: the process then gets a SIGCHLD which triggers a wait and it goes into STOPPED:
RUNNING --sigchld/wait--> STOPPED
It is stopped due to an rpc or by config commit removing the config. In that case the parent
process kills the process and enters into EXITING waiting for a SIGCHLD that triggers a wait:
RUNNING --stop--> EXITING --sigchld/wait--> STOPPED
It is restarted due to an rpc or config change (eg a server is added, a key modified, etc). Then
a new process is started which enters RUNNING, while the old process (the dying clone) enters EXITING:
STOPPED --restart--> RUNNING(newpid)
RUNNING --stop--> EXITING --sigchld/wait--> REMOVED (oldpid/clone)
*/
#ifdef HAVE_CONFIG_H
@ -313,7 +327,40 @@ clixon_process_op_str2int(char *opstr)
return clicon_str2int(proc_operation_map, opstr);
}
/*! Make a copy of process-entry struct */
/*! Access function process list argv list
*
* @param[in] h Clixon handle
* @param[in] name Name of process
* @param[out] argv Malloced argv list (Null terminated)
* @param[out] argc Length of argv
*
* @note Can be used to change in the argv list elements directly with care: Dont change list
* itself, but its elements can be freed and re-alloced.
*/
int
clixon_process_argv_get(clicon_handle h,
const char *name,
char ***argv,
int *argc)
{
process_entry_t *pe;
pe = _proc_entry_list;
do {
if (strcmp(pe->pe_name, name) == 0){
*argv = pe->pe_argv;
*argc = pe->pe_argc;
}
pe = NEXTQ(process_entry_t *, pe);
} while (pe != _proc_entry_list);
return 0;
}
/*! Make a copy of process-entry struct
*
* @param[in] pe0 Original process-entry
* @param[in] pnew New copy of pe0
*/
static int
clixon_process_register_dup(process_entry_t *pe0,
process_entry_t **pnew)
@ -604,10 +651,13 @@ clixon_process_status(clicon_handle h,
cprintf(cbret, "%s", pe->pe_argv[i]);
}
cprintf(cbret, "</command>");
cprintf(cbret, "<status xmlns=\"%s\">%u</status>", CLIXON_LIB_NS, pe->pe_status);
if (run && time2str(pe->pe_starttime, timestr, sizeof(timestr)) < 0)
goto done;
cprintf(cbret, "<starttime xmlns=\"%s\">%s</starttime>", CLIXON_LIB_NS, timestr);
if (run && timerisset(&pe->pe_starttime)){
if (time2str(pe->pe_starttime, timestr, sizeof(timestr)) < 0){
clicon_err(OE_UNIX, errno, "time2str");
goto done;
}
cprintf(cbret, "<starttime xmlns=\"%s\">%s</starttime>", CLIXON_LIB_NS, timestr);
}
cprintf(cbret, "</rpc-reply>");
break; /* hit break here */
}
@ -706,16 +756,26 @@ clixon_process_sched(int fd,
}
if (op == PROC_OP_STOP)
break;
if (clixon_proc_background(pe->pe_argv, pe->pe_netns, &newpid) < 0)
goto done;
gettimeofday(&pe->pe_starttime, NULL);
clicon_debug(1, "%s restart pid:%d -> %d", __FUNCTION__, pe->pe_pid, newpid);
/* Create a new pe */
if (clixon_process_register_dup(pe, &pe1) < 0)
goto done;
pe->pe_clone = 1; /* Delete when reaped */
pe1->pe_op = PROC_OP_NONE; /* Dont restart again */
pe1->pe_pid = newpid;
if (!run){
if (clixon_proc_background(pe->pe_argv, pe->pe_netns, &pe->pe_pid) < 0)
goto done;
gettimeofday(&pe->pe_starttime, NULL);
clicon_debug(1, "%s started pid:%d", __FUNCTION__, pe->pe_pid);
}
else {
/* This is the case where there is an existing process running.
* it was killed above but still runs and needs to be reaped */
if (clixon_proc_background(pe->pe_argv, pe->pe_netns, &newpid) < 0)
goto done;
gettimeofday(&pe->pe_starttime, NULL);
clicon_debug(1, "%s restart pid:%d -> %d", __FUNCTION__, pe->pe_pid, newpid);
/* Create a new pe */
if (clixon_process_register_dup(pe, &pe1) < 0)
goto done;
pe->pe_clone = 1; /* Delete when reaped */
pe1->pe_op = PROC_OP_NONE; /* Dont restart again */
pe1->pe_pid = newpid;
}
break;
case PROC_OP_START:
if (run) /* Already runs */

View file

@ -331,6 +331,7 @@ clicon_msg_send(int s,
struct clicon_msg *msg)
{
int retval = -1;
int e;
clicon_debug(2, "%s: send msg len=%d",
__FUNCTION__, ntohl(msg->op_len));
@ -338,9 +339,10 @@ clicon_msg_send(int s,
msg_dump(msg);
if (atomicio((ssize_t (*)(int, void *, size_t))write,
s, msg, ntohl(msg->op_len)) < 0){
clicon_err(OE_CFG, errno, "atomicio");
e = errno;
clicon_err(OE_CFG, e, "atomicio");
clicon_log(LOG_WARNING, "%s: write: %s len:%u msg:%s", __FUNCTION__,
strerror(errno), ntohs(msg->op_len), msg->op_body);
strerror(e), ntohs(msg->op_len), msg->op_body);
goto done;
}
retval = 0;

View file

@ -72,3 +72,8 @@ CLIXON_CONFIG_REV="2021-03-08"
CLIXON_RESTCONF_REV="2020-12-30"
CLIXON_EXAMPLE_REV="2020-12-01"
# Length of TSL RSA key
# Problem with small key such as 1024 not allowed in centos8 for example (why is this)
# Problem with long keys are they take time to generate, eg on ARM
CERTKEYLEN=2048

View file

@ -202,9 +202,9 @@ function restconf_config()
PRETTY=$2
if [ $RCPROTO = http ]; then
RESTCONFIG="<restconf><enable>true</enable><auth-type>$AUTH</auth-type><pretty>$PRETTY</pretty><debug>$DBG</debug><socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket></restconf>"
echo "<restconf><enable>true</enable><auth-type>$AUTH</auth-type><pretty>$PRETTY</pretty><debug>$DBG</debug><socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket></restconf>"
else
RESTCONFIG="<restconf><enable>true</enable><auth-type>$AUTH</auth-type><pretty>$PRETTY</pretty><server-cert-path>/etc/ssl/certs/clixon-server-crt.pem</server-cert-path><server-key-path>/etc/ssl/private/clixon-server-key.pem</server-key-path><server-ca-cert-path>/etc/ssl/certs/clixon-ca-crt.pem</server-ca-cert-path><debug>$DBG</debug><socket><namespace>default</namespace><address>0.0.0.0</address><port>443</port><ssl>true</ssl></socket></restconf>"
echo "<restconf><enable>true</enable><auth-type>$AUTH</auth-type><pretty>$PRETTY</pretty><server-cert-path>/etc/ssl/certs/clixon-server-crt.pem</server-cert-path><server-key-path>/etc/ssl/private/clixon-server-key.pem</server-key-path><server-ca-cert-path>/etc/ssl/certs/clixon-ca-crt.pem</server-ca-cert-path><debug>$DBG</debug><socket><namespace>default</namespace><address>0.0.0.0</address><port>443</port><ssl>true</ssl></socket></restconf>"
fi
}
@ -707,23 +707,19 @@ function expectmatch(){
fi
}
# Create server certs
# Create CA certs
# Output variables set as filenames on entry, set as cert/keys on exit:
# Vars:
# 1: cakey filename
# 2: cacert filename
# 3: srvkey filename
# 4: srvcert filename
function servercerts()
function cacerts()
{
if [ $# -ne 4 ]; then
echo "servercerts function: Expected: cakey cacert srvkey srvcert"
if [ $# -ne 2 ]; then
echo "cacerts function: Expected: cakey cacert"
exit 1
fi
cakey=$1
cacert=$2
srvkey=$3
srvcert=$4
tmpdir=$dir/tmpcertdir
@ -765,7 +761,32 @@ challengePassword = test
EOF
# Generate CA cert
openssl req -x509 -days 1 -config $tmpdir/ca.cnf -keyout $cakey -out $cacert
openssl req -x509 -days 1 -config $tmpdir/ca.cnf -keyout $cakey -out $cacert || err "Generate CA cert"
rm -rf $tmpdir
}
# Create server certs
# Output variables set as filenames on entry, set as cert/keys on exit:
# Vars:
# 1: cakey filename (input)
# 2: cacert filename (input)
# 3: srvkey filename (output)
# 4: srvcert filename (output)
function servercerts()
{
if [ $# -ne 4 ]; then
echo "servercerts function: Expected: cakey cacert srvkey srvcert"
exit 1
fi
cakey=$1
cacert=$2
srvkey=$3
srvcert=$4
tmpdir=$dir/tmpcertdir
test -d $tmpdir || mkdir $tmpdir
cat<<EOF > $tmpdir/srv.cnf
[req]
@ -783,13 +804,13 @@ subjectAltName = DNS:clicon.org
EOF
# Generate server key
openssl genrsa -out $srvkey ${CERTKEYLEN}
openssl genrsa -out $srvkey ${CERTKEYLEN} || err "Generate server key"
# Generate CSR (signing request)
openssl req -new -config $tmpdir/srv.cnf -key $srvkey -out $tmpdir/srv_csr.pem
openssl req -new -config $tmpdir/srv.cnf -key $srvkey -out $tmpdir/srv_csr.pem || err "Generate signing request"
# Sign server cert by CA
openssl x509 -req -extfile $tmpdir/srv.cnf -days 1 -passin "pass:password" -in $tmpdir/srv_csr.pem -CA $cacert -CAkey $cakey -CAcreateserial -out $srvcert
openssl x509 -req -extfile $tmpdir/srv.cnf -days 1 -passin "pass:password" -in $tmpdir/srv_csr.pem -CA $cacert -CAkey $cakey -CAcreateserial -out $srvcert || err "Sign server cert"
rm -rf $tmpdir
}

View file

@ -22,7 +22,7 @@ fyang=$dir/scaling.yang
fconfig=$dir/large.xml
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
cat <<EOF > $fyang
module scaling{

View file

@ -29,7 +29,4 @@ IPv6=true
# start
NGINXCHECK=true
# Lenght of TSL RSA key
# Problem with small key such as 1024 not allowed in centos8 for example (why is this)
# Problem with long keys are they take time to generate, eg on ARM
CERTKEYLEN=2048

View file

@ -25,7 +25,7 @@ if [ ! -d $pdir ]; then
fi
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -24,7 +24,7 @@ fyang=$dir/main.yang
fyang2=$dir/ietf-interfaces@2019-03-04.yang
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -15,7 +15,7 @@ cfg=$dir/choice.xml
fyang=$dir/type.yang
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -22,7 +22,7 @@ if [ ! -d $pdir ]; then
fi
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -30,7 +30,7 @@ cfg=$dir/conf_yang.xml
# Use yang in example
# Define default restconfig config: RESTCONFIG
restconf_config none true
RESTCONFIG=$(restconf_config none true)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -11,7 +11,7 @@ cfg=$dir/conf_yang.xml
fyang=$dir/example-my-crypto.yang
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -18,7 +18,7 @@ cfg=$dir/conf_yang.xml
fyang=$dir/nacm-example.yang
# Define default restconfig config: RESTCONFIG
restconf_config user false
RESTCONFIG=$(restconf_config user false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -46,7 +46,7 @@ fyang=$dir/nacm-example.yang
fyang2=$dir/itf.yang
# Define default restconfig config: RESTCONFIG
restconf_config user false
RESTCONFIG=$(restconf_config user false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -18,7 +18,7 @@ cfg=$dir/conf_yang.xml
fyang=$dir/nacm-example.yang
# Define default restconfig config: RESTCONFIG
restconf_config user false
RESTCONFIG=$(restconf_config user false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -26,7 +26,7 @@ fyang=$dir/nacm-example.yang
fyang2=$dir/nacm-example2.yang
# Define default restconfig config: RESTCONFIG
restconf_config user false
RESTCONFIG=$(restconf_config user false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -18,7 +18,7 @@ cfg=$dir/conf_yang.xml
fyang=$dir/nacm-example.yang
# Define default restconfig config: RESTCONFIG
restconf_config user false
RESTCONFIG=$(restconf_config user false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -14,7 +14,7 @@ fyang=$dir/nacm-example.yang
: ${format:=xml}
# Define default restconfig config: RESTCONFIG
restconf_config user false
RESTCONFIG=$(restconf_config user false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -16,7 +16,7 @@ fyang=$dir/nacm-example.yang
nacmfile=$dir/nacmfile
# Define default restconfig config: RESTCONFIG
restconf_config user false
RESTCONFIG=$(restconf_config user false)
# Note filter out example_backend_nacm.so in CLICON_BACKEND_REGEXP below
cat <<EOF > $cfg

View file

@ -19,7 +19,7 @@ cfg=$dir/conf_yang.xml
fyang=$dir/nacm-example.yang
# Define default restconfig config: RESTCONFIG
restconf_config user false
RESTCONFIG=$(restconf_config user false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -32,7 +32,7 @@ cfg=$dir/conf_yang.xml
fyang=$dir/nacm-example.yang
# Define default restconfig config: RESTCONFIG
restconf_config user false
RESTCONFIG=$(restconf_config user false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -35,7 +35,7 @@ cfg=$dir/conf_yang.xml
fyang=$dir/nacm-example.yang
# Define default restconfig config: RESTCONFIG
restconf_config user false
RESTCONFIG=$(restconf_config user false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -21,7 +21,7 @@ fyang=$dir/nacm-example.yang
# cred:none, exact, except
# Define default restconfig config: RESTCONFIG
restconf_config user false
RESTCONFIG=$(restconf_config user false)
cat <<EOF > $fyang
module nacm-example{

View file

@ -53,7 +53,7 @@ module scaling{
EOF
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -30,7 +30,7 @@ fconfig=$dir/large.xml
fstate=$dir/state.xml
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -30,7 +30,7 @@ fconfig=$dir/large.xml
fstate=$dir/state.xml
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -49,10 +49,11 @@ if [ "${WITH_RESTCONF}" = "native" ]; then
cacert=$certdir/ca_cert.pem
test -d $certdir || mkdir $certdir
# Create server certs and CA
cacerts $cakey $cacert
servercerts $cakey $cacert $srvkey $srvcert
else
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
fi
# This is a fixed 'state' implemented in routing_backend. It is assumed to be always there

View file

@ -13,7 +13,7 @@ cfg=$dir/conf.xml
fyang=$dir/restconf.yang
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
# <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
cat <<EOF > $cfg

View file

@ -193,7 +193,7 @@ function testrun()
# echo "expectmsg:$expectmsg"
# Change restconf configuration before start restconf daemon
restconf_config $auth false
RESTCONFIG=$(restconf_config $auth false)
# Start with common config, then append fcgi/native specific config
cat <<EOF > $cfg

View file

@ -31,7 +31,7 @@ fxml=$dir/initial.xml
fstate=$dir/state.xml
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
# <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
cat <<EOF > $cfg

View file

@ -24,7 +24,7 @@ cat <<EOF > $dir/example-system.yang
EOF
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
# <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
cat <<EOF > $cfg

View file

@ -11,7 +11,7 @@ cfg=$dir/conf.xml
fyang=$dir/list.yang
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
# <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
cat <<EOF > $cfg

View file

@ -44,6 +44,7 @@ cacert=$certdir/ca_cert.pem
test -d $certdir || mkdir $certdir
# Create server certs and CA
cacerts $cakey $cacert
servercerts $cakey $cacert $srvkey $srvcert
# XXX Note default port need to be 80 for wait_restconf to work

View file

@ -43,7 +43,7 @@ fyang=$dir/stream.yang
xml=$dir/xml.xml
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
# <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
cat <<EOF > $cfg

View file

@ -13,7 +13,7 @@ startupdb=$dir/startup_db
fjukebox=$dir/example-jukebox.yang
# Define default restconfig config: RESTCONFIG
restconf_config user false
RESTCONFIG=$(restconf_config user false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -20,7 +20,7 @@ cfg=$dir/conf.xml
startupdb=$dir/startup_db
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

262
test/test_restconf_rpc2.sh Executable file
View file

@ -0,0 +1,262 @@
#!/usr/bin/env bash
# Send restconf rpc:s when starting from backend
# Two specific usecases that have been problematic are tested here
# In comparison test_restconf_rpc.sh:
# - uses externally started restconf, here started by backend
# - generic tests, here specific
# The first usecases is:
# 1. Start a minimal restconf
# 2. Kill it externally (or it exits)
# 3. Start a server
# 4. Query status (Error message is returned)
# The second usecase is
# 1. Start server with bad address
# 2. Zombie process appears
# Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
APPNAME=example
cfg=$dir/conf.xml
startupdb=$dir/startup_db
# Restconf debug
RESTCONFDBG=0
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_FEATURE>ietf-netconf:startup</CLICON_FEATURE>
<CLICON_FEATURE>clixon-restconf:allow-auth-none</CLICON_FEATURE> <!-- Use auth-type=none -->
<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>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<CLICON_BACKEND_REGEXP>example_backend.so$</CLICON_BACKEND_REGEXP>
<CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<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>$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>
</clixon-config>
EOF
cat <<EOF > $dir/example.yang
module example {
namespace "urn:example:clixon";
prefix ex;
revision 2021-03-05;
leaf val{
type string;
}
}
EOF
function testrpc()
{
operation=$1
expectret=$2
sleep $DEMSLEEP
new "send rpc $operation"
ret=$($clixon_netconf -qf $cfg<<EOF
$DEFAULTHELLO
<rpc $DEFAULTNS>
<process-control xmlns="http://clicon.org/lib">
<name>restconf</name>
<operation>$operation</operation>
</process-control>
</rpc>]]>]]>
EOF
)
>&2 echo "ret:$ret" # debug
expect1="<pid xmlns=\"http://clicon.org/lib\">[0-9]*</pid>"
match=$(echo "$ret" | grep --null -Go "$expect1")
# >&2 echo "match:$match" # debug
if [ -z "$match" ]; then
pid=0
else
pid=$(echo "$match" | awk -F'[<>]' '{print $3}')
fi
>&2 echo "pid:$pid" # debug
if [ -z "$pid" ]; then
err "Running process" "$ret"
fi
new "check restconf retvalue"
if [ $operation = "status" ]; then
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
echo "$pid" # cant use return that only uses 0-255
fi
sleep $DEMSLEEP
}
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 init -f $cfg"
start_backend -s init -f $cfg
fi
new "wait backend"
wait_backend
RESTCONFIG1=$(cat <<EOF
<restconf xmlns="http://clicon.org/restconf">
<enable>true</enable>
<debug>$RESTCONFDBG</debug>
</restconf>
EOF
)
LIBNS='xmlns="http://clicon.org/lib"'
new "get status 1"
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>status</operation></process-control></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><active $LIBNS>false</active><description $LIBNS>Clixon RESTCONF process</description><command $LIBNS>/www-data/clixon_restconf -f $cfg -D $RESTCONFDBG</command></rpc-reply>]]>]]>$"
new "enable minimal restconf, no server"
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><edit-config><target><candidate/></target><config>$RESTCONFIG1</config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
new "netconf commit"
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
# Get pid2
pid2=$(testrpc status 1)
echo "pid:$pid2"
new "get status 2"
ret=$($clixon_netconf -qf $cfg<<EOF
$DEFAULTHELLO
<rpc $DEFAULTNS>
<process-control xmlns="http://clicon.org/lib">
<name>restconf</name>
<operation>status</operation>
</process-control>
</rpc>]]>]]>
EOF
)
expect="^<rpc-reply $DEFAULTNS><active $LIBNS>true</active><description $LIBNS>Clixon RESTCONF process</description><pid $LIBNS>$pid2</pid><command $LIBNS>/www-data/clixon_restconf -f $cfg -D $RESTCONFDBG</command><starttime $LIBNS>20[0-9][0-9]\-[0-9][0-9]\-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9]*Z</starttime>"
match=$(echo "$ret" | grep --null -Go "$expect")
if [ -z "$match" ]; then
err "$expect" "$ret"
fi
# Kill it
sudo kill $pid2
sleep $DEMSLEEP
# Ensure no pid
pid2=$(testrpc status 0)
RESTCONFIG2=$(cat <<EOF
<restconf xmlns="http://clicon.org/restconf">
<socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket>
</restconf>
EOF
)
new "create a server"
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><edit-config><target><candidate/></target><config>$RESTCONFIG2</config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
new "netconf commit"
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
# 3. get status
new "get status 3"
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>status</operation></process-control></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><active $LIBNS>true</active><description $LIBNS>Clixon RESTCONF process</description><pid $LIBNS>"
if [ $BE -ne 0 ]; then
new "Kill backend"
# Check if premature kill
pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then
err "backend already dead"
fi
# kill backend
stop_backend -f $cfg
fi
sleep $DEMSLEEP # Lots of processes need to die before next test
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 init -f $cfg"
start_backend -s init -f $cfg
fi
new "wait backend"
wait_backend
new "get status 1"
testrpc status 0
RESTCONFIG1=$(cat <<EOF
<restconf xmlns="http://clicon.org/restconf">
<enable>true</enable>
<debug>$RESTCONFDBG</debug>
<auth-type>none</auth-type>
<server-cert-path>$srvcert</server-cert-path>
<server-key-path>$srvkey</server-key-path>
<server-ca-cert-path>$cakey</server-ca-cert-path>
<pretty>false</pretty>
<socket><namespace>default</namespace><address>221.0.0.1</address><port>80</port><ssl>false</ssl></socket>
</restconf>
EOF
)
new "Create server with invalid address"
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><edit-config><target><candidate/></target><config>$RESTCONFIG1</config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
new "netconf commit"
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
sleep $DEMSLEEP
new "Check zombies"
ret=$(ps aux|grep defunc | grep -v grep)
if [ -n "$ret" ]; then
err "No zombie process" "$ret"
fi
new "endtest"
endtest
# Set by restconf_config
unset RESTCONFIG1
unset RESTCONFIG2
unset RESTCONFDBG
rm -rf $dir

View file

@ -25,15 +25,19 @@ cfg=$dir/conf.xml
# Local for test here
certdir=$dir/certs
cakey=$certdir/ca_key.pem
cacert=$certdir/ca_cert.pem
srvkey=$certdir/srv_key.pem
srvcert=$certdir/srv_cert.pem
cakey=$certdir/ca_key.pem # needed?
cacert=$certdir/ca_cert.pem
# These is another CA (invalid) for creating invalid client certs
xcakey=$certdir/xca_key.pem
xcacert=$certdir/xca_cert.pem
users="andy guest" # generate certs for some users in nacm.sh
xusers="limited" # Set invalid cert
x1users="limited" # Set invalid cert
x2users="invalid" # Wrong CA
# Whether to generate new keys or not (only if $dir is not removed)
# Here dont generate keys if restconf started stand-alone (RC=0)
@ -93,10 +97,14 @@ EOF
if $genkeys; then
# Create server certs
cacerts $cakey $cacert
servercerts $cakey $cacert $srvkey $srvcert
# Other (invalid)
cacerts $xcakey $xcacert
# create client certs
for name in $users $xusers; do
for name in $users $x1users; do
cat<<EOF > $dir/$name.cnf
[req]
prompt = no
@ -119,9 +127,33 @@ EOF
done # client key
# invalid (days = 0)
for name in $xusers; do
for name in $x1users; do
openssl x509 -req -extfile $dir/$name.cnf -days 0 -passin "pass:password" -in $certdir/$name.csr -CA $cacert -CAkey $cakey -CAcreateserial -out $certdir/$name.crt
done # invalid
# create client certs from invalid CA
for name in $x2users; do
cat<<EOF > $dir/$name.cnf
[req]
prompt = no
distinguished_name = dn
[dn]
CN = $name # This can be verified using SSL_set1_host
emailAddress = $name@foo.bar
O = Clixon
L = Stockholm
C = SE
EOF
# Create client key
openssl genrsa -out "$certdir/$name.key" 2048
# Generate CSR (signing request)
openssl req -new -config $dir/$name.cnf -key $certdir/$name.key -out $certdir/$name.csr
# Sign by CA
openssl x509 -req -extfile $dir/$name.cnf -days 1 -passin "pass:password" -in $certdir/$name.csr -CA $xcacert -CAkey $xcakey -CAcreateserial -out $certdir/$name.crt
done # client key
fi # genkeys
# Write local config
@ -222,6 +254,9 @@ EOF
new "limited invalid cert"
expectpart "$(curl $CURLOPTS --key $certdir/limited.key --cert $certdir/limited.crt -X GET $RCPROTO://localhost/restconf/data/example:x 2>&1)" "35 55 56" # 55 "certificate expired"
new "invalid cert from wrong CA"
expectpart "$(curl $CURLOPTS --key $certdir/invalid.key --cert $certdir/limited.crt -X GET $RCPROTO://localhost/restconf/data/example:x 2>&1)" 58 "unable to set private key file" # 58 unable to set private key file
# Just ensure all is OK
new "admin get x 42"
expectpart "$(curl $CURLOPTS --key $certdir/andy.key --cert $certdir/andy.crt -X GET $RCPROTO://localhost/restconf/data/example:x)" 0 "HTTP/1.1 200 OK" '{"example:x":42}'

View file

@ -35,7 +35,7 @@ EOF
# Use yang in example
# Define default restconfig config: RESTCONFIG
restconf_config none true
RESTCONFIG=$(restconf_config none true)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -14,7 +14,7 @@ APPNAME=example
cfg=$dir/conf.xml
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
# Use yang in example
cat <<EOF > $cfg

View file

@ -28,7 +28,7 @@ fextra1=$dir/extra1.yang # Referenced from sub1
fextra2=$dir/extra2.yang # Referenced from sub2
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">

View file

@ -22,7 +22,7 @@ funknown=$dir/yang/unknown.yang
fstate=$dir/state.xml
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
cat <<EOF > $fanydata
module any{

View file

@ -14,7 +14,7 @@ fyang1=$dir/example1.yang
fyang2=$dir/example2.yang
# Define default restconfig config: RESTCONFIG
restconf_config none false
RESTCONFIG=$(restconf_config none false)
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">