* Added xml_wrap function that adds an XML node above a node as a wrapper
* also renamed `xml_insert` to `xml_wrap_all`. * Added `clicon_argv_get()` function to get the user command-line options, ie the args in `-- <args>`. This is an alternative to using them passed to `plugin_start()`.
This commit is contained in:
parent
8624be0a67
commit
6ff36a2894
9 changed files with 642 additions and 54 deletions
|
|
@ -34,6 +34,8 @@
|
|||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
|
@ -64,6 +66,12 @@ static int _reset = 0;
|
|||
*/
|
||||
static int _state = 0;
|
||||
|
||||
/*! Variable to control upgrade callbacks.
|
||||
* If set, call test-case for upgrading ietf-interfaces, otherwise call
|
||||
* auto-upgrade
|
||||
*/
|
||||
static int _upgrade = 0;
|
||||
|
||||
/* forward */
|
||||
static int example_stream_timer_setup(clicon_handle h);
|
||||
|
||||
|
|
@ -246,7 +254,7 @@ example_statedata(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Registered Upgrade callback function
|
||||
/*! Testcase upgrade function moving interfaces-state to interfaces
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] xn XML tree to be updated
|
||||
* @param[in] ns Namespace of module (for info)
|
||||
|
|
@ -258,21 +266,131 @@ example_statedata(clicon_handle h,
|
|||
* @retval 0 Invalid
|
||||
* @retval -1 Error
|
||||
* @see clicon_upgrade_cb
|
||||
* @see test_upgrade_interfaces.sh
|
||||
* @see upgrade_interfaces_2016
|
||||
* This example shows a two-step upgrade where the 2014 function does:
|
||||
* - Move /if:interfaces-state/if:interface/if:admin-status to
|
||||
* /if:interfaces/if:interface/
|
||||
* - Move /if:interfaces-state/if:interface/if:statistics to
|
||||
* /if:interfaces/if:interface/
|
||||
* - Rename /interfaces/interface/description to descr
|
||||
*/
|
||||
static int
|
||||
upgrade_all(clicon_handle h,
|
||||
cxobj *xt,
|
||||
char *ns,
|
||||
uint32_t from,
|
||||
uint32_t to,
|
||||
void *arg,
|
||||
cbuf *cbret)
|
||||
upgrade_interfaces_2014(clicon_handle h,
|
||||
cxobj *xt,
|
||||
char *ns,
|
||||
uint32_t from,
|
||||
uint32_t to,
|
||||
void *arg,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_spec *yspec;
|
||||
yang_stmt *ym;
|
||||
cxobj **vec = NULL;
|
||||
cxobj *xc;
|
||||
cxobj *xi; /* xml /interfaces-states/interface node */
|
||||
cxobj *x;
|
||||
cxobj *xif; /* xml /interfaces/interface node */
|
||||
size_t vlen;
|
||||
int i;
|
||||
char *name;
|
||||
|
||||
/* Get Yang module for this namespace. Note it may not exist (if obsolete) */
|
||||
yspec = clicon_dbspec_yang(h);
|
||||
if ((ym = yang_find_module_by_namespace(yspec, ns)) == NULL)
|
||||
goto ok; /* shouldnt happen */
|
||||
clicon_debug(1, "%s module %s", __FUNCTION__, ym?ym->ys_argument:"none");
|
||||
/* Get all XML nodes with that namespace */
|
||||
if (xml_namespace_vec(h, xt, ns, &vec, &vlen) < 0)
|
||||
goto done;
|
||||
for (i=0; i<vlen; i++){
|
||||
xc = vec[i];
|
||||
/* Iterate through interfaces-state */
|
||||
if (strcmp(xml_name(xc),"interfaces-state") == 0){
|
||||
/* Note you cannot delete or move xml objects directly under xc
|
||||
* in the loop (eg xi objects) but you CAN move children of xi
|
||||
*/
|
||||
xi = NULL;
|
||||
while ((xi = xml_child_each(xc, xi, CX_ELMNT)) != NULL) {
|
||||
if (strcmp(xml_name(xi), "interface"))
|
||||
continue;
|
||||
if ((name = xml_find_body(xi, "name")) == NULL)
|
||||
continue; /* shouldnt happen */
|
||||
/* Get corresponding /interfaces/interface entry */
|
||||
xif = xpath_first(xt, "/interfaces/interface[name=\"%s\"]", name);
|
||||
/* - Move /if:interfaces-state/if:interface/if:admin-status to
|
||||
* /if:interfaces/if:interface/ */
|
||||
if ((x = xml_find(xi, "admin-status")) != NULL && xif){
|
||||
if (xml_addsub(xif, x) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* - Move /if:interfaces-state/if:interface/if:statistics to
|
||||
* /if:interfaces/if:interface/*/
|
||||
if ((x = xml_find(xi, "statistics")) != NULL){
|
||||
if (xml_addsub(xif, x) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strcmp(xml_name(xc),"interfaces") == 0){
|
||||
/* Iterate through interfaces */
|
||||
xi = NULL;
|
||||
while ((xi = xml_child_each(xc, xi, CX_ELMNT)) != NULL) {
|
||||
if (strcmp(xml_name(xi), "interface"))
|
||||
continue;
|
||||
/* Rename /interfaces/interface/description to descr */
|
||||
if ((x = xml_find(xi, "description")) != NULL)
|
||||
if (xml_name_set(x, "descr") < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
ok:
|
||||
retval = 1;
|
||||
done:
|
||||
if (vec)
|
||||
free(vec);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Testcase upgrade function removing interfaces-state
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] xn XML tree to be updated
|
||||
* @param[in] ns Namespace of module (for info)
|
||||
* @param[in] from From revision on the form YYYYMMDD
|
||||
* @param[in] to To revision on the form YYYYMMDD (0 not in system)
|
||||
* @param[in] arg User argument given at rpc_callback_register()
|
||||
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
|
||||
* @retval 1 OK
|
||||
* @retval 0 Invalid
|
||||
* @retval -1 Error
|
||||
* @see clicon_upgrade_cb
|
||||
* @see test_upgrade_interfaces.sh
|
||||
* @see upgrade_interfaces_2014
|
||||
* The 2016 function does:
|
||||
* - Delete /if:interfaces-state
|
||||
* - Wrap /interfaces/interface/descr to /interfaces/interface/docs/descr
|
||||
* - Change type /interfaces/interface/statistics/in-octets to decimal64 with
|
||||
* fraction-digits 3 and divide all values with 1000
|
||||
*/
|
||||
static int
|
||||
upgrade_interfaces_2016(clicon_handle h,
|
||||
cxobj *xt,
|
||||
char *ns,
|
||||
uint32_t from,
|
||||
uint32_t to,
|
||||
void *arg,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_spec *yspec;
|
||||
yang_stmt *ym;
|
||||
cxobj **vec = NULL;
|
||||
cxobj *xc;
|
||||
cxobj *xi;
|
||||
cxobj *x;
|
||||
cxobj *xb;
|
||||
size_t vlen;
|
||||
int i;
|
||||
|
||||
|
|
@ -286,7 +404,35 @@ upgrade_all(clicon_handle h,
|
|||
goto done;
|
||||
for (i=0; i<vlen; i++){
|
||||
xc = vec[i];
|
||||
clicon_debug(1, "%s update %s", __FUNCTION__, xml_name(xc));
|
||||
/* Delete /if:interfaces-state */
|
||||
if (strcmp(xml_name(xc), "interfaces-state") == 0)
|
||||
xml_purge(xc);
|
||||
/* Iterate through interfaces */
|
||||
else if (strcmp(xml_name(xc),"interfaces") == 0){
|
||||
/* Iterate through interfaces */
|
||||
xi = NULL;
|
||||
while ((xi = xml_child_each(xc, xi, CX_ELMNT)) != NULL) {
|
||||
if (strcmp(xml_name(xi), "interface"))
|
||||
continue;
|
||||
/* Wrap /interfaces/interface/descr to /interfaces/interface/docs/descr */
|
||||
if ((x = xml_find(xi, "descr")) != NULL)
|
||||
if (xml_wrap(x, "docs") < 0)
|
||||
goto done;
|
||||
/* Change type /interfaces/interface/statistics/in-octets to
|
||||
* decimal64 with fraction-digits 3 and divide values with 1000
|
||||
*/
|
||||
if ((x = xpath_first(xi, "statistics/in-octets")) != NULL){
|
||||
if ((xb = xml_body_get(x)) != NULL){
|
||||
uint64_t u64;
|
||||
cbuf *cb = cbuf_new();
|
||||
parse_uint64(xml_value(xb), &u64, NULL);
|
||||
cprintf(cb, "%" PRIu64 ".%03d", u64/1000, (int)(u64%1000));
|
||||
xml_value_set(xb, cbuf_get(cb));
|
||||
cbuf_free(cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ok:
|
||||
retval = 1;
|
||||
|
|
@ -355,7 +501,7 @@ example_reset(clicon_handle h,
|
|||
*
|
||||
* plugin_start is called once everything has been initialized, right before
|
||||
* the main event loop is entered.
|
||||
* From the CLI, command line options can be passed to the
|
||||
* From the cli/backend, command line options can be passed to the
|
||||
* plugins by using "-- <args>" where <args> is any choice of
|
||||
* options specific to the application. These options are passed to the
|
||||
* plugin_start function via the argc and argv arguments which
|
||||
|
|
@ -363,22 +509,9 @@ example_reset(clicon_handle h,
|
|||
*/
|
||||
int
|
||||
example_start(clicon_handle h,
|
||||
int argc,
|
||||
char **argv)
|
||||
int argc,
|
||||
char **argv)
|
||||
{
|
||||
char c;
|
||||
|
||||
opterr = 0;
|
||||
optind = 1;
|
||||
while ((c = getopt(argc, argv, "rs")) != -1)
|
||||
switch (c) {
|
||||
case 'r':
|
||||
_reset = 1;
|
||||
break;
|
||||
case 's':
|
||||
_state = 1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -409,13 +542,36 @@ static clixon_plugin_api api = {
|
|||
* @param[in] h Clixon handle
|
||||
* @retval NULL Error with clicon_err set
|
||||
* @retval api Pointer to API struct
|
||||
* In this example, you can pass -r, -s, -u to control the behaviour, mainly
|
||||
* for use in the test suites.
|
||||
*/
|
||||
clixon_plugin_api *
|
||||
clixon_plugin_init(clicon_handle h)
|
||||
{
|
||||
struct timeval retention = {0,0};
|
||||
int argc; /* command-line options (after --) */
|
||||
char **argv;
|
||||
char c;
|
||||
|
||||
clicon_debug(1, "%s backend", __FUNCTION__);
|
||||
|
||||
if (clicon_argv_get(h, &argc, &argv) < 0)
|
||||
goto done;
|
||||
opterr = 0;
|
||||
optind = 1;
|
||||
while ((c = getopt(argc, argv, "rsu")) != -1)
|
||||
switch (c) {
|
||||
case 'r':
|
||||
_reset = 1;
|
||||
break;
|
||||
case 's':
|
||||
_state = 1;
|
||||
break;
|
||||
case 'u':
|
||||
_upgrade = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Example stream initialization:
|
||||
* 1) Register EXAMPLE stream
|
||||
* 2) setup timer for notifications, so something happens on stream
|
||||
|
|
@ -464,9 +620,18 @@ clixon_plugin_init(clicon_handle h)
|
|||
"copy-config"
|
||||
) < 0)
|
||||
goto done;
|
||||
/* General purpose upgrade callback */
|
||||
if (upgrade_callback_register(h, xml_changelog_upgrade, NULL, 0, 0, NULL) < 0)
|
||||
goto done;
|
||||
/* Upgrade callback: if you start the backend with -- -u you will get the
|
||||
* test interface example. Otherwise the auto-upgrade feature is enabled.
|
||||
*/
|
||||
if (_upgrade){
|
||||
if (upgrade_callback_register(h, upgrade_interfaces_2014, "urn:example:interfaces", 0, 0, NULL) < 0)
|
||||
goto done;
|
||||
if (upgrade_callback_register(h, upgrade_interfaces_2016, "urn:example:interfaces", 0, 0, NULL) < 0)
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
if (upgrade_callback_register(h, xml_changelog_upgrade, NULL, 0, 0, NULL) < 0)
|
||||
goto done;
|
||||
|
||||
/* Return plugin API */
|
||||
return &api;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue