Initial implementation of NETCONF confirmed-commit

This commit is contained in:
Phil Heller 2022-09-30 19:17:13 -06:00
parent 954e5d56fd
commit 284316b646
16 changed files with 1375 additions and 26 deletions

View file

@ -76,5 +76,6 @@ int xmldb_modified_set(clicon_handle h, const char *db, int value);
int xmldb_empty_get(clicon_handle h, const char *db);
int xmldb_dump(clicon_handle h, FILE *f, cxobj *xt);
int xmldb_print(clicon_handle h, FILE *f);
int xmldb_rename(clicon_handle h, const char *db, const char *newdb, const char *suffix);
#endif /* _CLIXON_DATASTORE_H */

View file

@ -1,4 +1,5 @@
/*
* t
*
***** BEGIN LICENSE BLOCK *****
@ -63,7 +64,7 @@ int clicon_rpc_get_pageable_list(clicon_handle h, char *datastore, char *xpath,
int clicon_rpc_close_session(clicon_handle h);
int clicon_rpc_kill_session(clicon_handle h, uint32_t session_id);
int clicon_rpc_validate(clicon_handle h, char *db);
int clicon_rpc_commit(clicon_handle h);
int clicon_rpc_commit(clicon_handle h, int confirmed, int cancel, uint32_t timeout, char *persist, char *persist_id);
int clicon_rpc_discard_changes(clicon_handle h);
int clicon_rpc_create_subscription(clicon_handle h, char *stream, char *filter, int *s);
int clicon_rpc_debug(clicon_handle h, int level);

View file

@ -418,10 +418,18 @@ xmldb_delete(clicon_handle h,
if (xmldb_db2file(h, db, &filename) < 0)
goto done;
if (lstat(filename, &sb) == 0)
if (truncate(filename, 0) < 0){
clicon_err(OE_DB, errno, "truncate %s", filename);
goto done;
}
// TODO this had been changed from unlink to truncate some time ago. It was changed back for confirmed-commit
// as the presence of the rollback_db at startup triggers loading of the rollback rather than the startup
// configuration. It might not be sufficient to check for a truncated file. Needs more review, switching back
// to unlink temporarily.
// if (truncate(filename, 0) < 0){
// clicon_err(OE_DB, errno, "truncate %s", filename);
// goto done;
// }
if (unlink(filename) < 0) {
clicon_err(OE_UNIX, errno, "unlink %s: %s", filename, strerror(errno));
goto done;
}
retval = 0;
done:
if (filename)
@ -594,3 +602,64 @@ xmldb_print(clicon_handle h,
done:
return retval;
}
/*! Rename an XML database
* @param[in] h Clicon handle
* @param[in] db Database name
* @param[in] newdb New Database name; if NULL, then same as new
* @param[in] suffix Suffix to append to new database name
* @retval -1 Error
* @retval 0 OK
* @note if newdb and suffix are null, OK is returned as it is a no-op
*/
int
xmldb_rename(clicon_handle h,
const char *db,
const char *newdb,
const char *suffix)
{
char *old;
char *fname;
int retval = -1;
if ((xmldb_db2file(h, db, &old)) < 0) {
goto done;
};
if (newdb == NULL && suffix == NULL)
// no-op
goto done;
newdb = newdb == NULL ? old : newdb;
suffix = suffix == NULL ? "" : suffix;
size_t size = strlen(newdb) + strlen(suffix);
if ((fname = malloc(size + 1)) == NULL) {
clicon_err(OE_UNIX, errno, "malloc: %s", strerror(errno));
goto done;
};
int actual = 0;
if ((actual = snprintf(fname, size, "%s%s", newdb, suffix)) < size) {
clicon_err(OE_UNIX, 0, "snprintf wrote fewer bytes (%d) than requested (%zu)", actual, size);
goto done;
};
if ((rename(old, fname)) < 0) {
clicon_err(OE_UNIX, errno, "rename: %s", strerror(errno));
goto done;
};
retval = 0;
done:
if (old)
free(old);
if (fname)
free(fname);
return retval;
}

View file

@ -83,6 +83,10 @@
#include "clixon_netconf_lib.h"
#include "clixon_proto_client.h"
#define PERSIST_ID_XML_FMT "<persist-id>%s</persist-id>"
#define PERSIST_XML_FMT "<persist>%s</persist>"
#define TIMEOUT_XML_FMT "<confirm-timeout>%u</confirm-timeout>"
/*! Connect to internal netconf socket
*/
int
@ -1266,7 +1270,12 @@ clicon_rpc_validate(clicon_handle h,
* @retval -1 Error and logged to syslog
*/
int
clicon_rpc_commit(clicon_handle h)
clicon_rpc_commit(clicon_handle h,
int confirmed,
int cancel,
uint32_t timeout,
char *persist,
char *persist_id)
{
int retval = -1;
struct clicon_msg *msg = NULL;
@ -1274,15 +1283,65 @@ clicon_rpc_commit(clicon_handle h)
cxobj *xerr;
char *username;
uint32_t session_id;
char *persist_id_xml = NULL;
char *persist_xml = NULL;
char *timeout_xml = NULL;
if (persist_id) {
if ((persist_id_xml = malloc(strlen(persist_id) + strlen(PERSIST_ID_XML_FMT) + 1)) == NULL) {
clicon_err(OE_UNIX, 0, "malloc: %s", strerror(errno));
}
sprintf(persist_id_xml, PERSIST_ID_XML_FMT, persist_id);
}
if (persist) {
if ((persist_xml = malloc(strlen(persist) + strlen(PERSIST_XML_FMT) + 1)) == NULL) {
clicon_err(OE_UNIX, 0, "malloc: %s", strerror(errno));
};
sprintf(persist_xml, PERSIST_XML_FMT, persist);
}
if (timeout > 0) {
/* timeout is a uint32_t, so max value is 2^32, a 10-digit number, we'll just always malloc for a string that
* may be that large rather than calculate the string length
*/
if ((timeout_xml = malloc(10 + 1 + strlen(TIMEOUT_XML_FMT))) == NULL) {
clicon_err(OE_UNIX, 0, "malloc: %s", strerror(errno));
};
sprintf(timeout_xml, TIMEOUT_XML_FMT, timeout);
}
if (session_id_check(h, &session_id) < 0)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s><commit/></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_MESSAGE_ID_ATTR)) == NULL)
if (cancel) {
msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s><cancel-commit>%s</cancel-commit></rpc>",
NETCONF_BASE_NAMESPACE,
username ? username : "",
NETCONF_MESSAGE_ID_ATTR,
persist_id ? persist_id_xml : "");
} else if (confirmed) {
msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s><commit><confirmed/>%s%s%s</commit></rpc>",
NETCONF_BASE_NAMESPACE,
username ? username : "",
NETCONF_MESSAGE_ID_ATTR,
timeout ? timeout_xml : "",
persist_id ? persist_id_xml : "",
persist ? persist_xml : "");
} else {
msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s><commit>%s</commit></rpc>",
NETCONF_BASE_NAMESPACE,
username ? username : "",
NETCONF_MESSAGE_ID_ATTR,
persist ? persist_xml : "");
}
if (msg == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -1296,6 +1355,12 @@ clicon_rpc_commit(clicon_handle h)
xml_free(xret);
if (msg)
free(msg);
if (persist_id_xml)
free(persist_id_xml);
if (persist_xml)
free(persist_xml);
if (timeout_xml)
free(timeout_xml);
return retval;
}
@ -1479,7 +1544,7 @@ clicon_rpc_restconf_debug(clicon_handle h,
clicon_err(OE_XML, 0, "rpc error"); /* XXX extract info from rpc-error */
goto done;
}
if ((retval = clicon_rpc_commit(h)) < 0)
if ((retval = clicon_rpc_commit(h, 0, 0, 0, NULL, NULL)) < 0)
goto done;
done:
if (msg)