* Added flags to example backend to control its behaviour:

* Start with `-- -r` to run the reset plugin
  * Start with `-- -s` to run the state callback
* Rewrote yang dir load algorithm to follow the algorithm in [FAQ](FAQ(doc/FAQ.md#how-are-yang-files-found) with more precise timestamp checks, etc.
This commit is contained in:
Olof hagsand 2019-03-18 16:31:34 +01:00
parent 8f656da15b
commit 606245ef02
20 changed files with 495 additions and 190 deletions

View file

@ -44,6 +44,10 @@
``` ```
### Minor changes ### Minor changes
* Added flags to example backend to control its behaviour:
* Start with `-- -r` to run the reset plugin
* Start with `-- -s` to run the state callback
* Rewrote yang dir load algorithm to follow the algorithm in [FAQ](FAQ(doc/FAQ.md#how-are-yang-files-found) with more precise timestamp checks, etc.
* Ensured you can add multiple callbacks for any RPC, including basic ones. * Ensured you can add multiple callbacks for any RPC, including basic ones.
* Extra RPC:s will be called _after_ the basic ones. * Extra RPC:s will be called _after_ the basic ones.
* One specific usecase is hook for `copy-config` (see [doc/ROADMAP.md](doc/ROADMAP.md) that can be implemented this way. * One specific usecase is hook for `copy-config` (see [doc/ROADMAP.md](doc/ROADMAP.md) that can be implemented this way.

View file

@ -568,11 +568,6 @@ from_client_validate(clicon_handle h,
goto done; goto done;
goto ok; goto ok;
} }
if (strcmp(db, "candidate") != 0 && strcmp(db, "tmp") != 0){
if (netconf_invalid_value(cbret, "protocol", "No such database")< 0)
goto done;
goto ok;
}
clicon_debug(1, "Validate %s", db); clicon_debug(1, "Validate %s", db);
/* 1. Start transaction */ /* 1. Start transaction */

View file

@ -596,7 +596,7 @@ main(int argc,
if (yang_spec_parse_module(h, str, clicon_yang_module_revision(h), if (yang_spec_parse_module(h, str, clicon_yang_module_revision(h),
yspec) < 0) yspec) < 0)
goto done; goto done;
/* 3. Load all modules in a directory */ /* 3. Load all modules in a directory (will not overwrite file loaded ^) */
if ((str = clicon_yang_main_dir(h)) != NULL) if ((str = clicon_yang_main_dir(h)) != NULL)
if (yang_spec_load_dir(h, str, yspec) < 0) if (yang_spec_load_dir(h, str, yspec) < 0)
goto done; goto done;

View file

@ -271,6 +271,11 @@ specific. The precedence of the options are as follows:
- `CLICON_YANG_MODULE_MAIN` - `CLICON_YANG_MODULE_MAIN`
- `CLICON_YANG_MAIN_DIR` - `CLICON_YANG_MAIN_DIR`
Note that using `CLICON_YANG_MAIN_DIR` Clixon may find several files
containing the same Yang module. Clixon will prefer the one without a
revision date if such a file exists. If no file has a revision date,
Clixon will prefer the newest.
## How do I enable Yang features? ## How do I enable Yang features?
Yang models have features, and parts of a specification can be Yang models have features, and parts of a specification can be

View file

@ -262,6 +262,8 @@ a real example would poll or get the interface counters via a system
call, as well as use the "xpath" argument to identify the requested call, as well as use the "xpath" argument to identify the requested
state data. state data.
The state data is enabled by starting the backend with: `-- -s`.
## Authentication and NACM ## Authentication and NACM
The example contains some stubs for authorization according to [RFC8341(NACM)](https://tools.ietf.org/html/rfc8341): The example contains some stubs for authorization according to [RFC8341(NACM)](https://tools.ietf.org/html/rfc8341):
* A basic auth HTTP callback, see: example_restconf_credentials() containing three example users: andy, wilma, and guest, according to the examples in Appendix A in [RFC8341](https://tools.ietf.org/html/rfc8341). * A basic auth HTTP callback, see: example_restconf_credentials() containing three example users: andy, wilma, and guest, according to the examples in Appendix A in [RFC8341](https://tools.ietf.org/html/rfc8341).

View file

@ -51,13 +51,19 @@
/* These include signatures for plugin and transaction callbacks. */ /* These include signatures for plugin and transaction callbacks. */
#include <clixon/clixon_backend.h> #include <clixon/clixon_backend.h>
/* Variable to control if reset code is run. /*! Variable to control if reset code is run.
* The reset code inserts "extra XML" which assumes ietf-interfaces is * The reset code inserts "extra XML" which assumes ietf-interfaces is
* loaded, and this is not always the case. * loaded, and this is not always the case.
* Therefore, the backend must be started with -- -r to enable the reset function * Therefore, the backend must be started with -- -r to enable the reset function
*/ */
static int _reset = 0; static int _reset = 0;
/*! Variable to control if state code is run
* The state code adds extra non-config data
* Therefore, the backend must be started with -- -s to enable the state function
*/
static int _state = 0;
/* forward */ /* forward */
static int example_stream_timer_setup(clicon_handle h); static int example_stream_timer_setup(clicon_handle h);
@ -210,7 +216,7 @@ example_copy_extra(clicon_handle h, /* Clicon handle */
type string; type string;
} }
} }
* * This yang snippet is present in clixon-example.yang for exampl.
*/ */
int int
example_statedata(clicon_handle h, example_statedata(clicon_handle h,
@ -220,6 +226,8 @@ example_statedata(clicon_handle h,
int retval = -1; int retval = -1;
cxobj **xvec = NULL; cxobj **xvec = NULL;
if (!_state)
goto ok;
/* Example of (static) statedata, real code would poll state /* Example of (static) statedata, real code would poll state
* Note this state needs to be accomanied by yang snippet * Note this state needs to be accomanied by yang snippet
* above * above
@ -230,6 +238,7 @@ example_statedata(clicon_handle h,
"<op>43</op>" /* should not be ordered */ "<op>43</op>" /* should not be ordered */
"</state>", NULL, &xstate) < 0) "</state>", NULL, &xstate) < 0)
goto done; goto done;
ok:
retval = 0; retval = 0;
done: done:
if (xvec) if (xvec)
@ -277,7 +286,8 @@ example_reset(clicon_handle h,
int ret; int ret;
cbuf *cbret = NULL; cbuf *cbret = NULL;
goto ok; /* Note not enabled by default */ if (!_reset)
goto ok; /* Note not enabled by default */
if (xml_parse_string("<config><interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\"><interface>" if (xml_parse_string("<config><interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\"><interface>"
"<name>lo</name><type>ex:loopback</type>" "<name>lo</name><type>ex:loopback</type>"
"</interface></interfaces></config>", NULL, &xt) < 0) "</interface></interfaces></config>", NULL, &xt) < 0)
@ -329,11 +339,14 @@ example_start(clicon_handle h,
opterr = 0; opterr = 0;
optind = 1; optind = 1;
while ((c = getopt(argc, argv, "r")) != -1) while ((c = getopt(argc, argv, "rs")) != -1)
switch (c) { switch (c) {
case 'r': case 'r':
_reset = 1; _reset = 1;
break; break;
case 's':
_state = 1;
break;
} }
return 0; return 0;
} }

View file

@ -67,7 +67,7 @@
/*! Create Netconf in-use error XML tree according to RFC 6241 Appendix A /*! Create Netconf in-use error XML tree according to RFC 6241 Appendix A
* *
* The request requires a resource that already is in use. * The request requires a resource that already is in use.
* @param[out] cb CLIgen buf. Error XML is written in this buffer * @param[out] cb CLIgen buf. Error XML is written in this buffer
* @param[in] type Error type: "application" or "protocol" * @param[in] type Error type: "application" or "protocol"
* @param[in] message Error message * @param[in] message Error message
*/ */
@ -376,7 +376,6 @@ netconf_missing_element(cbuf *cb,
return retval; return retval;
} }
/*! Create Netconf missing-element error XML tree according to RFC 6241 App A /*! Create Netconf missing-element error XML tree according to RFC 6241 App A
* @param[out] xret Error XML tree. Free with xml_free after use * @param[out] xret Error XML tree. Free with xml_free after use
* @param[in] type Error type: "application" or "protocol" * @param[in] type Error type: "application" or "protocol"

View file

@ -96,7 +96,9 @@
/* /*
* Local variables * Local variables
*/ */
/* Mapping between yang keyword string <--> clicon constants */ /* Mapping between yang keyword string <--> clicon constants
* Here is also the place where doc on some types store variables (cv)
*/
static const map_str2int ykmap[] = { static const map_str2int ykmap[] = {
{"anydata", Y_ANYDATA}, {"anydata", Y_ANYDATA},
{"anyxml", Y_ANYXML}, {"anyxml", Y_ANYXML},
@ -107,7 +109,7 @@ static const map_str2int ykmap[] = {
{"bit", Y_BIT}, {"bit", Y_BIT},
{"case", Y_CASE}, {"case", Y_CASE},
{"choice", Y_CHOICE}, {"choice", Y_CHOICE},
{"config", Y_CONFIG}, {"config", Y_CONFIG}, /* cv: boolean config flag */
{"contact", Y_CONTACT}, {"contact", Y_CONTACT},
{"container", Y_CONTAINER}, {"container", Y_CONTAINER},
{"default", Y_DEFAULT}, {"default", Y_DEFAULT},
@ -118,8 +120,8 @@ static const map_str2int ykmap[] = {
{"error-app-tag", Y_ERROR_APP_TAG}, {"error-app-tag", Y_ERROR_APP_TAG},
{"error_message", Y_ERROR_MESSAGE}, {"error_message", Y_ERROR_MESSAGE},
{"extension", Y_EXTENSION}, {"extension", Y_EXTENSION},
{"feature", Y_FEATURE}, {"feature", Y_FEATURE}, /* cv: feature as boolean */
{"fraction-digits", Y_FRACTION_DIGITS}, {"fraction-digits", Y_FRACTION_DIGITS}, /* cv: fraction-digits as uint8 */
{"grouping", Y_GROUPING}, {"grouping", Y_GROUPING},
{"identity", Y_IDENTITY}, {"identity", Y_IDENTITY},
{"if-feature", Y_IF_FEATURE}, {"if-feature", Y_IF_FEATURE},
@ -127,11 +129,11 @@ static const map_str2int ykmap[] = {
{"include", Y_INCLUDE}, {"include", Y_INCLUDE},
{"input", Y_INPUT}, {"input", Y_INPUT},
{"key", Y_KEY}, {"key", Y_KEY},
{"leaf", Y_LEAF}, {"leaf", Y_LEAF}, /* cv: store default value (if any)*/
{"leaf-list", Y_LEAF_LIST}, {"leaf-list", Y_LEAF_LIST}, /* cv: store default value (if any)*/
{"length", Y_LENGTH}, {"length", Y_LENGTH},
{"list", Y_LIST}, {"list", Y_LIST},
{"mandatory", Y_MANDATORY}, {"mandatory", Y_MANDATORY}, /* cv: store mandatory boolean */
{"max-elements", Y_MAX_ELEMENTS}, {"max-elements", Y_MAX_ELEMENTS},
{"min-elements", Y_MIN_ELEMENTS}, {"min-elements", Y_MIN_ELEMENTS},
{"modifier", Y_MODIFIER}, {"modifier", Y_MODIFIER},
@ -151,8 +153,8 @@ static const map_str2int ykmap[] = {
{"reference", Y_REFERENCE}, {"reference", Y_REFERENCE},
{"refine", Y_REFINE}, {"refine", Y_REFINE},
{"require-instance", Y_REQUIRE_INSTANCE}, {"require-instance", Y_REQUIRE_INSTANCE},
{"revision", Y_REVISION}, {"revision", Y_REVISION}, /* cv: YYYY-MM-DD as uint32 */
{"revision-date", Y_REVISION_DATE}, {"revision-date", Y_REVISION_DATE}, /* cv: YYYY-MM-DD as uint32 */
{"rpc", Y_RPC}, {"rpc", Y_RPC},
{"status", Y_STATUS}, {"status", Y_STATUS},
{"submodule", Y_SUBMODULE}, {"submodule", Y_SUBMODULE},
@ -160,7 +162,7 @@ static const map_str2int ykmap[] = {
{"typedef", Y_TYPEDEF}, {"typedef", Y_TYPEDEF},
{"unique", Y_UNIQUE}, {"unique", Y_UNIQUE},
{"units", Y_UNITS}, {"units", Y_UNITS},
{"unknown", Y_UNKNOWN}, {"unknown", Y_UNKNOWN}, /* cv: store extra string */
{"uses", Y_USES}, {"uses", Y_USES},
{"value", Y_VALUE}, {"value", Y_VALUE},
{"when", Y_WHEN}, {"when", Y_WHEN},
@ -171,6 +173,9 @@ static const map_str2int ykmap[] = {
{NULL, -1} {NULL, -1}
}; };
/* forward declaration */
static int ys_parse_date_arg(char *str, uint32_t *date);
/*! Create new yang specification /*! Create new yang specification
* @retval yspec Free with yspec_free() * @retval yspec Free with yspec_free()
* @retval NULL Error * @retval NULL Error
@ -426,8 +431,8 @@ yn_each(yang_node *yn,
* @see yang_match returns number of matches * @see yang_match returns number of matches
*/ */
yang_stmt * yang_stmt *
yang_find(yang_node *yn, yang_find(yang_node *yn,
int keyword, int keyword,
const char *argument) const char *argument)
{ {
yang_stmt *ys = NULL; yang_stmt *ys = NULL;
@ -2514,6 +2519,13 @@ yang_spec_parse_file(clicon_handle h,
* @retval 0 OK * @retval 0 OK
* @retval -1 Error * @retval -1 Error
* @see yang_spec_parse_file * @see yang_spec_parse_file
* Load all yang files in a directory as primary objects.
* Some details if several same yang module x exists:
* 1) If x is already loaded (eg via direct file loading) skip it
* 2) Prefer x.yang over x@rev.yang (no revision)
* 3) If only x@rev.yang's found, prefer newest (newest revision)
* There is also an extra failsafe which may not be necessary, which removes
* the oldest module if 1-3 for some reason fails.
*/ */
int int
yang_spec_load_dir(clicon_handle h, yang_spec_load_dir(clicon_handle h,
@ -2524,13 +2536,26 @@ yang_spec_load_dir(clicon_handle h,
int ndp; int ndp;
struct dirent *dp = NULL; struct dirent *dp = NULL;
int i; int i;
int j;
char filename[MAXPATHLEN]; char filename[MAXPATHLEN];
char *base = NULL; /* filename without dir */ char *base = NULL; /* filename without dir */
char *b;
int j;
int modnr; int modnr;
yang_stmt *ym; /* yang module */
yang_stmt *ym0; /* (existing) yang module */
yang_stmt *yrev; /* yang revision */
uint32_t revf; /* revision in filename */
uint32_t revm; /* revision in parsed new module (same as revf) */
uint32_t rev0; /* revision in existing module */
char *s;
char *oldbase = NULL;
int taken = 0;
/* Get plugin objects names from plugin directory */ /* Get yang files names from yang module directory. Note that these
* are sorted alphatetically:
* a.yang,
* a@2000-01-01.yang,
* a@2111-11-11.yang
*/
if((ndp = clicon_file_dirent(dir, &dp, "(.yang)$", S_IFREG)) < 0) if((ndp = clicon_file_dirent(dir, &dp, "(.yang)$", S_IFREG)) < 0)
goto done; goto done;
if (ndp == 0) if (ndp == 0)
@ -2541,40 +2566,76 @@ yang_spec_load_dir(clicon_handle h,
/* Load all yang files in dir */ /* Load all yang files in dir */
for (i = 0; i < ndp; i++) { for (i = 0; i < ndp; i++) {
/* base = module name [+ @rev ] + .yang */ /* base = module name [+ @rev ] + .yang */
if (base) if (oldbase)
free(base); free(oldbase);
oldbase = base; base = NULL;
if ((base = strdup(dp[i].d_name)) == NULL){ if ((base = strdup(dp[i].d_name)) == NULL){
clicon_err(OE_UNIX, errno, "strdup"); clicon_err(OE_UNIX, errno, "strdup");
goto done; goto done;
} }
clicon_debug(1, "%s %s", __FUNCTION__, base);
*rindex(base, '.') = '\0'; /* strip postfix .yang */ *rindex(base, '.') = '\0'; /* strip postfix .yang */
/* base = module name [+ @rev] /* base = module name [+ @rev]
* if it hasnt @rev then prefer it (dont check other files w @rev) * if it hasnt @rev then prefer it (dont check other files w @rev)
* Otherwise see if there is a newer
*/ */
if ((b = index(base, '@')) != NULL){ revf = 0;
*b = '\0'; if ((s = index(base, '@')) != NULL){
/* base = module name */ *s++ = '\0';
if (ys_parse_date_arg(s, &revf) < 0)
/* Entries are sorted, see if later entry exists (include @), if so goto done;
* skip this one and take last.
* Assume file without @ is last
*/
for (j = (i+1); j < ndp; j++)
if (strncmp(base, dp[j].d_name, strlen(base)) == 0)
break;
if (j<ndp){ /* exists later entry */
clicon_debug(1, "%s skip %s", __FUNCTION__, dp[i].d_name);
continue;
}
} }
if (oldbase && strcmp(base, oldbase)) /* new yang file basename */
taken = 0;
if (revf == 0){ /* No revision: a.yang - take that */
taken = 1;
}
else{ /* a@xxx.yang */
if (taken)
continue; /* skip if already taken */
/* is there anyone else later? */
if (i+1<ndp && strncmp(base, dp[i+1].d_name, strlen(base)) == 0)
continue; /* same base: skip; */
taken = 1; /* last in line and not taken */
}
/* Here only a single file is reached(taken)
* Check if module already exists -> ym0/rev0 */
rev0 = 0;
if ((ym0 = yang_find((yang_node*)yspec, Y_MODULE, base)) != NULL ||
(ym0 = yang_find((yang_node*)yspec, Y_SUBMODULE, base)) != NULL){
yrev = yang_find((yang_node*)ym0, Y_REVISION, NULL);
rev0 = cv_uint32_get(yrev->ys_cv);
continue; /* skip if already added by specific file or module */
}
/* Create full filename */
snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dp[i].d_name); snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dp[i].d_name);
/* Dont parse if already exists */ if ((ym = yang_parse_filename(filename, yspec)) == NULL)
if (yang_find((yang_node*)yspec, Y_MODULE, base) != NULL ||
yang_find((yang_node*)yspec, Y_SUBMODULE, base) != NULL)
continue;
if (yang_parse_filename(filename, yspec) == NULL)
goto done; goto done;
revm = 0;
if ((yrev = yang_find((yang_node*)ym, Y_REVISION, NULL)) != NULL)
revm = cv_uint32_get(yrev->ys_cv);
/* Sanity check that file revision does not match internal rev stmt */
if (revf && revm && revm != revf){
clicon_err(OE_YANG, EINVAL, "Yang module file revision and in yang does not match: %s vs %u", filename, revm);
goto done;
}
/* If ym0 and ym exists, delete the yang with oldest revision
* This is a failsafe in case anything else fails
*/
if (revm && rev0){
int size;
if (revm > rev0) /* Loaded module is older or eq -> remove ym */
ym = ym0;
for (j=0; j<yspec->yp_len; j++)
if (yspec->yp_stmt[j] == ym)
break;
size = (yspec->yp_len - j - 1)*sizeof(struct yang_stmt *);
memmove(&yspec->yp_stmt[j],
&yspec->yp_stmt[j+1],
size);
ys_free(ym);
yspec->yp_len--;
yspec->yp_stmt[yspec->yp_len] = NULL;
}
} }
if (yang_parse_post(h, yspec, modnr) < 0) if (yang_parse_post(h, yspec, modnr) < 0)
goto done; goto done;
@ -2584,10 +2645,11 @@ yang_spec_load_dir(clicon_handle h,
free(dp); free(dp);
if (base) if (base)
free(base); free(base);
if (oldbase)
free(oldbase);
return retval; return retval;
} }
/*! Apply a function call recursively on all yang-stmt s recursively /*! Apply a function call recursively on all yang-stmt s recursively
* *
* Recursively traverse all yang-nodes in a parse-tree and apply fn(arg) for * Recursively traverse all yang-nodes in a parse-tree and apply fn(arg) for
@ -2843,6 +2905,42 @@ yang_desc_schema_nodeid(yang_node *yn,
return retval; return retval;
} }
/*! parse yang date-arg string
*/
static int
ys_parse_date_arg(char *str,
uint32_t *date)
{
int retval = -1;
int i;
uint32_t d = 0;
if (strlen(str) != 10 || str[4] != '-' || str[7] != '-'){
clicon_err(OE_YANG, EINVAL, "Revision date %s, but expected: YYYY-MM-DD", str);
goto done;
}
if ((i = cligen_tonum(4, str)) < 0){
clicon_err(OE_YANG, EINVAL, "Revision date %s, but expected: YYYY-MM-DD", str);
goto done;
}
d = i*10000; /* year */
if ((i = cligen_tonum(2, &str[5])) < 0){
clicon_err(OE_YANG, EINVAL, "Revision date %s, but expected: YYYY-MM-DD", str);
goto done;
}
d += i*100; /* month */
if ((i = cligen_tonum(2, &str[8])) < 0){
clicon_err(OE_YANG, EINVAL, "Revision date %s, but expected: YYYY-MM-DD", str);
goto done;
}
d += i; /* day */
*date = d;
retval = 0;
done:
return retval;
}
/*! Parse argument as CV and save result in yang cv variable /*! Parse argument as CV and save result in yang cv variable
* *
* Note that some CV:s are parsed directly (eg fraction-digits) while others are parsed * Note that some CV:s are parsed directly (eg fraction-digits) while others are parsed
@ -2897,6 +2995,7 @@ ys_parse_sub(yang_stmt *ys,
{ {
int retval = -1; int retval = -1;
uint8_t fd; uint8_t fd;
uint32_t date = 0;
switch (ys->ys_keyword){ switch (ys->ys_keyword){
case Y_FRACTION_DIGITS: case Y_FRACTION_DIGITS:
@ -2908,6 +3007,16 @@ ys_parse_sub(yang_stmt *ys,
goto done; goto done;
} }
break; break;
case Y_REVISION:
case Y_REVISION_DATE: /* YYYY-MM-DD encoded as uint32 YYYYMMDD */
if (ys_parse_date_arg(ys->ys_argument, &date) < 0)
goto done;
if ((ys->ys_cv = cv_new(CGV_UINT32)) == NULL){
clicon_err(OE_YANG, errno, "cv_new");
goto done;
}
cv_uint32_set(ys->ys_cv, date);
break;
case Y_UNKNOWN: /* XXX This code assumes ymod already loaded case Y_UNKNOWN: /* XXX This code assumes ymod already loaded
but it may not be */ but it may not be */
if (extra == NULL) if (extra == NULL)
@ -2998,7 +3107,6 @@ yang_config(yang_stmt *ys)
return 1; return 1;
} }
/*! Given a yang node, translate the argument string to a cv vector /*! Given a yang node, translate the argument string to a cv vector
* *
* @param[in] ys Yang statement * @param[in] ys Yang statement

View file

@ -9,7 +9,7 @@ fi
err=0 err=0
testnr=0 testnr=0
for test in test*.sh; do for test in test_*.sh; do
if [ $testnr != 0 ]; then echo; fi if [ $testnr != 0 ]; then echo; fi
testfile=$test testfile=$test
. ./$test . ./$test

View file

@ -24,7 +24,6 @@
# Site file, an example of this file in README.md # Site file, an example of this file in README.md
if [ -f ./site.sh ]; then if [ -f ./site.sh ]; then
. ./site.sh . ./site.sh
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
return -1 # skip return -1 # skip
@ -102,7 +101,8 @@ dir=/var/tmp/$0
if [ ! -d $dir ]; then if [ ! -d $dir ]; then
mkdir $dir mkdir $dir
fi fi
# If we bring our own backend BE=0 (it is already started),the backend may
# If you bring your own backend BE=0 (it is already started),the backend may
# have created some files (eg unix socket) in $dir and therefore cannot # have created some files (eg unix socket) in $dir and therefore cannot
# be deleted # be deleted
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
@ -440,3 +440,4 @@ expectmatch(){
fi fi
fi fi
} }

View file

@ -24,7 +24,6 @@ s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
APPNAME=example APPNAME=example
# include err() and new() functions and creates $dir # include err() and new() functions and creates $dir
. ./lib.sh
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml

View file

@ -137,9 +137,9 @@ if [ $BE -ne 0 ]; then
err err
fi fi
sleep 1 sleep 1
new "start backend -s init -f $cfg" new "start backend -s init -f $cfg -- -s"
# start new backend # start new backend
start_backend -s init -f $cfg start_backend -s init -f $cfg -- -s
fi fi
new "kill old restconf daemon" new "kill old restconf daemon"

View file

@ -133,8 +133,8 @@ if [ $BE -ne 0 ]; then
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
new "start backend -s init -f $cfg" new "start backend -s init -f $cfg -- -s"
start_backend -s init -f $cfg start_backend -s init -f $cfg -- -s
fi fi
new "kill old restconf daemon" new "kill old restconf daemon"

View file

@ -42,8 +42,8 @@ if [ $BE -ne 0 ]; then
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
new "start backend -s init -f $cfg" new "start backend -s init -f $cfg -- -s"
start_backend -s init -f $cfg start_backend -s init -f $cfg -- -s
new "waiting" new "waiting"
sleep $RCWAIT sleep $RCWAIT

View file

@ -147,7 +147,7 @@ cat <<EOF > $dbdir/running_db
</config> </config>
EOF EOF
new "test params: -s running -f $cfg -y $fyang" new "test params: -s running -f $cfg -y $fyang -- -s"
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "kill old backend" new "kill old backend"
@ -156,7 +156,7 @@ if [ $BE -ne 0 ]; then
err err
fi fi
new "start backend" new "start backend"
start_backend -s running -f $cfg -y $fyang start_backend -s running -f $cfg -y $fyang -- -s
new "waiting" new "waiting"
sleep $RCWAIT sleep $RCWAIT

View file

@ -43,8 +43,8 @@ if [ $BE -ne 0 ]; then
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
new "start backend -s init -f $cfg" new "start backend -s init -f $cfg -- -s"
start_backend -s init -f $cfg start_backend -s init -f $cfg -- -s
fi fi
new "kill old restconf daemon" new "kill old restconf daemon"

View file

@ -3,14 +3,14 @@
# This relieas on storing RFC7895 YANG Module Library modules-state info # This relieas on storing RFC7895 YANG Module Library modules-state info
# in the datastore (or XML files?) # in the datastore (or XML files?)
# The test is made with three Yang models A, B and C as follows: # The test is made with three Yang models A, B and C as follows:
# Yang module A has revisions "814-01-28" and "2019-01-01" # Yang module A has revisions "0814-01-28" and "2019-01-01"
# Yang module B has only revision "2019-01-01" # Yang module B has only revision "2019-01-01"
# Yang module C has only revision "2019-01-01" # Yang module C has only revision "2019-01-01"
# The system is started YANG modules: # The system is started YANG modules:
# A revision "2019-01-01" # A revision "2019-01-01"
# B revision "2019-01-01" # B revision "2019-01-01"
# The (startup) configuration XML file has: # The (startup) configuration XML file has:
# A revision "814-01-28"; # A revision "0814-01-28";
# B revision "2019-01-01" # B revision "2019-01-01"
# C revision "2019-01-01" # C revision "2019-01-01"
# Which means the following: # Which means the following:
@ -19,24 +19,26 @@
# B has a compatible version # B has a compatible version
# C is not present in the system # C is not present in the system
# 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 APPNAME=example
# include err() and new() functions and creates $dir
. ./lib.sh
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
fyangA0=$dir/A@814-01-28.yang fyangA0=$dir/A@0814-01-28.yang
fyangA1=$dir/A@2019-01-01.yang fyangA1=$dir/A@2019-01-01.yang
fyangB=$dir/B@2019-01-01.yang fyangB=$dir/B@2019-01-01.yang
# Yang module A revision "814-01-28" # Yang module A revision "0814-01-28"
# Note that this Yang model will exist in the DIR but will not be loaded # Note that this Yang model will exist in the DIR but will not be loaded
# by the system. Just here for reference # by the system. Just here for reference
# XXX: Maybe it should be loaded and used in draft-wu? # XXX: Maybe it should be loaded and used in draft-wu?
cat <<EOF > $fyangA0 cat <<EOF > $fyangA0
module A{ module A{
prefix a; prefix a;
revision 814-01-28; revision 0814-01-28;
namespace "urn:example:a"; namespace "urn:example:a";
leaf a0{ leaf a0{
type string; type string;
@ -52,7 +54,7 @@ cat <<EOF > $fyangA1
module A{ module A{
prefix a; prefix a;
revision 2019-01-01; revision 2019-01-01;
revision 814-01-28; revision 0814-01-28;
namespace "urn:example:a"; namespace "urn:example:a";
/* leaf a0 has been removed */ /* leaf a0 has been removed */
leaf a1{ leaf a1{
@ -171,7 +173,7 @@ cat <<EOF > $dir/non-compat-valid.xml
<module-set-id>42</module-set-id> <module-set-id>42</module-set-id>
<module> <module>
<name>A</name> <name>A</name>
<revision>814-01-28</revision> <revision>0814-01-28</revision>
<namespace>urn:example:a</namespace> <namespace>urn:example:a</namespace>
</module> </module>
<module> <module>
@ -198,7 +200,7 @@ cat <<EOF > $dir/non-compat-invalid.xml
<module-set-id>42</module-set-id> <module-set-id>42</module-set-id>
<module> <module>
<name>A</name> <name>A</name>
<revision>814-01-28</revision> <revision>0814-01-28</revision>
<namespace>urn:example:a</namespace> <namespace>urn:example:a</namespace>
</module> </module>
<module> <module>
@ -332,7 +334,8 @@ runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1><b xmlns="
new "5. Load non-compat invalid startup. Enter failsafe, startup invalid." new "5. Load non-compat invalid startup. Enter failsafe, startup invalid."
(cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases (cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases
(cd $dir; cp non-compat-invalid.xml startup_db) (cd $dir; cp non-compat-invalid.xml startup_db)
runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1></data>' '<data><a0 xmlns="urn:example:a">old version</a0><a1 xmlns="urn:example:a">always work</a1><b xmlns="urn:example:b">other text</b><c xmlns="urn:example:c">bla bla</c></data>' #runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1></data>' '<data><a0 xmlns="urn:example:a">old version</a0><a1 xmlns="urn:example:a">always work</a1><b xmlns="urn:example:b">other text</b><c xmlns="urn:example:c">bla bla</c></data>' # sorted
runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1></data>' '<data><a1 xmlns="urn:example:a">always work</a1><b xmlns="urn:example:b">other text</b><a0 xmlns="urn:example:a">old version</a0><c xmlns="urn:example:c">bla bla</c></data>' # unsorted
new "6. Load non-compat invalid running. Enter failsafe, startup invalid." new "6. Load non-compat invalid running. Enter failsafe, startup invalid."
(cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases (cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases
@ -345,7 +348,8 @@ runtest true running '<data><a1 xmlns="urn:example:a">always work</a1></data>' '
new "7. Load compatible invalid startup." new "7. Load compatible invalid startup."
(cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases (cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases
(cd $dir; cp compat-invalid.xml startup_db) (cd $dir; cp compat-invalid.xml startup_db)
runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1></data>' '<data><a0 xmlns="urn:example:a">old version</a0><a1 xmlns="urn:example:a">always work</a1><b xmlns="urn:example:b">other text</b><c xmlns="urn:example:c">bla bla</c></data>' #runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1></data>' '<data><a0 xmlns="urn:example:a">old version</a0><a1 xmlns="urn:example:a">always work</a1><b xmlns="urn:example:b">other text</b><c xmlns="urn:example:c">bla bla</c></data>' # sorted
runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1></data>' '<data><a1 xmlns="urn:example:a">always work</a1><b xmlns="urn:example:b">other text</b><a0 xmlns="urn:example:a">old version</a0><c xmlns="urn:example:c">bla bla</c></data>' # unsorted
# This testcase contains an error/exception of the clixon xml parser, and # This testcase contains an error/exception of the clixon xml parser, and
# I cant track down the memory leakage. # I cant track down the memory leakage.
@ -354,8 +358,7 @@ new "8. Load non-compat startup. Syntax fail, enter failsafe, startup invalid"
(cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases (cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases
(cd $dir; cp compat-err.xml startup_db) (cd $dir; cp compat-err.xml startup_db)
runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1></data>' '<rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>read registry</error-message></rpc-error>' runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1></data>' '<rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>read registry</error-message></rpc-error>'
fi # valgrindtest
fi
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
rm -rf $dir rm -rf $dir

145
test/test_upgrade_repair.sh Executable file
View file

@ -0,0 +1,145 @@
#!/bin/bash
# Start clixon with module A rec 2019
# Load startup with non-compatible and invalid module A with rev 0814-01-28
# Go into fail-safe with invalid startup
# 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_yang.xml
fyangA0=$dir/A@0814-01-28.yang
fyangA1=$dir/A@2019-01-01.yang
# Yang module A revision "0814-01-28"
# Note that this Yang model will exist in the DIR but will not be loaded
# by the system. Just here for reference
# XXX: Maybe it should be loaded and used in draft-wu?
cat <<EOF > $fyangA0
module A{
prefix a;
revision 0814-01-28;
namespace "urn:example:a";
leaf a0{
type string;
}
leaf a1{
type string;
}
}
EOF
# Yang module A revision "2019-01-01"
cat <<EOF > $fyangA1
module A{
prefix a;
revision 2019-01-01;
revision 0814-01-28;
namespace "urn:example:a";
/* leaf a0 has been removed */
leaf a1{
description "exists in both versions";
type string;
}
leaf a2{
description "has been added";
type string;
}
}
EOF
# Create configuration
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_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_DIR>/usr/local/lib/example/backend</CLICON_BACKEND_DIR>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
<CLICON_XMLDB_PLUGIN>/usr/local/lib/xmldb/text.so</CLICON_XMLDB_PLUGIN>
<CLICON_XMLDB_MODSTATE>true</CLICON_XMLDB_MODSTATE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
</clixon-config>
EOF
# Create failsafe db
cat <<EOF > $dir/failsafe_db
<config>
<a1 xmlns="urn:example:a">always work</a1>
</config>
EOF
# Create non-compat startup db
# startup config XML with following (A obsolete, B OK, C lacking)
cat <<EOF > $dir/non-compat-invalid.xml
<config>
<modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
<module-set-id>42</module-set-id>
<module>
<name>A</name>
<revision>0814-01-28</revision>
<namespace>urn:example:a</namespace>
</module>
</modules-state>
<a0 xmlns="urn:example:a">old version</a0>
<a1 xmlns="urn:example:a">always work</a1>
</config>
EOF
(cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases
(cd $dir; cp non-compat-invalid.xml startup_db)
mode=startup
new "test params: -f $cfg"
# Bring your own backend
if [ $BE -ne 0 ]; then
# kill old backend (if any)
new "kill old backend"
sudo clixon_backend -zf $cfg
if [ $? -ne 0 ]; then
err
fi
new "start backend -s $mode -f $cfg"
start_backend -s $mode -f $cfg
fi
new "waiting"
sleep $RCWAIT
new "kill old restconf daemon"
sudo pkill -u www-data clixon_restconf
new "start restconf daemon"
start_restconf -f $cfg
new "waiting"
sleep $RCWAIT
new "Check running db content is failsafe"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><running/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><a1 xmlns="urn:example:a">always work</a1></data></rpc-reply>]]>]]>$'
#repair
#exit
new "Kill restconf daemon"
stop_restconf
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
rm -rf $dir
fi

View file

@ -10,16 +10,20 @@ s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
APPNAME=example APPNAME=example
OLDDATE=0814-01-28 # This is alphabeticaly after 2018-12-02
NEWDATE=2018-12-02
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
fyang1=$dir/$APPNAME@2018-12-02.yang fyang1=$dir/$APPNAME@2018-12-02.yang
fyang2=$dir/$APPNAME@2018-01-01.yang fyang2=$dir/$APPNAME@$OLDDATE.yang
fyang3=$dir/other.yang fyang3=$dir/other.yang
# 1st variant of the example module # 1st variant of the example module
cat <<EOF > $fyang1 cat <<EOF > $fyang1
module example{ module example{
prefix ex; prefix ex;
revision 2018-12-02; revision $NEWDATE;
revision $OLDDATE;
namespace "urn:example:clixon"; namespace "urn:example:clixon";
leaf newex{ leaf newex{
type string; type string;
@ -31,7 +35,7 @@ EOF
cat <<EOF > $fyang2 cat <<EOF > $fyang2
module example{ module example{
prefix ex; prefix ex;
revision 2018-01-01; revision $OLDDATE;
namespace "urn:example:clixon"; namespace "urn:example:clixon";
leaf oldex{ leaf oldex{
type string; type string;
@ -43,7 +47,7 @@ EOF
cat <<EOF > $fyang3 cat <<EOF > $fyang3
module other{ module other{
prefix oth; prefix oth;
revision 2018-01-01; revision $NEWDATE;
namespace "urn:example:clixon2"; namespace "urn:example:clixon2";
leaf other{ leaf other{
type string; type string;
@ -94,20 +98,18 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
new "Set other should fail" new "Set other should fail"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>other</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>other</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
if [ $BE -eq 0 ]; then if [ $BE -ne 0 ]; then
exit # BE 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
sudo pkill -u root -f clixon_backend
fi fi
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
sudo pkill -u root -f clixon_backend
#-------------------------------------- #--------------------------------------
new "2. Load old module as file" new "2. Load old module as file"
cat <<EOF > $cfg cat <<EOF > $cfg
@ -128,12 +130,14 @@ cat <<EOF > $cfg
</clixon-config> </clixon-config>
EOF EOF
new "start backend -s init -f $cfg" if [ $BE -ne 0 ]; then
# start new backend new "start backend -s init -f $cfg"
start_backend -s init -f $cfg # start new backend
start_backend -s init -f $cfg
new "waiting" new "waiting"
sleep $RCWAIT sleep $RCWAIT
fi
new "Set oldex" new "Set oldex"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
@ -144,15 +148,17 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
new "Set other should fail" new "Set other should fail"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>other</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>other</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
new "Kill backend" if [ $BE -ne 0 ]; then
# Check if premature kill new "Kill backend"
pid=`pgrep -u root -f clixon_backend` # Check if premature kill
if [ -z "$pid" ]; then pid=`pgrep -u root -f clixon_backend`
err "backend already dead" if [ -z "$pid" ]; then
err "backend already dead"
fi
# kill backend
stop_backend -f $cfg
sudo pkill -u root -f clixon_backend
fi fi
# kill backend
stop_backend -f $cfg
sudo pkill -u root -f clixon_backend
#-------------------------------------- #--------------------------------------
new "3. Load module with no revision" new "3. Load module with no revision"
@ -170,11 +176,13 @@ cat <<EOF > $cfg
</clixon-config> </clixon-config>
EOF EOF
new "start backend -s init -f $cfg" if [ $BE -ne 0 ]; then
start_backend -s init -f $cfg new "start backend -s init -f $cfg"
start_backend -s init -f $cfg
new "waiting" new "waiting"
sleep $RCWAIT sleep $RCWAIT
fi
new "Set newex" new "Set newex"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex xmlns="urn:example:clixon">str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex xmlns="urn:example:clixon">str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
@ -185,14 +193,16 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
new "Set other should fail" new "Set other should fail"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>other</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>other</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
new "Kill backend" if [ $BE -ne 0 ]; then
# Check if premature kill new "Kill backend"
pid=`pgrep -u root -f clixon_backend` # Check if premature kill
if [ -z "$pid" ]; then pid=`pgrep -u root -f clixon_backend`
err "backend already dead" if [ -z "$pid" ]; then
err "backend already dead"
fi
stop_backend -f $cfg
sudo pkill -u root -f clixon_backend
fi fi
stop_backend -f $cfg
sudo pkill -u root -f clixon_backend
#-------------------------------------- #--------------------------------------
new "4. Load module with old revision" new "4. Load module with old revision"
@ -203,7 +213,7 @@ cat <<EOF > $cfg
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
<CLICON_YANG_MODULE_REVISION>2018-01-01</CLICON_YANG_MODULE_REVISION> <CLICON_YANG_MODULE_REVISION>$OLDDATE</CLICON_YANG_MODULE_REVISION>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK> <CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE> <CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR> <CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
@ -211,11 +221,13 @@ cat <<EOF > $cfg
</clixon-config> </clixon-config>
EOF EOF
new "start backend -s init -f $cfg" if [ $BE -ne 0 ]; then
start_backend -s init -f $cfg new "start backend -s init -f $cfg"
start_backend -s init -f $cfg
new "waiting" new "waiting"
sleep $RCWAIT sleep $RCWAIT
fi
new "Set oldex" new "Set oldex"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
@ -226,15 +238,17 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
new "Set other should fail" new "Set other should fail"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>other</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>other</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
new "Kill backend" if [ $BE -ne 0 ]; then
# Check if premature kill new "Kill backend"
pid=`pgrep -u root -f clixon_backend` # Check if premature kill
if [ -z "$pid" ]; then pid=`pgrep -u root -f clixon_backend`
err "backend already dead" if [ -z "$pid" ]; then
err "backend already dead"
fi
# kill backend
stop_backend -f $cfg
sudo pkill -u root -f clixon_backend
fi fi
# kill backend
stop_backend -f $cfg
sudo pkill -u root -f clixon_backend
#-------------------------------------- #--------------------------------------
new "5. Load dir" new "5. Load dir"
@ -252,11 +266,13 @@ cat <<EOF > $cfg
</clixon-config> </clixon-config>
EOF EOF
new "start backend -s init -f $cfg" if [ $BE -ne 0 ]; then
start_backend -s init -f $cfg new "start backend -s init -f $cfg"
start_backend -s init -f $cfg
new "waiting" new "waiting"
sleep $RCWAIT sleep $RCWAIT
fi
new "Set newex" new "Set newex"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex xmlns="urn:example:clixon">str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex xmlns="urn:example:clixon">str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
@ -267,15 +283,18 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
new "Set other" new "Set other"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "Kill backend" if [ $BE -ne 0 ]; then
# Check if premature kill new "Kill backend"
pid=`pgrep -u root -f clixon_backend` # Check if premature kill
if [ -z "$pid" ]; then pid=`pgrep -u root -f clixon_backend`
err "backend already dead" if [ -z "$pid" ]; then
err "backend already dead"
fi
# kill backend
stop_backend -f $cfg
sudo pkill -u root -f clixon_backend
fi fi
# kill backend
stop_backend -f $cfg
sudo pkill -u root -f clixon_backend
#-------------------------------------- #--------------------------------------
new "6. Load dir override with file" new "6. Load dir override with file"
@ -294,12 +313,13 @@ cat <<EOF > $cfg
</clixon-config> </clixon-config>
EOF EOF
new "start backend -s init -f $cfg" if [ $BE -ne 0 ]; then
start_backend -s init -f $cfg new "start backend -s init -f $cfg"
start_backend -s init -f $cfg
new "waiting"
sleep $RCWAIT
new "waiting"
sleep $RCWAIT
fi
new "Set oldex" new "Set oldex"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
@ -309,16 +329,17 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
new "Set other" new "Set other"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "Kill backend" if [ $BE -ne 0 ]; then
# Check if premature kill new "Kill backend"
pid=`pgrep -u root -f clixon_backend` # Check if premature kill
if [ -z "$pid" ]; then pid=`pgrep -u root -f clixon_backend`
err "backend already dead" if [ -z "$pid" ]; then
err "backend already dead"
fi
# kill backend
stop_backend -f $cfg
sudo pkill -u root -f clixon_backend
fi fi
# kill backend
stop_backend -f $cfg
sudo pkill -u root -f clixon_backend
#-------------------------------------- #--------------------------------------
new "7. Load dir override with module + revision" new "7. Load dir override with module + revision"
@ -330,7 +351,7 @@ cat <<EOF > $cfg
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR> <CLICON_YANG_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
<CLICON_YANG_MODULE_REVISION>2018-01-01</CLICON_YANG_MODULE_REVISION> <CLICON_YANG_MODULE_REVISION>$OLDDATE</CLICON_YANG_MODULE_REVISION>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK> <CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE> <CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR> <CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
@ -338,11 +359,13 @@ cat <<EOF > $cfg
</clixon-config> </clixon-config>
EOF EOF
new "start backend -s init -f $cfg" if [ $BE -ne 0 ]; then
start_backend -s init -f $cfg new "start backend -s init -f $cfg"
start_backend -s init -f $cfg
new "waiting" new "waiting"
sleep $RCWAIT sleep $RCWAIT
fi
new "Set oldex" new "Set oldex"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
@ -353,15 +376,17 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
new "Set other" new "Set other"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "Kill backend" if [ $BE -ne 0 ]; then
# Check if premature kill new "Kill backend"
pid=`pgrep -u root -f clixon_backend` # Check if premature kill
if [ -z "$pid" ]; then pid=`pgrep -u root -f clixon_backend`
err "backend already dead" if [ -z "$pid" ]; then
err "backend already dead"
fi
# kill backend
stop_backend -f $cfg
sudo pkill -u root -f clixon_backend
fi fi
# kill backend
stop_backend -f $cfg
sudo pkill -u root -f clixon_backend
#-------------------------------------- #--------------------------------------
new "8. Load module w new revision overrided by old file" new "8. Load module w new revision overrided by old file"
@ -373,7 +398,7 @@ cat <<EOF > $cfg
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang2</CLICON_YANG_MAIN_FILE> <CLICON_YANG_MAIN_FILE>$fyang2</CLICON_YANG_MAIN_FILE>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
<CLICON_YANG_MODULE_REVISION>2018-12-02</CLICON_YANG_MODULE_REVISION> <CLICON_YANG_MODULE_REVISION>$NEWDATE</CLICON_YANG_MODULE_REVISION>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK> <CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE> <CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR> <CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
@ -381,11 +406,13 @@ cat <<EOF > $cfg
</clixon-config> </clixon-config>
EOF EOF
new "start backend -s init -f $cfg" if [ $BE -ne 0 ]; then
start_backend -s init -f $cfg new "start backend -s init -f $cfg"
start_backend -s init -f $cfg
new "waiting" new "waiting"
sleep $RCWAIT sleep $RCWAIT
fi
new "Set oldex" new "Set oldex"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
@ -396,14 +423,18 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
new "Set other should fail" new "Set other should fail"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>other</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>other</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
new "Kill backend" if [ $BE -ne 0 ]; then
# Check if premature kill new "Kill backend"
pid=`pgrep -u root -f clixon_backend` # Check if premature kill
if [ -z "$pid" ]; then pid=`pgrep -u root -f clixon_backend`
err "backend already dead" if [ -z "$pid" ]; then
fi err "backend already dead"
# kill backend fi
stop_backend -f $cfg # kill backend
sudo pkill -u root -f clixon_backend stop_backend -f $cfg
sudo pkill -u root -f clixon_backend
rm -rf $dir
fi
rm -rf $dir

View file

@ -99,7 +99,7 @@ new "netconf get config example1 and example2"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon1">42</x><x xmlns="urn:example:clixon2"><y>99</y></x></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon1">42</x><x xmlns="urn:example:clixon2"><y>99</y></x></data></rpc-reply>]]>]]>$'
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang1" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "restconf set x in example1" new "restconf set x in example1"
expecteq "$(curl -s -X POST -d '{"example1:x":42}' http://localhost/restconf/data)" 0 '' expecteq "$(curl -s -X POST -d '{"example1:x":42}' http://localhost/restconf/data)" 0 ''