* Fixed: Configure option CLICON_RESTCONF_PATH was marked as obsolete but was still used.

* `CLICON_RESTCONF_PATH` is now obsolete for sure
    * Instead if you use fgci/nginx:
      * Use `restconf/fcgi-socket`
      * Ensure `<CLICON_FEATURE>clixon-restconf:fcgi</CLICON_FEATURE>` is set
* Added default values to restconf-config and save fcgi-socket-path in memory
This commit is contained in:
Olof hagsand 2021-12-31 17:05:39 +01:00
parent 1808015cf6
commit 50ac510803
10 changed files with 163 additions and 96 deletions

View file

@ -64,6 +64,11 @@ Users may have to change how they access the system
* Fixed: Configure option `CLICON_RESTCONF_PRETTY` was marked as obsolete but was still used.
* `CLICON_RESTCONF_PRETTY` is now obsolete for sure
* Instead restconf/pretty is used with API function restconf_pretty_get()
* Fixed: Configure option `CLICON_RESTCONF_PATH` was marked as obsolete but was still used.
* `CLICON_RESTCONF_PATH` is now obsolete for sure
* Instead if you use fgci/nginx:
* Use `restconf/fcgi-socket`
* Ensure `<CLICON_FEATURE>clixon-restconf:fcgi</CLICON_FEATURE>` is set
### Minor features

View file

@ -94,6 +94,7 @@ struct restconf_handle {
clicon_hash_t *rh_params; /* restconf parameters, including http headers */
clixon_auth_type_t rh_auth_type; /* authentication type */
int rh_pretty; /* pretty-print for http replies */
char *rh_fcgi_socket; /* if-feature fcgi, XXX: use WITH_RESTCONF_FCGI ? */
};
/*! Creates and returns a clicon config handle for other CLICON API calls
@ -115,6 +116,10 @@ restconf_handle_init(void)
int
restconf_handle_exit(clicon_handle h)
{
struct restconf_handle *rh = handle(h);
if (rh->rh_fcgi_socket)
free(rh->rh_fcgi_socket);
clicon_handle_exit(h); /* frees h and options (and streams) */
return 0;
}
@ -240,3 +245,36 @@ restconf_pretty_set(clicon_handle h,
rh->rh_pretty = pretty;
return 0;
}
/*! Get restconf fcgi socket path
* @param[in] h Clicon handle
* @retval socketpath
*/
char*
restconf_fcgi_socket_get(clicon_handle h)
{
struct restconf_handle *rh = handle(h);
return rh->rh_fcgi_socket;
}
/*! Set restconf fcgi socketpath
* @param[in] h Clicon handle
* @param[in] name Data name
* @param[in] val Data value as null-terminated string
* @retval 0 OK
* @retval -1 Error
* Currently using clixon runtime data but there is risk for colliding names
*/
int
restconf_fcgi_socket_set(clicon_handle h,
char *socketpath)
{
struct restconf_handle *rh = handle(h);
if ((rh->rh_fcgi_socket = strdup(socketpath)) == NULL){
clicon_err(OE_RESTCONF, errno, "strdup");
return -1;
}
return 0;
}

View file

@ -51,5 +51,7 @@ clixon_auth_type_t restconf_auth_type_get(clicon_handle h);
int restconf_auth_type_set(clicon_handle h, clixon_auth_type_t type);
int restconf_pretty_get(clicon_handle h);
int restconf_pretty_set(clicon_handle h, int pretty);
char *restconf_fcgi_socket_get(clicon_handle h);
int restconf_fcgi_socket_set(clicon_handle h, char *socketpath);
#endif /* _RESTCONF_HANDLE_H_ */

View file

@ -754,7 +754,15 @@ restconf_config_init(clicon_handle h,
char *bstr;
cvec *nsc = NULL;
int auth_type;
yang_stmt *yspec;
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No DB_SPEC");
goto done;
}
/* Apply default values (removed in clear function) */
if (xml_default_recurse(xrestconf, 0) < 0)
goto done;
if ((x = xpath_first(xrestconf, nsc, "enable")) != NULL &&
(enable = xml_body(x)) != NULL){
if (strcmp(enable, "false") == 0){
@ -778,6 +786,11 @@ restconf_config_init(clicon_handle h,
else if (strcmp(bstr, "false") == 0)
restconf_pretty_set(h, 0);
}
if ((x = xpath_first(xrestconf, nsc, "fcgi-socket")) != NULL &&
(bstr = xml_body(x)) != NULL){
if (restconf_fcgi_socket_set(h, bstr) < 0)
goto done;
}
retval = 1;
done:
return retval;

View file

@ -125,6 +125,90 @@ fcgi_params_set(clicon_handle h,
return retval;
}
/*! Try to get config: inline, config-file or query backend
*/
static int
restconf_main_config(clicon_handle h,
yang_stmt *yspec,
const char *inline_config)
{
int retval = -1;
struct passwd *pw;
cxobj *xconfig = NULL;
cxobj *xrestconf = NULL;
uint32_t id = 0;
cxobj *xerr = NULL;
int configure_done = 0; /* First try local then backend */
cvec *nsc = NULL;
int ret;
/* 1. try inline configure option */
if (inline_config != NULL && strlen(inline_config)){
clicon_debug(1, "restconf_main_fcgi using restconf inline config");
if ((ret = clixon_xml_parse_string(inline_config, YB_MODULE, yspec, &xrestconf, &xerr)) < 0)
goto done;
if (ret == 0){
clixon_netconf_error(xerr, "Inline restconf config", NULL);
goto done;
}
/* Replace parent w first child */
if (xml_rootchild(xrestconf, 0, &xrestconf) < 0)
goto done;
}
else if (clicon_option_bool(h, "CLICON_BACKEND_RESTCONF_PROCESS") == 0){
/* 2. If not read from backend, try to get restconf config from local config-file */
xrestconf = clicon_conf_restconf(h);
}
/* 3. If no local config, or it is disabled, try to query backend of config. */
else {
/* Loop to wait for backend starting, try again if not done */
while (1){
if (clicon_hello_req(h, &id) < 0){
if (errno == ENOENT){
fprintf(stderr, "waiting");
sleep(1);
continue;
}
clicon_err(OE_UNIX, errno, "clicon_session_id_get");
goto done;
}
clicon_session_id_set(h, id);
break;
}
if ((nsc = xml_nsctx_init(NULL, CLIXON_RESTCONF_NS)) == NULL)
goto done;
if ((pw = getpwuid(getuid())) == NULL){
clicon_err(OE_UNIX, errno, "getpwuid");
goto done;
}
if (clicon_rpc_get_config(h, pw->pw_name, "running", "/restconf", nsc, &xconfig) < 0)
goto done;
if ((xerr = xpath_first(xconfig, NULL, "/rpc-error")) != NULL){
clixon_netconf_error(xerr, "Get backend restconf config", NULL);
goto done;
}
/* Extract restconf configuration */
xrestconf = xpath_first(xconfig, nsc, "restconf");
}
configure_done = 0;
if (xrestconf != NULL &&
(configure_done = restconf_config_init(h, xrestconf)) < 0)
goto done;
if (!configure_done){ /* Query backend of config. */
clicon_err(OE_DAEMON, EFAULT, "Restconf daemon config not found or disabled");
goto done;
}
retval = 0;
done:
if (nsc)
cvec_free(nsc);
if (inline_config != NULL && strlen(inline_config) && xrestconf)
xml_free(xrestconf);
if (xconfig)
xml_free(xconfig);
return retval;
}
/* XXX Need global variable to for SIGCHLD signal handler
*/
static clicon_handle _CLICON_HANDLE = NULL;
@ -221,20 +305,11 @@ main(int argc,
int finish = 0;
char *str;
clixon_plugin_t *cp = NULL;
uint32_t id = 0;
cvec *nsctx_global = NULL; /* Global namespace context */
size_t cligen_buflen;
size_t cligen_bufthreshold;
int dbg = 0;
int ret;
cxobj *xrestconf1 = NULL; /* Inline */
cxobj *xrestconf2 = NULL; /* Local config file */
cxobj *xconfig3 = NULL;
cxobj *xrestconf3 = NULL; /* Config from backend */
int configure_done = 0; /* First try local then backend */
cvec *nsc = NULL;
cxobj *xerr = NULL;
struct passwd *pw;
char *wwwuser;
char *inline_config = NULL;
@ -457,83 +532,13 @@ main(int argc,
if (clixon_plugin_start_all(h) < 0)
goto done;
/* 1. try inline configure option */
if (inline_config != NULL && strlen(inline_config)){
clicon_debug(1, "restconf_main_fcgi using restconf inline config");
if ((ret = clixon_xml_parse_string(inline_config, YB_MODULE, yspec, &xrestconf1, &xerr)) < 0)
goto done;
if (ret == 0){
clixon_netconf_error(xerr, "Inline restconf config", NULL);
goto done;
}
/* Replace parent w first child */
if (xml_rootchild(xrestconf1, 0, &xrestconf1) < 0)
goto done;
if ((ret = restconf_config_init(h, xrestconf1)) < 0)
goto done;
if (ret == 1)
configure_done = 1;
}
else if (clicon_option_bool(h, "CLICON_BACKEND_RESTCONF_PROCESS") == 0){
/* 2. If not read from backend, try to get restconf config from local config-file */
if ((xrestconf2 = clicon_conf_restconf(h)) != NULL){
if ((ret = restconf_config_init(h, xrestconf2)) < 0)
goto done;
if (ret == 1)
configure_done = 1;
}
}
/* 3. If no local config, or it is disabled, try to query backend of config. */
else {
/* Loop to wait for backend starting, try again if not done */
while (1){
if (clicon_hello_req(h, &id) < 0){
if (errno == ENOENT){
fprintf(stderr, "waiting");
sleep(1);
continue;
}
clicon_err(OE_UNIX, errno, "clicon_session_id_get");
goto done;
}
clicon_session_id_set(h, id);
break;
}
if ((nsc = xml_nsctx_init(NULL, CLIXON_RESTCONF_NS)) == NULL)
goto done;
if ((pw = getpwuid(getuid())) == NULL){
clicon_err(OE_UNIX, errno, "getpwuid");
goto done;
}
if (clicon_rpc_get_config(h, pw->pw_name, "running", "/restconf", nsc, &xconfig3) < 0)
goto done;
if ((xerr = xpath_first(xconfig3, NULL, "/rpc-error")) != NULL){
clixon_netconf_error(xerr, "Get backend restconf config", NULL);
goto done;
}
/* Extract restconf configuration */
if ((xrestconf3 = xpath_first(xconfig3, nsc, "restconf")) != NULL){
if ((ret = restconf_config_init(h, xrestconf3)) < 0)
goto done;
if (ret == 1)
configure_done = 1;
}
}
if (!configure_done){ /* Query backend of config. */
clicon_err(OE_DAEMON, EFAULT, "Restconf daemon config not found or disabled");
/* Try to get config: inline, config-file or query backend */
if (restconf_main_config(h, yspec, inline_config) < 0)
goto done;
}
/* XXX see restconf_config_init access directly */
if ((sockpath = clicon_option_str(h, "CLICON_RESTCONF_PATH")) == NULL){
clicon_err(OE_CFG, errno, "No CLICON_RESTCONF_PATH in clixon configure file");
if ((sockpath = restconf_fcgi_socket_get(h)) == NULL){
clicon_err(OE_CFG, 0, "No restconf fcgi-socket (have you set FEATURE fcgi in config?)");
goto done;
}
/* XXX CLICON_RESTCONF_PATH is marked as obsolete and should use
* fcgi-socket in clixon-restconf.yang instead */
if ((sockpath = clicon_option_str(h, "CLICON_RESTCONF_PATH")) == NULL){
clicon_err(OE_CFG, errno, "No CLICON_RESTCONF_PATH in clixon configure file");
goto done;
}
if (FCGX_Init() != 0){ /* How to cleanup memory after this? */
clicon_err(OE_CFG, errno, "FCGX_Init");
goto done;
@ -649,12 +654,6 @@ main(int argc,
} /* while */
retval = 0;
done:
if (xrestconf1)
xml_free(xrestconf1);
if (xconfig3)
xml_free(xconfig3);
if (nsc)
cvec_free(nsc);
stream_child_freeall(h);
restconf_terminate(h);
return retval;

View file

@ -226,8 +226,13 @@ function restconf_config()
AUTH=$1
PRETTY=$2
if [ ${WITH_RESTCONF} = "fcgi" ]; then
FEATURES="<CLICON_FEATURE>clixon-restconf:fcgi</CLICON_FEATURE>"
else
FEATURES=""
fi
if [ $RCPROTO = http ]; then
echo "<restconf><enable>true</enable><auth-type>$AUTH</auth-type><pretty>$PRETTY</pretty><debug>$DBG</debug><socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket></restconf>"
echo "${FEATURES}<restconf><enable>true</enable><auth-type>$AUTH</auth-type><pretty>$PRETTY</pretty><debug>$DBG</debug><socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket></restconf>"
else
certdir=$dir/certs
if [ ! -f ${dir}/clixon-server-crt.pem ]; then
@ -240,7 +245,7 @@ function restconf_config()
cacerts $cakey $cacert
servercerts $cakey $cacert $srvkey $srvcert
fi
echo "<restconf><enable>true</enable><auth-type>$AUTH</auth-type><pretty>$PRETTY</pretty><server-cert-path>${certdir}/clixon-server-crt.pem</server-cert-path><server-key-path>${certdir}/clixon-server-key.pem</server-key-path><server-ca-cert-path>${certdir}/clixon-ca-crt.pem</server-ca-cert-path><debug>$DBG</debug><socket><namespace>default</namespace><address>0.0.0.0</address><port>443</port><ssl>true</ssl></socket></restconf>"
echo "${FEATURES}<restconf><enable>true</enable><auth-type>$AUTH</auth-type><pretty>$PRETTY</pretty><server-cert-path>${certdir}/clixon-server-crt.pem</server-cert-path><server-key-path>${certdir}/clixon-server-key.pem</server-key-path><server-ca-cert-path>${certdir}/clixon-ca-crt.pem</server-ca-cert-path><debug>$DBG</debug><socket><namespace>default</namespace><address>0.0.0.0</address><port>443</port><ssl>true</ssl></socket></restconf>"
fi
}

View file

@ -537,7 +537,9 @@ function testrun()
}
# Go thru all combinations of IPv4/IPv6, http/https, local/backend config
if ${HAVE_LIBEVHTP}; then
if [ "${WITH_RESTCONF}" = "fcgi" ]; then
protos="http"
elif ${HAVE_LIBEVHTP}; then
protos="http" # No plain http for http/2 only
fi
if [ "${WITH_RESTCONF}" = "native" ]; then

View file

@ -23,7 +23,8 @@
# Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
if ! ${HAVE_LIBEVHTP}; then
# Does not work with evhtpnative http/2-only
if [ "${WITH_RESTCONF}" = "native" -a ${HAVE_LIBEVHTP} = false ]; then
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
if [ "$s" = $0 ]; then exit 0; else return 0; fi
fi

View file

@ -14,7 +14,8 @@
# Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
if ! ${HAVE_LIBEVHTP}; then
# Does not work with evhtpnative http/2-only
if [ "${WITH_RESTCONF}" = "native" -a ${HAVE_LIBEVHTP} = false ]; then
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
if [ "$s" = $0 ]; then exit 0; else return 0; fi
fi

View file

@ -25,7 +25,8 @@
# Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
if ! ${HAVE_LIBEVHTP}; then
# Does not work with evhtpnative http/2-only
if [ "${WITH_RESTCONF}" = "native" -a ${HAVE_LIBEVHTP} = false ]; then
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
if [ "$s" = $0 ]; then exit 0; else return 0; fi
fi