diff --git a/apps/backend/backend_plugin_restconf.c b/apps/backend/backend_plugin_restconf.c index f4f3a07e..f7d448b8 100644 --- a/apps/backend/backend_plugin_restconf.c +++ b/apps/backend/backend_plugin_restconf.c @@ -61,6 +61,44 @@ #define RESTCONF_PROCESS "restconf" +/*! Set current debug flag when starting process using -D + * + * 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 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; diff --git a/apps/restconf/restconf_main_native.c b/apps/restconf/restconf_main_native.c index a446b3bc..0ebb371a 100644 --- a/apps/restconf/restconf_main_native.c +++ b/apps/restconf/restconf_main_native.c @@ -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); diff --git a/docker/base/Dockerfile b/docker/base/Dockerfile index c41ab488..6a77d12d 100644 --- a/docker/base/Dockerfile +++ b/docker/base/Dockerfile @@ -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///' 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 diff --git a/docker/base/README.md b/docker/base/README.md index b3a2fcab..6c01c990 100644 --- a/docker/base/README.md +++ b/docker/base/README.md @@ -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 diff --git a/docker/main/Dockerfile.native b/docker/main/Dockerfile.native index 734f1e2f..23628edc 100644 --- a/docker/main/Dockerfile.native +++ b/docker/main/Dockerfile.native @@ -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/ # diff --git a/lib/clixon/clixon_proc.h b/lib/clixon/clixon_proc.h index 6c8b1a05..cfe6f2f4 100644 --- a/lib/clixon/clixon_proc.h +++ b/lib/clixon/clixon_proc.h @@ -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); diff --git a/lib/src/clixon_proc.c b/lib/src/clixon_proc.c index 93e05f4e..99aafa35 100644 --- a/lib/src/clixon_proc.c +++ b/lib/src/clixon_proc.c @@ -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, ""); - cprintf(cbret, "%u", CLIXON_LIB_NS, pe->pe_status); - if (run && time2str(pe->pe_starttime, timestr, sizeof(timestr)) < 0) - goto done; - cprintf(cbret, "%s", 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, "%s", CLIXON_LIB_NS, timestr); + } cprintf(cbret, ""); 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 */ diff --git a/lib/src/clixon_proto.c b/lib/src/clixon_proto.c index f4b7f453..3b17eecc 100644 --- a/lib/src/clixon_proto.c +++ b/lib/src/clixon_proto.c @@ -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; diff --git a/test/config.sh.in b/test/config.sh.in index 8459cd1a..c1fee465 100755 --- a/test/config.sh.in +++ b/test/config.sh.in @@ -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 + diff --git a/test/lib.sh b/test/lib.sh index 1a258658..26722c3c 100755 --- a/test/lib.sh +++ b/test/lib.sh @@ -202,9 +202,9 @@ function restconf_config() PRETTY=$2 if [ $RCPROTO = http ]; then - RESTCONFIG="true$AUTH$PRETTY$DBGdefault
0.0.0.0
80false
" + echo "true$AUTH$PRETTY$DBGdefault
0.0.0.0
80false
" else - RESTCONFIG="true$AUTH$PRETTY/etc/ssl/certs/clixon-server-crt.pem/etc/ssl/private/clixon-server-key.pem/etc/ssl/certs/clixon-ca-crt.pem$DBGdefault
0.0.0.0
443true
" + echo "true$AUTH$PRETTY/etc/ssl/certs/clixon-server-crt.pem/etc/ssl/private/clixon-server-key.pem/etc/ssl/certs/clixon-ca-crt.pem$DBGdefault
0.0.0.0
443true
" 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< $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 } diff --git a/test/long.sh b/test/long.sh index 35d49aaa..98a91513 100755 --- a/test/long.sh +++ b/test/long.sh @@ -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 < $fyang module scaling{ diff --git a/test/site.sh b/test/site.sh index 7b5d9aec..ab3887a6 100644 --- a/test/site.sh +++ b/test/site.sh @@ -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 + diff --git a/test/test_api.sh b/test/test_api.sh index 76cdee51..3b3dd3e2 100755 --- a/test/test_api.sh +++ b/test/test_api.sh @@ -25,7 +25,7 @@ if [ ! -d $pdir ]; then fi # Define default restconfig config: RESTCONFIG -restconf_config none false +RESTCONFIG=$(restconf_config none false) cat < $cfg diff --git a/test/test_augment.sh b/test/test_augment.sh index 15cf6bbd..b3a32f78 100755 --- a/test/test_augment.sh +++ b/test/test_augment.sh @@ -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 < $cfg diff --git a/test/test_choice.sh b/test/test_choice.sh index ab909ccf..106322c4 100755 --- a/test/test_choice.sh +++ b/test/test_choice.sh @@ -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 < $cfg diff --git a/test/test_client.sh b/test/test_client.sh index 69a1ccf0..63c4b67d 100755 --- a/test/test_client.sh +++ b/test/test_client.sh @@ -22,7 +22,7 @@ if [ ! -d $pdir ]; then fi # Define default restconfig config: RESTCONFIG -restconf_config none false +RESTCONFIG=$(restconf_config none false) cat < $cfg diff --git a/test/test_copy_config.sh b/test/test_copy_config.sh index 772e5a04..e4821280 100755 --- a/test/test_copy_config.sh +++ b/test/test_copy_config.sh @@ -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 < $cfg diff --git a/test/test_identity.sh b/test/test_identity.sh index eccbea15..c10fd85c 100755 --- a/test/test_identity.sh +++ b/test/test_identity.sh @@ -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 < $cfg diff --git a/test/test_nacm.sh b/test/test_nacm.sh index b2f81b39..85078da7 100755 --- a/test/test_nacm.sh +++ b/test/test_nacm.sh @@ -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 < $cfg diff --git a/test/test_nacm_datanode.sh b/test/test_nacm_datanode.sh index c45e502b..ca7e5a07 100755 --- a/test/test_nacm_datanode.sh +++ b/test/test_nacm_datanode.sh @@ -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 < $cfg diff --git a/test/test_nacm_datanode_paths.sh b/test/test_nacm_datanode_paths.sh index 2dfd738c..68185dab 100755 --- a/test/test_nacm_datanode_paths.sh +++ b/test/test_nacm_datanode_paths.sh @@ -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 < $cfg diff --git a/test/test_nacm_datanode_read.sh b/test/test_nacm_datanode_read.sh index 8b954aaa..637f3ee6 100755 --- a/test/test_nacm_datanode_read.sh +++ b/test/test_nacm_datanode_read.sh @@ -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 < $cfg diff --git a/test/test_nacm_datanode_write.sh b/test/test_nacm_datanode_write.sh index 44123c08..8e06e46b 100755 --- a/test/test_nacm_datanode_write.sh +++ b/test/test_nacm_datanode_write.sh @@ -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 < $cfg diff --git a/test/test_nacm_default.sh b/test/test_nacm_default.sh index 9e57ea62..69fbbc92 100755 --- a/test/test_nacm_default.sh +++ b/test/test_nacm_default.sh @@ -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 < $cfg diff --git a/test/test_nacm_ext.sh b/test/test_nacm_ext.sh index c80a9266..5b5554dc 100755 --- a/test/test_nacm_ext.sh +++ b/test/test_nacm_ext.sh @@ -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 < $cfg diff --git a/test/test_nacm_module_read.sh b/test/test_nacm_module_read.sh index 27583712..5dd8b480 100755 --- a/test/test_nacm_module_read.sh +++ b/test/test_nacm_module_read.sh @@ -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 < $cfg diff --git a/test/test_nacm_module_write.sh b/test/test_nacm_module_write.sh index e20beb27..df654c9f 100755 --- a/test/test_nacm_module_write.sh +++ b/test/test_nacm_module_write.sh @@ -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 < $cfg diff --git a/test/test_nacm_protocol.sh b/test/test_nacm_protocol.sh index e5176c30..938a1eda 100755 --- a/test/test_nacm_protocol.sh +++ b/test/test_nacm_protocol.sh @@ -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 < $cfg diff --git a/test/test_nacm_recovery.sh b/test/test_nacm_recovery.sh index 1e1c3472..cb4b3a2a 100755 --- a/test/test_nacm_recovery.sh +++ b/test/test_nacm_recovery.sh @@ -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 < $fyang module nacm-example{ diff --git a/test/test_perf_restconf.sh b/test/test_perf_restconf.sh index a9e20b72..dd21f045 100755 --- a/test/test_perf_restconf.sh +++ b/test/test_perf_restconf.sh @@ -53,7 +53,7 @@ module scaling{ EOF # Define default restconfig config: RESTCONFIG -restconf_config none false +RESTCONFIG=$(restconf_config none false) cat < $cfg diff --git a/test/test_perf_state.sh b/test/test_perf_state.sh index 5a224a96..35d3a8f8 100755 --- a/test/test_perf_state.sh +++ b/test/test_perf_state.sh @@ -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 < $cfg diff --git a/test/test_perf_state_only.sh b/test/test_perf_state_only.sh index 6ba8ac0d..9a2ecd9d 100755 --- a/test/test_perf_state_only.sh +++ b/test/test_perf_state_only.sh @@ -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 < $cfg diff --git a/test/test_restconf.sh b/test/test_restconf.sh index 438d50f5..924650ca 100755 --- a/test/test_restconf.sh +++ b/test/test_restconf.sh @@ -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 diff --git a/test/test_restconf2.sh b/test/test_restconf2.sh index 8b27e9f9..674a4285 100755 --- a/test/test_restconf2.sh +++ b/test/test_restconf2.sh @@ -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) # example cat < $cfg diff --git a/test/test_restconf_basic_auth.sh b/test/test_restconf_basic_auth.sh index fa254578..42f5b1cc 100755 --- a/test/test_restconf_basic_auth.sh +++ b/test/test_restconf_basic_auth.sh @@ -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 < $cfg diff --git a/test/test_restconf_err.sh b/test/test_restconf_err.sh index 486bf2b3..17700e4f 100755 --- a/test/test_restconf_err.sh +++ b/test/test_restconf_err.sh @@ -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) # example cat < $cfg diff --git a/test/test_restconf_jukebox.sh b/test/test_restconf_jukebox.sh index 10cd0345..ab09704e 100755 --- a/test/test_restconf_jukebox.sh +++ b/test/test_restconf_jukebox.sh @@ -24,7 +24,7 @@ cat < $dir/example-system.yang EOF # Define default restconfig config: RESTCONFIG -restconf_config none false +RESTCONFIG=$(restconf_config none false) # example cat < $cfg diff --git a/test/test_restconf_listkey.sh b/test/test_restconf_listkey.sh index 9fd67a45..821a6c71 100755 --- a/test/test_restconf_listkey.sh +++ b/test/test_restconf_listkey.sh @@ -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) # example cat < $cfg diff --git a/test/test_restconf_netns.sh b/test/test_restconf_netns.sh index d06d4811..102e0d42 100755 --- a/test/test_restconf_netns.sh +++ b/test/test_restconf_netns.sh @@ -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 diff --git a/test/test_restconf_notifications.sh b/test/test_restconf_notifications.sh index 13954f05..3f9c04e8 100755 --- a/test/test_restconf_notifications.sh +++ b/test/test_restconf_notifications.sh @@ -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) # example cat < $cfg diff --git a/test/test_restconf_patch.sh b/test/test_restconf_patch.sh index 0f4cd77b..8511437a 100755 --- a/test/test_restconf_patch.sh +++ b/test/test_restconf_patch.sh @@ -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 < $cfg diff --git a/test/test_restconf_rpc.sh b/test/test_restconf_rpc.sh index f2d0ebe7..993d3521 100755 --- a/test/test_restconf_rpc.sh +++ b/test/test_restconf_rpc.sh @@ -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 < $cfg diff --git a/test/test_restconf_rpc2.sh b/test/test_restconf_rpc2.sh new file mode 100755 index 00000000..eceddbaf --- /dev/null +++ b/test/test_restconf_rpc2.sh @@ -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 < $cfg + + $cfg + ietf-netconf:startup + clixon-restconf:allow-auth-none + /usr/local/share/clixon + $IETFRFC + $dir + /usr/local/lib/$APPNAME/clispec + /usr/local/lib/$APPNAME/backend + example_backend.so$ + /usr/local/lib/$APPNAME/restconf + /usr/local/lib/$APPNAME/cli + $APPNAME + /usr/local/var/$APPNAME/$APPNAME.sock + /usr/local/var/$APPNAME/$APPNAME.pidfile + $dir + true + + true + +EOF + +cat < $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< + + restconf + $operation + +]]>]]> +EOF +) + + >&2 echo "ret:$ret" # debug + + expect1="[0-9]*" + 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 < + true + $RESTCONFDBG + +EOF +) + +LIBNS='xmlns="http://clicon.org/lib"' + +new "get status 1" +expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLOrestconfstatus]]>]]>" "^falseClixon RESTCONF process/www-data/clixon_restconf -f $cfg -D $RESTCONFDBG]]>]]>$" + +new "enable minimal restconf, no server" +expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO$RESTCONFIG1]]>]]>" "^]]>]]>$" + +new "netconf commit" +expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^]]>]]>$" + +# Get pid2 +pid2=$(testrpc status 1) +echo "pid:$pid2" + +new "get status 2" +ret=$($clixon_netconf -qf $cfg< + + restconf + status + +]]>]]> +EOF +) +expect="^trueClixon RESTCONF process$pid2/www-data/clixon_restconf -f $cfg -D $RESTCONFDBG20[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" +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 < + default
0.0.0.0
80false
+ +EOF +) +new "create a server" +expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO$RESTCONFIG2]]>]]>" "^]]>]]>$" + +new "netconf commit" +expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^]]>]]>$" + +# 3. get status + +new "get status 3" +expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLOrestconfstatus]]>]]>" "^trueClixon RESTCONF process" + +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 < + true + $RESTCONFDBG + none + $srvcert + $srvkey + $cakey + false + default
221.0.0.1
80false
+ +EOF +) + +new "Create server with invalid address" +expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO$RESTCONFIG1]]>]]>" "^]]>]]>$" + +new "netconf commit" +expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^]]>]]>$" + +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 + diff --git a/test/test_restconf_ssl_certs.sh b/test/test_restconf_ssl_certs.sh index 4c760476..55f26163 100755 --- a/test/test_restconf_ssl_certs.sh +++ b/test/test_restconf_ssl_certs.sh @@ -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< $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< $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}' diff --git a/test/test_restconf_startup.sh b/test/test_restconf_startup.sh index bf4f176c..7c273a4f 100755 --- a/test/test_restconf_startup.sh +++ b/test/test_restconf_startup.sh @@ -35,7 +35,7 @@ EOF # Use yang in example # Define default restconfig config: RESTCONFIG -restconf_config none true +RESTCONFIG=$(restconf_config none true) cat < $cfg diff --git a/test/test_rpc.sh b/test/test_rpc.sh index bbdf03db..0181f66c 100755 --- a/test/test_rpc.sh +++ b/test/test_rpc.sh @@ -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 < $cfg diff --git a/test/test_submodule.sh b/test/test_submodule.sh index b9207829..a12df67f 100755 --- a/test/test_submodule.sh +++ b/test/test_submodule.sh @@ -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 < $cfg diff --git a/test/test_yang_anydata.sh b/test/test_yang_anydata.sh index 12ddcfec..c92147e9 100755 --- a/test/test_yang_anydata.sh +++ b/test/test_yang_anydata.sh @@ -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 < $fanydata module any{ diff --git a/test/test_yang_namespace.sh b/test/test_yang_namespace.sh index 5cd5b476..8e6967d3 100755 --- a/test/test_yang_namespace.sh +++ b/test/test_yang_namespace.sh @@ -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 < $cfg