* New yang changelog experimental feature for automatic upgrade

* Added modules-state diff parameter to xmldb_get datastore function for startup scenarios.
* Allowed Yang extended Xpath functions (syntax only):
  * re-match, deref, derived-from, derived-from-or-self, enum-value, bit-is-set
* XSD regular expression handling of dash(`-`)
  *: Translate XDS `[xxx\-yyy]` to POSIX `[xxxyyy-]`.
* YANG Anydata treated same as Anyxml
This commit is contained in:
Olof hagsand 2019-03-21 17:42:53 +01:00
parent 434f0b930e
commit 3f68cca06c
37 changed files with 1475 additions and 351 deletions

View file

@ -407,23 +407,25 @@ clixon_plugin_auth(clicon_handle h,
* When namespace and name match, the callback is made
*/
typedef struct {
qelem_t rc_qelem; /* List header */
qelem_t rc_qelem; /* List header */
clicon_rpc_cb rc_callback; /* RPC Callback */
void *rc_arg; /* Application specific argument to cb */
char *rc_namespace;/* Namespace to combine with name tag */
char *rc_name; /* Xml/json tag/name */
void *rc_arg; /* Application specific argument to cb */
char *rc_namespace;/* Namespace to combine with name tag */
char *rc_name; /* Xml/json tag/name */
} rpc_callback_t;
/* List of rpc callback entries */
/* List of rpc callback entries XXX hang on handle */
static rpc_callback_t *rpc_cb_list = NULL;
/*! Register a RPC callback by appending a new RPC to the list
*
* @param[in] h clicon handle
* @param[in] cb, Callback called
* @param[in] arg, Domain-specific argument to send to callback
* @param[in] cb Callback called
* @param[in] arg Domain-specific argument to send to callback
* @param[in] namespace namespace of rpc
* @param[in] name RPC name
* @retval 0 OK
* @retval -1 Error
* @see rpc_callback_call which makes the actual callback
*/
int
@ -530,3 +532,151 @@ rpc_callback_call(clicon_handle h,
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
/*--------------------------------------------------------------------
* Upgrade callbacks for backend upgrade of datastore
* Register upgrade callbacks in plugin_init() with a module and a "from" and "to"
* revision.
*/
typedef struct {
qelem_t uc_qelem; /* List header */
clicon_upgrade_cb uc_callback; /* RPC Callback */
void *uc_arg; /* Application specific argument to cb */
char *uc_name; /* Module name */
char *uc_namespace; /* Module namespace ??? */
uint32_t uc_from; /* Module revision (from) or 0 in YYYYMMDD format */
uint32_t uc_to; /* Module revision (to) in YYYYMMDD format */
} upgrade_callback_t;
/* List of rpc callback entries XXX hang on handle */
static upgrade_callback_t *upgrade_cb_list = NULL;
/*! Register an upgrade callback by appending the new callback to the list
*
* @param[in] h clicon handle
* @param[in] cb Callback called
* @param[in] arg Domain-specific argument to send to callback
* @param[in] name Module name (if NULL all modules)
* @param[in] namespace Module namespace (NOTE not relevant)
* @param[in] from From module revision (0 from any revision)
* @param[in] to To module revision (0 means module obsoleted)
* @retval 0 OK
* @retval -1 Error
* @see upgrade_callback_call which makes the actual callback
*/
int
upgrade_callback_register(clicon_handle h,
clicon_upgrade_cb cb,
void *arg,
char *name,
char *namespace,
uint32_t from,
uint32_t to)
{
upgrade_callback_t *uc;
if ((uc = malloc(sizeof(upgrade_callback_t))) == NULL) {
clicon_err(OE_DB, errno, "malloc: %s", strerror(errno));
goto done;
}
memset(uc, 0, sizeof(*uc));
uc->uc_callback = cb;
uc->uc_arg = arg;
if (name)
uc->uc_name = strdup(name);
if (namespace)
uc->uc_namespace = strdup(namespace);
uc->uc_from = from;
uc->uc_to = to;
ADDQ(uc, upgrade_cb_list);
return 0;
done:
if (uc){
if (uc->uc_name)
free(uc->uc_name);
if (uc->uc_namespace)
free(uc->uc_namespace);
free(uc);
}
return -1;
}
/*! Delete all Upgrade callbacks
*/
int
upgrade_callback_delete_all(void)
{
upgrade_callback_t *uc;
while((uc = upgrade_cb_list) != NULL) {
DELQ(uc, upgrade_cb_list, upgrade_callback_t *);
if (uc->uc_name)
free(uc->uc_name);
if (uc->uc_namespace)
free(uc->uc_namespace);
free(uc);
}
return 0;
}
/*! Search Upgrade callbacks and invoke if module match
*
* @param[in] h clicon handle
* @param[in] xt XML tree to be updated
* @param[in] modname Name of module
* @param[in] modns 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[out] cbret Return XML (as string in CLIgen buffer), on invalid
* @retval -1 Error
* @retval 0 Invalid - cbret contains reason as netconf
* @retval 1 OK
* @see upgrade_callback_register which registers the callbacks
*/
int
upgrade_callback_call(clicon_handle h,
cxobj *xt,
char *modname,
char *modns,
uint32_t from,
uint32_t to,
cbuf *cbret)
{
int retval = -1;
upgrade_callback_t *uc;
int nr = 0; /* How many callbacks */
int ret;
if (upgrade_cb_list == NULL)
return 0;
uc = upgrade_cb_list;
do {
/* For matching an upgrade callback:
* - No module name registered (matches all modules) OR
* - Names match
* AND
* - No registered from revision (matches all revisions) OR
* - Registered from revision >= from AND
* - Registered to revision <= to (which includes case both 0)
*/
if (uc->uc_name == NULL || strcmp(uc->uc_name, modname)==0)
if ((uc->uc_from == 0) ||
(uc->uc_from >= from && uc->uc_to <= to)){
if ((ret = uc->uc_callback(h, xt, modname, modns, from, to, uc->uc_arg, cbret)) < 0){
clicon_debug(1, "%s Error in: %s", __FUNCTION__, uc->uc_name);
goto done;
}
if (ret == 0)
goto fail;
nr++;
}
uc = NEXTQ(upgrade_callback_t *, uc);
} while (uc != upgrade_cb_list);
retval = 1;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
return retval;
fail:
retval =0;
goto done;
}