}
if(options.machinereadable){
- printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped:\n");
+ printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped:Inactive:\n");
for(i=0;i<nodemap->num;i++){
if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
continue;
}
- printf(":%d:%s:%d:%d:%d:%d:%d:\n", nodemap->nodes[i].pnn,
+ printf(":%d:%s:%d:%d:%d:%d:%d:%d:\n", nodemap->nodes[i].pnn,
ctdb_addr_to_str(&nodemap->nodes[i].addr),
!!(nodemap->nodes[i].flags&NODE_FLAGS_DISCONNECTED),
!!(nodemap->nodes[i].flags&NODE_FLAGS_BANNED),
!!(nodemap->nodes[i].flags&NODE_FLAGS_PERMANENTLY_DISABLED),
!!(nodemap->nodes[i].flags&NODE_FLAGS_UNHEALTHY),
- !!(nodemap->nodes[i].flags&NODE_FLAGS_STOPPED));
+ !!(nodemap->nodes[i].flags&NODE_FLAGS_STOPPED),
+ !!(nodemap->nodes[i].flags&NODE_FLAGS_INACTIVE));
}
return 0;
}
{ NODE_FLAGS_UNHEALTHY, "UNHEALTHY" },
{ NODE_FLAGS_DELETED, "DELETED" },
{ NODE_FLAGS_STOPPED, "STOPPED" },
+ { NODE_FLAGS_INACTIVE, "INACTIVE" },
};
char *flags_str = NULL;
int j;
return 0;
}
-
/*
- display the status of the monitoring scripts
+ display the status of the scripts for monitoring (or other events)
*/
-static int control_scriptstatus(struct ctdb_context *ctdb, int argc, const char **argv)
+static int control_one_scriptstatus(struct ctdb_context *ctdb,
+ enum ctdb_eventscript_call type)
{
- int i, ret;
- struct ctdb_monitoring_wire *script_status;
+ struct ctdb_scripts_wire *script_status;
+ int ret, i;
- ret = ctdb_ctrl_getscriptstatus(ctdb, TIMELIMIT(), options.pnn, ctdb, &script_status);
+ ret = ctdb_ctrl_getscriptstatus(ctdb, TIMELIMIT(), options.pnn, ctdb, type, &script_status);
if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to get script status from node %u\n", options.pnn));
return ret;
}
- printf("%d scripts were executed last monitoring cycle\n", script_status->num_scripts);
+ if (script_status == NULL) {
+ if (!options.machinereadable) {
+ printf("%s cycle never run\n",
+ ctdb_eventscript_call_names[type]);
+ }
+ return 0;
+ }
+
+ if (!options.machinereadable) {
+ printf("%d scripts were executed last %s cycle\n",
+ script_status->num_scripts,
+ ctdb_eventscript_call_names[type]);
+ }
for (i=0; i<script_status->num_scripts; i++) {
- if (script_status->scripts[i].disabled) {
- printf("%-20s Status:DISABLED\n",
- script_status->scripts[i].name);
+ const char *status = NULL;
+
+ switch (script_status->scripts[i].status) {
+ case -ETIME:
+ status = "TIMEDOUT";
+ break;
+ case -ENOEXEC:
+ status = "DISABLED";
+ break;
+ case 0:
+ status = "OK";
+ break;
+ default:
+ if (script_status->scripts[i].status > 0)
+ status = "ERROR";
+ break;
+ }
+ if (options.machinereadable) {
+ printf("%s:%s:%i:%s:%lu.%06lu:%lu.%06lu:%s:\n",
+ ctdb_eventscript_call_names[type],
+ script_status->scripts[i].name,
+ script_status->scripts[i].status,
+ status,
+ (long)script_status->scripts[i].start.tv_sec,
+ (long)script_status->scripts[i].start.tv_usec,
+ (long)script_status->scripts[i].finished.tv_sec,
+ (long)script_status->scripts[i].finished.tv_usec,
+ script_status->scripts[i].output);
continue;
- }
- printf("%-20s Status:%s ",
- script_status->scripts[i].name,
- script_status->scripts[i].timedout?"TIMEDOUT":script_status->scripts[i].status==0?"OK":"ERROR");
- if (script_status->scripts[i].timedout == 0) {
+ }
+ if (status)
+ printf("%-20s Status:%s ",
+ script_status->scripts[i].name, status);
+ else
+ /* Some other error, eg from stat. */
+ printf("%-20s Status:CANNOT RUN (%s)",
+ script_status->scripts[i].name,
+ strerror(-script_status->scripts[i].status));
+
+ if (script_status->scripts[i].status >= 0) {
printf("Duration:%.3lf ",
timeval_delta(&script_status->scripts[i].finished,
&script_status->scripts[i].start));
}
- printf("%s",
- ctime(&script_status->scripts[i].start.tv_sec));
- if ((script_status->scripts[i].timedout != 0)
- || (script_status->scripts[i].status != 0) ) {
- printf(" OUTPUT:%s\n",
- script_status->scripts[i].output);
+ if (script_status->scripts[i].status != -ENOEXEC) {
+ printf("%s",
+ ctime(&script_status->scripts[i].start.tv_sec));
+ if (script_status->scripts[i].status != 0) {
+ printf(" OUTPUT:%s\n",
+ script_status->scripts[i].output);
+ }
+ } else {
+ printf("\n");
+ }
+ }
+ return 0;
+}
+
+
+static int control_scriptstatus(struct ctdb_context *ctdb,
+ int argc, const char **argv)
+{
+ int ret;
+ enum ctdb_eventscript_call type, min, max;
+ const char *arg;
+
+ if (argc > 1) {
+ DEBUG(DEBUG_ERR, ("Unknown arguments to scriptstatus\n"));
+ return -1;
+ }
+
+ if (argc == 0)
+ arg = ctdb_eventscript_call_names[CTDB_EVENT_MONITOR];
+ else
+ arg = argv[0];
+
+ for (type = 0; type < CTDB_EVENT_MAX; type++) {
+ if (strcmp(arg, ctdb_eventscript_call_names[type]) == 0) {
+ min = type;
+ max = type+1;
+ break;
+ }
+ }
+ if (type == CTDB_EVENT_MAX) {
+ if (strcmp(arg, "all") == 0) {
+ min = 0;
+ max = CTDB_EVENT_MAX;
+ } else {
+ DEBUG(DEBUG_ERR, ("Unknown event type %s\n", argv[0]));
+ return -1;
+ }
+ }
+
+ if (options.machinereadable) {
+ printf(":Type:Name:Code:Status:Start:End:Error Output...:\n");
+ }
+
+ for (type = min; type < max; type++) {
+ ret = control_one_scriptstatus(ctdb, type);
+ if (ret != 0) {
+ return ret;
}
}
return 0;
}
-
/*
enable an eventscript
return 0;
}
+/*
+ public ip info
+ */
+static int control_ipinfo(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+ int i, ret;
+ ctdb_sock_addr addr;
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+ struct ctdb_control_public_ip_info *info;
+
+ if (argc != 1) {
+ talloc_free(tmp_ctx);
+ usage();
+ }
+
+ if (parse_ip(argv[0], NULL, 0, &addr) == 0) {
+ DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0]));
+ return -1;
+ }
+
+ /* read the public ip info from this node */
+ ret = ctdb_ctrl_get_public_ip_info(ctdb, TIMELIMIT(), options.pnn,
+ tmp_ctx, &addr, &info);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to get public ip[%s]info from node %u\n",
+ argv[0], options.pnn));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ printf("Public IP[%s] info on node %u\n",
+ ctdb_addr_to_str(&info->ip.addr),
+ options.pnn);
+
+ printf("IP:%s\nCurrentNode:%d\nNumInterfaces:%u\n",
+ ctdb_addr_to_str(&info->ip.addr),
+ info->ip.pnn, info->num);
+
+ for (i=0; i<info->num; i++) {
+ info->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
+
+ printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
+ i+1, info->ifaces[i].name,
+ info->ifaces[i].link_state?"up":"down",
+ (unsigned int)info->ifaces[i].references,
+ (i==info->active_idx)?" (active)":"");
+ }
+
+ talloc_free(tmp_ctx);
+ return 0;
+}
+
+/*
+ display interfaces status
+ */
+static int control_ifaces(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+ int i, ret;
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+ struct ctdb_control_get_ifaces *ifaces;
+
+ /* read the public ip list from this node */
+ ret = ctdb_ctrl_get_ifaces(ctdb, TIMELIMIT(), options.pnn,
+ tmp_ctx, &ifaces);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to get interfaces from node %u\n",
+ options.pnn));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ if (options.machinereadable){
+ printf(":Name:LinkStatus:References:\n");
+ } else {
+ printf("Interfaces on node %u\n", options.pnn);
+ }
+
+ for (i=0; i<ifaces->num; i++) {
+ if (options.machinereadable){
+ printf(":%s:%s:%u\n",
+ ifaces->ifaces[i].name,
+ ifaces->ifaces[i].link_state?"1":"0",
+ (unsigned int)ifaces->ifaces[i].references);
+ } else {
+ printf("name:%s link:%s references:%u\n",
+ ifaces->ifaces[i].name,
+ ifaces->ifaces[i].link_state?"up":"down",
+ (unsigned int)ifaces->ifaces[i].references);
+ }
+ }
+
+ talloc_free(tmp_ctx);
+ return 0;
+}
+
+
+/*
+ set link status of an interface
+ */
+static int control_setifacelink(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+ int ret;
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+ struct ctdb_control_iface_info info;
+
+ ZERO_STRUCT(info);
+
+ if (argc != 2) {
+ usage();
+ }
+
+ if (strlen(argv[0]) > CTDB_IFACE_SIZE) {
+ DEBUG(DEBUG_ERR, ("interfaces name '%s' too long\n",
+ argv[0]));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+ strcpy(info.name, argv[0]);
+
+ if (strcmp(argv[1], "up") == 0) {
+ info.link_state = 1;
+ } else if (strcmp(argv[1], "down") == 0) {
+ info.link_state = 0;
+ } else {
+ DEBUG(DEBUG_ERR, ("link state invalid '%s' should be 'up' or 'down'\n",
+ argv[1]));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ /* read the public ip list from this node */
+ ret = ctdb_ctrl_set_iface_link(ctdb, TIMELIMIT(), options.pnn,
+ tmp_ctx, &info);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to set link state for interfaces %s node %u\n",
+ argv[0], options.pnn));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ talloc_free(tmp_ctx);
+ return 0;
+}
+
/*
display pid of a ctdb daemon
*/
ret = ctdb_dump_db(ctdb_db, stdout);
if (ret == -1) {
DEBUG(DEBUG_ERR, ("Unable to dump database\n"));
+ DEBUG(DEBUG_ERR, ("Maybe try 'ctdb getdbstatus %s'"
+ " and 'ctdb getvar AllowUnhealthyDBRead'\n",
+ db_name));
return -1;
}
talloc_free(ctdb_db);
return ret;
}
+ if(options.machinereadable){
+ printf(":ID:Name:Path:Persistent:Unhealthy:\n");
+ for(i=0;i<dbmap->num;i++){
+ const char *path;
+ const char *name;
+ const char *health;
+ bool persistent;
+
+ ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.pnn,
+ dbmap->dbs[i].dbid, ctdb, &path);
+ ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn,
+ dbmap->dbs[i].dbid, ctdb, &name);
+ ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn,
+ dbmap->dbs[i].dbid, ctdb, &health);
+ persistent = dbmap->dbs[i].persistent;
+ printf(":0x%08X:%s:%s:%d:%d:\n",
+ dbmap->dbs[i].dbid, name, path,
+ !!(persistent), !!(health));
+ }
+ return 0;
+ }
+
printf("Number of databases:%d\n", dbmap->num);
for(i=0;i<dbmap->num;i++){
const char *path;
const char *name;
+ const char *health;
bool persistent;
ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &path);
ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &name);
+ ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &health);
persistent = dbmap->dbs[i].persistent;
- printf("dbid:0x%08x name:%s path:%s %s\n", dbmap->dbs[i].dbid, name,
- path, persistent?"PERSISTENT":"");
+ printf("dbid:0x%08x name:%s path:%s%s%s\n",
+ dbmap->dbs[i].dbid, name, path,
+ persistent?" PERSISTENT":"",
+ health?" UNHEALTHY":"");
}
return 0;
}
+/*
+ display the status of a database on a remote ctdb
+ */
+static int control_getdbstatus(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+ int i, ret;
+ struct ctdb_dbid_map *dbmap=NULL;
+ const char *db_name;
+
+ if (argc < 1) {
+ usage();
+ }
+
+ db_name = argv[0];
+
+ ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, ctdb, &dbmap);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to get dbids from node %u\n", options.pnn));
+ return ret;
+ }
+
+ for(i=0;i<dbmap->num;i++){
+ const char *path;
+ const char *name;
+ const char *health;
+ bool persistent;
+
+ ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &name);
+ if (strcmp(name, db_name) != 0) {
+ continue;
+ }
+
+ ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &path);
+ ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &health);
+ persistent = dbmap->dbs[i].persistent;
+ printf("dbid: 0x%08x\nname: %s\npath: %s\nPERSISTENT: %s\nHEALTH: %s\n",
+ dbmap->dbs[i].dbid, name, path,
+ persistent?"yes":"no",
+ health?health:"OK");
+ return 0;
+ }
+
+ DEBUG(DEBUG_ERR, ("db %s doesn't exist on node %u\n", db_name, options.pnn));
+ return 0;
+}
+
/*
check if the local node is recmaster or not
it will return 1 if this node is the recmaster and 0 if it is not
struct backup_data *bd;
int fh = -1;
int status = -1;
+ const char *reason = NULL;
if (argc != 2) {
DEBUG(DEBUG_ERR,("Invalid arguments\n"));
return -1;
}
+ ret = ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn,
+ dbmap->dbs[i].dbid, tmp_ctx, &reason);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR,("Unable to get dbhealth for database '%s'\n",
+ argv[0]));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+ if (reason) {
+ uint32_t allow_unhealthy = 0;
+
+ ctdb_ctrl_get_tunable(ctdb, TIMELIMIT(), options.pnn,
+ "AllowUnhealthyDBRead",
+ &allow_unhealthy);
+
+ if (allow_unhealthy != 1) {
+ DEBUG(DEBUG_ERR,("database '%s' is unhealthy: %s\n",
+ argv[0], reason));
+
+ DEBUG(DEBUG_ERR,("disallow backup : tunnable AllowUnhealthyDBRead = %u\n",
+ allow_unhealthy));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ DEBUG(DEBUG_WARNING,("WARNING database '%s' is unhealthy - see 'ctdb getdbstatus %s'\n",
+ argv[0], argv[0]));
+ DEBUG(DEBUG_WARNING,("WARNING! allow backup of unhealthy database: "
+ "tunnable AllowUnhealthyDBRead = %u\n",
+ allow_unhealthy));
+ }
ctdb_db = ctdb_attach(ctdb, argv[0], dbmap->dbs[i].persistent, 0);
if (ctdb_db == NULL) {
return -1;
}
+ data.dptr = (void *)&ctdb_db->db_id;
+ data.dsize = sizeof(ctdb_db->db_id);
+
+ /* mark the database as healthy */
+ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+ if (ctdb_client_async_control(ctdb, CTDB_CONTROL_DB_SET_HEALTHY,
+ nodes, 0,
+ TIMELIMIT(), false, data,
+ NULL, NULL,
+ NULL) != 0) {
+ DEBUG(DEBUG_ERR, ("Failed to mark database as healthy.\n"));
+ ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
data.dptr = (void *)&generation;
data.dsize = sizeof(generation);
return 0;
}
+/*
+ * dump a database backup from a file
+ */
+static int control_dumpdbbackup(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+ TDB_DATA outdata;
+ struct db_file_header dbhdr;
+ int i, fh;
+ struct tm *tm;
+ char tbuf[100];
+ struct ctdb_rec_data *rec = NULL;
+ struct ctdb_marshall_buffer *m;
+
+ if (argc != 1) {
+ DEBUG(DEBUG_ERR,("Invalid arguments\n"));
+ return -1;
+ }
+
+ fh = open(argv[0], O_RDONLY);
+ if (fh == -1) {
+ DEBUG(DEBUG_ERR,("Failed to open file '%s'\n", argv[0]));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ read(fh, &dbhdr, sizeof(dbhdr));
+ if (dbhdr.version != DB_VERSION) {
+ DEBUG(DEBUG_ERR,("Invalid version of database dump. File is version %lu but expected version was %u\n", dbhdr.version, DB_VERSION));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ outdata.dsize = dbhdr.size;
+ outdata.dptr = talloc_size(tmp_ctx, outdata.dsize);
+ if (outdata.dptr == NULL) {
+ DEBUG(DEBUG_ERR,("Failed to allocate data of size '%lu'\n", dbhdr.size));
+ close(fh);
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+ read(fh, outdata.dptr, outdata.dsize);
+ close(fh);
+ m = (struct ctdb_marshall_buffer *)outdata.dptr;
+
+ tm = localtime(&dbhdr.timestamp);
+ strftime(tbuf,sizeof(tbuf)-1,"%Y/%m/%d %H:%M:%S", tm);
+ printf("Backup of database name:'%s' dbid:0x%x08x from @ %s\n",
+ dbhdr.name, m->db_id, tbuf);
+
+ for (i=0; i < m->count; i++) {
+ uint32_t reqid = 0;
+ TDB_DATA key, data;
+
+ /* we do not want the header splitted, so we pass NULL*/
+ rec = ctdb_marshall_loop_next(m, rec, &reqid,
+ NULL, &key, &data);
+
+ ctdb_dumpdb_record(ctdb, key, data, stdout);
+ }
+
+ printf("Dumped %d records\n", i);
+ talloc_free(tmp_ctx);
+ return 0;
+}
+
+/*
+ * wipe a database from a file
+ */
+static int control_wipedb(struct ctdb_context *ctdb, int argc,
+ const char **argv)
+{
+ int ret;
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+ TDB_DATA data;
+ struct ctdb_db_context *ctdb_db;
+ struct ctdb_node_map *nodemap = NULL;
+ struct ctdb_vnn_map *vnnmap = NULL;
+ int i;
+ struct ctdb_control_wipe_database w;
+ uint32_t *nodes;
+ uint32_t generation;
+ struct ctdb_dbid_map *dbmap = NULL;
+
+ if (argc != 1) {
+ DEBUG(DEBUG_ERR,("Invalid arguments\n"));
+ return -1;
+ }
+
+ ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx,
+ &dbmap);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to get dbids from node %u\n",
+ options.pnn));
+ return ret;
+ }
+
+ for(i=0;i<dbmap->num;i++){
+ const char *name;
+
+ ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn,
+ dbmap->dbs[i].dbid, tmp_ctx, &name);
+ if(!strcmp(argv[0], name)){
+ talloc_free(discard_const(name));
+ break;
+ }
+ talloc_free(discard_const(name));
+ }
+ if (i == dbmap->num) {
+ DEBUG(DEBUG_ERR, ("No database with name '%s' found\n",
+ argv[0]));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ ctdb_db = ctdb_attach(ctdb, argv[0], dbmap->dbs[i].persistent, 0);
+ if (ctdb_db == NULL) {
+ DEBUG(DEBUG_ERR, ("Unable to attach to database '%s'\n",
+ argv[0]));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb,
+ &nodemap);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n",
+ options.pnn));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx,
+ &vnnmap);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to get vnnmap from node %u\n",
+ options.pnn));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ /* freeze all nodes */
+ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+ for (i=1; i<=NUM_DB_PRIORITIES; i++) {
+ ret = ctdb_client_async_control(ctdb, CTDB_CONTROL_FREEZE,
+ nodes, i,
+ TIMELIMIT(),
+ false, tdb_null,
+ NULL, NULL,
+ NULL);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to freeze nodes.\n"));
+ ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn,
+ CTDB_RECOVERY_ACTIVE);
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+ }
+
+ generation = vnnmap->generation;
+ data.dptr = (void *)&generation;
+ data.dsize = sizeof(generation);
+
+ /* start a cluster wide transaction */
+ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+ ret = ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_START,
+ nodes, 0,
+ TIMELIMIT(), false, data,
+ NULL, NULL,
+ NULL);
+ if (ret!= 0) {
+ DEBUG(DEBUG_ERR, ("Unable to start cluster wide "
+ "transactions.\n"));
+ return -1;
+ }
+
+ w.db_id = ctdb_db->db_id;
+ w.transaction_id = generation;
+
+ data.dptr = (void *)&w;
+ data.dsize = sizeof(w);
+
+ /* wipe all the remote databases. */
+ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+ if (ctdb_client_async_control(ctdb, CTDB_CONTROL_WIPE_DATABASE,
+ nodes, 0,
+ TIMELIMIT(), false, data,
+ NULL, NULL,
+ NULL) != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to wipe database.\n"));
+ ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ data.dptr = (void *)&ctdb_db->db_id;
+ data.dsize = sizeof(ctdb_db->db_id);
+
+ /* mark the database as healthy */
+ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+ if (ctdb_client_async_control(ctdb, CTDB_CONTROL_DB_SET_HEALTHY,
+ nodes, 0,
+ TIMELIMIT(), false, data,
+ NULL, NULL,
+ NULL) != 0) {
+ DEBUG(DEBUG_ERR, ("Failed to mark database as healthy.\n"));
+ ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ data.dptr = (void *)&generation;
+ data.dsize = sizeof(generation);
+
+ /* commit all the changes */
+ if (ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_COMMIT,
+ nodes, 0,
+ TIMELIMIT(), false, data,
+ NULL, NULL,
+ NULL) != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to commit databases.\n"));
+ ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ /* thaw all nodes */
+ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true);
+ if (ctdb_client_async_control(ctdb, CTDB_CONTROL_THAW,
+ nodes, 0,
+ TIMELIMIT(),
+ false, tdb_null,
+ NULL, NULL,
+ NULL) != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to thaw nodes.\n"));
+ ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ talloc_free(tmp_ctx);
+ return 0;
+}
+
/*
* set flags of a node in the nodemap
*/
{ "statistics", control_statistics, false, false, "show statistics" },
{ "statisticsreset", control_statistics_reset, true, false, "reset statistics"},
{ "ip", control_ip, false, false, "show which public ip's that ctdb manages" },
+ { "ipinfo", control_ipinfo, true, false, "show details about a public ip that ctdb manages", "<ip>" },
+ { "ifaces", control_ifaces, true, false, "show which interfaces that ctdb manages" },
+ { "setifacelink", control_setifacelink, true, false, "set interface link status", "<iface> <status>" },
{ "process-exists", control_process_exists, true, false, "check if a process exists on a node", "<pid>"},
{ "getdbmap", control_getdbmap, true, false, "show the database map" },
+ { "getdbstatus", control_getdbstatus, true, false, "show the status of a database", "<dbname>" },
{ "catdb", control_catdb, true, false, "dump a database" , "<dbname>"},
{ "getmonmode", control_getmonmode, true, false, "show monitoring mode" },
{ "getcapabilities", control_getcapabilities, true, false, "show node capabilities" },
{ "eventscript", control_eventscript, true, false, "run the eventscript with the given parameters on a node", "<arguments>"},
{ "backupdb", control_backupdb, false, false, "backup the database into a file.", "<database> <file>"},
{ "restoredb", control_restoredb, false, false, "restore the database from a file.", "<file>"},
+ { "dumpdbbackup", control_dumpdbbackup, false, true, "dump database backup from a file.", "<file>"},
+ { "wipedb", control_wipedb, false, false, "wipe the contents of a database.", "<dbname>"},
{ "recmaster", control_recmaster, false, false, "show the pnn for the recovery master."},
{ "setflags", control_setflags, false, false, "set flags for a node in the nodemap.", "<node> <flags>"},
- { "scriptstatus", control_scriptstatus, false, false, "show the status of the monitoring scripts"},
+ { "scriptstatus", control_scriptstatus, false, false, "show the status of the monitoring scripts (or all scripts)", "[all]"},
{ "enablescript", control_enablescript, false, false, "enable an eventscript", "<script>"},
{ "disablescript", control_disablescript, false, false, "disable an eventscript", "<script>"},
{ "natgwlist", control_natgwlist, false, false, "show the nodes belonging to this natgw configuration"},