xml config default; api_path_fmt2api_path cleanup

This commit is contained in:
Olof hagsand 2017-10-03 22:41:12 +02:00
parent e1b7ea8449
commit 5cea5fa768
10 changed files with 165 additions and 70 deletions

View file

@ -250,6 +250,7 @@ main(int argc, char **argv)
/* Initiate CLICON handle */ /* Initiate CLICON handle */
if ((h = cli_handle_init()) == NULL) if ((h = cli_handle_init()) == NULL)
goto done; goto done;
if (cli_plugin_init(h) != 0) if (cli_plugin_init(h) != 0)
goto done; goto done;
once = 0; once = 0;
@ -486,6 +487,7 @@ main(int argc, char **argv)
// Gets in your face if we log on stderr // Gets in your face if we log on stderr
clicon_log_init(__PROGRAM__, LOG_INFO, 0); /* Log on syslog no stderr */ clicon_log_init(__PROGRAM__, LOG_INFO, 0); /* Log on syslog no stderr */
clicon_log(LOG_NOTICE, "%s: %u Terminated\n", __PROGRAM__, getpid()); clicon_log(LOG_NOTICE, "%s: %u Terminated\n", __PROGRAM__, getpid());
if (h)
cli_terminate(h); cli_terminate(h);
return 0; return 0;

View file

@ -99,7 +99,8 @@ expand_dbvar(void *h,
cvec *helptexts) cvec *helptexts)
{ {
int retval = -1; int retval = -1;
char *api_path; char *api_path_fmt;
char *api_path = NULL;
char *dbstr; char *dbstr;
cxobj *xt = NULL; cxobj *xt = NULL;
char *xpath = NULL; char *xpath = NULL;
@ -145,13 +146,16 @@ expand_dbvar(void *h,
clicon_err(OE_PLUGIN, 0, "%s: Error when accessing argument <api_path>"); clicon_err(OE_PLUGIN, 0, "%s: Error when accessing argument <api_path>");
goto done; goto done;
} }
api_path = cv_string_get(cv); api_path_fmt = cv_string_get(cv);
/* api_path = /interface/%s/address/%s /* api_path_fmt = /interface/%s/address/%s
--> ^/interface/eth0/address/.*$ --> ^/interface/eth0/address/.*$
--> /interface/[name=eth0]/address --> /interface/[name=eth0]/address
*/ */
if (api_path_fmt2xpath(api_path, cvv, &xpath) < 0) if (api_path_fmt2xpath(api_path_fmt, cvv, &xpath) < 0)
goto done; goto done;
if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path) < 0)
goto done;
/* XXX read whole configuration, why not send xpath? */ /* XXX read whole configuration, why not send xpath? */
if (clicon_rpc_get_config(h, dbstr, "/", &xt) < 0) if (clicon_rpc_get_config(h, dbstr, "/", &xt) < 0)
goto done; goto done;
@ -165,7 +169,7 @@ expand_dbvar(void *h,
if ((xtop = xml_new("config", NULL)) == NULL) if ((xtop = xml_new("config", NULL)) == NULL)
goto done; goto done;
xbot = xtop; xbot = xtop;
/* This is primarily to get "y", XXX xbot can be broken (contains =%s) /* This is primarily to get "y",
* xpath2xml would have worked!! * xpath2xml would have worked!!
*/ */
if (api_path && api_path2xml(api_path, yspec, xtop, 0, &xbot, &y) < 0) if (api_path && api_path2xml(api_path, yspec, xtop, 0, &xbot, &y) < 0)
@ -236,6 +240,8 @@ expand_dbvar(void *h,
} }
retval = 0; retval = 0;
done: done:
if (api_path)
free(api_path);
if (xvec) if (xvec)
free(xvec); free(xvec);
if (xtop) if (xtop)

View file

@ -31,7 +31,7 @@ sudo /etc/init.d nginx start
Start clixon restconf daemon Start clixon restconf daemon
``` ```
olof@vandal> sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/routing.conf " -s /bin/sh www-data olof@vandal> sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/routing.xml " -s /bin/sh www-data
``` ```
Make restconf calls with curl Make restconf calls with curl
@ -67,7 +67,7 @@ curl -sX POST -d '{"interfaces":{"interface":{"name":"eth1","type":"eth","enable
Start the restconf fastcgi program with debug flag: Start the restconf fastcgi program with debug flag:
``` ```
sudo su -c "/www-data/clixon_restconf -Df /usr/local/etc/routing.conf" -s /bin/sh www-data sudo su -c "/www-data/clixon_restconf -Df /usr/local/etc/routing.xml" -s /bin/sh www-data
``` ```
Look at syslog: Look at syslog:
``` ```

View file

@ -39,7 +39,7 @@
* sudo apt-get install libfcgi-dev * sudo apt-get install libfcgi-dev
* gcc -o fastcgi fastcgi.c -lfcgi * gcc -o fastcgi fastcgi.c -lfcgi
* sudo su -c "/www-data/clixon_restconf -Df /usr/local/etc/routing.conf " -s /bin/sh www-data * sudo su -c "/www-data/clixon_restconf -Df /usr/local/etc/routing.xml " -s /bin/sh www-data
* This is the interface: * This is the interface:
* api/data/profile=<name>/metric=<name> PUT data:enable=<flag> * api/data/profile=<name>/metric=<name> PUT data:enable=<flag>

View file

@ -39,7 +39,7 @@
* sudo apt-get install libfcgi-dev * sudo apt-get install libfcgi-dev
* gcc -o fastcgi fastcgi.c -lfcgi * gcc -o fastcgi fastcgi.c -lfcgi
* sudo su -c "/www-data/clixon_restconf -Df /usr/local/etc/routing.conf " -s /bin/sh www-data * sudo su -c "/www-data/clixon_restconf -Df /usr/local/etc/routing.xml " -s /bin/sh www-data
* This is the interface: * This is the interface:
* api/data/profile=<name>/metric=<name> PUT data:enable=<flag> * api/data/profile=<name>/metric=<name> PUT data:enable=<flag>

View file

@ -59,9 +59,9 @@ Build using 'make doc' and aim your browser at doc/html/index.html or
use the web resource: http://clicon.org/ref/index.html use the web resource: http://clicon.org/ref/index.html
## How do you run the example? ## How do you run the example?
- Start a backend server: 'clixon_backend -Ff /usr/local/etc/routing.conf' - Start a backend server: 'clixon_backend -Ff /usr/local/etc/routing.xml'
- Start a cli session: clixon_cli -f /usr/local/etc/routing.conf - Start a cli session: clixon_cli -f /usr/local/etc/routing.xml
- Start a netconf session: clixon_netconf -f /usr/local/etc/routing.conf - Start a netconf session: clixon_netconf -f /usr/local/etc/routing.xml
## How is configuration data stored? ## How is configuration data stored?
Configuration data is stored in an XML datastore. The default is a Configuration data is stored in an XML datastore. The default is a
@ -82,10 +82,7 @@ is the core functionality of a clixon system.
## What is a Clixon configuration file? ## What is a Clixon configuration file?
Clixon options are stored in a configuration file you must specify Clixon options are stored in a configuration file you must specify
when you start a backend or client using -f. The example configuration when you start a backend or client using -f. The example configuration
file is /usr/local/etc/routing.conf. file is installed at /usr/local/etc/routing.xml.
This file is generated from the base source clixon.conf.cpp.cpp and
is merged with local configuration files, such as routing.conf.local.
This is slightly confusing and could be improved.
## Can I run Clixon as docker containers? ## Can I run Clixon as docker containers?
Yes, the example works as docker containers as well. backend and cli needs a Yes, the example works as docker containers as well. backend and cli needs a
@ -107,12 +104,12 @@ You may also push the containers with 'make push' but you may then consider chan
As an alternative to cli configuration, you can use netconf. Easiest is to just pipe netconf commands to the clixon_netconf application. As an alternative to cli configuration, you can use netconf. Easiest is to just pipe netconf commands to the clixon_netconf application.
Example: Example:
echo "<rpc><get-config><source><candidate/></source><configuration/></get-config></rpc>]]>]]>" | clixon_netconf -f /usr/local/etc/routing.conf echo "<rpc><get-config><source><candidate/></source><configuration/></get-config></rpc>]]>]]>" | clixon_netconf -f /usr/local/etc/routing.xml
However, more useful is to run clixon_netconf as an SSH However, more useful is to run clixon_netconf as an SSH
subsystem. Register the subsystem in /etc/sshd_config: subsystem. Register the subsystem in /etc/sshd_config:
``` ```
Subsystem netconf /usr/local/bin/clixon_netconf -f /usr/local/etc/routing.conf Subsystem netconf /usr/local/bin/clixon_netconf -f /usr/local/etc/routing.xml
``` ```
and then invoke it from a client using and then invoke it from a client using
``` ```
@ -147,7 +144,7 @@ cli>
``` ```
or via netconf: or via netconf:
``` ```
clixon_netconf -qf /usr/local/etc/routing.conf clixon_netconf -qf /usr/local/etc/routing.xml
<rpc><create-subscription><stream>ROUTING</stream></create-subscription></rpc>]]>]]> <rpc><create-subscription><stream>ROUTING</stream></create-subscription></rpc>]]>]]>
<rpc-reply><ok/></rpc-reply>]]>]]> <rpc-reply><ok/></rpc-reply>]]>]]>
<notification><event>Routing notification</event></notification>]]>]]> <notification><event>Routing notification</event></notification>]]>]]>
@ -156,7 +153,7 @@ clixon_netconf -qf /usr/local/etc/routing.conf
``` ```
## I want to program. How do I extend the example? ## I want to program. How do I extend the example?
- routing.conf.local - Override default settings - routing.xml - Change the configuration file
- The yang specifications - This is the central part. It changes the XML, database and the config cli. - The yang specifications - This is the central part. It changes the XML, database and the config cli.
- routing_cli.cli - Change the fixed part of the CLI commands - routing_cli.cli - Change the fixed part of the CLI commands
- routing_cli.c - Cli C-commands are placed here. - routing_cli.c - Cli C-commands are placed here.

View file

@ -7,15 +7,15 @@
``` ```
Start backend: Start backend:
``` ```
clixon_backend -f /usr/local/etc/routing.conf -I clixon_backend -f /usr/local/etc/routing.xml -I
``` ```
Edit cli: Edit cli:
``` ```
clixon_cli -f /usr/local/etc/routing.conf clixon_cli -f /usr/local/etc/routing.xml
``` ```
Send netconf command: Send netconf command:
``` ```
clixon_netconf -f /usr/local/etc/routing.conf clixon_netconf -f /usr/local/etc/routing.xml
``` ```
## Setting data example using netconf ## Setting data example using netconf

View file

@ -1,5 +1,5 @@
<config> <config>
<CLICON_CONFIGFILE>/usr/local/etc/routing.conf</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>/usr/local/etc/routing.xml</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/routing/yang</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/routing/yang</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
<CLICON_CLI_MODE>routing</CLICON_CLI_MODE> <CLICON_CLI_MODE>routing</CLICON_CLI_MODE>

View file

@ -993,15 +993,21 @@ yang2api_path_fmt(yang_stmt *ys,
/*! Transform an xml key format and a vector of values to an XML key /*! Transform an xml key format and a vector of values to an XML key
* Used for actual key, eg in clicon_rpc_change(), xmldb_put_xkey() * Used for actual key, eg in clicon_rpc_change(), xmldb_put_xkey()
* Example: * Example:
* xmlkeyfmt: /aaa/%s/name * xmlkeyfmt: /interfaces/interface=%s/ipv4/address=%s
* cvv: key=17 * cvv: 0 : set interfaces interface e ipv4 address 1.2.3.4
* xmlkey: /aaa/17/name * 1 : name = "e"
* 2 : ip = "1.2.3.4"
* api_path: /interfaces/interface=e/ipv4/address=1.2.3.4
* @param[in] api_path_fmt XML key format, eg /aaa/%s/name * @param[in] api_path_fmt XML key format, eg /aaa/%s/name
* @param[in] cvv cligen variable vector, one for every wildchar in api_path_fmt * @param[in] cvv cligen variable vector, one for every wildchar in
* api_path_fmt
* @param[out] api_path api_path, eg /aaa/17. Free after use * @param[out] api_path api_path, eg /aaa/17. Free after use
* @param[out] yang_arg yang-stmt argument name. Free after use * @param[out] yang_arg yang-stmt argument name. Free after use
* @note first and last elements of cvv are not used,.. * @note first and last elements of cvv are not used,..
* @see cli_dbxml where this function is called * @see api_path_fmt2xpath
*
* /interfaces/interface=%s/name --> /interfaces/interface/name
* /interfaces/interface=%s/ipv4/address=%s --> /interfaces/interface=e/ipv4/address
*/ */
int int
api_path_fmt2api_path(char *api_path_fmt, api_path_fmt2api_path(char *api_path_fmt,
@ -1016,19 +1022,19 @@ api_path_fmt2api_path(char *api_path_fmt,
int j; int j;
char *str; char *str;
char *strenc=NULL; char *strenc=NULL;
cg_var *cv;
#if 1
/* Sanity check */ /* Sanity check */
#if 0
j = 0; /* Count % */ j = 0; /* Count % */
for (i=0; i<strlen(api_path_fmt); i++) for (i=0; i<strlen(api_path_fmt); i++)
if (api_path_fmt[i] == '%') if (api_path_fmt[i] == '%')
j++; j++;
if (j+2 < cvec_len(cvv)) { if (j > cvec_len(cvv)) { //cvec_len can be longer
clicon_log(LOG_WARNING, "%s xmlkey format string mismatch(j=%d, cvec_len=%d): %s", clicon_log(LOG_WARNING, "%s api_path_fmt number of %% is %d, does not match number of cvv entries %d",
api_path_fmt, api_path_fmt,
j, j,
cvec_len(cvv), cvec_len(cvv));
cv_string_get(cvec_i(cvv, 0)));
goto done; goto done;
} }
#endif #endif
@ -1043,8 +1049,12 @@ api_path_fmt2api_path(char *api_path_fmt,
esc = 0; esc = 0;
if (c!='s') if (c!='s')
continue; continue;
if ((str = cv2str_dup(cvec_i(cvv, j++))) == NULL){ if (j == cvec_len(cvv)) /* last element */
clicon_err(OE_UNIX, errno, "strdup"); ;
else{
cv = cvec_i(cvv, j++);
if ((str = cv2str_dup(cv)) == NULL){
clicon_err(OE_UNIX, errno, "cv2str_dup");
goto done; goto done;
} }
if (percent_encode(str, &strenc) < 0) if (percent_encode(str, &strenc) < 0)
@ -1053,15 +1063,17 @@ api_path_fmt2api_path(char *api_path_fmt,
free(strenc); strenc = NULL; free(strenc); strenc = NULL;
free(str); str = NULL; free(str); str = NULL;
} }
}
else else
if (c == '%') if (c == '%')
esc++; esc++;
else if (c == '/'){ else{
cprintf(cb, "%c", c); if ((c == '=' || c == ',') && api_path_fmt[i+1]=='%' && j == cvec_len(cvv))
} ; /* skip */
else else
cprintf(cb, "%c", c); cprintf(cb, "%c", c);
} }
}
if ((*api_path = strdup(cbuf_get(cb))) == NULL){ if ((*api_path = strdup(cbuf_get(cb))) == NULL){
clicon_err(OE_UNIX, errno, "strdup"); clicon_err(OE_UNIX, errno, "strdup");
goto done; goto done;
@ -1073,12 +1085,12 @@ api_path_fmt2api_path(char *api_path_fmt,
return retval; return retval;
} }
/*! Transform an xml key format and a vector of values to an XML path /*! Transform an xml key format and a vector of values to an XML path
* Used to input xmldb_get() or xmldb_get_vec * Used to input xmldb_get() or xmldb_get_vec
* Add .* in last %s position. * Add .* in last %s position.
* Example: * Example:
* xmlkeyfmt: /interface/%s/address/%s OLDXXX * api_path_fmt: /interface/%s/address/%s
* xmlkeyfmt: /interface=%s/address=%s
* cvv: name=eth0 * cvv: name=eth0
* xmlkey: /interface/[name=eth0]/address * xmlkey: /interface/[name=eth0]/address
* Example2: * Example2:
@ -1102,21 +1114,20 @@ api_path_fmt2xpath(char *api_path_fmt,
int j; int j;
char *str; char *str;
cg_var *cv; cg_var *cv;
int skip = 0;
/* Sanity check: count '%' */ /* Sanity check: count '%' */
#if 0 #if 1
j = 0; /* Count % */ j = 0; /* Count % */
for (i=0; i<strlen(api_path_fmt); i++) for (i=0; i<strlen(api_path_fmt); i++)
if (api_path_fmt[i] == '%') if (api_path_fmt[i] == '%')
j++; j++;
if (j < cvec_len(cvv)-1) { if (j > cvec_len(cvv)) {
clicon_log(LOG_WARNING, "%s xmlkey format string mismatch(j=%d, cvec_len=%d): %s", clicon_log(LOG_WARNING, "%s xmlkey format string mismatch(j=%d, cvec_len=%d): %s",
api_path_fmt, api_path_fmt,
j, j,
cvec_len(cvv), cvec_len(cvv),
cv_string_get(cvec_i(cvv, 0))); cv_string_get(cvec_i(cvv, 0)));
// goto done; goto done;
} }
#endif #endif
if ((cb = cbuf_new()) == NULL){ if ((cb = cbuf_new()) == NULL){
@ -1130,9 +1141,7 @@ api_path_fmt2xpath(char *api_path_fmt,
esc = 0; esc = 0;
if (c!='s') if (c!='s')
continue; continue;
if (j == cvec_len(cvv)) /* last element */ if (j == cvec_len(cvv)) /* last element */
//skip++;
; ;
else{ else{
cv = cvec_i(cvv, j++); cv = cvec_i(cvv, j++);
@ -1148,9 +1157,6 @@ api_path_fmt2xpath(char *api_path_fmt,
if (c == '%') if (c == '%')
esc++; esc++;
else{ else{
if (skip)
skip=0;
else
if ((c == '=' || c == ',') && api_path_fmt[i+1]=='%') if ((c == '=' || c == ',') && api_path_fmt[i+1]=='%')
; /* skip */ ; /* skip */
else else
@ -1687,7 +1693,7 @@ api_path2xml_vec(char **vec,
} }
switch (y->ys_keyword){ switch (y->ys_keyword){
case Y_LEAF_LIST: case Y_LEAF_LIST:
if (restval==NULL){ if (0 && restval==NULL){
clicon_err(OE_XML, 0, "malformed key, expected '=<restval>'"); clicon_err(OE_XML, 0, "malformed key, expected '=<restval>'");
goto done; goto done;
} }
@ -1697,7 +1703,7 @@ api_path2xml_vec(char **vec,
if ((xb = xml_new("body", x)) == NULL) if ((xb = xml_new("body", x)) == NULL)
goto done; goto done;
xml_type_set(xb, CX_BODY); xml_type_set(xb, CX_BODY);
if (xml_value_set(xb, restval) < 0) if (restval && xml_value_set(xb, restval) < 0)
goto done; goto done;
break; break;
case Y_LIST: case Y_LIST:
@ -1983,3 +1989,70 @@ done:
return retval; return retval;
} }
/*
* Turn this on for uni-test programs
* Usage: clixon_string join
* Example compile:
gcc -g -o clixon_xml_map -I. -I../clixon ./clixon_xml_map.c -lclixon -lcligen
* Example run:
/interfaces/interface=%s/name --> interfaces/interface/name
/interfaces/interface=%s/ipv4/address=%s e --> /interfaces/interface=e/ipv4/address
/interfaces/interface=%s,%s/ipv4/address=%s e f --> /interfaces/interface=e,f/ipv4/address
/interfaces/interface=%s/ipv4/address=%s,%s e f --> /interfaces/interface=e/ipv4/address=f
/interfaces/interface=%s/ipv4/address=%s/prefix-length eth 1.2.3.4 -->
/interfaces/interface=eth/ipv4/address=1.2.3.4/prefix-length
*/
#if 0 /* Test program */
static int
usage(char *argv0)
{
fprintf(stderr, "usage:%s <api_path_fmt> <cv0>, <cv1>,...\n", argv0);
exit(0);
}
int
main(int argc, char **argv)
{
int nvec;
char **vec;
char *str0;
char *str1;
int i;
char *api_path_fmt;
cg_var *cv;
cvec *cvv;
char *api_path=NULL;
clicon_log_init(__FILE__, LOG_INFO, CLICON_LOG_STDERR);
if (argc < 2){
usage(argv[0]);
return 0;
}
api_path_fmt = argv[1];
if ((cvv = cvec_new(0)) == NULL){
perror("cvec_new");
return -1;
}
cv = cv_new(CGV_STRING);
cv_string_set(cv, "CLI base command");
cvec_append_var(cvv, cv);
for (i=2; i<argc; i++){
cv = cv_new(CGV_STRING);
if (cv_parse(argv[i], cv) < 0){
perror("cv_parse");
return -1;
}
cvec_append_var(cvv, cv);
}
if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path) < 0)
return -1;
printf("%s\n", api_path);
return 0;
}
#endif /* Test program */

View file

@ -32,6 +32,17 @@ module example{
} }
} }
} }
list sender{
key name;
leaf name{
type string;
}
leaf template{
type leafref{
path "/sender/name";
}
}
}
} }
EOF EOF
@ -96,6 +107,12 @@ expectfn "$clixon_cli -1f $clixon_cf -y /tmp/leafref.yang -l o set default-addre
new "cli leafref validate" new "cli leafref validate"
expectfn "$clixon_cli -1f $clixon_cf -y /tmp/leafref.yang -l o validate" "^$" expectfn "$clixon_cli -1f $clixon_cf -y /tmp/leafref.yang -l o validate" "^$"
new "cli sender"
expectfn "$clixon_cli -1f $clixon_cf -y /tmp/leafref.yang -l o set sender a" "^$"
new "cli sender template"
expectfn "$clixon_cli -1f $clixon_cf -y /tmp/leafref.yang -l o set sender b template a" "^$"
new "Kill backend" new "Kill backend"
# Check if still alive # Check if still alive
pid=`pgrep clixon_backend` pid=`pgrep clixon_backend`