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

View file

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

View file

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

View file

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

View file

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