Inital commit
This commit is contained in:
parent
edc5e091bb
commit
d6e393ea58
145 changed files with 58117 additions and 0 deletions
684
apps/backend/backend_commit.c
Normal file
684
apps/backend/backend_commit.c
Normal file
|
|
@ -0,0 +1,684 @@
|
|||
/*
|
||||
*
|
||||
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
|
||||
|
||||
This file is part of CLICON.
|
||||
|
||||
CLICON is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
CLICON is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with CLICON; see the file COPYING. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "clicon_config.h" /* generated by config & autoconf */
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <pwd.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
/* clicon */
|
||||
#include <clicon/clicon.h>
|
||||
|
||||
#include "clicon_backend_transaction.h"
|
||||
#include "backend_plugin.h"
|
||||
#include "backend_handle.h"
|
||||
#include "backend_commit.h"
|
||||
#include "backend_client.h"
|
||||
|
||||
/*! Key values are checked for validity independent of user-defined callbacks
|
||||
*
|
||||
* Key values are checked as follows:
|
||||
* 1. If no value and default value defined, add it.
|
||||
* 2. If no value and mandatory flag set in spec, report error.
|
||||
* 3. Validate value versus spec, and report error if no match. Currently only int ranges and
|
||||
* string regexp checked.
|
||||
* See also db_lv_set() where defaults are also filled in. The case here for defaults
|
||||
* are if code comes via XML/NETCONF.
|
||||
* @param yspec Yang spec
|
||||
* @param td Transaction data
|
||||
*/
|
||||
static int
|
||||
generic_validate(yang_spec *yspec,
|
||||
transaction_data_t *td)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *x1;
|
||||
cxobj *x2;
|
||||
int i;
|
||||
yang_stmt *ys;
|
||||
|
||||
/* changed entries */
|
||||
for (i=0; i<td->td_clen; i++){
|
||||
x1 = td->td_scvec[i]; /* source changed */
|
||||
x2 = td->td_tcvec[i]; /* target changed */
|
||||
ys = xml_spec(x1);
|
||||
if (xml_yang_validate(x2, ys) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* deleted entries */
|
||||
for (i=0; i<td->td_dlen; i++){
|
||||
x1 = td->td_dvec[i];
|
||||
ys = xml_spec(x1);
|
||||
if (yang_mandatory(ys)){
|
||||
clicon_err(OE_CFG, 0,"Removed mandatory variable: %s",
|
||||
xml_name(x1));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
/* added entries */
|
||||
for (i=0; i<td->td_alen; i++){
|
||||
x2 = td->td_avec[i];
|
||||
if (xml_yang_validate(x2, xml_spec(x2)) < 0)
|
||||
goto done;
|
||||
if (xml_apply(x2, CX_ELMNT,
|
||||
(xml_applyfn_t*)xml_yang_validate, NULL) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Do a diff between candidate and running, then start a commit transaction
|
||||
*
|
||||
* The code reverts changes if the commit fails. But if the revert
|
||||
* fails, we just ignore the errors and proceed. Maybe we should
|
||||
* do something more drastic?
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] running The current database. The original backend state
|
||||
* @param[in] candidate: The candidate database. The wanted backend state
|
||||
*/
|
||||
int
|
||||
candidate_commit(clicon_handle h,
|
||||
char *candidate,
|
||||
char *running)
|
||||
{
|
||||
int retval = -1;
|
||||
// int i, j;
|
||||
// int failed = 0;
|
||||
struct stat sb;
|
||||
void *firsterr = NULL;
|
||||
yang_spec *yspec;
|
||||
transaction_data_t *td = NULL;
|
||||
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
}
|
||||
/* Sanity checks that databases exists. */
|
||||
if (stat(running, &sb) < 0){
|
||||
clicon_err(OE_DB, errno, "%s", running);
|
||||
goto done;
|
||||
}
|
||||
if (stat(candidate, &sb) < 0){
|
||||
clicon_err(OE_DB, errno, "%s", candidate);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* 1. Start transaction */
|
||||
if ((td = transaction_new()) == NULL)
|
||||
goto done;
|
||||
|
||||
/* 2. Parse xml trees */
|
||||
if (xmldb_get(running, "/", yspec, &td->td_src) < 0)
|
||||
goto done;
|
||||
if (xmldb_get(candidate, "/", yspec, &td->td_target) < 0)
|
||||
goto done;
|
||||
|
||||
/* 3. Compute differences */
|
||||
if (xml_diff(yspec,
|
||||
td->td_src,
|
||||
td->td_target,
|
||||
&td->td_dvec, /* removed: only in running */
|
||||
&td->td_dlen,
|
||||
&td->td_avec, /* added: only in candidate */
|
||||
&td->td_alen,
|
||||
&td->td_scvec, /* changed: original values */
|
||||
&td->td_tcvec, /* changed: wanted values */
|
||||
&td->td_clen) < 0)
|
||||
goto done;
|
||||
if (debug)
|
||||
transaction_print(stderr, td);
|
||||
|
||||
/* 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. */
|
||||
if (generic_validate(yspec, td) < 0)
|
||||
goto done;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 7. Call plugin transaction commit callbacks */
|
||||
if (plugin_transaction_commit(h, td) < 0)
|
||||
goto done;
|
||||
|
||||
/* 8. Copy running back to candidate in case end functions triggered
|
||||
updates in running */
|
||||
if (file_cp(running, candidate) < 0){
|
||||
/* ignore errors or signal major setback ? */
|
||||
clicon_err(OE_UNIX, errno, "file_cp(running, candidate)");
|
||||
clicon_log(LOG_NOTICE, "Error in rollback, trying to continue");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* 9. Call plugin transaction end callbacks */
|
||||
plugin_transaction_end(h, td);
|
||||
|
||||
#ifdef OBSOLETE
|
||||
/* Find the differences between the two databases and store it in df vector. */
|
||||
memset(&df, 0, sizeof(df));
|
||||
if (db_diff(running, candidate,
|
||||
__FUNCTION__,
|
||||
clicon_dbspec_key(h),
|
||||
&df
|
||||
) < 0)
|
||||
goto done;
|
||||
|
||||
if (debug){
|
||||
struct dbdiff_ent *dfe;
|
||||
for (i=0; i<df.df_nr; i++) {
|
||||
dfe = &df.df_ents[i];
|
||||
clicon_debug(1, "%s op:%d key:%s",
|
||||
__FUNCTION__,
|
||||
dfe->dfe_op,
|
||||
cvec_name_get(dfe->dfe_vec1?dfe->dfe_vec1:dfe->dfe_vec2));
|
||||
}
|
||||
}
|
||||
/* 1. Get commit processing to dbdiff vector: one entry per key that changed.
|
||||
changes are registered as if they exist in the 1st(candidate) or
|
||||
2nd(running) dbs.
|
||||
*/
|
||||
if (dbdep_commitvec(h, &df, &nvec, &ddvec) < 0)
|
||||
goto done;
|
||||
|
||||
/* 2. Call transaction_begin hooks */
|
||||
if (plugin_transaction_begin(h) < 0)
|
||||
goto done;
|
||||
|
||||
/* call generic cv_validate() on all new or changed keys. */
|
||||
if (generic_validate(yspec, NULL) < 0)
|
||||
goto done;
|
||||
|
||||
/* user-defined validate callbacks registered in dbdep_validate */
|
||||
// if (validate_db(h, nvec, ddvec, running, candidate) < 0)
|
||||
// goto done;
|
||||
|
||||
/* Call plugin post-commit hooks */
|
||||
if (plugin_transaction_complete(h) < 0)
|
||||
goto done;
|
||||
|
||||
if (clicon_commit_order(h) == 0){
|
||||
for (i=0; i < nvec; i++){ /* revert in opposite order */
|
||||
dd = &ddvec[i];
|
||||
dp = dd->dd_dep; /* op, callback, arg */
|
||||
if ((dp->dp_type & TRANS_CB_COMMIT) == 0)
|
||||
continue;
|
||||
dfe = dd->dd_dbdiff; /* key1/key2/op */
|
||||
op = dbdiff2commit_op(dfe->dfe_op);
|
||||
if (plugin_commit_callback(h,
|
||||
op, /* oper */
|
||||
running, /* db1 */
|
||||
candidate, /* db2 */
|
||||
dd->dd_mkey1, /* key1 */
|
||||
dd->dd_mkey2, /* key2 */
|
||||
dd->dd_dbdiff->dfe_vec1, /* vec1 */
|
||||
dd->dd_dbdiff->dfe_vec2, /* vec2 */
|
||||
dp /* callback */
|
||||
) < 0){
|
||||
firsterr = clicon_err_save(); /* save this error */
|
||||
failed++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!failed)
|
||||
if (file_cp(candidate, running) < 0){ /* Commit here in case cp fails */
|
||||
clicon_err(OE_UNIX, errno, "file_cp");
|
||||
failed++;
|
||||
}
|
||||
/* Failed operation, start error handling: rollback in opposite order */
|
||||
if (failed){
|
||||
for (j=i-1; j>=0; j--){ /* revert in opposite order */
|
||||
dd = &ddvec[j];
|
||||
dp = dd->dd_dep; /* op, callback, arg */
|
||||
if ((dp->dp_type & TRANS_CB_COMMIT) == 0)
|
||||
continue;
|
||||
dfe = dd->dd_dbdiff; /* key1/key2/op */
|
||||
op = dbdiff2commit_op(dfe->dfe_op);
|
||||
switch (op){ /* reverse operation */
|
||||
case CO_ADD:
|
||||
op = CO_DELETE;
|
||||
break;
|
||||
case CO_DELETE:
|
||||
op = CO_ADD;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (plugin_commit_callback(h,
|
||||
op, /* oper */
|
||||
candidate, /* db1 */
|
||||
running, /* db2 */
|
||||
dd->dd_mkey2, /* key1 */
|
||||
dd->dd_mkey1, /* key2 */
|
||||
dd->dd_dbdiff->dfe_vec2, /* vec1 */
|
||||
dd->dd_dbdiff->dfe_vec1, /* vec2 */
|
||||
dp /* callback */
|
||||
) < 0){
|
||||
/* ignore errors or signal major setback ? */
|
||||
clicon_log(LOG_NOTICE, "Error in rollback, trying to continue");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
goto done;
|
||||
} /* error handling */
|
||||
}
|
||||
else { /* commit_order == 1 or 2 */
|
||||
/* Now follows commit rules in order.
|
||||
* 4. For all keys that are not in candidate but in running, delete key
|
||||
* in reverse prio order
|
||||
*/
|
||||
for (i = nvec-1; i >= 0; i--){
|
||||
dd = &ddvec[i];
|
||||
dp = dd->dd_dep; /* op, callback, arg */
|
||||
if ((dp->dp_type & TRANS_CB_COMMIT) == 0)
|
||||
continue;
|
||||
dfe = dd->dd_dbdiff; /* key1/key2/op */
|
||||
op = dbdiff2commit_op(dfe->dfe_op);
|
||||
/* original mode 2 where CHANGE=DEL/ADD */
|
||||
if (clicon_commit_order(h) == 2 && op == CO_CHANGE)
|
||||
op = CO_DELETE;
|
||||
if (op != CO_DELETE)
|
||||
continue;
|
||||
if (plugin_commit_callback(h,
|
||||
op, /* oper */
|
||||
running, /* db1 */
|
||||
candidate, /* db2 */
|
||||
dd->dd_mkey1, /* key1 */
|
||||
dd->dd_mkey2, /* key2 */
|
||||
dd->dd_dbdiff->dfe_vec1, /* vec1 */
|
||||
dd->dd_dbdiff->dfe_vec2, /* vec2 */
|
||||
dp /* callback */
|
||||
) < 0){
|
||||
firsterr = clicon_err_save(); /* save this error */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* 5. Failed deletion, add the key value back to running */
|
||||
if (i >= 0){ /* failed */
|
||||
for (j=i+1; j<nvec; j++){ /* revert in opposite order */
|
||||
dd = &ddvec[j];
|
||||
dp = dd->dd_dep; /* op, callback, arg */
|
||||
if ((dp->dp_type & TRANS_CB_COMMIT) == 0)
|
||||
continue;
|
||||
dfe = dd->dd_dbdiff; /* key1/key2/op */
|
||||
op = dbdiff2commit_op(dfe->dfe_op);
|
||||
/* original mode 2 where CHANGE=DEL/ADD */
|
||||
if (clicon_commit_order(h) == 2 && op == CO_CHANGE)
|
||||
op = CO_DELETE;
|
||||
if (op != CO_DELETE)
|
||||
continue;
|
||||
if (plugin_commit_callback(h,
|
||||
op, /* oper */
|
||||
candidate, /* db1 */
|
||||
running, /* db2 */
|
||||
dd->dd_mkey2, /* key1 */
|
||||
dd->dd_mkey1, /* key2 */
|
||||
dd->dd_dbdiff->dfe_vec2, /* vec1 */
|
||||
dd->dd_dbdiff->dfe_vec1, /* vec2 */
|
||||
dp /* callback */
|
||||
) < 0){
|
||||
/* ignore errors or signal major setback ? */
|
||||
clicon_log(LOG_NOTICE, "Error in rollback, trying to continue");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
/*
|
||||
* 6. For all added or changed keys
|
||||
*/
|
||||
for (i=0; i < nvec; i++){
|
||||
dd = &ddvec[i];
|
||||
dp = dd->dd_dep; /* op, callback, arg */
|
||||
if ((dp->dp_type & TRANS_CB_COMMIT) == 0)
|
||||
continue;
|
||||
dfe = dd->dd_dbdiff; /* key1/key2/op */
|
||||
op = dbdiff2commit_op(dfe->dfe_op);
|
||||
if (op != CO_CHANGE && op != CO_ADD)
|
||||
continue;
|
||||
/* original mode 2 where CHANGE=DEL/ADD */
|
||||
if (clicon_commit_order(h) == 2 && op == CO_CHANGE)
|
||||
op = CO_ADD;
|
||||
if (plugin_commit_callback(h,
|
||||
op, /* oper */
|
||||
running, /* db1 */
|
||||
candidate, /* db2 */
|
||||
dd->dd_mkey1, /* key1 */
|
||||
dd->dd_mkey2, /* key2 */
|
||||
dd->dd_dbdiff->dfe_vec1, /* vec1 */
|
||||
dd->dd_dbdiff->dfe_vec2, /* vec2 */
|
||||
dp /* callback */
|
||||
) < 0){
|
||||
firsterr = clicon_err_save(); /* save this error */
|
||||
failed++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!failed) /* Commit here in case cp fails */
|
||||
if (file_cp(candidate, running) < 0){
|
||||
clicon_err(OE_UNIX, errno, "file_cp(candidate; running)");
|
||||
failed++;
|
||||
}
|
||||
/* 10. Failed setting keys in running, first remove the keys set */
|
||||
if (failed){ /* failed */
|
||||
for (j=i-1; j>=0; j--){ /* revert in opposite order */
|
||||
dd = &ddvec[j];
|
||||
dp = dd->dd_dep; /* op, callback, arg */
|
||||
if ((dp->dp_type & TRANS_CB_COMMIT) == 0)
|
||||
continue;
|
||||
dfe = dd->dd_dbdiff; /* key1/key2/op */
|
||||
op = dbdiff2commit_op(dfe->dfe_op);
|
||||
if (op != CO_CHANGE && op != CO_ADD)
|
||||
continue;
|
||||
/* original mode 2 where CHANGE=DEL/ADD */
|
||||
if (clicon_commit_order(h) == 2 && op == CO_CHANGE)
|
||||
op = CO_ADD;
|
||||
if (op == CO_ADD) /* reverse op */
|
||||
op = CO_DELETE;
|
||||
if (plugin_commit_callback(h,
|
||||
op, /* oper */
|
||||
candidate, /* db1 */
|
||||
running, /* db2 */
|
||||
dd->dd_mkey2, /* key1 */
|
||||
dd->dd_mkey1, /* key2 */
|
||||
dd->dd_dbdiff->dfe_vec2, /* vec1 */
|
||||
dd->dd_dbdiff->dfe_vec1, /* vec2 */
|
||||
dp /* callback */
|
||||
) < 0){
|
||||
/* ignore errors or signal major setback ? */
|
||||
clicon_log(LOG_NOTICE, "Error in rollback, trying to continue");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for (j=0; j < nvec; j++){ /* revert in opposite order */
|
||||
dd = &ddvec[j];
|
||||
dp = dd->dd_dep; /* op, callback, arg */
|
||||
if ((dp->dp_type & TRANS_CB_COMMIT) == 0)
|
||||
continue;
|
||||
dfe = dd->dd_dbdiff; /* key1/key2/op */
|
||||
op = dbdiff2commit_op(dfe->dfe_op);
|
||||
/* original mode 2 where CHANGE=DEL/ADD */
|
||||
if (clicon_commit_order(h) == 2 && op == CO_CHANGE)
|
||||
op = CO_DELETE;
|
||||
if (op != CO_DELETE)
|
||||
continue;
|
||||
op = CO_ADD;
|
||||
if (plugin_commit_callback(h,
|
||||
op, /* oper */
|
||||
candidate, /* db1 */
|
||||
running, /* db2 */
|
||||
dd->dd_mkey2, /* key1 */
|
||||
dd->dd_mkey1, /* key2 */
|
||||
dd->dd_dbdiff->dfe_vec2, /* vec1 */
|
||||
dd->dd_dbdiff->dfe_vec1, /* vec2 */
|
||||
dp /* callback */
|
||||
) < 0){
|
||||
/* ignore errors or signal major setback ? */
|
||||
clicon_log(LOG_NOTICE, "Error in rollback, trying to continue");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
} /* commit_order */
|
||||
#endif /* OBSOLETE */
|
||||
|
||||
|
||||
retval = 0;
|
||||
done:
|
||||
/* In case of failure, call plugin transaction termination callbacks */
|
||||
if (retval < 0 && td)
|
||||
plugin_transaction_abort(h, td);
|
||||
if (td)
|
||||
transaction_free(td);
|
||||
if (firsterr)
|
||||
clicon_err_restore(firsterr);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Do a diff between candidate and running, then start a validate transaction
|
||||
*
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] running The current database. The original backend state
|
||||
* @param[in] candidate: The candidate database. The wanted backend state
|
||||
*/
|
||||
int
|
||||
candidate_validate(clicon_handle h,
|
||||
char *candidate,
|
||||
char *running)
|
||||
{
|
||||
int retval = -1;
|
||||
struct stat sb;
|
||||
yang_spec *yspec;
|
||||
transaction_data_t *td = NULL;
|
||||
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
}
|
||||
/* Sanity checks that databases exists. */
|
||||
if (stat(running, &sb) < 0){
|
||||
clicon_err(OE_DB, errno, "%s", running);
|
||||
goto done;
|
||||
}
|
||||
if (stat(candidate, &sb) < 0){
|
||||
clicon_err(OE_DB, errno, "%s", candidate);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* 1. Start transaction */
|
||||
if ((td = transaction_new()) == NULL)
|
||||
goto done;
|
||||
|
||||
/* 2. Parse xml trees */
|
||||
if (xmldb_get(running, "/", yspec, &td->td_src) < 0)
|
||||
goto done;
|
||||
if (xmldb_get(candidate, "/", yspec, &td->td_target) < 0)
|
||||
goto done;
|
||||
|
||||
/* 3. Compute differences */
|
||||
if (xml_diff(yspec,
|
||||
td->td_src,
|
||||
td->td_target,
|
||||
&td->td_dvec, /* removed: only in running */
|
||||
&td->td_dlen,
|
||||
&td->td_avec, /* added: only in candidate */
|
||||
&td->td_alen,
|
||||
&td->td_scvec, /* changed: original values */
|
||||
&td->td_tcvec, /* changed: wanted values */
|
||||
&td->td_clen) < 0)
|
||||
goto done;
|
||||
|
||||
if (debug)
|
||||
transaction_print(stderr, td);
|
||||
|
||||
/* 4. Call plugin start transaction callbacks */
|
||||
if (plugin_transaction_begin(h, td) < 0)
|
||||
goto done;
|
||||
|
||||
/* 5. Make generic validation on all new or changed data. */
|
||||
if (generic_validate(yspec, td) < 0)
|
||||
goto done;
|
||||
|
||||
/* 6. Call plugin validate transaction callbacks */
|
||||
if (plugin_transaction_validate(h, td) < 0)
|
||||
goto done;
|
||||
|
||||
/* 7. Call plugin complete transaction callbacks */
|
||||
if (plugin_transaction_complete(h, td) < 0)
|
||||
goto done;
|
||||
|
||||
retval = 0;
|
||||
done:
|
||||
/* In case of failure, call plugin transaction termination callbacks */
|
||||
if (retval < 0 && td)
|
||||
plugin_transaction_abort(h, td);
|
||||
if (td)
|
||||
transaction_free(td);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Handle an incoming commit message from a client.
|
||||
* XXX: If commit succeeds and snapshot/startup fails, we have strange state:
|
||||
* the commit has succeeded but an error message is returned.
|
||||
*/
|
||||
int
|
||||
from_client_commit(clicon_handle h,
|
||||
int s,
|
||||
struct clicon_msg *msg,
|
||||
const char *label)
|
||||
{
|
||||
int retval = -1;
|
||||
char *candidate;
|
||||
char *running;
|
||||
uint32_t snapshot;
|
||||
uint32_t startup;
|
||||
char *snapshot_0;
|
||||
char *archive_dir;
|
||||
char *startup_config;
|
||||
|
||||
if (clicon_msg_commit_decode(msg, &candidate, &running,
|
||||
&snapshot, &startup, label) < 0)
|
||||
goto err;
|
||||
|
||||
if (candidate_commit(h, candidate, running) < 0){
|
||||
clicon_debug(1, "Commit %s failed", candidate);
|
||||
retval = 0; /* We ignore errors from commit, but maybe
|
||||
we should fail on fatal errors? */
|
||||
goto err;
|
||||
}
|
||||
clicon_debug(1, "Commit %s", candidate);
|
||||
if (snapshot){
|
||||
if ((archive_dir = clicon_archive_dir(h)) == NULL){
|
||||
clicon_err(OE_PLUGIN, 0, "snapshot set and clicon_archive_dir not defined");
|
||||
goto err;
|
||||
}
|
||||
if (config_snapshot(h, running, archive_dir) < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (startup){
|
||||
if ((archive_dir = clicon_archive_dir(h)) == NULL){
|
||||
clicon_err(OE_PLUGIN, 0, "startup set but clicon_archive_dir not defined");
|
||||
goto err;
|
||||
}
|
||||
if ((startup_config = clicon_startup_config(h)) == NULL){
|
||||
clicon_err(OE_PLUGIN, 0, "startup set but startup_config not defined");
|
||||
goto err;
|
||||
}
|
||||
snapshot_0 = chunk_sprintf(__FUNCTION__, "%s/0", archive_dir);
|
||||
if (file_cp(snapshot_0, startup_config) < 0){
|
||||
clicon_err(OE_PROTO, errno, "%s: Error when creating startup",
|
||||
__FUNCTION__);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
if (send_msg_ok(s) < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
err:
|
||||
/* XXX: more elaborate errstring? */
|
||||
if (send_msg_err(s, clicon_errno, clicon_suberrno, "%s", clicon_err_reason) < 0)
|
||||
retval = -1;
|
||||
done:
|
||||
unchunk_group(__FUNCTION__);
|
||||
|
||||
return retval; /* may be zero if we ignoring errors from commit */
|
||||
} /* from_client_commit */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Call backend plugin
|
||||
*/
|
||||
int
|
||||
from_client_validate(clicon_handle h,
|
||||
int s,
|
||||
struct clicon_msg *msg,
|
||||
const char *label)
|
||||
{
|
||||
char *dbname;
|
||||
char *running_db;
|
||||
int retval = -1;
|
||||
|
||||
if (clicon_msg_validate_decode(msg, &dbname, label) < 0){
|
||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
||||
clicon_err_reason);
|
||||
goto err;
|
||||
}
|
||||
|
||||
clicon_debug(1, "Validate %s", dbname);
|
||||
if ((running_db = clicon_running_db(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "running db not set");
|
||||
goto err;
|
||||
}
|
||||
if (candidate_validate(h, dbname, running_db) < 0){
|
||||
clicon_debug(1, "Validate %s failed", dbname);
|
||||
retval = 0; /* We ignore errors from commit, but maybe
|
||||
we should fail on fatal errors? */
|
||||
goto err;
|
||||
}
|
||||
retval = 0;
|
||||
if (send_msg_ok(s) < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
err:
|
||||
/* XXX: more elaborate errstring? */
|
||||
if (send_msg_err(s, clicon_errno, clicon_suberrno, "%s", clicon_err_reason) < 0)
|
||||
retval = -1;
|
||||
done:
|
||||
unchunk_group(__FUNCTION__);
|
||||
return retval;
|
||||
} /* from_client_validate */
|
||||
Loading…
Add table
Add a link
Reference in a new issue