diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2bbbac90..850eb04d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -38,6 +38,8 @@ Expected: April
* Each peer MUST send at least the base NETCONF capability, "urn:ietf:params:netconf:base:1.1" (or 1.0 for RFC 4741)
* The netconf client will terminate (close the socket) if the client does not comply
* You can set `CLICON_NETCONF_HELLO_OPTIONAL` to true to use the old behavior of essentially ignoring hellos.
+* New clixon-lib@2020-03-08.yang revision
+ * Changed: RPC process-control output to choice dependent on operation
* New clixon-config@2020-03-08.yang revision
* Added: `CLICON_NETCONF_HELLO_OPTIONAL`
diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c
index 41326a24..9a7d4fa3 100644
--- a/apps/backend/backend_client.c
+++ b/apps/backend/backend_client.c
@@ -1596,8 +1596,14 @@ from_client_process_control(clicon_handle h,
/* Make the actual process operation (with wrap function enabled) */
if (clixon_process_operation(h, name, op, 1, &pid) < 0)
goto done;
- cprintf(cbret, "%u",
- NETCONF_BASE_NAMESPACE, CLIXON_LIB_NS, pid);
+ if (op == PROC_OP_STATUS)
+ cprintf(cbret, "%s%u",
+ NETCONF_BASE_NAMESPACE,
+ CLIXON_LIB_NS, pid?"true":"false",
+ CLIXON_LIB_NS, pid);
+ else
+ cprintf(cbret, "",
+ NETCONF_BASE_NAMESPACE, CLIXON_LIB_NS);
retval = 0;
done:
return retval;
diff --git a/doc/DEVELOP.md b/doc/DEVELOP.md
index 97bc60d0..21867f0f 100644
--- a/doc/DEVELOP.md
+++ b/doc/DEVELOP.md
@@ -68,10 +68,19 @@ How to debug
CFLAGS="-g -Wall" INSTALLFLAGS="" ./configure
```
-### Set backend debug flag using curl
+### Set backend debug using curl
-curl -Ssik -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/operations/clixon-lib:debug -d '{"clixon-lib:input":{"level":1}}'
+Set backend debug using rpc
+curl -Ssik -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/operations/clixon-lib:debug -d '{"clixon-lib:input":{"level":1}}'
+### Set restconf debug using curl
+
+Only if using clixon-restconf.yang
+
+curl -Ssik -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/clixon-rstconf:restconf/debug -d '{"clixon-restconf:debug":{"level":1}}'
+
+Get restconf daemon status
+curl -Ssik -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/operations/clixon-lib:process-control -d '{"clixon-lib:input":{"name":"restconf","operation":"status"}}'
### Make your own simplified yang and configuration file.
```
diff --git a/lib/src/clixon_proc.c b/lib/src/clixon_proc.c
index 96273f41..455ddd11 100644
--- a/lib/src/clixon_proc.c
+++ b/lib/src/clixon_proc.c
@@ -494,10 +494,14 @@ proc_op_run(pid_t pid0,
* @param[in] name Name of process
* @param[in] op start, stop, restart, status
* @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
+ * @param[out] pid >0 process# and is running / 0: not running
* @retval -1 Error
* @retval 0 OK
* @see upgrade_callback_reg_fn which registers the callbacks
+ * @note operations are not made directly but postponed by a scheduling the actions.
+ * This is not really necessary for all operations (like start) but made for all
+ * for reducing complexity of code.
+ * @see clixon_process_sched where operations are actually executed
*/
int
clixon_process_operation(clicon_handle h,
@@ -516,19 +520,26 @@ clixon_process_operation(clicon_handle h,
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;
- clicon_debug(1, "%s name: %s pid:%d op: %s", __FUNCTION__,
- name, pe->pe_pid, clicon_int2str(proc_operation_map, op));
- if (op == PROC_OP_START || op == PROC_OP_STOP || op == PROC_OP_RESTART){
- pe->pe_op = op;
- clicon_debug(1, "%s scheduling %s pid:%d", __FUNCTION__, name, pe->pe_pid);
- sched++;
+ if (op == PROC_OP_STATUS){
+ if (pe->pe_clone)
+ continue; /* this may be a dying duplicate */
+ if (pid)
+ *pid = pe->pe_pid;
+ }
+ else {
+ /* 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;
+ clicon_debug(1, "%s name: %s pid:%d op: %s", __FUNCTION__,
+ name, pe->pe_pid, clicon_int2str(proc_operation_map, op));
+ if (op == PROC_OP_START || op == PROC_OP_STOP || op == PROC_OP_RESTART){
+ pe->pe_op = op;
+ clicon_debug(1, "%s scheduling %s pid:%d", __FUNCTION__, name, pe->pe_pid);
+ sched++;
+ }
+
}
- if (pid)
- *pid = pe->pe_pid;
break; /* hit break here */
}
pe = NEXTQ(process_entry_t *, pe);
@@ -587,6 +598,7 @@ clixon_process_start_all(clicon_handle h)
* (2) edit changes or rpc restart especially of restconf where you may saw of your arm and terminate
* return socket.
* A special complexity is restarting processes, where the old is killed, but state must be kept until it is reaped
+ * @see clixon_process_waitpid where killed/restarted processes are "reaped"
*/
static int
clixon_process_sched(int fd,
diff --git a/test/config.sh.in b/test/config.sh.in
index 53b7b3e5..bd213d7f 100755
--- a/test/config.sh.in
+++ b/test/config.sh.in
@@ -66,3 +66,8 @@ CLIXON_VERSION=@CLIXON_VERSION@
# see also DATASTORE_TOP_SYMBOL
DATASTORE_TOP="config"
+# clixon yang revisions occuring in tests
+CLIXON_LIB_REV="2021-03-08"
+CLIXON_CONFIG_REV="2021-03-08"
+CLIXON_EXAMPLE_REV="2020-12-01"
+
diff --git a/test/test_restconf.sh b/test/test_restconf.sh
index 99382cdd..5f09b10e 100755
--- a/test/test_restconf.sh
+++ b/test/test_restconf.sh
@@ -25,7 +25,8 @@ cfg=$dir/conf.xml
# clixon-example and clixon-restconf is used in the test, need local copy
# This is a kludge: look in src otherwise assume it is installed in /usr/local/share
# Note that revisions may change and may need to be updated
-y=clixon-example@2020-12-01.yang
+y="clixon-example@${CLIXON_EXAMPLE_REV}.yang"
+
if [ -d ${TOP_SRCDIR}/example/main/$y ]; then
cp ${TOP_SRCDIR}/example/main/$y $dir/
else
@@ -193,7 +194,7 @@ function 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-30","'
+ 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\":\"${CLIXON_EXAMPLE_REV}\",\"namespace\":\"urn:example:clixon\",\"conformance-type\":\"implement\"},{\"name\":\"clixon-lib\",\"revision\":\"${CLIXON_LIB_REV}\",\""
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"
diff --git a/test/test_restconf_jukebox.sh b/test/test_restconf_jukebox.sh
index 898c9629..fccff480 100755
--- a/test/test_restconf_jukebox.sh
+++ b/test/test_restconf_jukebox.sh
@@ -104,7 +104,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-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"}'
+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\":\"${CLIXON_LIB_REV}\",\"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' 'urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=expliciturn:ietf:params:restconf:capability:depth
diff --git a/test/test_restconf_rpc.sh b/test/test_restconf_rpc.sh
index e3dcd849..5a7718ba 100755
--- a/test/test_restconf_rpc.sh
+++ b/test/test_restconf_rpc.sh
@@ -141,8 +141,8 @@ if [ $BE -ne 0 ]; then
fi
# For debug
-#>&2 echo "curl $CURLOPTS -X POST -H \"Content-Type: application/yang-data+json\" $RCPROTO://localhost/restconf/operations/clixon-lib:process-control -d '{\"clixon-lib:input\":{\"name\":\"restconf\",\"operation\":\"status\"}}'"
-
+>&2 echo "curl $CURLOPTS -X POST -H \"Content-Type: application/yang-data+json\" $RCPROTO://localhost/restconf/operations/clixon-lib:process-control -d '{\"clixon-lib:input\":{\"name\":\"restconf\",\"operation\":\"status\"}}'"
+exit
# Get pid of running process and check return xml
new "1. Get rpc status"
pid0=$(testrpc status 1) # Save pid0
diff --git a/test/test_upgrade_quit.sh b/test/test_upgrade_quit.sh
index 95524531..3e6c5c7e 100755
--- a/test/test_upgrade_quit.sh
+++ b/test/test_upgrade_quit.sh
@@ -301,7 +301,7 @@ cat < $dir/startup_db
${DATASTORE_TOP}>
EOF
-MODSTATE1='0clixon-lib2020-12-30http://clicon.org/lib'
+MODSTATE1="0clixon-lib${CLIXON_LIB_REV}http://clicon.org/lib"
MODSTATE2='interfaces2018-02-20urn:example:interfaces'
diff --git a/yang/clixon/Makefile.in b/yang/clixon/Makefile.in
index 448ddecb..6578514a 100644
--- a/yang/clixon/Makefile.in
+++ b/yang/clixon/Makefile.in
@@ -42,7 +42,7 @@ datarootdir = @datarootdir@
YANG_INSTALLDIR = @YANG_INSTALLDIR@
YANGSPECS = clixon-config@2021-03-08.yang
-YANGSPECS += clixon-lib@2020-12-30.yang
+YANGSPECS += clixon-lib@2021-03-08.yang
YANGSPECS += clixon-rfc5277@2008-07-01.yang
YANGSPECS += clixon-xml-changelog@2019-03-21.yang
YANGSPECS += clixon-restconf@2020-12-30.yang
diff --git a/yang/clixon/clixon-lib@2021-03-08.yang b/yang/clixon/clixon-lib@2021-03-08.yang
new file mode 100644
index 00000000..9bdd90b0
--- /dev/null
+++ b/yang/clixon/clixon-lib@2021-03-08.yang
@@ -0,0 +1,201 @@
+module clixon-lib {
+ yang-version 1.1;
+ namespace "http://clicon.org/lib";
+ prefix cl;
+
+ organization
+ "Clicon / Clixon";
+
+ contact
+ "Olof Hagsand ";
+
+ description
+ "Clixon Netconf extensions for communication between clients and backend.
+
+ ***** BEGIN LICENSE BLOCK *****
+ Copyright (C) 2009-2019 Olof Hagsand
+ Copyright (C) 2020-2021 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 2021-03-08 {
+ description
+ "Changed: RPC process-control output to choice dependent on operation";
+ }
+ 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 process 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 {
+ choice result {
+ case status {
+ description
+ "Output from status rpc";
+ leaf status {
+ description "True if process is running, false if not";
+ type boolean;
+ }
+ leaf pid {
+ description "Process-id of running process or 0 if not running
+ Value is only valid for operation status";
+ type uint32;
+ }
+ }
+ case other {
+ description
+ "Output from start/stop/restart rpc";
+ leaf ok {
+ type empty;
+ }
+ }
+ }
+ }
+ }
+}