diff --git a/CHANGELOG.md b/CHANGELOG.md index 93af25a2..0ebde7b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,12 @@ Expected: June 2024 ### API changes on existing protocol/config features Users may have to change how they access the system +* If `CLICON_XMLDB_MULTI` is set, datastores are stored in a new directory + * Previously: `CLICON_XMLDB_DIR/_db` + * New: `CLICON_XMLDB_DIR/d/` + * In particular, the top-level is moved from `_db` to `.d/0.xml` + * Backward-compatible: + * If backend is started with `-s startup` or `-s running` then `_db` is read if `.d/0.xml` is not found * Openssl mandatory for all configs, not only restconf ### Corrected Bugs diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index e46ba2bc..050cb431 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -921,6 +921,13 @@ main(int argc, goto done; } + /* Multi-upgrade: If .d/0.xml does not exist, but _d does, copy _db to .d/0.xml */ + if (clicon_option_bool(h, "CLICON_XMLDB_MULTI")){ + if (xmldb_multi_upgrade(h, "running") < 0) + goto done; + if (xmldb_multi_upgrade(h, "startup") < 0) + goto done; + } /* Init running db if it is not there * change running_startup -> running or startup depending on if running exists or not */ diff --git a/lib/clixon/clixon_datastore.h b/lib/clixon/clixon_datastore.h index 807407a2..5df21bf4 100644 --- a/lib/clixon/clixon_datastore.h +++ b/lib/clixon/clixon_datastore.h @@ -103,5 +103,6 @@ int xmldb_volatile_set(clixon_handle h, const char *db, int value); int xmldb_print(clixon_handle h, FILE *f); int xmldb_rename(clixon_handle h, const char *db, const char *newdb, const char *suffix); int xmldb_populate(clixon_handle h, const char *db); +int xmldb_multi_upgrade(clixon_handle h, const char *db); #endif /* _CLIXON_DATASTORE_H */ diff --git a/lib/src/clixon_datastore.c b/lib/src/clixon_datastore.c index 2baf1a5e..fecd9ac0 100644 --- a/lib/src/clixon_datastore.c +++ b/lib/src/clixon_datastore.c @@ -127,19 +127,18 @@ clicon_db_elmnt_set(clixon_handle h, /*! Translate from symbolic database name to actual filename in file-system * + * Internal function for explicit XMLDB_MULTI use or not * @param[in] h Clixon handle * @param[in] db Symbolic database name, eg "candidate", "running" + * @param[in] multi Use multi/split datastores, see CLICON_XMLDB_MULTI * @param[out] filename Filename. Unallocate after use with free() * @retval 0 OK * @retval -1 Error - * @note Could need a way to extend which databases exists, eg to register new. - * The currently allowed databases are: - * candidate, tmp, running, result - * The filename reside in CLICON_XMLDB_DIR option */ -int -xmldb_db2file(clixon_handle h, +static int +xmldb_db2file1(clixon_handle h, const char *db, + int multi, char **filename) { int retval = -1; @@ -154,7 +153,13 @@ xmldb_db2file(clixon_handle h, clixon_err(OE_XML, errno, "CLICON_XMLDB_DIR not set"); goto done; } - cprintf(cb, "%s/%s_db", dir, db); + /* Multi: write (root) to: .d/0.xml + * Classic: write to: _db + */ + if (multi) + cprintf(cb, "%s/%s.d/0.xml", dir, db); /* Hardcoded to XML, XXX: JSON? */ + else + cprintf(cb, "%s/%s_db", dir, db); if ((*filename = strdup4(cbuf_get(cb))) == NULL){ clixon_err(OE_UNIX, errno, "strdup"); goto done; @@ -166,6 +171,26 @@ xmldb_db2file(clixon_handle h, return retval; } +/*! Translate from symbolic database name to actual filename in file-system + * + * @param[in] h Clixon handle + * @param[in] db Symbolic database name, eg "candidate", "running" + * @param[out] filename Filename. Unallocate after use with free() + * @retval 0 OK + * @retval -1 Error + * @note Could need a way to extend which databases exists, eg to register new. + * The currently allowed databases are: + * candidate, tmp, running, result + * The filename reside in CLICON_XMLDB_DIR option + */ +int +xmldb_db2file(clixon_handle h, + const char *db, + char **filename) +{ + return xmldb_db2file1(h, db, clicon_option_bool(h, "CLICON_XMLDB_MULTI"), filename); +} + /*! Translate from symbolic database name to sub-directory of configure sub-files, no checks * * @param[in] h Clixon handle @@ -253,6 +278,7 @@ xmldb_disconnect(clixon_handle h) return retval; } + /*! Copy datastore from db1 to db2 * * May include copying datastore directory structure @@ -263,8 +289,8 @@ xmldb_disconnect(clixon_handle h) * @retval -1 Error */ int -xmldb_copy(clixon_handle h, - const char *from, +xmldb_copy(clixon_handle h, + const char *from, const char *to) { int retval = -1; @@ -337,8 +363,6 @@ xmldb_copy(clixon_handle h, if (clicon_file_copy(fromfile, tofile) < 0) goto done; if (clicon_option_bool(h, "CLICON_XMLDB_MULTI")) { - - if (xmldb_db2subdir(h, from, &fromdir) < 0) goto done; if (xmldb_db2subdir(h, to, &todir) < 0) @@ -627,13 +651,13 @@ int xmldb_create(clixon_handle h, const char *db) { - int retval = -1; - char *filename = NULL; - int fd = -1; - db_elmnt *de = NULL; - cxobj *xt = NULL; - char *subdir = NULL; - struct stat st = {0,}; + int retval = -1; + char *filename = NULL; + int fd = -1; + db_elmnt *de = NULL; + cxobj *xt = NULL; + char *subdir = NULL; + struct stat st = {0,}; clixon_debug(CLIXON_DBG_DATASTORE | CLIXON_DBG_DETAIL, "%s", db); if ((de = clicon_db_elmnt_get(h, db)) != NULL){ @@ -642,12 +666,6 @@ xmldb_create(clixon_handle h, de->de_xml = NULL; } } - if (xmldb_db2file(h, db, &filename) < 0) - goto done; - if ((fd = open(filename, O_CREAT|O_WRONLY, S_IRWXU)) == -1) { - clixon_err(OE_UNIX, errno, "open(%s)", filename); - goto done; - } if (clicon_option_bool(h, "CLICON_XMLDB_MULTI")){ if (xmldb_db2subdir(h, db, &subdir) < 0) goto done; @@ -658,6 +676,12 @@ xmldb_create(clixon_handle h, } } } + if (xmldb_db2file(h, db, &filename) < 0) + goto done; + if ((fd = open(filename, O_CREAT|O_WRONLY, S_IRWXU)) == -1) { + clixon_err(OE_UNIX, errno, "open(%s)", filename); + goto done; + } retval = 0; done: clixon_debug(CLIXON_DBG_DATASTORE | CLIXON_DBG_DETAIL, "retval:%d", retval); @@ -958,3 +982,43 @@ xmldb_populate(clixon_handle h, done: return retval; } + +/*! Upgrade datastore from original non-multi to multi/split mode + * + * This is for upgrading the datastores on startup using CLICON_XMLDB_MULTI + * (1) If .d/0.xml does not exist AND + * (2) _db does exist and is a regular file + * (3) THEN copy file from _db to .d/0.xml + * @param[in] h Clixon handle + * @param[in] db Datastore + */ +int +xmldb_multi_upgrade(clixon_handle h, + const char *db) +{ + int retval = -1; + char *fromfile = NULL; + char *tofile = NULL; + struct stat st = {0,}; + + if (xmldb_db2file1(h, db, 1, &tofile) < 0) + goto done; + if (stat(tofile, &st) < 0 && errno == ENOENT) { + /* db.d/0.xml does not exist */ + if (xmldb_create(h, db) < 0) + goto done; + if (xmldb_db2file1(h, db, 0, &fromfile) < 0) + goto done; + if (stat(fromfile, &st) == 0 && S_ISREG(st.st_mode)){ + if (clicon_file_copy(fromfile, tofile) < 0) + goto done; + } + } + retval = 0; + done: + if (fromfile) + free(fromfile); + if (tofile) + free(tofile); + return retval; +} diff --git a/test/test_datastore_multi.sh b/test/test_datastore_multi.sh index f2c7f6aa..93291575 100755 --- a/test/test_datastore_multi.sh +++ b/test/test_datastore_multi.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash -# Datastore split test, eg x_db has x.d/ directory with subdirs# ALso test cache bevahour, that unmodified +# Datastore split test, eg x_db has x.d/ directory with subdirs +# Also test cache bevahour, that unmodified # subteres are not touched # For now subdirs only enabled for mointpoints, so this test is with mountpoints as well @@ -152,7 +153,7 @@ function check_db() dbname=$1 subfile=$2 - sudo chmod o+r $dir/${dbname}_db + sudo chmod o+r $dir/${dbname}.d/0.xml sudo chmod o+r $dir/${dbname}.d/$subfile sudo rm -f $dir/x_db @@ -167,9 +168,11 @@ function check_db() EOF new "Check ${dbname}_db" - ret=$(diff $dir/x_db $dir/${dbname}_db) + # ret=$(diff $dir/x_db $dir/${dbname}_db) + ret=$(diff $dir/x_db $dir/${dbname}.d/0.xml) if [ $? -ne 0 ]; then - err "$(cat $dir/x_db)" "$(cat $dir/${dbname}_db)" + # err "$(cat $dir/x_db)" "$(cat $dir/${dbname}_db)" + err "$(cat $dir/x_db)" "$(cat $dir/${dbname}.d/0.xml)" fi cat < $dir/x_subfile @@ -343,6 +346,9 @@ if [ $BE -ne 0 ]; then if [ $? -ne 0 ]; then err fi +fi + +if [ $BE -ne 0 ]; then new "start backend -s running -f $cfg -- -m clixon-mount1 -M urn:example:mount1" start_backend -s running -f $cfg -- -m clixon-mount1 -M urn:example:mount1 fi @@ -361,6 +367,30 @@ if [ $BE -ne 0 ]; then stop_backend -f $cfg fi +# move running.d/0.xml to running_db to trigger upgrade +sudo mv $dir/running.d/0.xml $dir/running_db + +new "Check backward compatible: if running.0/0.xml is not found read running_db on startup" +if [ $BE -ne 0 ]; then + new "start backend -s running -f $cfg -- -m clixon-mount1 -M urn:example:mount1" + start_backend -s running -f $cfg -- -m clixon-mount1 -M urn:example:mount1 +fi + +new "Check running after restart" +check_db running ${subfilename} + +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 +fi + + sudo rm -rf $dir unset dbname