* New process-control RPC feature in clixon-lib.yang to manage processes
* This is an alternative to manage a clixon daemon via sudtemd, containerd or other
* One important special case is starting the clixon-restconf daemon internally
* This is how it works:
* Register a process via `clixon_process_register(h, name, namespace, argv, argc)`
* Use process-control RPC defined in clixon-lib.yang to start/stop/restart or query status on that process
* Example code in the main example
This commit is contained in:
parent
8540820698
commit
22adc58187
19 changed files with 971 additions and 47 deletions
|
|
@ -29,6 +29,13 @@
|
|||
|
||||
### New features
|
||||
|
||||
* New process-control RPC feature in clixon-lib.yang to manage processes
|
||||
* This is an alternative to manage a clixon daemon via sudtemd, containerd or other
|
||||
* One important special case is starting the clixon-restconf daemon internally
|
||||
* This is how it works:
|
||||
* Register a process via `clixon_process_register(h, name, namespace, argv, argc)`
|
||||
* Use process-control RPC defined in clixon-lib.yang to start/stop/restart or query status on that process
|
||||
* Example code in the main example
|
||||
* More YANG extension functionality,
|
||||
* See [Augment auto-cli for hiding/modifying cli syntax #156](https://github.com/clicon/clixon/issues/156) and [hiding auto-generated CLI entries #153](https://github.com/clicon/clixon/issues/153)
|
||||
* Extensions can be used in augmentations
|
||||
|
|
|
|||
|
|
@ -1560,7 +1560,49 @@ from_client_restart_plugin(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
/*! Control a specific process or daemon: start/stop, etc
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] xe Request: <rpc><xn></rpc>
|
||||
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
|
||||
* @param[in] arg client-entry
|
||||
* @param[in] regarg User argument given at rpc_callback_register()
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
from_client_process_control(clicon_handle h,
|
||||
cxobj *xe,
|
||||
cbuf *cbret,
|
||||
void *arg,
|
||||
void *regarg)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *x;
|
||||
char *name = NULL;
|
||||
char *operation = NULL;
|
||||
int status = 0;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((x = xml_find_type(xe, NULL, "name", CX_ELMNT)) != NULL)
|
||||
name = xml_body(x);
|
||||
if ((x = xml_find_type(xe, NULL, "operation", CX_ELMNT)) != NULL)
|
||||
operation = xml_body(x);
|
||||
/* Make the actual process operation */
|
||||
if (clixon_process_operation(h, name, operation, &status) < 0)
|
||||
goto done;
|
||||
if (strcmp(operation, "status") == 0)
|
||||
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><status xmlns=\"%s\">%s</status></rpc-reply>",
|
||||
NETCONF_BASE_NAMESPACE,
|
||||
CLIXON_LIB_NS,
|
||||
status?"true":"false");
|
||||
else
|
||||
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><ok/></rpc-reply>", NETCONF_BASE_NAMESPACE);
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Clixon hello to check liveness
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
|
|
@ -1569,7 +1611,6 @@ from_client_hello(clicon_handle h,
|
|||
cxobj *x,
|
||||
struct client_entry *ce,
|
||||
cbuf *cbret)
|
||||
|
||||
{
|
||||
int retval = -1;
|
||||
uint32_t id;
|
||||
|
|
@ -1592,6 +1633,7 @@ from_client_hello(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! An internal clicon message has arrived from a client. Receive and dispatch.
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] s Socket where message arrived. read from this.
|
||||
|
|
@ -1922,6 +1964,9 @@ backend_rpc_init(clicon_handle h)
|
|||
if (rpc_callback_register(h, from_client_restart_plugin, NULL,
|
||||
CLIXON_LIB_NS, "restart-plugin") < 0)
|
||||
goto done;
|
||||
if (rpc_callback_register(h, from_client_process_control, NULL,
|
||||
CLIXON_LIB_NS, "process-control") < 0)
|
||||
goto done;
|
||||
retval =0;
|
||||
done:
|
||||
return retval;
|
||||
|
|
|
|||
|
|
@ -127,6 +127,9 @@ backend_terminate(clicon_handle h)
|
|||
rpc_callback_delete_all(h);
|
||||
/* Delete all backend plugin upgrade callbacks */
|
||||
upgrade_callback_delete_all(h);
|
||||
/* Delete all process-control entries */
|
||||
clixon_process_delete_all(h);
|
||||
|
||||
xpath_optimize_exit();
|
||||
|
||||
if (pidfile)
|
||||
|
|
@ -529,6 +532,10 @@ main(int argc,
|
|||
usage(h, argv[0]);
|
||||
goto done;
|
||||
}
|
||||
/* Add some specific options from autotools configure NOT config file */
|
||||
clicon_option_str_set(h, "CLICON_WWWUSER", WWWUSER);
|
||||
clicon_option_str_set(h, "CLICON_WWWDIR", WWWDIR);
|
||||
|
||||
/* External NACM file? */
|
||||
nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE");
|
||||
if (nacm_mode && strcmp(nacm_mode, "external") == 0)
|
||||
|
|
|
|||
|
|
@ -1196,7 +1196,6 @@ restconf_config(clicon_handle h,
|
|||
xml_free(xconfig2);
|
||||
if (nsc)
|
||||
cvec_free(nsc);
|
||||
clicon_debug(1, "restconf_main_evhtp done");
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
7
configure
vendored
7
configure
vendored
|
|
@ -5397,6 +5397,11 @@ cat >>confdefs.h <<_ACEOF
|
|||
#define WWWUSER "$wwwuser"
|
||||
_ACEOF
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define WWWDIR "$wwwdir"
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
|
||||
# Set default config file location
|
||||
|
|
@ -5560,7 +5565,7 @@ fi
|
|||
fi
|
||||
|
||||
#
|
||||
for ac_func in inet_aton sigaction sigvec strlcpy strsep strndup alphasort versionsort getpeereid
|
||||
for ac_func in inet_aton sigaction sigvec strlcpy strsep strndup alphasort versionsort getpeereid setns
|
||||
do :
|
||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
||||
|
|
|
|||
|
|
@ -250,6 +250,7 @@ if test "x${with_restconf}" != "x"; then
|
|||
fi
|
||||
AC_MSG_RESULT(www user is $wwwuser)
|
||||
AC_DEFINE_UNQUOTED(WWWUSER, "$wwwuser", [WWW user for restconf daemon])
|
||||
AC_DEFINE_UNQUOTED(WWWDIR, "$wwwdir", [WWW dir for restconf daemon])
|
||||
fi
|
||||
|
||||
# Set default config file location
|
||||
|
|
@ -272,7 +273,7 @@ if test "${with_libxml2}"; then
|
|||
fi
|
||||
|
||||
#
|
||||
AC_CHECK_FUNCS(inet_aton sigaction sigvec strlcpy strsep strndup alphasort versionsort getpeereid)
|
||||
AC_CHECK_FUNCS(inet_aton sigaction sigvec strlcpy strsep strndup alphasort versionsort getpeereid setns)
|
||||
|
||||
# Checks for getsockopt options for getting unix socket peer credentials on
|
||||
# Linux
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ However, releases are made periodically (ca every 1 month) which is more tested.
|
|||
|
||||
A release branch can be made, eg release-4.0 where 4.0.0, 4.0.1 are tagged
|
||||
|
||||
## How the meta-configure stuff works
|
||||
## How the autotools stuff works
|
||||
```
|
||||
configure.ac --.
|
||||
| .------> autoconf* -----> configure
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
# Clixon FAQ
|
||||
|
||||
This FAQ may be outdated. Main [Clixon documentation](clixon-docs.readthedocs.io/) contains more detailed information.
|
||||
|
||||
* [What is Clixon?](#what-is-clixon)
|
||||
* [Why should I use Clixon?](#why-should-i-use-clixon)
|
||||
* [What license is available?](#what-license-is-available)
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
# Clixon roadmap
|
||||
|
||||
- Support for restconf call-home (RFC 8071)
|
||||
- NETCONF
|
||||
- Support for additional Netconf [edit-config modes](https://github.com/clicon/clixon/issues/53)
|
||||
- Netconf [framing](https://github.com/clicon/clixon/issues/50)
|
||||
- [Child ordering](https://github.com/clicon/clixon/issues/22)
|
||||
- [gRPC](https://github.com/clicon/clixon/issues/43)
|
||||
|
||||
|
||||
|
||||
|
|
@ -66,7 +66,7 @@
|
|||
#include <clixon/clixon_backend.h>
|
||||
|
||||
/* Command line options to be passed to getopt(3) */
|
||||
#define BACKEND_EXAMPLE_OPTS "rsS:iuUt:v:"
|
||||
#define BACKEND_EXAMPLE_OPTS "rsS:iuUt:v:n:"
|
||||
|
||||
/*! Variable to control if reset code is run.
|
||||
* The reset code inserts "extra XML" which assumes ietf-interfaces is
|
||||
|
|
@ -119,6 +119,11 @@ static int _transaction_log = 0;
|
|||
static char *_validate_fail_xpath = NULL;
|
||||
static int _validate_fail_toggle = 0; /* fail at validate and commit */
|
||||
|
||||
/* -n <ns>
|
||||
* Network namespace for starting restconf process in another namespace
|
||||
*/
|
||||
static char *_proc_netns = NULL;
|
||||
|
||||
/* forward */
|
||||
static int example_stream_timer_setup(clicon_handle h);
|
||||
|
||||
|
|
@ -1079,6 +1084,9 @@ clixon_plugin_init(clicon_handle h)
|
|||
case 'v': /* validate fail */
|
||||
_validate_fail_xpath = optarg;
|
||||
break;
|
||||
case 'n': /* process restconf namespace*/
|
||||
_proc_netns = optarg;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Example stream initialization:
|
||||
|
|
@ -1142,7 +1150,36 @@ clixon_plugin_init(clicon_handle h)
|
|||
else
|
||||
if (upgrade_callback_register(h, xml_changelog_upgrade, NULL, NULL) < 0)
|
||||
goto done;
|
||||
{
|
||||
char **argv = NULL;
|
||||
int i;
|
||||
int nr;
|
||||
char dbgstr[8];
|
||||
char wwwstr[64];
|
||||
|
||||
nr = 4;
|
||||
if (clicon_debug_get() != 0)
|
||||
nr += 2;
|
||||
if ((argv = calloc(nr, sizeof(char *))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "calloc");
|
||||
goto done;
|
||||
}
|
||||
i = 0;
|
||||
snprintf(wwwstr, sizeof(wwwstr)-1, "%s/clixon_restconf", clicon_option_str(h, "CLICON_WWWDIR"));
|
||||
argv[i++] = wwwstr;
|
||||
argv[i++] = "-f";
|
||||
argv[i++] = clicon_option_str(h, "CLICON_CONFIGFILE");
|
||||
if (clicon_debug_get() != 0){
|
||||
argv[i++] = "-D";
|
||||
snprintf(dbgstr, sizeof(dbgstr)-1, "%d", clicon_debug_get());
|
||||
argv[i++] = dbgstr;
|
||||
}
|
||||
argv[i++] = NULL;
|
||||
if (clixon_process_register(h, "restconf", _proc_netns, argv, nr) < 0)
|
||||
goto done;
|
||||
if (argv != NULL)
|
||||
free(argv);
|
||||
}
|
||||
/* Return plugin API */
|
||||
return &api;
|
||||
done:
|
||||
|
|
|
|||
|
|
@ -39,12 +39,21 @@
|
|||
/* Define to 1 if you have the `cligen' library (-lcligen). */
|
||||
#undef HAVE_LIBCLIGEN
|
||||
|
||||
/* Define to 1 if you have the `crypto' library (-lcrypto). */
|
||||
#undef HAVE_LIBCRYPTO
|
||||
|
||||
/* Define to 1 if you have the `curl' library (-lcurl). */
|
||||
#undef HAVE_LIBCURL
|
||||
|
||||
/* Define to 1 if you have the `dl' library (-ldl). */
|
||||
#undef HAVE_LIBDL
|
||||
|
||||
/* Define to 1 if you have the `event' library (-levent). */
|
||||
#undef HAVE_LIBEVENT
|
||||
|
||||
/* Define to 1 if you have the `event_openssl' library (-levent_openssl). */
|
||||
#undef HAVE_LIBEVENT_OPENSSL
|
||||
|
||||
/* Define to 1 if you have the `evhtp' library (-levhtp). */
|
||||
#undef HAVE_LIBEVHTP
|
||||
|
||||
|
|
@ -54,15 +63,24 @@
|
|||
/* Define to 1 if you have the `m' library (-lm). */
|
||||
#undef HAVE_LIBM
|
||||
|
||||
/* Define to 1 if you have the `pthread' library (-lpthread). */
|
||||
#undef HAVE_LIBPTHREAD
|
||||
|
||||
/* Define to 1 if you have the `socket' library (-lsocket). */
|
||||
#undef HAVE_LIBSOCKET
|
||||
|
||||
/* Define to 1 if you have the `ssl' library (-lssl). */
|
||||
#undef HAVE_LIBSSL
|
||||
|
||||
/* Define to 1 if you have the `xml2' library (-lxml2). */
|
||||
#undef HAVE_LIBXML2
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `setns' function. */
|
||||
#undef HAVE_SETNS
|
||||
|
||||
/* Define to 1 if you have the `sigaction' function. */
|
||||
#undef HAVE_SIGACTION
|
||||
|
||||
|
|
@ -129,6 +147,9 @@
|
|||
/* Restconf package */
|
||||
#undef WITH_RESTCONF
|
||||
|
||||
/* WWW dir for restconf daemon */
|
||||
#undef WWWDIR
|
||||
|
||||
/* WWW user for restconf daemon */
|
||||
#undef WWWUSER
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ extern "C" {
|
|||
#include <clixon/clixon_yang_type.h>
|
||||
#include <clixon/clixon_event.h>
|
||||
#include <clixon/clixon_string.h>
|
||||
#include <clixon/clixon_proc.h>
|
||||
#include <clixon/clixon_file.h>
|
||||
#include <clixon/clixon_xml.h>
|
||||
#include <clixon/clixon_xml_sort.h>
|
||||
|
|
|
|||
51
lib/clixon/clixon_proc.h
Normal file
51
lib/clixon/clixon_proc.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
|
||||
Copyright (C) 2017-2019 Olof Hagsand
|
||||
Copyright (C) 2020 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 *****
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _CLIXON_PROC_H_
|
||||
#define _CLIXON_PROC_H_
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int clixon_proc_run(char **argv, void (outcb)(char *), int doerr);
|
||||
int clixon_proc_background(char **argv, char *netns, pid_t *pid);
|
||||
int clixon_proc_daemon(char **argv, pid_t *pid);
|
||||
int clixon_process_register(clicon_handle h, const char *name, const char *netns, char **argv, int argc);
|
||||
int clixon_process_delete_all(clicon_handle h);
|
||||
int clixon_process_operation(clicon_handle h, char *name, char *op, int *status);
|
||||
|
||||
#endif /* _CLIXON_PROC_H_ */
|
||||
|
|
@ -48,6 +48,7 @@ int set_signal(int signo, void (*handler)(int), void (**oldhandler)(int));
|
|||
void clicon_signal_block(int);
|
||||
void clicon_signal_unblock(int);
|
||||
|
||||
int pidfile_get_fd(FILE *f, pid_t *pid0);
|
||||
int pidfile_get(char *pidfile, pid_t *pid0);
|
||||
int pidfile_write(char *pidfile);
|
||||
int pidfile_zapold(pid_t pid);
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ INCLUDES = -I. @INCLUDES@ -I$(top_srcdir)/lib/clixon -I$(top_srcdir)/include -I$
|
|||
SRC = clixon_sig.c clixon_uid.c clixon_log.c clixon_err.c clixon_event.c \
|
||||
clixon_string.c clixon_regex.c clixon_handle.c clixon_file.c \
|
||||
clixon_xml.c clixon_xml_io.c clixon_xml_sort.c clixon_xml_map.c clixon_xml_vec.c \
|
||||
clixon_xml_bind.c clixon_json.c \
|
||||
clixon_xml_bind.c clixon_json.c clixon_proc.c \
|
||||
clixon_yang.c clixon_yang_type.c clixon_yang_module.c clixon_yang_parse_lib.c \
|
||||
clixon_yang_cardinality.c clixon_xml_changelog.c clixon_xml_nsctx.c \
|
||||
clixon_path.c clixon_validate.c \
|
||||
|
|
|
|||
559
lib/src/clixon_proc.c
Normal file
559
lib/src/clixon_proc.c
Normal file
|
|
@ -0,0 +1,559 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
|
||||
Copyright (C) 2017-2019 Olof Hagsand
|
||||
Copyright (C) 2020 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 *****
|
||||
|
||||
* Processes daemons
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "clixon_config.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_SETNS /* linux network namespaces */
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <grp.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_SETNS /* linux network namespaces */
|
||||
#include <sched.h> /* setns / unshare */
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
/* clicon */
|
||||
#include "clixon_err.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_sig.h"
|
||||
#include "clixon_string.h"
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_proc.h"
|
||||
|
||||
/*
|
||||
* Child process ID
|
||||
* XXX Really shouldn't be a global variable
|
||||
*/
|
||||
static int _clicon_proc_child = 0;
|
||||
|
||||
/*
|
||||
* Make sure child is killed by ctrl-C
|
||||
*/
|
||||
static void
|
||||
clixon_proc_sigint(int sig)
|
||||
{
|
||||
if (_clicon_proc_child > 0)
|
||||
kill(_clicon_proc_child, SIGINT);
|
||||
}
|
||||
|
||||
/*! Fork a child process, setup a pipe between parent and child.
|
||||
* Allowing parent to read the output of the child.
|
||||
* @param[in] doerr If non-zero, stderr will be directed to the pipe as well.
|
||||
* The pipe for the parent to write
|
||||
* to the child is closed and cannot be used.
|
||||
*
|
||||
* When child process is done with the pipe setup, execute the specified
|
||||
* command, execv(argv[0], argv).
|
||||
*
|
||||
* When parent is done with the pipe setup it will read output from the child
|
||||
* until eof. The read output will be sent to the specified output callback,
|
||||
* 'outcb' function.
|
||||
*
|
||||
* @param[in] argv NULL-terminated Argument vector
|
||||
* @param[in] outcb
|
||||
* @param[in] doerr
|
||||
* @retval number Matches (processes affected).
|
||||
* @retval -1 Error.
|
||||
*/
|
||||
int
|
||||
clixon_proc_run(char **argv,
|
||||
void (outcb)(char *),
|
||||
int doerr)
|
||||
{
|
||||
int retval = -1;
|
||||
char buf[512];
|
||||
int outfd[2] = { -1, -1 };
|
||||
int n;
|
||||
int status;
|
||||
pid_t child;
|
||||
sigfn_t oldhandler = NULL;
|
||||
sigset_t oset;
|
||||
int sig = 0;
|
||||
|
||||
if (argv == NULL){
|
||||
clicon_err(OE_UNIX, EINVAL, "argv is NULL");
|
||||
goto done;
|
||||
}
|
||||
if (pipe(outfd) == -1){
|
||||
clicon_err(OE_UNIX, errno, "pipe");
|
||||
goto done;
|
||||
}
|
||||
sigprocmask(0, NULL, &oset);
|
||||
set_signal(SIGINT, clixon_proc_sigint, &oldhandler);
|
||||
sig++;
|
||||
|
||||
if ((child = fork()) < 0) {
|
||||
clicon_err(OE_UNIX, errno, "fork");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (child == 0) { /* Child */
|
||||
|
||||
/* Unblock all signals except TSTP */
|
||||
clicon_signal_unblock(0);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
|
||||
close(outfd[0]); /* Close unused read ends */
|
||||
outfd[0] = -1;
|
||||
|
||||
/* Divert stdout and stderr to pipes */
|
||||
dup2(outfd[1], STDOUT_FILENO);
|
||||
if (doerr)
|
||||
dup2(outfd[1], STDERR_FILENO);
|
||||
|
||||
execvp(argv[0], argv);
|
||||
perror("execvp"); /* Shouldnt reach here */
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Parent */
|
||||
|
||||
/* Close unused write ends */
|
||||
close(outfd[1]);
|
||||
outfd[1] = -1;
|
||||
|
||||
/* Read from pipe */
|
||||
while ((n = read(outfd[0], buf, sizeof(buf)-1)) != 0) {
|
||||
if (n < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
buf[n] = '\0';
|
||||
/* Pass read data to callback function is defined */
|
||||
if (outcb)
|
||||
outcb(buf);
|
||||
}
|
||||
|
||||
/* Wait for child to finish */
|
||||
if(waitpid(child, &status, 0) == child)
|
||||
retval = WEXITSTATUS(status);
|
||||
done:
|
||||
/* Clean up all pipes */
|
||||
if (outfd[0] != -1)
|
||||
close(outfd[0]);
|
||||
if (outfd[1] != -1)
|
||||
close(outfd[1]);
|
||||
if (sig){ /* Restore sigmask and fn */
|
||||
sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||
set_signal(SIGINT, oldhandler, NULL);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Fork and exec a sub-process, let it run and return pid
|
||||
*
|
||||
* @param[in] argv NULL-terminated Argument vector
|
||||
* @param[in] netns Network namespace (or NULL)
|
||||
* @param[out] pid
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error.
|
||||
* @see clixon_proc_daemon
|
||||
* @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)
|
||||
{
|
||||
int retval = -1;
|
||||
pid_t child;
|
||||
int i;
|
||||
sigfn_t oldhandler = NULL;
|
||||
sigset_t oset;
|
||||
struct rlimit rlim = {0, };
|
||||
|
||||
clicon_debug(1, "%s netns:%s", __FUNCTION__, netns);
|
||||
if (argv == NULL){
|
||||
clicon_err(OE_UNIX, EINVAL, "argv is NULL");
|
||||
goto quit;
|
||||
}
|
||||
/* Before here call quit on error */
|
||||
sigprocmask(0, NULL, &oset);
|
||||
set_signal(SIGINT, clixon_proc_sigint, &oldhandler);
|
||||
/* Now call done on error */
|
||||
|
||||
if ((child = fork()) < 0) {
|
||||
clicon_err(OE_UNIX, errno, "fork");
|
||||
goto done;
|
||||
}
|
||||
if (child == 0) { /* Child */
|
||||
char nsfile[PATH_MAX];
|
||||
int nsfd;
|
||||
|
||||
clicon_debug(1, "%s child", __FUNCTION__);
|
||||
clicon_signal_unblock(0);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
if (chdir("/") < 0){
|
||||
clicon_err(OE_UNIX, errno, "chdirq");
|
||||
exit(1);
|
||||
}
|
||||
/* Close open descriptors */
|
||||
if ( ! getrlimit(RLIMIT_NOFILE, &rlim))
|
||||
for (i = 0; i < rlim.rlim_cur; i++)
|
||||
close(i);
|
||||
#ifdef HAVE_SETNS /* linux network namespaces */
|
||||
/* If network namespace is defined, let child join it
|
||||
* XXX: this is work-in-progress
|
||||
*/
|
||||
if (netns != NULL) {
|
||||
snprintf(nsfile, PATH_MAX, "/var/run/netns/%s", netns); /* see man setns / ip netns */
|
||||
clicon_debug(1, "%s nsfile:%s", __FUNCTION__, nsfile);
|
||||
/* Change network namespace */
|
||||
if ((nsfd = open(nsfile, O_RDONLY | O_CLOEXEC)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "open");
|
||||
exit(1);
|
||||
}
|
||||
if (setns(nsfd, 0) < 0){ /* Join that namespace */
|
||||
clicon_err(OE_UNIX, errno, "setns");
|
||||
exit(1);
|
||||
}
|
||||
close(nsfd);
|
||||
if (unshare(CLONE_NEWNS) < 0){
|
||||
clicon_err(OE_UNIX, errno, "unshare");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#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);
|
||||
}
|
||||
/* Not reached */
|
||||
}
|
||||
done:
|
||||
sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||
set_signal(SIGINT, oldhandler, NULL);
|
||||
/* Ensure reap proc child in same session */
|
||||
if (set_signal(SIGCHLD, SIG_IGN, NULL) < 0)
|
||||
goto quit;
|
||||
*pid0 = child;
|
||||
retval = 0;
|
||||
quit:
|
||||
clicon_debug(1, "%s retval:%d child:%d", __FUNCTION__, retval, child);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Double fork and exec a sub-process as a daemon, let it run and return pid
|
||||
*
|
||||
* @param[in] argv NULL-terminated Argument vector
|
||||
* @param[out] pid
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error.
|
||||
* @see clixon_proc_background
|
||||
*/
|
||||
int
|
||||
clixon_proc_daemon(char **argv,
|
||||
pid_t *pid0)
|
||||
{
|
||||
int retval = -1;
|
||||
int status;
|
||||
pid_t child;
|
||||
pid_t pid;
|
||||
int i;
|
||||
struct rlimit rlim = {0, };
|
||||
FILE *fpid = NULL;
|
||||
|
||||
if (argv == NULL){
|
||||
clicon_err(OE_UNIX, EINVAL, "argv is NULL");
|
||||
goto done;
|
||||
}
|
||||
if ((fpid = tmpfile()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "tmpfile");
|
||||
goto done;
|
||||
}
|
||||
if ((child = fork()) < 0) {
|
||||
clicon_err(OE_UNIX, errno, "fork");
|
||||
goto done;
|
||||
}
|
||||
if (child == 0) { /* Child */
|
||||
clicon_signal_unblock(0);
|
||||
if ((pid = fork()) < 0) {
|
||||
clicon_err(OE_UNIX, errno, "fork");
|
||||
return -1;
|
||||
}
|
||||
if (pid == 0) { /* Grandchild, create new session */
|
||||
setsid();
|
||||
if (chdir("/") < 0){
|
||||
clicon_err(OE_UNIX, errno, "chdirq");
|
||||
exit(1);
|
||||
}
|
||||
/* Close open descriptors */
|
||||
if ( ! getrlimit(RLIMIT_NOFILE, &rlim))
|
||||
for (i = 0; i < rlim.rlim_cur; i++)
|
||||
close(i);
|
||||
if (execv(argv[0], argv) < 0) {
|
||||
clicon_err(OE_UNIX, errno, "execv");
|
||||
exit(1);
|
||||
}
|
||||
/* Not reached */
|
||||
}
|
||||
if (fprintf(fpid, "%ld\n", (long) pid) < 1){
|
||||
clicon_err(OE_DAEMON, errno, "fprintf Could not write pid");
|
||||
goto done;
|
||||
}
|
||||
fclose(fpid);
|
||||
// waitpid(pid, &status2, 0);
|
||||
exit(pid);
|
||||
}
|
||||
|
||||
if (waitpid(child, &status, 0) > 0){
|
||||
pidfile_get_fd(fpid, pid0);
|
||||
retval = 0;
|
||||
}
|
||||
fclose(fpid);
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------------*
|
||||
* Process management: start/stop registered processes for internal use
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/*! Register an internal process
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] name Process name
|
||||
* @param[in] netns Namespace netspace (or NULL)
|
||||
* @param[in] argv NULL-terminated vector of vectors
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @note name, netns, argv and its elements are all copied / re-alloced.
|
||||
*/
|
||||
int
|
||||
clixon_process_register(clicon_handle h,
|
||||
const char *name,
|
||||
const char *netns,
|
||||
char **argv,
|
||||
int argc)
|
||||
{
|
||||
int retval = -1;
|
||||
process_entry_t *pe = NULL;
|
||||
int i;
|
||||
|
||||
if (name == NULL){
|
||||
clicon_err(OE_DB, EINVAL, "name is NULL");
|
||||
goto done;
|
||||
}
|
||||
if (argv == NULL){
|
||||
clicon_err(OE_DB, EINVAL, "argv is NULL");
|
||||
goto done;
|
||||
}
|
||||
if ((pe = malloc(sizeof(process_entry_t))) == NULL) {
|
||||
clicon_err(OE_DB, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(pe, 0, sizeof(*pe));
|
||||
if ((pe->pe_name = strdup(name)) == NULL){
|
||||
clicon_err(OE_DB, errno, "strdup name");
|
||||
goto done;
|
||||
}
|
||||
if (netns && (pe->pe_netns = strdup(netns)) == NULL){
|
||||
clicon_err(OE_DB, errno, "strdup netns");
|
||||
goto done;
|
||||
}
|
||||
if ((pe->pe_argv = calloc(argc, sizeof(char *))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "calloc");
|
||||
goto done;
|
||||
}
|
||||
for (i=0; i<argc; i++){
|
||||
if (argv[i] != NULL &&
|
||||
(pe->pe_argv[i] = strdup(argv[i])) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
}
|
||||
}
|
||||
ADDQ(pe, proc_entry_list);
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Delete all Upgrade callbacks
|
||||
*/
|
||||
int
|
||||
clixon_process_delete_all(clicon_handle h)
|
||||
{
|
||||
process_entry_t *pe;
|
||||
char **pa;
|
||||
|
||||
while((pe = proc_entry_list) != NULL) {
|
||||
DELQ(pe, proc_entry_list, process_entry_t *);
|
||||
if (pe->pe_name)
|
||||
free(pe->pe_name);
|
||||
if (pe->pe_netns)
|
||||
free(pe->pe_netns);
|
||||
if (pe->pe_argv){
|
||||
for (pa = pe->pe_argv; *pa != NULL; pa++){
|
||||
if (*pa)
|
||||
free(*pa);
|
||||
}
|
||||
free(pe->pe_argv);
|
||||
}
|
||||
free(pe);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
proc_op_run(process_entry_t *pe,
|
||||
int *runp)
|
||||
{
|
||||
int retval = -1;
|
||||
int run;
|
||||
pid_t pid;
|
||||
|
||||
run = 0;
|
||||
if ((pid = pe->pe_pid) != 0){ /* if 0 stopped */
|
||||
/* Check if lives */
|
||||
run = 1;
|
||||
if ((kill(pid, 0)) < 0){
|
||||
if (errno == ESRCH){
|
||||
run = 0;
|
||||
}
|
||||
else{
|
||||
clicon_err(OE_UNIX, errno, "kill(%d)", pid);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (runp)
|
||||
*runp = run;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Upgrade specific module identified by namespace, search matching callbacks
|
||||
*
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] name Name of process
|
||||
* @param[in] op start, stop.
|
||||
* @param[out] status true if process is running / false if not running on entry
|
||||
* @retval -1 Error
|
||||
* @retval 0 OK
|
||||
* @see upgrade_callback_reg_fn which registers the callbacks
|
||||
*/
|
||||
int
|
||||
clixon_process_operation(clicon_handle h,
|
||||
char *name,
|
||||
char *op,
|
||||
int *status)
|
||||
{
|
||||
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)
|
||||
goto ok;
|
||||
pe = proc_entry_list;
|
||||
do {
|
||||
if (strcmp(pe->pe_name, name) == 0){
|
||||
/* Check if running */
|
||||
if (proc_op_run(pe, &run) < 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 */
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
@ -80,7 +80,6 @@ set_signal(int signo,
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*! Block signal.
|
||||
* @param[in] sig Signal number to block, If 0, block all signals
|
||||
*/
|
||||
|
|
@ -117,34 +116,50 @@ clicon_signal_unblock (int sig)
|
|||
sigprocmask (SIG_UNBLOCK, &set, NULL);
|
||||
}
|
||||
|
||||
/*! Read pidfile and return pid using file descriptor
|
||||
*
|
||||
* @param[in] pidfile Name of pidfile
|
||||
* @param[out] pid Process id of (eventual) existing daemon process
|
||||
* @retval 0 OK. if pid > 0 old process exists w that pid
|
||||
* @retval -1 Error, and clicon_err() called
|
||||
*/
|
||||
int
|
||||
pidfile_get_fd(FILE *f,
|
||||
pid_t *pid0)
|
||||
{
|
||||
char *ptr;
|
||||
char buf[32];
|
||||
pid_t pid;
|
||||
|
||||
*pid0 = 0;
|
||||
ptr = fgets(buf, sizeof(buf), f);
|
||||
if (ptr != NULL && (pid = atoi(ptr)) > 1) {
|
||||
if (kill(pid, 0) == 0 || errno != ESRCH) {
|
||||
/* Yes there is a process */
|
||||
*pid0 = pid;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Read pidfile and return pid, if any
|
||||
*
|
||||
* @param[in] pidfile Name of pidfile
|
||||
* @param[out] pid0 Process id of (eventual) existing daemon process
|
||||
* @param[out] pid Process id of (eventual) existing daemon process
|
||||
* @retval 0 OK. if pid > 0 old process exists w that pid
|
||||
* @retval -1 Error, and clicon_err() called
|
||||
*/
|
||||
int
|
||||
pidfile_get(char *pidfile,
|
||||
pid_t *pid0)
|
||||
pid_t *pid)
|
||||
{
|
||||
FILE *f;
|
||||
char *ptr;
|
||||
char buf[32];
|
||||
pid_t pid;
|
||||
|
||||
if ((f = fopen (pidfile, "r")) != NULL){
|
||||
ptr = fgets(buf, sizeof(buf), f);
|
||||
fclose (f);
|
||||
if (ptr != NULL && (pid = atoi (ptr)) > 1) {
|
||||
if (kill (pid, 0) == 0 || errno != ESRCH) {
|
||||
/* Yes there is a process */
|
||||
*pid0 = pid;
|
||||
return 0;
|
||||
*pid = 0;
|
||||
if ((f = fopen(pidfile, "r")) != NULL){
|
||||
pidfile_get_fd(f, pid);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
*pid0 = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -169,7 +184,7 @@ pidfile_zapold(pid_t pid)
|
|||
clicon_err(OE_UNIX, errno, "usleep");
|
||||
goto done;
|
||||
}
|
||||
if ((kill (pid, 0)) < 0){
|
||||
if ((kill(pid, 0)) < 0){
|
||||
if (errno != ESRCH){
|
||||
clicon_err(OE_DAEMON, errno, "Killing old demon");
|
||||
goto done;
|
||||
|
|
|
|||
188
test/test_restconf_rpc.sh
Executable file
188
test/test_restconf_rpc.sh
Executable file
|
|
@ -0,0 +1,188 @@
|
|||
#!/usr/bin/env bash
|
||||
# Restconf direct start/stop using RPC (as alternative to systemd or other)
|
||||
# Also try ip netns
|
||||
|
||||
# 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
|
||||
|
||||
# Cant get it to work in the general case, single tests work fine
|
||||
# More specifically, if mem.sh background netconf, netconf crashes
|
||||
if [ $valgrindtest -ne 0 ]; then
|
||||
echo "...skipped "
|
||||
return 0 # skip
|
||||
fi
|
||||
|
||||
cat <<EOF > $cfg
|
||||
<clixon-config xmlns="http://clicon.org/config">
|
||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||
<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_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
||||
<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>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||
<CLICON_MODULE_LIBRARY_RFC7895>true</CLICON_MODULE_LIBRARY_RFC7895>
|
||||
$RESTCONFIG
|
||||
</clixon-config>
|
||||
EOF
|
||||
|
||||
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
|
||||
|
||||
new "waiting"
|
||||
wait_backend
|
||||
fi
|
||||
|
||||
new "kill old restconf"
|
||||
stop_restconf_pre
|
||||
|
||||
new "1)check no restconf"
|
||||
ps=$(ps aux|grep "$WWWDIR/clixon_restconf" | grep -v grep)
|
||||
if [ -n "$ps" ]; then
|
||||
err "No restconf running" "$ps"
|
||||
fi
|
||||
|
||||
new "2)check status off"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>status</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><status xmlns=\"http://clicon.org/lib\">false</status></rpc-reply>]]>]]>"
|
||||
|
||||
new "start restconf"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>start</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>"
|
||||
|
||||
new "3)check restconf on"
|
||||
ps=$(ps aux|grep "$WWWDIR/clixon_restconf -f $cfg" | grep -v grep)
|
||||
if [ -z "$ps" ]; then
|
||||
err "restconf running"
|
||||
fi
|
||||
|
||||
new "4)check status on"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>status</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><status xmlns=\"http://clicon.org/lib\">true</status></rpc-reply>]]>]]>"
|
||||
|
||||
new "stop restconf"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>stop</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>"
|
||||
|
||||
new "start restconf again"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>start</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>"
|
||||
|
||||
new "5)check restconf on"
|
||||
ps=$(ps aux|grep "$WWWDIR/clixon_restconf -f $cfg" | grep -v grep)
|
||||
if [ -z "$ps" ]; then
|
||||
err "A restconf running"
|
||||
fi
|
||||
|
||||
new "kill restconf"
|
||||
stop_restconf_pre
|
||||
|
||||
new "6)check no restconf"
|
||||
ps=$(ps aux|grep "$WWWDIR/clixon_restconf" | grep -v grep)
|
||||
if [ -n "$ps" ]; then
|
||||
err "No restconf running" "$ps"
|
||||
fi
|
||||
|
||||
new "restart restconf"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>restart</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>"
|
||||
|
||||
new "7)check status on"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>status</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><status xmlns=\"http://clicon.org/lib\">true</status></rpc-reply>]]>]]>"
|
||||
|
||||
pid0=$(pgrep clixon_restconf)
|
||||
|
||||
new "restart restconf"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>restart</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>"
|
||||
|
||||
new "8)check status on"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>status</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><status xmlns=\"http://clicon.org/lib\">true</status></rpc-reply>]]>]]>"
|
||||
|
||||
new "9)check new pid"
|
||||
pid1=$(pgrep clixon_restconf)
|
||||
if [ $pid0 -eq $pid1 ]; then
|
||||
err "Different pids" "pid0:$pid0 = pid1:$pid1"
|
||||
fi
|
||||
|
||||
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
|
||||
|
||||
new "10)check no restconf"
|
||||
ps=$(ps aux|grep "$WWWDIR/clixon_restconf" | grep -v grep)
|
||||
if [ -n "$ps" ]; then
|
||||
err "No restconf running" "$ps"
|
||||
fi
|
||||
fi
|
||||
|
||||
if false; then # Work in progress
|
||||
#-------------------------------
|
||||
# Now in a separate network namespace
|
||||
new "restconf rpc in network namespace"
|
||||
netns=xxx
|
||||
sudo ip netns delete $netns
|
||||
#sudo ip netns add $netns
|
||||
|
||||
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 -- -n $netns"
|
||||
start_backend -s init -f $cfg -- -n $netns
|
||||
|
||||
new "waiting"
|
||||
wait_backend
|
||||
fi
|
||||
|
||||
new "kill old restconf"
|
||||
stop_restconf_pre
|
||||
|
||||
new "netconf start restconf"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>start</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>"
|
||||
|
||||
new "10)check status on"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>status</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><status xmlns=\"http://clicon.org/lib\">true</status></rpc-reply>]]>]]>"
|
||||
|
||||
new "stop restconf"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><process-control xmlns=\"http://clicon.org/lib\"><name>restconf</name><operation>stop</operation></process-control></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>"
|
||||
|
||||
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
|
||||
|
||||
new "11)check no restconf"
|
||||
ps=$(ps aux|grep "$WWWDIR/clixon_restconf" | grep -v grep)
|
||||
fi
|
||||
|
||||
sudo ip netns delete $netns
|
||||
|
||||
fi # namespaces
|
||||
|
||||
rm -rf $dir
|
||||
|
|
@ -164,14 +164,10 @@ module clixon-lib {
|
|||
description
|
||||
"One of the strings 'start', 'stop', 'restart', or 'status'.";
|
||||
}
|
||||
leaf namespace {
|
||||
type string;
|
||||
description
|
||||
"Network namespace.";
|
||||
}
|
||||
}
|
||||
output {
|
||||
leaf status {
|
||||
description "For status: is the process running?";
|
||||
type boolean;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue