Added several fields to process-control status operation: active, description, command, status, starttime, pid
This commit is contained in:
parent
7e9a207ab2
commit
07d196dfd0
8 changed files with 144 additions and 58 deletions
|
|
@ -39,7 +39,7 @@ Expected: April
|
|||
* 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
|
||||
* Changed: RPC process-control output to choice with status fields
|
||||
* New clixon-config@2020-03-08.yang revision
|
||||
* Added: `CLICON_NETCONF_HELLO_OPTIONAL`
|
||||
|
||||
|
|
@ -55,6 +55,7 @@ Developers may need to change their code
|
|||
|
||||
### Minor features
|
||||
|
||||
* Added several fields to process-control status operation: active, description, command, status, starttime, pid
|
||||
* Changed signal handling
|
||||
* Moved clixon-proc sigchild handling from handler to clixon_events
|
||||
* The base capability has been changed to "urn:ietf:params:netconf:base:1.1" following RFC6241.
|
||||
|
|
|
|||
|
|
@ -1584,7 +1584,6 @@ from_client_process_control(clicon_handle h,
|
|||
cxobj *x;
|
||||
char *name = NULL;
|
||||
char *opstr = NULL;
|
||||
uint32_t pid = 0;
|
||||
proc_operation op = PROC_OP_NONE;
|
||||
|
||||
if ((x = xml_find_type(xe, NULL, "name", CX_ELMNT)) != NULL)
|
||||
|
|
@ -1594,16 +1593,16 @@ from_client_process_control(clicon_handle h,
|
|||
op = clixon_process_op_str2int(opstr);
|
||||
}
|
||||
/* Make the actual process operation (with wrap function enabled) */
|
||||
if (clixon_process_operation(h, name, op, 1, &pid) < 0)
|
||||
goto done;
|
||||
if (op == PROC_OP_STATUS)
|
||||
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><status xmlns=\"%s\">%s</status><pid xmlns=\"%s\">%u</pid></rpc-reply>",
|
||||
NETCONF_BASE_NAMESPACE,
|
||||
CLIXON_LIB_NS, pid?"true":"false",
|
||||
CLIXON_LIB_NS, pid);
|
||||
else
|
||||
if (op == PROC_OP_STATUS){
|
||||
if (clixon_process_status(h, name, cbret) < 0)
|
||||
goto done;
|
||||
}
|
||||
else{
|
||||
if (clixon_process_operation(h, name, op, 1) < 0)
|
||||
goto done;
|
||||
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><ok xmlns=\"%s\"/></rpc-reply>",
|
||||
NETCONF_BASE_NAMESPACE, CLIXON_LIB_NS);
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ restconf_pseudo_process_control(clicon_handle h)
|
|||
argv[i++] = NULL;
|
||||
assert(i==nr);
|
||||
if (clixon_process_register(h, RESTCONF_PROCESS,
|
||||
"Clixon RESTCONF process",
|
||||
NULL /* XXX network namespace */,
|
||||
restconf_rpc_wrapper,
|
||||
argv, nr) < 0)
|
||||
|
|
@ -196,7 +197,7 @@ restconf_pseudo_process_commit(clicon_handle h,
|
|||
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, NULL) < 0)
|
||||
enabled?PROC_OP_START:PROC_OP_STOP, 0) < 0)
|
||||
goto done;
|
||||
}
|
||||
else if (enabled){ /* If something changed and running, restart process */
|
||||
|
|
@ -209,7 +210,7 @@ restconf_pseudo_process_commit(clicon_handle h,
|
|||
* Specifically, the socket is terminated where the reply is sent, which will
|
||||
* cause the curl to fail.
|
||||
*/
|
||||
if (clixon_process_operation(h, RESTCONF_PROCESS, PROC_OP_RESTART, 0, NULL) < 0)
|
||||
if (clixon_process_operation(h, RESTCONF_PROCESS, PROC_OP_RESTART, 0) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,9 +62,10 @@ 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_register(clicon_handle h, const char *name, const char *netns, proc_cb_t *callback, 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, uint32_t *pid);
|
||||
int clixon_process_operation(clicon_handle h, const char *name, proc_operation op, const int wrapit);
|
||||
int clixon_process_status(clicon_handle h, const char *name, cbuf *cbret);
|
||||
int clixon_process_start_all(clicon_handle h);
|
||||
int clixon_process_sched_register(clicon_handle h);
|
||||
int clixon_process_waitpid(clicon_handle h);
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_hash.h"
|
||||
|
|
|
|||
|
|
@ -71,10 +71,14 @@
|
|||
#include "clixon_queue.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_options.h"
|
||||
#include "clixon_event.h"
|
||||
#include "clixon_sig.h"
|
||||
#include "clixon_string.h"
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_netconf_lib.h"
|
||||
#include "clixon_proc.h"
|
||||
|
||||
/*
|
||||
|
|
@ -85,6 +89,7 @@
|
|||
struct process_entry_t {
|
||||
qelem_t pe_qelem; /* List header */
|
||||
char *pe_name; /* Name of process used for internal use. Unique with exiting=0 */
|
||||
char *pe_description; /* Description of service */
|
||||
char *pe_netns; /* Network namespace */
|
||||
char **pe_argv; /* argv with command as element 0 and NULL-terminated */
|
||||
int pe_argc; /* Length of argc */
|
||||
|
|
@ -93,6 +98,7 @@ struct process_entry_t {
|
|||
int pe_clone; /* Duplicate when restarting, delete when reaped */
|
||||
pid_t pe_status; /* Status on exit as defined in waitpid */
|
||||
proc_operation pe_op; /* Operation pending? */
|
||||
struct timeval pe_starttime; /* Start time */
|
||||
proc_cb_t *pe_callback; /* Wrapper function, may be called from process_operation */
|
||||
};
|
||||
|
||||
|
|
@ -336,6 +342,10 @@ clixon_process_register_dup(process_entry_t *pe0,
|
|||
clicon_err(OE_DB, errno, "strdup name");
|
||||
goto done;
|
||||
}
|
||||
if (pe0->pe_description && (pe1->pe_description = strdup(pe0->pe_description)) == NULL){
|
||||
clicon_err(OE_DB, errno, "strdup name");
|
||||
goto done;
|
||||
}
|
||||
if (pe0->pe_netns && (pe1->pe_netns = strdup(pe0->pe_netns)) == NULL){
|
||||
clicon_err(OE_DB, errno, "strdup netns");
|
||||
goto done;
|
||||
|
|
@ -363,6 +373,7 @@ clixon_process_register_dup(process_entry_t *pe0,
|
|||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] name Process name
|
||||
* @param[in] description Description of process
|
||||
* @param[in] netns Namespace netspace (or NULL)
|
||||
* @param[in] callback
|
||||
* @param[in] argv NULL-terminated vector of vectors
|
||||
|
|
@ -374,6 +385,7 @@ clixon_process_register_dup(process_entry_t *pe0,
|
|||
int
|
||||
clixon_process_register(clicon_handle h,
|
||||
const char *name,
|
||||
const char *description,
|
||||
const char *netns,
|
||||
proc_cb_t *callback,
|
||||
char **argv,
|
||||
|
|
@ -400,6 +412,10 @@ clixon_process_register(clicon_handle h,
|
|||
clicon_err(OE_DB, errno, "strdup name");
|
||||
goto done;
|
||||
}
|
||||
if (description && (pe->pe_description = strdup(description)) == NULL){
|
||||
clicon_err(OE_DB, errno, "strdup description");
|
||||
goto done;
|
||||
}
|
||||
if (netns && (pe->pe_netns = strdup(netns)) == NULL){
|
||||
clicon_err(OE_DB, errno, "strdup netns");
|
||||
goto done;
|
||||
|
|
@ -430,6 +446,8 @@ clixon_process_delete_only(process_entry_t *pe)
|
|||
|
||||
if (pe->pe_name)
|
||||
free(pe->pe_name);
|
||||
if (pe->pe_description)
|
||||
free(pe->pe_description);
|
||||
if (pe->pe_netns)
|
||||
free(pe->pe_netns);
|
||||
if (pe->pe_argv){
|
||||
|
|
@ -488,13 +506,12 @@ proc_op_run(pid_t pid0,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Find process operation entry given name and op and perform operation if found
|
||||
/*! Find process entry given name and schedule operation
|
||||
*
|
||||
* @param[in] h clicon handle
|
||||
* @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] pid >0 process# and is running / 0: not running
|
||||
* @retval -1 Error
|
||||
* @retval 0 OK
|
||||
* @see upgrade_callback_reg_fn which registers the callbacks
|
||||
|
|
@ -507,8 +524,7 @@ int
|
|||
clixon_process_operation(clicon_handle h,
|
||||
const char *name,
|
||||
proc_operation op,
|
||||
int wrapit,
|
||||
uint32_t *pid)
|
||||
int wrapit)
|
||||
{
|
||||
int retval = -1;
|
||||
process_entry_t *pe;
|
||||
|
|
@ -520,25 +536,16 @@ clixon_process_operation(clicon_handle h,
|
|||
pe = _proc_entry_list;
|
||||
do {
|
||||
if (strcmp(pe->pe_name, name) == 0){
|
||||
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++;
|
||||
}
|
||||
|
||||
/* 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++;
|
||||
}
|
||||
break; /* hit break here */
|
||||
}
|
||||
|
|
@ -553,6 +560,66 @@ clixon_process_operation(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Get process status according to clixon-lib.yang
|
||||
*
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] name Name of process
|
||||
* @param[out] cbret XML status string
|
||||
* @retval -1 Error
|
||||
* @retval 0 OK
|
||||
*/
|
||||
int
|
||||
clixon_process_status(clicon_handle h,
|
||||
const char *name,
|
||||
cbuf *cbret)
|
||||
|
||||
{
|
||||
int retval = -1;
|
||||
process_entry_t *pe;
|
||||
int run;
|
||||
int i;
|
||||
char timestr[28];
|
||||
|
||||
if (_proc_entry_list == NULL)
|
||||
goto ok;
|
||||
pe = _proc_entry_list;
|
||||
do {
|
||||
if (strcmp(pe->pe_name, name) == 0){
|
||||
if (pe->pe_clone)
|
||||
continue; /* this may be a dying duplicate */
|
||||
/* Check if running */
|
||||
run = 0;
|
||||
if (pe->pe_pid && proc_op_run(pe->pe_pid, &run) < 0)
|
||||
goto done;
|
||||
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><active xmlns=\"%s\">%s</active>",
|
||||
NETCONF_BASE_NAMESPACE, CLIXON_LIB_NS, run?"true":"false");
|
||||
if (pe->pe_description)
|
||||
cprintf(cbret, "<description xmlns=\"%s\">%s</description>", CLIXON_LIB_NS, pe->pe_description);
|
||||
if (pe->pe_pid)
|
||||
cprintf(cbret, "<pid xmlns=\"%s\">%u</pid>", CLIXON_LIB_NS, pe->pe_pid);
|
||||
cprintf(cbret, "<command xmlns=\"%s\">", CLIXON_LIB_NS);
|
||||
for (i=0; i<pe->pe_argc-1; i++){
|
||||
if (i)
|
||||
cprintf(cbret, " ");
|
||||
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);
|
||||
cprintf(cbret, "</rpc-reply>");
|
||||
break; /* hit break here */
|
||||
}
|
||||
pe = NEXTQ(process_entry_t *, pe);
|
||||
} while (pe != _proc_entry_list);
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Go through process list and start all processes that are enabled via config wrap function
|
||||
* @param[in] h Clixon handle
|
||||
* Commit rules should have done this, but there are some cases such as backend -s none mode
|
||||
|
|
@ -623,7 +690,6 @@ clixon_process_sched(int fd,
|
|||
pe->pe_exiting == 0){
|
||||
/* Check if running */
|
||||
run = 0;
|
||||
clicon_debug(1, "%s run: %d", __FUNCTION__, run);
|
||||
if (proc_op_run(pe->pe_pid, &run) < 0)
|
||||
goto done;
|
||||
switch (op){
|
||||
|
|
@ -642,6 +708,7 @@ clixon_process_sched(int fd,
|
|||
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)
|
||||
|
|
@ -655,6 +722,7 @@ clixon_process_sched(int fd,
|
|||
break;
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -76,22 +76,18 @@ $DEFAULTHELLO
|
|||
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
|
||||
|
||||
# >&2 echo "ret:$ret" # debug
|
||||
|
||||
expect2="</pid></rpc-reply>]]>]]>"
|
||||
match=$(echo "$ret" | grep --null -Go "$expect2")
|
||||
|
||||
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
|
||||
err "$expect2" "$ret"
|
||||
pid=0
|
||||
else
|
||||
pid=$(echo "$match" | awk -F'[<>]' '{print $3}')
|
||||
fi
|
||||
new "check rpc $operation get pid"
|
||||
pid=$(echo "$ret" | awk -F'[<>]' '{print $5}')
|
||||
>&2 echo "pid:$pid" # debug
|
||||
|
||||
if [ -z "$pid" ]; then
|
||||
err "Running process" "$ret"
|
||||
fi
|
||||
|
|
@ -107,9 +103,9 @@ EOF
|
|||
err "Running process"
|
||||
fi
|
||||
fi
|
||||
echo "$pid" # cant use return that only uses 0-255
|
||||
fi
|
||||
sleep $DEMSLEEP
|
||||
echo "$pid" # cant use return that only uses 0-255
|
||||
}
|
||||
|
||||
new "ENABLE true"
|
||||
|
|
@ -141,8 +137,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\"}}'"
|
||||
exit
|
||||
#>&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\"}}'"
|
||||
|
||||
# Get pid of running process and check return xml
|
||||
new "1. Get rpc status"
|
||||
pid0=$(testrpc status 1) # Save pid0
|
||||
|
|
@ -165,7 +161,7 @@ new "wait restconf"
|
|||
wait_restconf
|
||||
|
||||
new "try restconf rpc status"
|
||||
expectpart "$(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"}}')" 0 "HTTP/1.1 200 OK" '{"clixon-lib:output":{"pid":'
|
||||
expectpart "$(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"}}')" 0 "HTTP/1.1 200 OK" '{"clixon-lib:output":' '"active":' '"pid":'
|
||||
|
||||
new "2. Get status"
|
||||
pid1=$(testrpc status 1)
|
||||
|
|
@ -177,7 +173,7 @@ if [ "$pid0" -ne "$pid1" ]; then
|
|||
fi
|
||||
|
||||
new "try restconf rpc restart"
|
||||
expectpart "$(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":"restart"}}')" 0 "HTTP/1.1 200 OK" '{"clixon-lib:output":{"pid":'
|
||||
expectpart "$(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":"restart"}}')" 0 "HTTP/1.1 204 No Content"
|
||||
|
||||
new "3. Get status"
|
||||
pid1=$(testrpc status 1)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ module clixon-lib {
|
|||
namespace "http://clicon.org/lib";
|
||||
prefix cl;
|
||||
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
organization
|
||||
"Clicon / Clixon";
|
||||
|
||||
|
|
@ -178,13 +181,28 @@ module clixon-lib {
|
|||
case status {
|
||||
description
|
||||
"Output from status rpc";
|
||||
leaf status {
|
||||
leaf active {
|
||||
description "True if process is running, false if not";
|
||||
type boolean;
|
||||
}
|
||||
leaf description {
|
||||
type string;
|
||||
description "Description of process. This is a static string";
|
||||
}
|
||||
leaf command {
|
||||
type string;
|
||||
description "Start command with arguments";
|
||||
}
|
||||
leaf status {
|
||||
description "Exit Status as defined by waitpid() - if exited";
|
||||
type int32;
|
||||
}
|
||||
leaf starttime {
|
||||
description "Time of starting process UTC";
|
||||
type yang:date-and-time;
|
||||
}
|
||||
leaf pid {
|
||||
description "Process-id of running process or 0 if not running
|
||||
Value is only valid for operation status";
|
||||
description "Process-id of main running process (if active)";
|
||||
type uint32;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue