#include "system/locale.h"
#include "popt.h"
#include "cmdline.h"
-#include "../include/version.h"
+#include "../include/ctdb_version.h"
#include "../include/ctdb.h"
#include "../include/ctdb_client.h"
#include "../include/ctdb_private.h"
/*
check if a database exists
*/
-static int db_exists(struct ctdb_context *ctdb, const char *db_name, bool *persistent)
+static bool db_exists(struct ctdb_context *ctdb, const char *dbarg, uint32_t *dbid, uint8_t *flags)
{
int i, ret;
struct ctdb_dbid_map *dbmap=NULL;
+ bool dbid_given = false, found = false;
+ uint32_t id;
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
- ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, ctdb, &dbmap);
+ 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 -1;
+ goto fail;
}
- for(i=0;i<dbmap->num;i++){
- const char *name;
+ if (strncmp(dbarg, "0x", 2) == 0) {
+ id = strtoul(dbarg, NULL, 0);
+ dbid_given = true;
+ }
- ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &name);
- if (!strcmp(name, db_name)) {
- if (persistent) {
- *persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
+ for(i=0; i<dbmap->num; i++) {
+ if (dbid_given) {
+ if (id == dbmap->dbs[i].dbid) {
+ found = true;
+ break;
+ }
+ } else {
+ const char *name;
+ ret = ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, tmp_ctx, &name);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to get dbname from dbid %u\n", dbmap->dbs[i].dbid));
+ goto fail;
+ }
+
+ if (strcmp(name, dbarg) == 0) {
+ id = dbmap->dbs[i].dbid;
+ found = true;
+ break;
}
- return 0;
}
}
- return -1;
+ if (found) {
+ if (dbid) *dbid = id;
+ if (flags) *flags = dbmap->dbs[i].flags;
+ } else {
+ DEBUG(DEBUG_ERR,("No database matching '%s' found\n", dbarg));
+ }
+
+fail:
+ talloc_free(tmp_ctx);
+ return found;
}
/*
{
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
struct ctdb_db_statistics *dbstat;
- struct ctdb_dbid_map *dbmap=NULL;
- int i, ret;
+ int i;
+ uint32_t db_id;
if (argc < 1) {
usage();
}
- 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);
+ if (!db_exists(ctdb, argv[0], &db_id, NULL)) {
return -1;
}
- if (!ctdb_getdbstat(ctdb_connection, options.pnn, dbmap->dbs[i].dbid, &dbstat)) {
+ if (!ctdb_getdbstat(ctdb_connection, options.pnn, db_id, &dbstat)) {
DEBUG(DEBUG_ERR,("Failed to read db statistics from node\n"));
talloc_free(tmp_ctx);
return -1;
return 0;
}
+
+/*
+ * scans all other nodes and returns a pnn for another node that can host this
+ * ip address or -1
+ */
+static int
+find_other_host_for_public_ip(struct ctdb_context *ctdb, ctdb_sock_addr *addr)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+ struct ctdb_all_public_ips *ips;
+ struct ctdb_node_map *nodemap=NULL;
+ int i, j, ret;
+
+ ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ for(i=0;i<nodemap->num;i++){
+ if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+ continue;
+ }
+ if (nodemap->nodes[i].pnn == options.pnn) {
+ continue;
+ }
+
+ /* read the public ip list from this node */
+ ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, tmp_ctx, &ips);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %u\n", nodemap->nodes[i].pnn));
+ return -1;
+ }
+
+ for (j=0;j<ips->num;j++) {
+ if (ctdb_same_ip(addr, &ips->ips[j].addr)) {
+ talloc_free(tmp_ctx);
+ return nodemap->nodes[i].pnn;
+ }
+ }
+ talloc_free(ips);
+ }
+
+ talloc_free(tmp_ctx);
+ return -1;
+}
+
+/* If pnn is -1 then try to find a node to move IP to... */
+static bool try_moveip(struct ctdb_context *ctdb, ctdb_sock_addr *addr, uint32_t pnn)
+{
+ bool pnn_specified = (pnn == -1 ? false : true);
+ int retries = 0;
+
+ while (retries < 5) {
+ if (!pnn_specified) {
+ pnn = find_other_host_for_public_ip(ctdb, addr);
+ if (pnn == -1) {
+ return false;
+ }
+ DEBUG(DEBUG_NOTICE,
+ ("Trying to move public IP to node %u\n", pnn));
+ }
+
+ if (move_ip(ctdb, addr, pnn) == 0) {
+ return true;
+ }
+
+ sleep(3);
+ retries++;
+ }
+
+ return false;
+}
+
+
/*
move/failover an ip address to a specific node
*/
static int control_moveip(struct ctdb_context *ctdb, int argc, const char **argv)
{
uint32_t pnn;
- int ret, retries = 0;
ctdb_sock_addr addr;
if (argc < 2) {
return -1;
}
- do {
- ret = move_ip(ctdb, &addr, pnn);
- if (ret != 0) {
- DEBUG(DEBUG_ERR,("Failed to move ip to node %d. Wait 3 second and try again.\n", pnn));
- sleep(3);
- retries++;
- }
- } while (retries < 5 && ret != 0);
- if (ret != 0) {
- DEBUG(DEBUG_ERR,("Failed to move ip to node %d. Giving up.\n", pnn));
+ if (!try_moveip(ctdb, &addr, pnn)) {
+ DEBUG(DEBUG_ERR,("Failed to move IP to node %d.\n", pnn));
return -1;
}
}
-/*
- * scans all other nodes and returns a pnn for another node that can host this
- * ip address or -1
- */
-static int
-find_other_host_for_public_ip(struct ctdb_context *ctdb, ctdb_sock_addr *addr)
-{
- TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
- struct ctdb_all_public_ips *ips;
- struct ctdb_node_map *nodemap=NULL;
- int i, j, ret;
-
- ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap);
- if (ret != 0) {
- DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
- talloc_free(tmp_ctx);
- return ret;
- }
-
- for(i=0;i<nodemap->num;i++){
- if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
- continue;
- }
- if (nodemap->nodes[i].pnn == options.pnn) {
- continue;
- }
-
- /* read the public ip list from this node */
- ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, tmp_ctx, &ips);
- if (ret != 0) {
- DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %u\n", nodemap->nodes[i].pnn));
- return -1;
- }
-
- for (j=0;j<ips->num;j++) {
- if (ctdb_same_ip(addr, &ips->ips[j].addr)) {
- talloc_free(tmp_ctx);
- return nodemap->nodes[i].pnn;
- }
- }
- talloc_free(ips);
- }
-
- talloc_free(tmp_ctx);
- return -1;
-}
-
-static uint32_t ipreallocate_finished;
+static bool ipreallocate_finished;
/*
handler for receiving the response to ipreallocate
static void ip_reallocate_handler(struct ctdb_context *ctdb, uint64_t srvid,
TDB_DATA data, void *private_data)
{
- ipreallocate_finished = 1;
+ ipreallocate_finished = true;
}
static void ctdb_every_second(struct event_context *ev, struct timed_event *te, struct timeval t, void *p)
int i, ret;
TDB_DATA data;
struct takeover_run_reply rd;
- uint32_t recmaster;
struct ctdb_node_map *nodemap=NULL;
- int retries=0;
+ int count;
struct timeval tv = timeval_current();
/* we need some events to trigger so we can timeout and restart
data.dsize = sizeof(rd);
again:
- /* check that there are valid nodes available */
+ /* get the number of nodes and node flags */
if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb, &nodemap) != 0) {
DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
return -1;
}
- for (i=0; i<nodemap->num;i++) {
- if ((nodemap->nodes[i].flags & (NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)) == 0) {
- break;
- }
- }
- if (i==nodemap->num) {
- DEBUG(DEBUG_ERR,("No recmaster available, no need to wait for cluster convergence\n"));
- return 0;
- }
-
- if (!ctdb_getrecmaster(ctdb_connection, options.pnn, &recmaster)) {
- DEBUG(DEBUG_ERR, ("Unable to get recmaster from node %u\n", options.pnn));
- return -1;
- }
-
- /* verify the node exists */
- if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), recmaster, ctdb, &nodemap) != 0) {
- DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
- return -1;
- }
-
-
- /* check tha there are nodes available that can act as a recmaster */
- for (i=0; i<nodemap->num; i++) {
- if (nodemap->nodes[i].flags & (NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)) {
+ ipreallocate_finished = false;
+ count = 0;
+ for (i=0; i<nodemap->num;i++) {
+ if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
continue;
+ } else {
+ /* Send to all active nodes. Only recmaster will reply. */
+ ret = ctdb_client_send_message(ctdb, i, CTDB_SRVID_TAKEOVER_RUN, data);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR,("Failed to send ip takeover run request message to %u\n", options.pnn));
+ return -1;
+ }
+ count++;
}
- break;
}
- if (i == nodemap->num) {
- DEBUG(DEBUG_ERR,("No possible nodes to host addresses.\n"));
+ if (count == 0) {
+ DEBUG(DEBUG_ERR,("No recmaster available, no need to wait for cluster convergence\n"));
return 0;
}
- /* verify the recovery master is not STOPPED, nor BANNED */
- if (nodemap->nodes[recmaster].flags & (NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)) {
- DEBUG(DEBUG_ERR,("No suitable recmaster found. Try again\n"));
- retries++;
- sleep(1);
- goto again;
- }
-
- /* verify the recovery master is not STOPPED, nor BANNED */
- if (nodemap->nodes[recmaster].flags & (NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)) {
- DEBUG(DEBUG_ERR,("No suitable recmaster found. Try again\n"));
- retries++;
- sleep(1);
- goto again;
- }
-
- ipreallocate_finished = 0;
- ret = ctdb_client_send_message(ctdb, recmaster, CTDB_SRVID_TAKEOVER_RUN, data);
- if (ret != 0) {
- DEBUG(DEBUG_ERR,("Failed to send ip takeover run request message to %u\n", options.pnn));
- return -1;
- }
-
tv = timeval_current();
/* this loop will terminate when we have received the reply */
- while (timeval_elapsed(&tv) < 5.0 && ipreallocate_finished == 0) {
+ while (timeval_elapsed(&tv) < 5.0 && !ipreallocate_finished) {
event_loop_once(ctdb->ev);
}
- if (ipreallocate_finished == 1) {
- return 0;
- }
- retries++;
- sleep(1);
- goto again;
+ if (!ipreallocate_finished) {
+ goto again;
+ }
return 0;
}
static int control_delip(struct ctdb_context *ctdb, int argc, const char **argv)
{
int i, ret;
- int retries = 0;
ctdb_sock_addr addr;
struct ctdb_control_ip_iface pub;
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
return -1;
}
+ /* This is an optimisation. If this node is hosting the IP
+ * then try to move it somewhere else without invoking a full
+ * takeover run. We don't care if this doesn't work!
+ */
if (ips->ips[i].pnn == options.pnn) {
- ret = find_other_host_for_public_ip(ctdb, &addr);
- if (ret != -1) {
- do {
- ret = move_ip(ctdb, &addr, ret);
- if (ret != 0) {
- DEBUG(DEBUG_ERR,("Failed to move ip to node %d. Wait 3 seconds and try again.\n", options.pnn));
- sleep(3);
- retries++;
- }
- } while (retries < 5 && ret != 0);
- if (ret != 0) {
- DEBUG(DEBUG_ERR,("Failed to move ip to node %d. Giving up.\n", options.pnn));
- return -1;
- }
- }
+ (void) try_moveip(ctdb, &addr, -1);
}
ret = ctdb_ctrl_del_public_ip(ctdb, TIMELIMIT(), options.pnn, &pub);
const char *db_name;
struct ctdb_db_context *ctdb_db;
int ret;
- bool persistent;
struct ctdb_dump_db_context c;
+ uint8_t flags;
if (argc < 1) {
usage();
db_name = argv[0];
-
- if (db_exists(ctdb, db_name, &persistent)) {
- DEBUG(DEBUG_ERR,("Database '%s' does not exist\n", db_name));
+ if (!db_exists(ctdb, db_name, NULL, &flags)) {
return -1;
}
- ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, persistent, 0);
-
+ ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, flags & CTDB_DB_FLAGS_PERSISTENT, 0);
if (ctdb_db == NULL) {
DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name));
return -1;
const char *db_name;
struct ctdb_db_context *ctdb_db;
struct cattdb_data d;
- bool persistent;
+ uint8_t flags;
if (argc < 1) {
usage();
db_name = argv[0];
-
- if (db_exists(ctdb, db_name, &persistent)) {
- DEBUG(DEBUG_ERR,("Database '%s' does not exist\n", db_name));
+ if (!db_exists(ctdb, db_name, NULL, &flags)) {
return -1;
}
- ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, persistent, 0);
-
+ ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, flags & CTDB_DB_FLAGS_PERSISTENT, 0);
if (ctdb_db == NULL) {
DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name));
return -1;
struct ctdb_record_handle *h;
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
TDB_DATA key, data;
- bool persistent;
+ uint8_t flags;
if (argc < 2) {
usage();
db_name = argv[0];
- if (db_exists(ctdb, db_name, &persistent)) {
- DEBUG(DEBUG_ERR,("Database '%s' does not exist\n", db_name));
+ if (!db_exists(ctdb, db_name, NULL, &flags)) {
return -1;
}
- ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, persistent, 0);
-
+ ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, flags & CTDB_DB_FLAGS_PERSISTENT, 0);
if (ctdb_db == NULL) {
DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name));
return -1;
struct ctdb_record_handle *h;
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
TDB_DATA key, data;
- bool persistent;
+ uint8_t flags;
if (argc < 3) {
usage();
db_name = argv[0];
- if (db_exists(ctdb, db_name, &persistent)) {
- DEBUG(DEBUG_ERR,("Database '%s' does not exist\n", db_name));
+ if (!db_exists(ctdb, db_name, NULL, &flags)) {
return -1;
}
- ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, persistent, 0);
-
+ ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, flags & CTDB_DB_FLAGS_PERSISTENT, 0);
if (ctdb_db == NULL) {
DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name));
return -1;
TDB_DATA key, data;
int fd, ret;
bool persistent;
+ uint8_t flags;
if (argc < 2) {
talloc_free(tmp_ctx);
db_name = argv[0];
-
- if (db_exists(ctdb, db_name, &persistent)) {
- DEBUG(DEBUG_ERR,("Database '%s' does not exist\n", db_name));
+ if (!db_exists(ctdb, db_name, NULL, &flags)) {
talloc_free(tmp_ctx);
return -1;
}
+ persistent = flags & CTDB_DB_FLAGS_PERSISTENT;
if (!persistent) {
DEBUG(DEBUG_ERR,("Database '%s' is not persistent\n", db_name));
talloc_free(tmp_ctx);
}
ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, persistent, 0);
-
if (ctdb_db == NULL) {
DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name));
talloc_free(tmp_ctx);
return 0;
}
+/*
+ * delete a record from a persistent database
+ */
+static int control_pdelete(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+ const char *db_name;
+ struct ctdb_db_context *ctdb_db;
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+ struct ctdb_transaction_handle *h;
+ TDB_DATA key;
+ int ret;
+ bool persistent;
+ uint8_t flags;
+
+ if (argc < 2) {
+ talloc_free(tmp_ctx);
+ usage();
+ }
+
+ db_name = argv[0];
+
+ if (!db_exists(ctdb, db_name, NULL, &flags)) {
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ persistent = flags & CTDB_DB_FLAGS_PERSISTENT;
+ if (!persistent) {
+ DEBUG(DEBUG_ERR, ("Database '%s' is not persistent\n", db_name));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, persistent, 0);
+ if (ctdb_db == NULL) {
+ DEBUG(DEBUG_ERR, ("Unable to attach to database '%s'\n", db_name));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ h = ctdb_transaction_start(ctdb_db, tmp_ctx);
+ if (h == NULL) {
+ DEBUG(DEBUG_ERR, ("Failed to start transaction on database %s\n", db_name));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ key.dptr = discard_const(argv[1]);
+ key.dsize = strlen(argv[1]);
+ ret = ctdb_transaction_store(h, key, tdb_null);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Failed to delete record\n"));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ ret = ctdb_transaction_commit(h);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Failed to commit transaction\n"));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ talloc_free(tmp_ctx);
+ return 0;
+}
+
/*
check if a service is bound to a port or not
*/
*/
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;
+ uint32_t db_id;
+ uint8_t flags;
+ const char *path;
+ const char *health;
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;
+ if (!db_exists(ctdb, db_name, &db_id, &flags)) {
+ return -1;
}
- for(i=0;i<dbmap->num;i++){
- const char *path;
- const char *name;
- const char *health;
- bool persistent;
- bool readonly;
- bool sticky;
+ ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.pnn, db_id, ctdb, &path);
+ ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn, db_id, ctdb, &health);
+ printf("dbid: 0x%08x\nname: %s\npath: %s\nPERSISTENT: %s\nSTICKY: %s\nREADONLY: %s\nHEALTH: %s\n",
+ db_id, db_name, path,
+ (flags & CTDB_DB_FLAGS_PERSISTENT ? "yes" : "no"),
+ (flags & CTDB_DB_FLAGS_STICKY ? "yes" : "no"),
+ (flags & CTDB_DB_FLAGS_READONLY ? "yes" : "no"),
+ (health ? health : "OK"));
- 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].flags & CTDB_DB_FLAGS_PERSISTENT;
- readonly = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
- sticky = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY;
- printf("dbid: 0x%08x\nname: %s\npath: %s\nPERSISTENT: %s\nSTICKY: %s\nREADONLY: %s\nHEALTH: %s\n",
- dbmap->dbs[i].dbid, name, path,
- persistent?"yes":"no",
- sticky?"yes":"no",
- readonly?"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;
}
}
+/*
+ get a node's runstate
+ */
+static int control_runstate(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+ int ret;
+ enum ctdb_runstate runstate;
+
+ ret = ctdb_ctrl_get_runstate(ctdb, TIMELIMIT(), options.pnn, &runstate);
+ if (ret == -1) {
+ printf("Unable to get runstate response from node %u\n",
+ options.pnn);
+ return -1;
+ } else {
+ bool found = true;
+ enum ctdb_runstate t;
+ int i;
+ for (i=0; i<argc; i++) {
+ found = false;
+ t = runstate_from_string(argv[i]);
+ if (t == CTDB_RUNSTATE_UNKNOWN) {
+ printf("Invalid run state (%s)\n", argv[i]);
+ return -1;
+ }
+
+ if (t == runstate) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ printf("CTDB not in required run state (got %s)\n",
+ runstate_to_string((enum ctdb_runstate)runstate));
+ return -1;
+ }
+ }
+
+ printf("%s\n", runstate_to_string(runstate));
+ return 0;
+}
+
+
/*
get a tunable
*/
usage();
}
- db_id = strtoul(argv[0], NULL, 0);
+ if (!db_exists(ctdb, argv[0], &db_id, NULL)) {
+ return -1;
+ }
ret = ctdb_ctrl_get_db_priority(ctdb, TIMELIMIT(), options.pnn, db_id, &priority);
if (ret != 0) {
{
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
uint32_t db_id;
- struct ctdb_dbid_map *dbmap=NULL;
- int i, ret;
+ int ret;
if (argc < 1) {
usage();
}
- if (!strncmp(argv[0], "0x", 2)) {
- db_id = strtoul(argv[0] + 2, NULL, 0);
- } else {
- 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));
- talloc_free(tmp_ctx);
- 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;
- }
- db_id = dbmap->dbs[i].dbid;
+ if (!db_exists(ctdb, argv[0], &db_id, NULL)) {
+ return -1;
}
ret = ctdb_ctrl_set_db_sticky(ctdb, options.pnn, db_id);
{
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
uint32_t db_id;
- struct ctdb_dbid_map *dbmap=NULL;
- int i, ret;
+ int ret;
if (argc < 1) {
usage();
}
- if (!strncmp(argv[0], "0x", 2)) {
- db_id = strtoul(argv[0] + 2, NULL, 0);
- } else {
- 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));
- talloc_free(tmp_ctx);
- 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;
- }
- db_id = dbmap->dbs[i].dbid;
+ if (!db_exists(ctdb, argv[0], &db_id, NULL)) {
+ return -1;
}
ret = ctdb_ctrl_set_db_readonly(ctdb, options.pnn, db_id);
usage();
}
- db_id = strtoul(argv[0], NULL, 0);
+ if (!db_exists(ctdb, argv[0], &db_id, NULL)) {
+ return -1;
+ }
ret = ctdb_getdbseqnum(ctdb_connection, options.pnn, db_id, &seqnum);
if (!ret) {
return 0;
}
+/*
+ * set db seqnum
+ */
+static int control_setdbseqnum(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+ bool ret;
+ struct ctdb_db_context *ctdb_db;
+ uint32_t db_id;
+ uint8_t flags;
+ uint64_t old_seqnum, new_seqnum;
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+ struct ctdb_transaction_handle *h;
+ TDB_DATA key, data;
+ bool persistent;
+
+ if (argc != 2) {
+ talloc_free(tmp_ctx);
+ usage();
+ }
+
+ if (!db_exists(ctdb, argv[0], &db_id, &flags)) {
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ persistent = flags & CTDB_DB_FLAGS_PERSISTENT;
+ if (!persistent) {
+ DEBUG(DEBUG_ERR,("Database '%s' is not persistent\n", argv[0]));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ ret = ctdb_getdbseqnum(ctdb_connection, options.pnn, db_id, &old_seqnum);
+ if (!ret) {
+ DEBUG(DEBUG_ERR, ("Unable to get seqnum from node."));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ new_seqnum = strtoull(argv[1], NULL, 0);
+ if (new_seqnum <= old_seqnum) {
+ DEBUG(DEBUG_ERR, ("New sequence number is less than current sequence number\n"));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), argv[0], persistent, 0);
+ if (ctdb_db == NULL) {
+ DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", argv[0]));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ h = ctdb_transaction_start(ctdb_db, tmp_ctx);
+ if (h == NULL) {
+ DEBUG(DEBUG_ERR,("Failed to start transaction on database %s\n", argv[0]));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ key.dptr = (uint8_t *)discard_const(CTDB_DB_SEQNUM_KEY);
+ key.dsize = strlen(CTDB_DB_SEQNUM_KEY) + 1;
+
+ data.dsize = sizeof(new_seqnum);
+ data.dptr = talloc_size(tmp_ctx, data.dsize);
+ *data.dptr = new_seqnum;
+
+ ret = ctdb_transaction_store(h, key, data);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR,("Failed to store record\n"));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ ret = ctdb_transaction_commit(h);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR,("Failed to commit transaction\n"));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ talloc_free(tmp_ctx);
+ return 0;
+}
+
/*
run an eventscript on a node
*/
*/
static int control_backupdb(struct ctdb_context *ctdb, int argc, const char **argv)
{
- int i, ret;
- struct ctdb_dbid_map *dbmap=NULL;
+ int ret;
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
struct db_file_header dbhdr;
struct ctdb_db_context *ctdb_db;
int fh = -1;
int status = -1;
const char *reason = NULL;
+ uint32_t db_id;
+ uint8_t flags;
if (argc != 2) {
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);
+ if (!db_exists(ctdb, argv[0], &db_id, &flags)) {
return -1;
}
ret = ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn,
- dbmap->dbs[i].dbid, tmp_ctx, &reason);
+ db_id, tmp_ctx, &reason);
if (ret != 0) {
DEBUG(DEBUG_ERR,("Unable to get dbhealth for database '%s'\n",
argv[0]));
allow_unhealthy));
}
- ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), argv[0], dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT, 0);
+ ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), argv[0], flags & CTDB_DB_FLAGS_PERSISTENT, 0);
if (ctdb_db == NULL) {
DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", argv[0]));
talloc_free(tmp_ctx);
dbhdr.version = DB_VERSION;
dbhdr.timestamp = time(NULL);
- dbhdr.persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
+ dbhdr.persistent = flags & CTDB_DB_FLAGS_PERSISTENT;
dbhdr.size = bd->len;
if (strlen(argv[0]) >= MAX_DB_NAME) {
DEBUG(DEBUG_ERR,("Too long dbname\n"));
struct ctdb_control_wipe_database w;
uint32_t *nodes;
uint32_t generation;
- struct ctdb_dbid_map *dbmap = NULL;
+ uint8_t flags;
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);
+ if (!db_exists(ctdb, argv[0], NULL, &flags)) {
return -1;
}
- ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), argv[0], dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT, 0);
+ ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), argv[0], flags & CTDB_DB_FLAGS_PERSISTENT, 0);
if (ctdb_db == NULL) {
DEBUG(DEBUG_ERR, ("Unable to attach to database '%s'\n",
argv[0]));
{ "status", control_status, true, false, "show node status" },
{ "uptime", control_uptime, true, false, "show node uptime" },
{ "ping", control_ping, true, false, "ping all nodes" },
+ { "runstate", control_runstate, true, false, "get/check runstate of a node", "[setup|first_recovery|startup|running]" },
{ "getvar", control_getvar, true, false, "get a tunable variable", "<name>"},
{ "setvar", control_setvar, true, false, "set a tunable variable", "<name> <value>"},
{ "listvars", control_listvars, true, false, "list tunable variables"},
{ "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 ctdb database" , "<dbname>"},
- { "cattdb", control_cattdb, true, false, "dump a local tdb database" , "<dbname>"},
+ { "getdbstatus", control_getdbstatus, true, false, "show the status of a database", "<dbname|dbid>" },
+ { "catdb", control_catdb, true, false, "dump a ctdb database" , "<dbname|dbid>"},
+ { "cattdb", control_cattdb, true, false, "dump a local tdb database" , "<dbname|dbid>"},
{ "getmonmode", control_getmonmode, true, false, "show monitoring mode" },
{ "getcapabilities", control_getcapabilities, true, false, "show node capabilities" },
{ "pnn", control_pnn, true, false, "show the pnn of the currnet node" },
{ "showban", control_showban, true, false, "show ban information"},
{ "shutdown", control_shutdown, true, false, "shutdown ctdbd" },
{ "recover", control_recover, true, false, "force recovery" },
- { "sync", control_ipreallocate, true, false, "wait until ctdbd has synced all state changes" },
+ { "sync", control_ipreallocate, false, false, "wait until ctdbd has synced all state changes" },
{ "ipreallocate", control_ipreallocate, true, false, "force the recovery daemon to perform a ip reallocation procedure" },
{ "thaw", control_thaw, true, false, "thaw databases", "[priority:1-3]" },
{ "isnotrecmaster", control_isnotrecmaster, false, false, "check if the local node is recmaster or not" },
{ "addip", control_addip, true, false, "add a ip address to a node", "<ip/mask> <iface>"},
{ "delip", control_delip, false, false, "delete an ip address from a node", "<ip>"},
{ "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>"},
+ { "backupdb", control_backupdb, false, false, "backup the database into a file.", "<dbname|dbid> <file>"},
{ "restoredb", control_restoredb, false, false, "restore the database from a file.", "<file> [dbname]"},
{ "dumpdbbackup", control_dumpdbbackup, false, true, "dump database backup from a file.", "<file>"},
- { "wipedb", control_wipedb, false, false, "wipe the contents of a database.", "<dbname>"},
+ { "wipedb", control_wipedb, false, false, "wipe the contents of a database.", "<dbname|dbid>"},
{ "recmaster", control_recmaster, true, false, "show the pnn for the recovery master."},
{ "scriptstatus", control_scriptstatus, true, false, "show the status of the monitoring scripts (or all scripts)", "[all]"},
{ "enablescript", control_enablescript, false, false, "enable an eventscript", "<script>"},
{ "setnatgwstate", control_setnatgwstate, false, false, "Set NATGW state to on/off", "{on|off}"},
{ "setlmasterrole", control_setlmasterrole, false, false, "Set LMASTER role to on/off", "{on|off}"},
{ "setrecmasterrole", control_setrecmasterrole, false, false, "Set RECMASTER role to on/off", "{on|off}"},
- { "setdbprio", control_setdbprio, false, false, "Set DB priority", "<dbid> <prio:1-3>"},
- { "getdbprio", control_getdbprio, false, false, "Get DB priority", "<dbid>"},
- { "setdbreadonly", control_setdbreadonly, false, false, "Set DB readonly capable", "<dbid>|<name>"},
- { "setdbsticky", control_setdbsticky, false, false, "Set DB sticky-records capable", "<dbid>|<name>"},
+ { "setdbprio", control_setdbprio, false, false, "Set DB priority", "<dbname|dbid> <prio:1-3>"},
+ { "getdbprio", control_getdbprio, false, false, "Get DB priority", "<dbname|dbid>"},
+ { "setdbreadonly", control_setdbreadonly, false, false, "Set DB readonly capable", "<dbname|dbid>"},
+ { "setdbsticky", control_setdbsticky, false, false, "Set DB sticky-records capable", "<dbname|dbid>"},
{ "msglisten", control_msglisten, false, false, "Listen on a srvid port for messages", "<msg srvid>"},
{ "msgsend", control_msgsend, false, false, "Send a message to srvid", "<srvid> <message>"},
- { "sync", control_ipreallocate, false, false, "wait until ctdbd has synced all state changes" },
- { "pfetch", control_pfetch, false, false, "fetch a record from a persistent database", "<db> <key> [<file>]" },
- { "pstore", control_pstore, false, false, "write a record to a persistent database", "<db> <key> <file containing record>" },
+ { "pfetch", control_pfetch, false, false, "fetch a record from a persistent database", "<dbname|dbid> <key> [<file>]" },
+ { "pstore", control_pstore, false, false, "write a record to a persistent database", "<dbname|dbid> <key> <file containing record>" },
+ { "pdelete", control_pdelete, false, false, "delete a record from a persistent database", "<dbname|dbid> <key>" },
{ "tfetch", control_tfetch, false, true, "fetch a record from a [c]tdb-file [-v]", "<tdb-file> <key> [<file>]" },
{ "tstore", control_tstore, false, true, "store a record (including ltdb header)", "<tdb-file> <key> <data+header>" },
{ "readkey", control_readkey, true, false, "read the content off a database key", "<tdb-file> <key>" },
{ "writekey", control_writekey, true, false, "write to a database key", "<tdb-file> <key> <value>" },
{ "checktcpport", control_chktcpport, false, true, "check if a service is bound to a specific tcp port or not", "<port>" },
{ "rebalancenode", control_rebalancenode, false, false, "release a node by allowing it to takeover ips", "<pnn>"},
- { "getdbseqnum", control_getdbseqnum, false, false, "get the sequence number off a database", "<dbid>" },
+ { "getdbseqnum", control_getdbseqnum, false, false, "get the sequence number off a database", "<dbname|dbid>" },
+ { "setdbseqnum", control_setdbseqnum, false, false, "set the sequence number for a database", "<dbname|dbid> <seqnum>" },
{ "nodestatus", control_nodestatus, true, false, "show and return node status" },
- { "dbstatistics", control_dbstatistics, false, false, "show db statistics", "<db>" },
+ { "dbstatistics", control_dbstatistics, false, false, "show db statistics", "<dbname|dbid>" },
{ "reloadips", control_reloadips, false, false, "reload the public addresses file on a node" },
{ "ipiface", control_ipiface, true, true, "Find which interface an ip address is hsoted on", "<ip>" },
};