xml changelog next iteration
This commit is contained in:
parent
1991c3870c
commit
8624be0a67
9 changed files with 532 additions and 353 deletions
|
|
@ -140,6 +140,194 @@ generic_validate(yang_spec *yspec,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Common startup validation
|
||||||
|
* Get db, upgrade it w potential transformed XML, populate it w yang spec,
|
||||||
|
* sort it, validate it by triggering a transaction
|
||||||
|
* and call application callback validations.
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] db The startup database. The wanted backend state
|
||||||
|
* @param[out] xtr Transformed XML
|
||||||
|
* @param[out] cbret CLIgen buffer w error stmt if retval = 0
|
||||||
|
* @retval -1 Error - or validation failed (but cbret not set)
|
||||||
|
* @retval 0 Validation failed (with cbret set)
|
||||||
|
* @retval 1 Validation OK
|
||||||
|
* @note Need to differentiate between error and validation fail
|
||||||
|
*
|
||||||
|
* 1. Parse startup XML (or JSON)
|
||||||
|
* 2. If syntax failure, call startup-cb(ERROR), copy failsafe db to
|
||||||
|
* candidate and commit. Done
|
||||||
|
* 3. Check yang module versions between backend and init config XML. (msdiff)
|
||||||
|
* 4. Validate startup db. (valid)
|
||||||
|
* 5. If valid fails, call startup-cb(Invalid, msdiff), keep startup in candidate and commit failsafe db. Done.
|
||||||
|
* 6. Call startup-cb(OK, msdiff) and commit.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
startup_common(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
transaction_data_t *td,
|
||||||
|
cbuf *cbret)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
yang_spec *yspec;
|
||||||
|
int ret;
|
||||||
|
modstate_diff_t *msd = NULL;
|
||||||
|
cxobj *xt = NULL;
|
||||||
|
|
||||||
|
/* If CLICON_XMLDB_MODSTATE is enabled, then get the db XML with
|
||||||
|
* potentially non-matching module-state in msd
|
||||||
|
*/
|
||||||
|
if (clicon_option_bool(h, "CLICON_XMLDB_MODSTATE"))
|
||||||
|
if ((msd = modstate_diff_new()) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (xmldb_get(h, db, "/", 1, &xt, msd) < 0)
|
||||||
|
goto done;
|
||||||
|
if (msd){
|
||||||
|
if ((ret = clixon_module_upgrade(h, xt, msd, cbret)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||||
|
clicon_err(OE_YANG, 0, "Yang spec not set");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* After upgrading, XML tree needs to be sorted and yang spec populated */
|
||||||
|
if (xml_apply0(xt, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||||
|
goto done;
|
||||||
|
if (xml_apply0(xt, CX_ELMNT, xml_sort, NULL) < 0)
|
||||||
|
goto done;
|
||||||
|
/* Handcraft transition with with only add tree */
|
||||||
|
td->td_target = xt;
|
||||||
|
if (cxvec_append(td->td_target, &td->td_avec, &td->td_alen) < 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* 4. Call plugin transaction start callbacks */
|
||||||
|
if (plugin_transaction_begin(h, td) < 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* 5. Make generic validation on all new or changed data.
|
||||||
|
Note this is only call that uses 3-values */
|
||||||
|
if ((ret = generic_validate(yspec, td, cbret)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
goto fail; /* STARTUP_INVALID */
|
||||||
|
|
||||||
|
/* 6. Call plugin transaction validate callbacks */
|
||||||
|
if (plugin_transaction_validate(h, td) < 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* 7. Call plugin transaction complete callbacks */
|
||||||
|
if (plugin_transaction_complete(h, td) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 1;
|
||||||
|
done:
|
||||||
|
if (msd)
|
||||||
|
modstate_diff_free(msd);
|
||||||
|
return retval;
|
||||||
|
fail:
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Read startup db, check upgrades and validate it, return upgraded XML
|
||||||
|
*
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] db The startup database. The wanted backend state
|
||||||
|
* @param[out] xtr (Potentially) transformed XML
|
||||||
|
* @param[out] cbret CLIgen buffer w error stmt if retval = 0
|
||||||
|
* @retval -1 Error - or validation failed (but cbret not set)
|
||||||
|
* @retval 0 Validation failed (with cbret set)
|
||||||
|
* @retval 1 Validation OK
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
startup_validate(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
cxobj **xtr,
|
||||||
|
cbuf *cbret)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
int ret;
|
||||||
|
transaction_data_t *td = NULL;
|
||||||
|
|
||||||
|
/* Handcraft a transition with only target and add trees */
|
||||||
|
if ((td = transaction_new()) == NULL)
|
||||||
|
goto done;
|
||||||
|
if ((ret = startup_common(h, db, td, cbret)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
goto fail;
|
||||||
|
if (xtr){
|
||||||
|
*xtr = td->td_target;
|
||||||
|
td->td_target = NULL;
|
||||||
|
}
|
||||||
|
retval = 1;
|
||||||
|
done:
|
||||||
|
if (td)
|
||||||
|
transaction_free(td);
|
||||||
|
return retval;
|
||||||
|
fail: /* cbret should be set */
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Read startup db, check upgrades and commit it
|
||||||
|
*
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] db The startup database. The wanted backend state
|
||||||
|
* @param[out] cbret CLIgen buffer w error stmt if retval = 0
|
||||||
|
* @retval -1 Error - or validation failed (but cbret not set)
|
||||||
|
* @retval 0 Validation failed (with cbret set)
|
||||||
|
* @retval 1 Validation OK
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
startup_commit(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
cbuf *cbret)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
int ret;
|
||||||
|
transaction_data_t *td = NULL;
|
||||||
|
|
||||||
|
/* Handcraft a transition with only target and add trees */
|
||||||
|
if ((td = transaction_new()) == NULL)
|
||||||
|
goto done;
|
||||||
|
if ((ret = startup_common(h, db, td, cbret)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
goto fail;
|
||||||
|
/* 8. Call plugin transaction commit callbacks */
|
||||||
|
if (plugin_transaction_commit(h, td) < 0)
|
||||||
|
goto done;
|
||||||
|
/* 9, write (potentially modified) tree to running
|
||||||
|
* XXX note here startup is copied to candidate, which may confuse everything
|
||||||
|
*/
|
||||||
|
if ((ret = xmldb_put(h, "running", OP_REPLACE, td->td_target,
|
||||||
|
clicon_username_get(h), cbret)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
goto fail;
|
||||||
|
/* 10. Call plugin transaction end callbacks */
|
||||||
|
plugin_transaction_end(h, td);
|
||||||
|
|
||||||
|
/* 11. Copy running back to candidate in case end functions updated running
|
||||||
|
* XXX: room for improvement: candidate and running may be equal.
|
||||||
|
* Copy only diffs?
|
||||||
|
*/
|
||||||
|
if (xmldb_copy(h, "running", "candidate") < 0){
|
||||||
|
/* ignore errors or signal major setback ? */
|
||||||
|
clicon_log(LOG_NOTICE, "Error in rollback, trying to continue");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
retval = 1;
|
||||||
|
done:
|
||||||
|
if (td)
|
||||||
|
transaction_free(td);
|
||||||
|
return retval;
|
||||||
|
fail: /* cbret should be set */
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Validate a candidate db and comnpare to running
|
/*! Validate a candidate db and comnpare to running
|
||||||
* Get both source and dest datastore, validate target, compute diffs
|
* Get both source and dest datastore, validate target, compute diffs
|
||||||
* and call application callback validations.
|
* and call application callback validations.
|
||||||
|
|
@ -152,10 +340,10 @@ generic_validate(yang_spec *yspec,
|
||||||
* (only done for generic_validate)
|
* (only done for generic_validate)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
validate_common(clicon_handle h,
|
from_validate_common(clicon_handle h,
|
||||||
char *candidate,
|
char *candidate,
|
||||||
transaction_data_t *td,
|
transaction_data_t *td,
|
||||||
cbuf *cbret)
|
cbuf *cbret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_spec *yspec;
|
yang_spec *yspec;
|
||||||
|
|
@ -248,211 +436,6 @@ validate_common(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Validate a candidate db and comnpare to running XXX Experimental
|
|
||||||
* Get both source and dest datastore, validate target, compute diffs
|
|
||||||
* and call application callback validations.
|
|
||||||
* @param[in] h Clicon handle
|
|
||||||
* @param[in] db The startup database. The wanted backend state
|
|
||||||
* @param[out] xtr Transformed XML
|
|
||||||
* @param[out] cbret CLIgen buffer w error stmt if retval = 0
|
|
||||||
* @retval -1 Error - or validation failed (but cbret not set)
|
|
||||||
* @retval 0 Validation failed (with cbret set)
|
|
||||||
* @retval 1 Validation OK
|
|
||||||
* @note Need to differentiate between error and validation fail
|
|
||||||
* 1. Parse startup XML (or JSON)
|
|
||||||
* 2. If syntax failure, call startup-cb(ERROR), copy failsafe db to
|
|
||||||
* candidate and commit. Done
|
|
||||||
* 3. Check yang module versions between backend and init config XML. (msdiff)
|
|
||||||
* 4. Validate startup db. (valid)
|
|
||||||
* 5. If valid fails, call startup-cb(Invalid, msdiff), keep startup in candidate and commit failsafe db. Done.
|
|
||||||
* 6. Call startup-cb(OK, msdiff) and commit.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
startup_validate(clicon_handle h,
|
|
||||||
char *db,
|
|
||||||
cxobj **xtr,
|
|
||||||
cbuf *cbret)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
yang_spec *yspec;
|
|
||||||
int ret;
|
|
||||||
modstate_diff_t *msd = NULL;
|
|
||||||
cxobj *xt = NULL;
|
|
||||||
transaction_data_t *td = NULL;
|
|
||||||
|
|
||||||
/* Handcraft a transition with only target and add trees */
|
|
||||||
if ((td = transaction_new()) == NULL)
|
|
||||||
goto done;
|
|
||||||
/* 2. Parse xml trees
|
|
||||||
* This is the state we are going to
|
|
||||||
* Note: xmsdiff contains non-matching modules
|
|
||||||
* Only if CLICON_XMLDB_MODSTATE is enabled
|
|
||||||
*/
|
|
||||||
if (clicon_option_bool(h, "CLICON_XMLDB_MODSTATE"))
|
|
||||||
if ((msd = modstate_diff_new()) == NULL)
|
|
||||||
goto done;
|
|
||||||
if (xmldb_get(h, db, "/", 1, &xt, msd) < 0)
|
|
||||||
goto done;
|
|
||||||
if ((ret = clixon_module_upgrade(h, xt, msd, cbret)) < 0)
|
|
||||||
goto done;
|
|
||||||
if (ret == 0)
|
|
||||||
goto fail;
|
|
||||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
|
||||||
clicon_err(OE_YANG, 0, "Yang spec not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* After upgrading, XML tree needs to be sorted and yang spec populated */
|
|
||||||
if (xml_apply0(xt, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
|
||||||
goto done;
|
|
||||||
if (xml_apply0(xt, CX_ELMNT, xml_sort, NULL) < 0)
|
|
||||||
goto done;
|
|
||||||
/* Handcraft transition with with only add tree */
|
|
||||||
td->td_target = xt;
|
|
||||||
if (cxvec_append(td->td_target, &td->td_avec, &td->td_alen) < 0)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
/* 4. Call plugin transaction start callbacks */
|
|
||||||
if (plugin_transaction_begin(h, td) < 0)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
/* 5. Make generic validation on all new or changed data.
|
|
||||||
Note this is only call that uses 3-values */
|
|
||||||
if ((ret = generic_validate(yspec, td, cbret)) < 0)
|
|
||||||
goto done;
|
|
||||||
if (ret == 0)
|
|
||||||
goto fail; /* STARTUP_INVALID */
|
|
||||||
|
|
||||||
/* 6. Call plugin transaction validate callbacks */
|
|
||||||
if (plugin_transaction_validate(h, td) < 0)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
/* 7. Call plugin transaction complete callbacks */
|
|
||||||
if (plugin_transaction_complete(h, td) < 0)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
if (xtr){
|
|
||||||
*xtr = td->td_target;
|
|
||||||
td->td_target = NULL;
|
|
||||||
}
|
|
||||||
retval = 1;
|
|
||||||
done:
|
|
||||||
if (td)
|
|
||||||
transaction_free(td);
|
|
||||||
if (msd)
|
|
||||||
modstate_diff_free(msd);
|
|
||||||
return retval;
|
|
||||||
fail: /* cbret should be set */
|
|
||||||
if (cbuf_len(cbret)==0){
|
|
||||||
clicon_err(OE_CFG, EINVAL, "Validation fail but cbret not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
retval = 0;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
startup_commit(clicon_handle h,
|
|
||||||
char *db,
|
|
||||||
cbuf *cbret)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
yang_spec *yspec;
|
|
||||||
int ret;
|
|
||||||
modstate_diff_t *msd = NULL;
|
|
||||||
cxobj *xt = NULL;
|
|
||||||
transaction_data_t *td = NULL;
|
|
||||||
|
|
||||||
/* Handcraft a transition with only target and add trees */
|
|
||||||
if ((td = transaction_new()) == NULL)
|
|
||||||
goto done;
|
|
||||||
/* 2. Parse xml trees
|
|
||||||
* This is the state we are going to
|
|
||||||
* Note: xmsdiff contains non-matching modules
|
|
||||||
* Only if CLICON_XMLDB_MODSTATE is enabled
|
|
||||||
*/
|
|
||||||
if (clicon_option_bool(h, "CLICON_XMLDB_MODSTATE"))
|
|
||||||
if ((msd = modstate_diff_new()) == NULL)
|
|
||||||
goto done;
|
|
||||||
if (xmldb_get(h, db, "/", 1, &xt, msd) < 0)
|
|
||||||
goto done;
|
|
||||||
if (msd){
|
|
||||||
if((ret = clixon_module_upgrade(h, xt, msd, cbret)) < 0)
|
|
||||||
goto done;
|
|
||||||
if (ret == 0)
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
|
||||||
clicon_err(OE_YANG, 0, "Yang spec not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* After upgrading, XML tree needs to be sorted and yang spec populated */
|
|
||||||
if (xml_apply0(xt, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
|
||||||
goto done;
|
|
||||||
if (xml_apply0(xt, CX_ELMNT, xml_sort, NULL) < 0)
|
|
||||||
goto done;
|
|
||||||
/* Handcraft transition with with only add tree */
|
|
||||||
td->td_target = xt;
|
|
||||||
if (cxvec_append(td->td_target, &td->td_avec, &td->td_alen) < 0)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
/* 4. Call plugin transaction start callbacks */
|
|
||||||
if (plugin_transaction_begin(h, td) < 0)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
/* 5. Make generic validation on all new or changed data.
|
|
||||||
Note this is only call that uses 3-values */
|
|
||||||
if ((ret = generic_validate(yspec, td, cbret)) < 0)
|
|
||||||
goto done;
|
|
||||||
if (ret == 0)
|
|
||||||
goto fail; /* STARTUP_INVALID */
|
|
||||||
|
|
||||||
/* 6. Call plugin transaction validate callbacks */
|
|
||||||
if (plugin_transaction_validate(h, td) < 0)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
/* 7. Call plugin transaction complete callbacks */
|
|
||||||
if (plugin_transaction_complete(h, td) < 0)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
/* 8. Call plugin transaction commit callbacks */
|
|
||||||
if (plugin_transaction_commit(h, td) < 0)
|
|
||||||
goto done;
|
|
||||||
/* 9, write (potentially modified) tree to running
|
|
||||||
* XXX note here startup is copied to candidate, which may confuse everything
|
|
||||||
*/
|
|
||||||
if ((ret = xmldb_put(h, "running", OP_REPLACE, td->td_target,
|
|
||||||
clicon_username_get(h), cbret)) < 0)
|
|
||||||
goto done;
|
|
||||||
if (ret == 0)
|
|
||||||
goto fail;
|
|
||||||
/* 10. Call plugin transaction end callbacks */
|
|
||||||
plugin_transaction_end(h, td);
|
|
||||||
|
|
||||||
/* 11. Copy running back to candidate in case end functions updated running
|
|
||||||
* XXX: room for improvement: candidate and running may be equal.
|
|
||||||
* Copy only diffs?
|
|
||||||
*/
|
|
||||||
if (xmldb_copy(h, "running", "candidate") < 0){
|
|
||||||
/* ignore errors or signal major setback ? */
|
|
||||||
clicon_log(LOG_NOTICE, "Error in rollback, trying to continue");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
retval = 1;
|
|
||||||
done:
|
|
||||||
if (td)
|
|
||||||
transaction_free(td);
|
|
||||||
if (msd)
|
|
||||||
modstate_diff_free(msd);
|
|
||||||
return retval;
|
|
||||||
fail: /* cbret should be set */
|
|
||||||
if (cbuf_len(cbret)==0){
|
|
||||||
clicon_err(OE_CFG, EINVAL, "Validation fail but cbret not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
retval = 0;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Do a diff between candidate and running, then start a commit transaction
|
/*! Do a diff between candidate and running, then start a commit transaction
|
||||||
*
|
*
|
||||||
* The code reverts changes if the commit fails. But if the revert
|
* The code reverts changes if the commit fails. But if the revert
|
||||||
|
|
@ -482,7 +465,7 @@ candidate_commit(clicon_handle h,
|
||||||
/* Common steps (with validate). Load candidate and running and compute diffs
|
/* Common steps (with validate). Load candidate and running and compute diffs
|
||||||
* Note this is only call that uses 3-values
|
* Note this is only call that uses 3-values
|
||||||
*/
|
*/
|
||||||
if ((ret = validate_common(h, candidate, td, cbret)) < 0)
|
if ((ret = from_validate_common(h, candidate, td, cbret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -697,7 +680,7 @@ from_client_validate(clicon_handle h,
|
||||||
if ((td = transaction_new()) == NULL)
|
if ((td = transaction_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
/* Common steps (with commit) */
|
/* Common steps (with commit) */
|
||||||
if ((ret = validate_common(h, db, td, cbret)) < 1){
|
if ((ret = from_validate_common(h, db, td, cbret)) < 1){
|
||||||
clicon_debug(1, "Validate %s failed", db);
|
clicon_debug(1, "Validate %s failed", db);
|
||||||
if (ret < 0){
|
if (ret < 0){
|
||||||
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
|
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
|
||||||
|
|
|
||||||
|
|
@ -249,8 +249,7 @@ example_statedata(clicon_handle h,
|
||||||
/*! Registered Upgrade callback function
|
/*! Registered Upgrade callback function
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] xn XML tree to be updated
|
* @param[in] xn XML tree to be updated
|
||||||
* @param[in] modname Name of module
|
* @param[in] ns Namespace of module (for info)
|
||||||
* @param[in] modns Namespace of module (for info)
|
|
||||||
* @param[in] from From revision on the form YYYYMMDD
|
* @param[in] from From revision on the form YYYYMMDD
|
||||||
* @param[in] to To revision on the form YYYYMMDD (0 not in system)
|
* @param[in] to To revision on the form YYYYMMDD (0 not in system)
|
||||||
* @param[in] arg User argument given at rpc_callback_register()
|
* @param[in] arg User argument given at rpc_callback_register()
|
||||||
|
|
@ -466,11 +465,9 @@ clixon_plugin_init(clicon_handle h)
|
||||||
) < 0)
|
) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* General purpose upgrade callback */
|
/* General purpose upgrade callback */
|
||||||
if (upgrade_callback_register(h, 0?upgrade_all:xml_changelog_upgrade,
|
if (upgrade_callback_register(h, xml_changelog_upgrade, NULL, 0, 0, NULL) < 0)
|
||||||
NULL, 0, 0, NULL) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
|
||||||
/* Return plugin API */
|
/* Return plugin API */
|
||||||
return &api;
|
return &api;
|
||||||
done:
|
done:
|
||||||
|
|
|
||||||
|
|
@ -201,6 +201,11 @@ struct clixon_plugin_api{
|
||||||
#define ca_trans_end u.cau_backend.cb_trans_end
|
#define ca_trans_end u.cau_backend.cb_trans_end
|
||||||
#define ca_trans_abort u.cau_backend.cb_trans_abort
|
#define ca_trans_abort u.cau_backend.cb_trans_abort
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macros
|
||||||
|
*/
|
||||||
|
#define upgrade_callback_register(h, cb, namespace, from, to, arg) upgrade_callback_reg_fn((h), (cb), #cb, (namespace), (from), (to), (arg))
|
||||||
|
|
||||||
typedef struct clixon_plugin_api clixon_plugin_api;
|
typedef struct clixon_plugin_api clixon_plugin_api;
|
||||||
|
|
||||||
/* Internal plugin structure with dlopen() handle and plugin_api
|
/* Internal plugin structure with dlopen() handle and plugin_api
|
||||||
|
|
@ -244,7 +249,7 @@ int rpc_callback_delete_all(void);
|
||||||
int rpc_callback_call(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg);
|
int rpc_callback_call(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg);
|
||||||
|
|
||||||
/* upgrade callback API */
|
/* upgrade callback API */
|
||||||
int upgrade_callback_register(clicon_handle h, clicon_upgrade_cb cb, char *namespace, uint32_t from, uint32_t to, void *arg);
|
int upgrade_callback_reg_fn(clicon_handle h, clicon_upgrade_cb cb, const char *strfn, char *namespace, uint32_t from, uint32_t to, void *arg);
|
||||||
int upgrade_callback_delete_all(void);
|
int upgrade_callback_delete_all(void);
|
||||||
int upgrade_callback_call(clicon_handle h, cxobj *xt, char *namespace, uint32_t from, uint32_t to, cbuf *cbret);
|
int upgrade_callback_call(clicon_handle h, cxobj *xt, char *namespace, uint32_t from, uint32_t to, cbuf *cbret);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -541,6 +541,7 @@ rpc_callback_call(clicon_handle h,
|
||||||
typedef struct {
|
typedef struct {
|
||||||
qelem_t uc_qelem; /* List header */
|
qelem_t uc_qelem; /* List header */
|
||||||
clicon_upgrade_cb uc_callback; /* RPC Callback */
|
clicon_upgrade_cb uc_callback; /* RPC Callback */
|
||||||
|
const char *uc_fnstr; /* Stringified fn name for debug */
|
||||||
void *uc_arg; /* Application specific argument to cb */
|
void *uc_arg; /* Application specific argument to cb */
|
||||||
char *uc_namespace; /* Module namespace */
|
char *uc_namespace; /* Module namespace */
|
||||||
uint32_t uc_rev; /* Module revision (to) in YYYYMMDD format or 0 */
|
uint32_t uc_rev; /* Module revision (to) in YYYYMMDD format or 0 */
|
||||||
|
|
@ -555,6 +556,7 @@ static upgrade_callback_t *upgrade_cb_list = NULL;
|
||||||
*
|
*
|
||||||
* @param[in] h clicon handle
|
* @param[in] h clicon handle
|
||||||
* @param[in] cb Callback called
|
* @param[in] cb Callback called
|
||||||
|
* @param[in] fnstr Stringified function for debug
|
||||||
* @param[in] arg Domain-specific argument to send to callback
|
* @param[in] arg Domain-specific argument to send to callback
|
||||||
* @param[in] namespace Module namespace (if NULL all modules)
|
* @param[in] namespace Module namespace (if NULL all modules)
|
||||||
* @param[in] rev To module revision (0 means module obsoleted)
|
* @param[in] rev To module revision (0 means module obsoleted)
|
||||||
|
|
@ -564,12 +566,13 @@ static upgrade_callback_t *upgrade_cb_list = NULL;
|
||||||
* @see upgrade_callback_call which makes the actual callback
|
* @see upgrade_callback_call which makes the actual callback
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
upgrade_callback_register(clicon_handle h,
|
upgrade_callback_reg_fn(clicon_handle h,
|
||||||
clicon_upgrade_cb cb,
|
clicon_upgrade_cb cb,
|
||||||
char *namespace,
|
const char *fnstr,
|
||||||
uint32_t revision,
|
char *namespace,
|
||||||
uint32_t from,
|
uint32_t revision,
|
||||||
void *arg)
|
uint32_t from,
|
||||||
|
void *arg)
|
||||||
{
|
{
|
||||||
upgrade_callback_t *uc;
|
upgrade_callback_t *uc;
|
||||||
|
|
||||||
|
|
@ -579,6 +582,7 @@ upgrade_callback_register(clicon_handle h,
|
||||||
}
|
}
|
||||||
memset(uc, 0, sizeof(*uc));
|
memset(uc, 0, sizeof(*uc));
|
||||||
uc->uc_callback = cb;
|
uc->uc_callback = cb;
|
||||||
|
uc->uc_fnstr = fnstr;
|
||||||
uc->uc_arg = arg;
|
uc->uc_arg = arg;
|
||||||
if (namespace)
|
if (namespace)
|
||||||
uc->uc_namespace = strdup(namespace);
|
uc->uc_namespace = strdup(namespace);
|
||||||
|
|
@ -623,7 +627,7 @@ upgrade_callback_delete_all(void)
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @retval 0 Invalid - cbret contains reason as netconf
|
* @retval 0 Invalid - cbret contains reason as netconf
|
||||||
* @retval 1 OK
|
* @retval 1 OK
|
||||||
* @see upgrade_callback_register which registers the callbacks
|
* @see upgrade_callback_reg_fn which registers the callbacks
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
upgrade_callback_call(clicon_handle h,
|
upgrade_callback_call(clicon_handle h,
|
||||||
|
|
@ -657,8 +661,14 @@ upgrade_callback_call(clicon_handle h,
|
||||||
clicon_debug(1, "%s Error in: %s", __FUNCTION__, uc->uc_namespace);
|
clicon_debug(1, "%s Error in: %s", __FUNCTION__, uc->uc_namespace);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (ret == 0)
|
if (ret == 0){
|
||||||
|
if (cbuf_len(cbret)==0){
|
||||||
|
clicon_err(OE_CFG, 0, "Validation fail %s(%s): cbret not set",
|
||||||
|
uc->uc_fnstr, namespace);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
nr++;
|
nr++;
|
||||||
}
|
}
|
||||||
uc = NEXTQ(upgrade_callback_t *, uc);
|
uc = NEXTQ(upgrade_callback_t *, uc);
|
||||||
|
|
|
||||||
|
|
@ -843,7 +843,7 @@ xml_addsub(cxobj *xp,
|
||||||
* @param[in] tag Name of new xml child
|
* @param[in] tag Name of new xml child
|
||||||
* @retval xc Return the new child (xc)
|
* @retval xc Return the new child (xc)
|
||||||
* @see xml_addsub
|
* @see xml_addsub
|
||||||
* The name of the function is somewhat misleading
|
* The name of the function is somewhat misleading, should be called "wrap"
|
||||||
*/
|
*/
|
||||||
cxobj *
|
cxobj *
|
||||||
xml_insert(cxobj *xp,
|
xml_insert(cxobj *xp,
|
||||||
|
|
|
||||||
|
|
@ -71,10 +71,146 @@
|
||||||
#include "clixon_xpath_ctx.h"
|
#include "clixon_xpath_ctx.h"
|
||||||
#include "clixon_xpath.h"
|
#include "clixon_xpath.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
changelog_rename(clicon_handle h,
|
||||||
|
cxobj *xt,
|
||||||
|
cxobj *xw,
|
||||||
|
char *tag)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
xp_ctx *xctx = NULL;
|
||||||
|
char *str = NULL;
|
||||||
|
|
||||||
|
if (tag == NULL){
|
||||||
|
clicon_err(OE_XML, 0, "tag required");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (xpath_vec_ctx(xw, tag, &xctx) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ctx2string(xctx, &str) < 0)
|
||||||
|
goto done;
|
||||||
|
if (!strlen(str)){
|
||||||
|
clicon_err(OE_XML, 0, "invalid rename tag: \"%s\"", str);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (xml_name_set(xw, str) < 0)
|
||||||
|
goto done;
|
||||||
|
// ok:
|
||||||
|
retval = 1;
|
||||||
|
done:
|
||||||
|
if (xctx)
|
||||||
|
ctx_free(xctx);
|
||||||
|
if (str)
|
||||||
|
free(str);
|
||||||
|
return retval;
|
||||||
|
// fail:
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* replace target XML */
|
||||||
|
static int
|
||||||
|
changelog_replace(clicon_handle h,
|
||||||
|
cxobj *xt,
|
||||||
|
cxobj *xw,
|
||||||
|
cxobj *xnew)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *x;
|
||||||
|
|
||||||
|
/* create a new node by parsing fttransform string and insert it at
|
||||||
|
target */
|
||||||
|
if (xnew == NULL){
|
||||||
|
clicon_err(OE_XML, 0, "new required");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* replace: remove all children of target */
|
||||||
|
while ((x = xml_child_i(xw, 0)) != NULL)
|
||||||
|
if (xml_purge(x) < 0)
|
||||||
|
goto done;
|
||||||
|
/* replace: first single node under <new> */
|
||||||
|
if (xml_child_nr(xnew) != 1){
|
||||||
|
clicon_err(OE_XML, 0, "Single child to <new> required");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
x = xml_child_i(xnew, 0);
|
||||||
|
/* Copy from xnew to (now) empty target */
|
||||||
|
if (xml_copy(x, xw) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 1;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a new node by parsing "new" and insert it at
|
||||||
|
target */
|
||||||
|
static int
|
||||||
|
changelog_insert(clicon_handle h,
|
||||||
|
cxobj *xt,
|
||||||
|
cxobj *xw,
|
||||||
|
cxobj *xnew)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *x;
|
||||||
|
|
||||||
|
if (xnew == NULL){
|
||||||
|
clicon_err(OE_XML, 0, "new required");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* replace: add all new children to target */
|
||||||
|
while ((x = xml_child_i(xnew, 0)) != NULL)
|
||||||
|
if (xml_addsub(xw, x) < 0)
|
||||||
|
goto done;
|
||||||
|
// ok:
|
||||||
|
retval = 1;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
// fail:
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* delete target */
|
||||||
|
static int
|
||||||
|
changelog_delete(clicon_handle h,
|
||||||
|
cxobj *xt,
|
||||||
|
cxobj *xw)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
|
||||||
|
if (xml_purge(xw) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 1;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move target node to location */
|
||||||
|
static int
|
||||||
|
changelog_move(clicon_handle h,
|
||||||
|
cxobj *xt,
|
||||||
|
cxobj *xw,
|
||||||
|
char *dst)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *xp; /* destination parent node */
|
||||||
|
|
||||||
|
if ((xp = xpath_first(xt, "%s", dst)) == NULL){
|
||||||
|
clicon_err(OE_XML, 0, "path required");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (xml_addsub(xp, xw) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 1;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Perform a changelog operation
|
/*! Perform a changelog operation
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] xt XML to upgrade
|
||||||
* @param[in] xi Changelog item
|
* @param[in] xi Changelog item
|
||||||
* @param[in] xn XML to upgrade
|
|
||||||
* @note XXX error handling!
|
* @note XXX error handling!
|
||||||
* @note XXX xn --> xt xpath may not match
|
* @note XXX xn --> xt xpath may not match
|
||||||
*/
|
*/
|
||||||
|
|
@ -84,72 +220,84 @@ changelog_op(clicon_handle h,
|
||||||
cxobj *xi)
|
cxobj *xi)
|
||||||
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *op;
|
char *op;
|
||||||
char *xptarget; /* xpath to target-node */
|
char *whenxpath; /* xpath to when */
|
||||||
char *xplocation; /* xpath to location-node (move) */
|
char *tag; /* xpath to extra path (move) */
|
||||||
char *ftransform; /* transform string format (modify, create) */
|
char *dst; /* xpath to extra path (move) */
|
||||||
cxobj *xtrg; /* xml target node */
|
cxobj *xnew; /* new xml (insert, replace) */
|
||||||
cxobj *xloc; /* xml location node */
|
char *wxpath; /* xpath to where (target-node) */
|
||||||
cxobj *xnew = NULL;
|
cxobj **wvec = NULL; /* Vector of where(target) nodes */
|
||||||
cxobj *x;
|
size_t wlen;
|
||||||
|
cxobj *xw;
|
||||||
|
int ret;
|
||||||
|
xp_ctx *xctx = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
if ((op = xml_find_body(xi, "change-operation")) == NULL)
|
if ((op = xml_find_body(xi, "op")) == NULL)
|
||||||
goto ok;
|
goto ok;
|
||||||
if ((xptarget = xml_find_body(xi, "target-node")) == NULL)
|
/* get common variables that may be used in the operations below */
|
||||||
|
tag = xml_find_body(xi, "tag");
|
||||||
|
dst = xml_find_body(xi, "dst");
|
||||||
|
xnew = xml_find(xi, "new");
|
||||||
|
whenxpath = xml_find_body(xi, "when");
|
||||||
|
if ((wxpath = xml_find_body(xi, "where")) == NULL)
|
||||||
goto ok;
|
goto ok;
|
||||||
/* target node (if any) */
|
/* Get vector of target nodes meeting the where requirement */
|
||||||
if ((xtrg = xpath_first(xt, "%s", xptarget)) == NULL)
|
if (xpath_vec(xt, "%s", &wvec, &wlen, wxpath) < 0)
|
||||||
goto fail;
|
goto done;
|
||||||
// fprintf(stderr, "%s %s %s\n", __FUNCTION__, op, xml_name(xt));
|
for (i=0; i<wlen; i++){
|
||||||
xplocation = xml_find_body(xi, "location-node");
|
xw = wvec[i];
|
||||||
ftransform = xml_find_body(xi, "transform");
|
/* If 'when' exists and is false, skip this target */
|
||||||
if (strcmp(op, "insert") == 0){
|
if (whenxpath){
|
||||||
/* create a new node by parsing fttransform string and insert it at
|
if (xpath_vec_ctx(xw, whenxpath, &xctx) < 0)
|
||||||
target */
|
goto done;
|
||||||
if (ftransform == NULL)
|
if ((ret = ctx2boolean(xctx)) < 0)
|
||||||
goto fail;
|
goto done;
|
||||||
if (xml_parse_va(&xtrg, NULL, "%s", ftransform) < 0)
|
if (xctx){
|
||||||
goto done;
|
ctx_free(xctx);
|
||||||
}
|
xctx = NULL;
|
||||||
else if (strcmp(op, "delete") == 0){
|
}
|
||||||
/* delete target */
|
if (ret == 0)
|
||||||
if (xml_purge(xtrg) < 0)
|
continue;
|
||||||
goto done;
|
}
|
||||||
}
|
/* Now switch on operation */
|
||||||
else if (strcmp(op, "move") == 0){
|
if (strcmp(op, "rename") == 0){
|
||||||
/* Move target node to location */
|
ret = changelog_rename(h, xt, xw, tag);
|
||||||
if ((xloc = xpath_first(xt, "%s", xplocation)) == NULL)
|
}
|
||||||
goto fail;
|
else if (strcmp(op, "replace") == 0){
|
||||||
if (xml_addsub(xloc, xtrg) < 0)
|
ret = changelog_replace(h, xt, xw, xnew);
|
||||||
goto done;
|
}
|
||||||
}
|
else if (strcmp(op, "insert") == 0){
|
||||||
else if (strcmp(op, "replace") == 0){
|
ret = changelog_insert(h, xt, xw, xnew);
|
||||||
/* create a new node by parsing fttransform string and insert it at
|
}
|
||||||
target */
|
else if (strcmp(op, "delete") == 0){
|
||||||
if (ftransform == NULL)
|
ret = changelog_delete(h, xt, xw);
|
||||||
goto fail;
|
}
|
||||||
/* replace: remove all children of target */
|
else if (strcmp(op, "move") == 0){
|
||||||
while ((x = xml_child_i(xtrg, 0)) != NULL)
|
ret = changelog_move(h, xt, xw, dst);
|
||||||
if (xml_purge(x) < 0)
|
}
|
||||||
goto done;
|
else{
|
||||||
/* Parse the new node */
|
clicon_err(OE_XML, 0, "Unknown operation: %s", op);
|
||||||
if (xml_parse_va(&xnew, NULL, "%s", ftransform) < 0)
|
goto done;
|
||||||
goto done;
|
}
|
||||||
if (xml_rootchild(xnew, 0, &xnew) < 0)
|
if (ret < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Copy old to new */
|
if (ret == 0)
|
||||||
if (xml_copy(xnew, xtrg) < 0)
|
goto fail;
|
||||||
goto done;
|
}
|
||||||
if (xml_purge(xnew) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
ok:
|
ok:
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
|
if (wvec)
|
||||||
|
free(wvec);
|
||||||
|
if (xctx)
|
||||||
|
ctx_free(xctx);
|
||||||
return retval;
|
return retval;
|
||||||
fail:
|
fail:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
clicon_debug(1, "%s fail op:%s ", __FUNCTION__, op);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,7 +318,7 @@ changelog_iterate(clicon_handle h,
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (xpath_vec(xch, "change-log", &vec, &veclen) < 0)
|
if (xpath_vec(xch, "step", &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Iterate through changelog items */
|
/* Iterate through changelog items */
|
||||||
for (i=0; i<veclen; i++){
|
for (i=0; i<veclen; i++){
|
||||||
|
|
@ -181,6 +329,7 @@ changelog_iterate(clicon_handle h,
|
||||||
}
|
}
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
|
clicon_debug(1, "%s retval: %d", __FUNCTION__, retval);
|
||||||
if (vec)
|
if (vec)
|
||||||
free(vec);
|
free(vec);
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -233,7 +382,7 @@ xml_changelog_upgrade(clicon_handle h,
|
||||||
* - find all changelogs in the interval: [from, to]
|
* - find all changelogs in the interval: [from, to]
|
||||||
* - note it t=0 then no changelog is applied
|
* - note it t=0 then no changelog is applied
|
||||||
*/
|
*/
|
||||||
if (xpath_vec(xchlog, "module[namespace=\"%s\"]",
|
if (xpath_vec(xchlog, "changelog[namespace=\"%s\"]",
|
||||||
&vec, &veclen, namespace) < 0)
|
&vec, &veclen, namespace) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Get all changelogs in the interval [from,to]*/
|
/* Get all changelogs in the interval [from,to]*/
|
||||||
|
|
|
||||||
|
|
@ -830,7 +830,6 @@ xp_union(xp_ctx *xc1,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Evaluate an XPATH on an XML tree
|
/*! Evaluate an XPATH on an XML tree
|
||||||
|
|
||||||
* The initial sequence of steps selects a set of nodes relative to a context node.
|
* The initial sequence of steps selects a set of nodes relative to a context node.
|
||||||
|
|
@ -1038,11 +1037,20 @@ xp_eval(xp_ctx *xc,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Given XML tree and xpath, returns xpath context
|
/*! Given XML tree and xpath, returns xpath context
|
||||||
|
* This is a raw form of xpath where you can do type conversion, etc,
|
||||||
|
* not just a nodeset.
|
||||||
* @param[in] xcur XML-tree where to search
|
* @param[in] xcur XML-tree where to search
|
||||||
* @param[in] xpath String with XPATH 1.0 syntax
|
* @param[in] xpath String with XPATH 1.0 syntax
|
||||||
* @param[out] xrp Return XPATH context
|
* @param[out] xrp Return XPATH context
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
|
* @code
|
||||||
|
* xp_ctx *xc = NULL;
|
||||||
|
* if (xpath_vec_ctx(x, xpath, &xc) < 0)
|
||||||
|
* err;
|
||||||
|
* if (xc)
|
||||||
|
* ctx_free(xc);
|
||||||
|
* @endcode
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xpath_vec_ctx(cxobj *xcur,
|
xpath_vec_ctx(cxobj *xcur,
|
||||||
|
|
@ -1295,6 +1303,7 @@ xpath_vec_flag(cxobj *xcur,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Given XML tree and xpath, returns boolean
|
/*! Given XML tree and xpath, returns boolean
|
||||||
|
* Returns true if the nodeset is non-empty
|
||||||
* @param[in] xcur xml-tree where to search
|
* @param[in] xcur xml-tree where to search
|
||||||
* @param[in] xpath stdarg string with XPATH 1.0 syntax
|
* @param[in] xpath stdarg string with XPATH 1.0 syntax
|
||||||
* @retval 1 True
|
* @retval 1 True
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,10 @@ module example-a{
|
||||||
type string;
|
type string;
|
||||||
description "no change";
|
description "no change";
|
||||||
}
|
}
|
||||||
|
leaf b {
|
||||||
|
type string;
|
||||||
|
description "rename tag";
|
||||||
|
}
|
||||||
leaf x {
|
leaf x {
|
||||||
type string;
|
type string;
|
||||||
description "delete";
|
description "delete";
|
||||||
|
|
@ -80,6 +84,10 @@ module example-a {
|
||||||
type string;
|
type string;
|
||||||
description "no change";
|
description "no change";
|
||||||
}
|
}
|
||||||
|
leaf c {
|
||||||
|
type string;
|
||||||
|
description "rename tag";
|
||||||
|
}
|
||||||
leaf host-name {
|
leaf host-name {
|
||||||
type string;
|
type string;
|
||||||
description "replace";
|
description "replace";
|
||||||
|
|
@ -144,6 +152,7 @@ cat <<EOF > $dir/startup_db
|
||||||
</modules-state>
|
</modules-state>
|
||||||
<system xmlns="urn:example:a">
|
<system xmlns="urn:example:a">
|
||||||
<a>dont change me</a>
|
<a>dont change me</a>
|
||||||
|
<b>rename me</b>
|
||||||
<host-name>modify me</host-name>
|
<host-name>modify me</host-name>
|
||||||
<x>remove me</x>
|
<x>remove me</x>
|
||||||
<z>move me</z>
|
<z>move me</z>
|
||||||
|
|
@ -157,7 +166,7 @@ cat <<EOF > $dir/startup_db
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Wanted new XML
|
# Wanted new XML
|
||||||
XML='<system xmlns="urn:example:a"><a>dont change me</a><host-name>i am modified</host-name><y>created</y></system><alt xmlns="urn:example:a"><z>move me</z></alt>'
|
XML='<system xmlns="urn:example:a"><a>dont change me</a><c>rename me</c><host-name>i am modified</host-name><y>created</y></system><alt xmlns="urn:example:a"><z>move me</z></alt>'
|
||||||
|
|
||||||
|
|
||||||
# Create configuration
|
# Create configuration
|
||||||
|
|
@ -182,46 +191,52 @@ EOF
|
||||||
|
|
||||||
# Changelog of example-a:
|
# Changelog of example-a:
|
||||||
cat <<EOF > $changelog
|
cat <<EOF > $changelog
|
||||||
<yang-modules xmlns="http://clicon.org/xml-changelog">
|
<changelogs xmlns="http://clicon.org/xml-changelog">
|
||||||
<module>
|
<changelog>
|
||||||
<namespace>urn:example:b</namespace>
|
<namespace>urn:example:b</namespace>
|
||||||
<revfrom>2017-12-01</revfrom>
|
<revfrom>2017-12-01</revfrom>
|
||||||
<revision>2017-12-20</revision>
|
<revision>2017-12-20</revision>
|
||||||
<change-log>
|
<step>
|
||||||
<index>0001</index>
|
<name>1</name>
|
||||||
<change-operation>delete</change-operation>
|
<op>delete</op>
|
||||||
<target-node>/b:system-b</target-node>
|
<where>/b:system-b</where>
|
||||||
</change-log>
|
</step>
|
||||||
</module>
|
</changelog>
|
||||||
<module>
|
<changelog>
|
||||||
<namespace>urn:example:a</namespace>
|
<namespace>urn:example:a</namespace>
|
||||||
<revfrom>2017-12-01</revfrom>
|
<revfrom>2017-12-01</revfrom>
|
||||||
<revision>2017-12-20</revision>
|
<revision>2017-12-20</revision>
|
||||||
<change-log>
|
<step>
|
||||||
<index>0001</index>
|
<name>0</name>
|
||||||
<change-operation>insert</change-operation>
|
<op>rename</op>
|
||||||
<target-node>/a:system</target-node>
|
<where>/a:system/a:b</where>
|
||||||
<transform><y>created</y></transform>
|
<tag>"c"</tag>
|
||||||
</change-log>
|
</step>
|
||||||
<change-log>
|
<step>
|
||||||
<index>0002</index>
|
<name>1</name>
|
||||||
<change-operation>delete</change-operation>
|
<op>insert</op>
|
||||||
<target-node>/a:system/a:x</target-node>
|
<where>/a:system</where>
|
||||||
</change-log>
|
<new><y>created</y></new>
|
||||||
<change-log>
|
</step>
|
||||||
<index>0003</index>
|
<step>
|
||||||
<change-operation>replace</change-operation>
|
<name>2</name>
|
||||||
<target-node>/a:system/a:host-name</target-node>
|
<op>delete</op>
|
||||||
<transform><host-name>i am modified</host-name></transform>
|
<where>/a:system/a:x</where>
|
||||||
</change-log>
|
</step>
|
||||||
<change-log>
|
<step>
|
||||||
<index>0004</index>
|
<name>3</name>
|
||||||
<change-operation>move</change-operation>
|
<op>replace</op>
|
||||||
<target-node>/a:system/a:z</target-node>
|
<where>/a:system/a:host-name</where>
|
||||||
<location-node>/a:alt</location-node>
|
<new><host-name>i am modified</host-name></new>
|
||||||
</change-log>
|
</step>
|
||||||
</module>
|
<step>
|
||||||
</yang-modules>
|
<name>4</name>
|
||||||
|
<op>move</op>
|
||||||
|
<where>/a:system/a:z</where>
|
||||||
|
<dst>/a:alt</dst>
|
||||||
|
</step>
|
||||||
|
</changelog>
|
||||||
|
</changelogs>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Start new system from old datastore
|
# Start new system from old datastore
|
||||||
|
|
|
||||||
|
|
@ -37,34 +37,37 @@ module clixon-xml-changelog {
|
||||||
More inspiration in XProc: https://www.w3.org/TR/xproc/#ex2";
|
More inspiration in XProc: https://www.w3.org/TR/xproc/#ex2";
|
||||||
type enumeration{
|
type enumeration{
|
||||||
enum rename {
|
enum rename {
|
||||||
description "Rename the target node (NYI)";
|
description
|
||||||
|
"Rename the 'where' node, ie XML label
|
||||||
|
Synopsis: rename(where:targets, when:bool, tag:string)";
|
||||||
}
|
}
|
||||||
enum replace {
|
enum replace {
|
||||||
description "Replace the target data node
|
description
|
||||||
modification is given by the leaf transform which
|
"Replace the target data node modification is given by the leaf
|
||||||
is a string with %s where the original value
|
transform which is a string with %s where the original value
|
||||||
is inserted";
|
is inserted.
|
||||||
|
Synopsis: replace(where:targets, when:bool, new:xml)";
|
||||||
}
|
}
|
||||||
enum insert {
|
enum insert {
|
||||||
description "Create new data nodes and insert under an existing node";
|
description
|
||||||
|
"Create new data nodes and insert under an existing node.
|
||||||
|
Synopsis: insert(where:parents, when:bool, new:xml)";
|
||||||
}
|
}
|
||||||
enum delete {
|
enum delete {
|
||||||
description "Delete the target node";
|
description
|
||||||
|
"Delete the target node.
|
||||||
|
Synopsis: delete(where:parents, when:bool)";
|
||||||
}
|
}
|
||||||
enum move {
|
enum move {
|
||||||
description "Move the target node(Added)";
|
description
|
||||||
}
|
"Move the target node(Added).
|
||||||
enum wrap {
|
Synopsis: move(where:parents, when:bool, dst:node)";
|
||||||
description "Wraps elements with additional elements(NYI)";
|
|
||||||
}
|
|
||||||
enum reorder {
|
|
||||||
description "Changes the order of elements (NYI)";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
container yang-modules {
|
container changelogs {
|
||||||
config false;
|
config false;
|
||||||
list module {
|
list changelog {
|
||||||
key "namespace revision";
|
key "namespace revision";
|
||||||
leaf namespace {
|
leaf namespace {
|
||||||
type string;
|
type string;
|
||||||
|
|
@ -90,22 +93,22 @@ module clixon-xml-changelog {
|
||||||
Several changelogs may be applied if the upgrade spans multiple
|
Several changelogs may be applied if the upgrade spans multiple
|
||||||
ranges: [from0,to0],..[fromN,toN]";
|
ranges: [from0,to0],..[fromN,toN]";
|
||||||
}
|
}
|
||||||
list change-log {
|
list step {
|
||||||
description
|
description
|
||||||
"List for module revision change log";
|
"List for module revision change log";
|
||||||
key "index";
|
key "name";
|
||||||
leaf index {
|
leaf name {
|
||||||
type uint32;
|
type string;
|
||||||
description
|
description
|
||||||
"Index for module change log";
|
"Unique step name";
|
||||||
}
|
}
|
||||||
leaf change-operation {
|
leaf op {
|
||||||
type operation_type;
|
type operation_type;
|
||||||
mandatory true;
|
mandatory true;
|
||||||
description
|
description
|
||||||
"This leaf indicate the change operation, such as create, move, delete, modify, etc.";
|
"This leaf indicate the change operation, such as create, move, delete, modify, etc.";
|
||||||
}
|
}
|
||||||
leaf target-node {
|
leaf where {
|
||||||
type yang:xpath1.0;
|
type yang:xpath1.0;
|
||||||
mandatory true;
|
mandatory true;
|
||||||
description
|
description
|
||||||
|
|
@ -115,19 +118,27 @@ module clixon-xml-changelog {
|
||||||
For create, it is the parent where it should be
|
For create, it is the parent where it should be
|
||||||
inserted.";
|
inserted.";
|
||||||
}
|
}
|
||||||
leaf location-node {
|
leaf when {
|
||||||
|
type yang:xpath1.0;
|
||||||
description
|
description
|
||||||
"If op is move, this denotes the destination";
|
"Boolean XPATH. Execute this step if this xpath exists
|
||||||
|
and evaluates to true";
|
||||||
|
}
|
||||||
|
leaf tag {
|
||||||
|
description
|
||||||
|
"For rename, a string XPath definining the new tag.";
|
||||||
type yang:xpath1.0;
|
type yang:xpath1.0;
|
||||||
}
|
}
|
||||||
leaf transform {
|
leaf dst {
|
||||||
description
|
description
|
||||||
"If op is modify or create, this denotes how to
|
"For move, a destination XPath definining the parent where
|
||||||
transform the XML encoding.
|
to insert.";
|
||||||
Special value %s for the original value.";
|
type yang:xpath1.0;
|
||||||
type string;
|
}
|
||||||
|
anydata new {
|
||||||
|
description
|
||||||
|
"If op is replace or insert, new XML for the new node.";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue