#include "popt.h"
#include "cmdline.h"
#include "../include/ctdb_version.h"
-#include "../include/ctdb.h"
#include "../include/ctdb_client.h"
#include "../include/ctdb_private.h"
#include "../common/rb_tree.h"
#include "db_wrap.h"
+#include "lib/util/dlinklist.h"
#define ERR_TIMEOUT 20 /* timed out trying to reach node */
#define ERR_NONODE 21 /* node does not exist */
#define ERR_DISNODE 22 /* node is disconnected */
-struct ctdb_connection *ctdb_connection;
-
static void usage(void);
static struct {
uint32_t pnn;
uint32_t *nodes;
int machinereadable;
+ const char *machineseparator;
int verbose;
int maxruntime;
int printemptyrecords;
int printrecordflags;
} options;
+#define LONGTIMEOUT options.timelimit*10
+
#define TIMELIMIT() timeval_current_ofs(options.timelimit, 0)
-#define LONGTIMELIMIT() timeval_current_ofs(options.timelimit*10, 0)
+#define LONGTIMELIMIT() timeval_current_ofs(LONGTIMEOUT, 0)
static int control_version(struct ctdb_context *ctdb, int argc, const char **argv)
{
return 0;
}
+/* Like printf(3) but substitute for separator in format */
+static int printm(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
+static int printm(const char *format, ...)
+{
+ va_list ap;
+ int ret;
+ size_t len = strlen(format);
+ char new_format[len+1];
+
+ strcpy(new_format, format);
+
+ if (options.machineseparator[0] != ':') {
+ all_string_sub(new_format,
+ ":", options.machineseparator, len + 1);
+ }
+
+ va_start(ap, format);
+ ret = vprintf(new_format, ap);
+ va_end(ap);
+
+ return ret;
+}
+
#define CTDB_NOMEM_ABORT(p) do { if (!(p)) { \
DEBUG(DEBUG_ALERT,("ctdb fatal error: %s\n", \
"Out of memory in " __location__ )); \
if (flags_str[0] == '\0') {
(void) strcpy(flags_str, flag_names[j].name);
} else {
- (void) strcat(flags_str, "|");
- (void) strcat(flags_str, flag_names[j].name);
+ (void) strncat(flags_str, "|", sizeof(flags_str)-1);
+ (void) strncat(flags_str, flag_names[j].name,
+ sizeof(flags_str)-1);
}
}
}
* explicitly specified.
*/
static bool parse_nodestring(struct ctdb_context *ctdb,
+ TALLOC_CTX *mem_ctx,
const char * nodestring,
uint32_t current_pnn,
bool dd_ok,
uint32_t **nodes,
uint32_t *pnn_mode)
{
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
int n;
uint32_t i;
struct ctdb_node_map *nodemap;
- bool ret = true;
-
+ int ret;
+
*nodes = NULL;
- if (!ctdb_getnodemap(ctdb_connection, CTDB_CURRENT_NODE, &nodemap)) {
+ ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap);
+ if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+ talloc_free(tmp_ctx);
exit(10);
}
if (nodestring != NULL) {
- *nodes = talloc_array(ctdb, uint32_t, 0);
- CTDB_NOMEM_ABORT(*nodes);
-
+ *nodes = talloc_array(mem_ctx, uint32_t, 0);
+ if (*nodes == NULL) {
+ goto failed;
+ }
+
n = 0;
if (strcmp(nodestring, "all") == 0) {
/* all */
for (i = 0; i < nodemap->num; i++) {
- if ((nodemap->nodes[i].flags &
+ if ((nodemap->nodes[i].flags &
(NODE_FLAGS_DISCONNECTED |
NODE_FLAGS_DELETED)) && !dd_ok) {
continue;
}
- *nodes = talloc_realloc(ctdb, *nodes,
+ *nodes = talloc_realloc(mem_ctx, *nodes,
uint32_t, n+1);
- CTDB_NOMEM_ABORT(*nodes);
+ if (*nodes == NULL) {
+ goto failed;
+ }
(*nodes)[n] = i;
n++;
}
} else {
/* x{,y...} */
char *ns, *tok;
-
- ns = talloc_strdup(ctdb, nodestring);
+
+ ns = talloc_strdup(tmp_ctx, nodestring);
tok = strtok(ns, ",");
while (tok != NULL) {
uint32_t pnn;
- i = (uint32_t)strtoul(tok, NULL, 0);
+ char *endptr;
+ i = (uint32_t)strtoul(tok, &endptr, 0);
+ if (i == 0 && tok == endptr) {
+ DEBUG(DEBUG_ERR,
+ ("Invalid node %s\n", tok));
+ talloc_free(tmp_ctx);
+ exit(ERR_NONODE);
+ }
if (i >= nodemap->num) {
DEBUG(DEBUG_ERR, ("Node %u does not exist\n", i));
+ talloc_free(tmp_ctx);
exit(ERR_NONODE);
}
if ((nodemap->nodes[i].flags &
(NODE_FLAGS_DISCONNECTED |
NODE_FLAGS_DELETED)) && !dd_ok) {
DEBUG(DEBUG_ERR, ("Node %u has status %s\n", i, pretty_print_flags(nodemap->nodes[i].flags)));
+ talloc_free(tmp_ctx);
exit(ERR_DISNODE);
}
- if (!ctdb_getpnn(ctdb_connection, i, &pnn)) {
+ if ((pnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), i)) < 0) {
DEBUG(DEBUG_ERR, ("Can not access node %u. Node is not operational.\n", i));
+ talloc_free(tmp_ctx);
exit(10);
}
- *nodes = talloc_realloc(ctdb, *nodes,
+ *nodes = talloc_realloc(mem_ctx, *nodes,
uint32_t, n+1);
- CTDB_NOMEM_ABORT(*nodes);
+ if (*nodes == NULL) {
+ goto failed;
+ }
(*nodes)[n] = i;
n++;
}
} else {
/* default - no nodes specified */
- *nodes = talloc_array(ctdb, uint32_t, 1);
- CTDB_NOMEM_ABORT(*nodes);
+ *nodes = talloc_array(mem_ctx, uint32_t, 1);
+ if (*nodes == NULL) {
+ goto failed;
+ }
*pnn_mode = CTDB_CURRENT_NODE;
- if (!ctdb_getpnn(ctdb_connection, current_pnn,
- &((*nodes)[0]))) {
- ret = false;
+ if (((*nodes)[0] = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), current_pnn)) < 0) {
+ goto failed;
}
}
- ctdb_free_nodemap(nodemap);
+ talloc_free(tmp_ctx);
+ return true;
- return ret;
+failed:
+ talloc_free(tmp_ctx);
+ return false;
}
/*
check if a database exists
*/
-static bool db_exists(struct ctdb_context *ctdb, const char *dbarg, uint32_t *dbid, uint8_t *flags)
+static bool db_exists(struct ctdb_context *ctdb, const char *dbarg,
+ uint32_t *dbid, const char **dbname, 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);
+ const char *name;
ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &dbmap);
if (ret != 0) {
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));
}
}
+ if (found && dbid_given && dbname != NULL) {
+ 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));
+ found = false;
+ goto fail;
+ }
+ }
+
if (found) {
if (dbid) *dbid = id;
+ if (dbname) *dbname = talloc_strdup(ctdb, name);
if (flags) *flags = dbmap->dbs[i].flags;
} else {
DEBUG(DEBUG_ERR,("No database matching '%s' found\n", dbarg));
if (options.machinereadable){
if (show_header) {
- printf("CTDB version:");
- printf("Current time of statistics:");
- printf("Statistics collected since:");
+ printm("CTDB version:");
+ printm("Current time of statistics:");
+ printm("Statistics collected since:");
for (i=0;i<ARRAY_SIZE(fields);i++) {
- printf("%s:", fields[i].name);
+ printm("%s:", fields[i].name);
}
- printf("num_reclock_ctdbd_latency:");
- printf("min_reclock_ctdbd_latency:");
- printf("avg_reclock_ctdbd_latency:");
- printf("max_reclock_ctdbd_latency:");
-
- printf("num_reclock_recd_latency:");
- printf("min_reclock_recd_latency:");
- printf("avg_reclock_recd_latency:");
- printf("max_reclock_recd_latency:");
-
- printf("num_call_latency:");
- printf("min_call_latency:");
- printf("avg_call_latency:");
- printf("max_call_latency:");
-
- printf("num_lockwait_latency:");
- printf("min_lockwait_latency:");
- printf("avg_lockwait_latency:");
- printf("max_lockwait_latency:");
-
- printf("num_childwrite_latency:");
- printf("min_childwrite_latency:");
- printf("avg_childwrite_latency:");
- printf("max_childwrite_latency:");
- printf("\n");
- }
- printf("%d:", CTDB_VERSION);
- printf("%d:", (int)s->statistics_current_time.tv_sec);
- printf("%d:", (int)s->statistics_start_time.tv_sec);
+ printm("num_reclock_ctdbd_latency:");
+ printm("min_reclock_ctdbd_latency:");
+ printm("avg_reclock_ctdbd_latency:");
+ printm("max_reclock_ctdbd_latency:");
+
+ printm("num_reclock_recd_latency:");
+ printm("min_reclock_recd_latency:");
+ printm("avg_reclock_recd_latency:");
+ printm("max_reclock_recd_latency:");
+
+ printm("num_call_latency:");
+ printm("min_call_latency:");
+ printm("avg_call_latency:");
+ printm("max_call_latency:");
+
+ printm("num_lockwait_latency:");
+ printm("min_lockwait_latency:");
+ printm("avg_lockwait_latency:");
+ printm("max_lockwait_latency:");
+
+ printm("num_childwrite_latency:");
+ printm("min_childwrite_latency:");
+ printm("avg_childwrite_latency:");
+ printm("max_childwrite_latency:");
+ printm("\n");
+ }
+ printm("%d:", CTDB_VERSION);
+ printm("%d:", (int)s->statistics_current_time.tv_sec);
+ printm("%d:", (int)s->statistics_start_time.tv_sec);
for (i=0;i<ARRAY_SIZE(fields);i++) {
- printf("%d:", *(uint32_t *)(fields[i].offset+(uint8_t *)s));
- }
- printf("%d:", s->reclock.ctdbd.num);
- printf("%.6f:", s->reclock.ctdbd.min);
- printf("%.6f:", s->reclock.ctdbd.num?s->reclock.ctdbd.total/s->reclock.ctdbd.num:0.0);
- printf("%.6f:", s->reclock.ctdbd.max);
-
- printf("%d:", s->reclock.recd.num);
- printf("%.6f:", s->reclock.recd.min);
- printf("%.6f:", s->reclock.recd.num?s->reclock.recd.total/s->reclock.recd.num:0.0);
- printf("%.6f:", s->reclock.recd.max);
-
- printf("%d:", s->call_latency.num);
- printf("%.6f:", s->call_latency.min);
- printf("%.6f:", s->call_latency.num?s->call_latency.total/s->call_latency.num:0.0);
- printf("%.6f:", s->call_latency.max);
-
- printf("%d:", s->childwrite_latency.num);
- printf("%.6f:", s->childwrite_latency.min);
- printf("%.6f:", s->childwrite_latency.num?s->childwrite_latency.total/s->childwrite_latency.num:0.0);
- printf("%.6f:", s->childwrite_latency.max);
- printf("\n");
+ printm("%d:", *(uint32_t *)(fields[i].offset+(uint8_t *)s));
+ }
+ printm("%d:", s->reclock.ctdbd.num);
+ printm("%.6f:", s->reclock.ctdbd.min);
+ printm("%.6f:", s->reclock.ctdbd.num?s->reclock.ctdbd.total/s->reclock.ctdbd.num:0.0);
+ printm("%.6f:", s->reclock.ctdbd.max);
+
+ printm("%d:", s->reclock.recd.num);
+ printm("%.6f:", s->reclock.recd.min);
+ printm("%.6f:", s->reclock.recd.num?s->reclock.recd.total/s->reclock.recd.num:0.0);
+ printm("%.6f:", s->reclock.recd.max);
+
+ printm("%d:", s->call_latency.num);
+ printm("%.6f:", s->call_latency.min);
+ printm("%.6f:", s->call_latency.num?s->call_latency.total/s->call_latency.num:0.0);
+ printm("%.6f:", s->call_latency.max);
+
+ printm("%d:", s->childwrite_latency.num);
+ printm("%.6f:", s->childwrite_latency.min);
+ printm("%.6f:", s->childwrite_latency.num?s->childwrite_latency.total/s->childwrite_latency.num:0.0);
+ printm("%.6f:", s->childwrite_latency.max);
+ printm("\n");
} else {
printf("CTDB version %u\n", CTDB_VERSION);
printf("Current time of statistics : %s", ctime(&s->statistics_current_time.tv_sec));
int i;
uint32_t db_id;
int num_hot_keys;
+ int ret;
if (argc < 1) {
usage();
}
- if (!db_exists(ctdb, argv[0], &db_id, NULL)) {
+ if (!db_exists(ctdb, argv[0], &db_id, NULL, NULL)) {
return -1;
}
- if (!ctdb_getdbstat(ctdb_connection, options.pnn, db_id, &dbstat)) {
+ ret = ctdb_ctrl_dbstatistics(ctdb, options.pnn, db_id, tmp_ctx, &dbstat);
+ if (ret != 0) {
DEBUG(DEBUG_ERR,("Failed to read db statistics from node\n"));
talloc_free(tmp_ctx);
return -1;
0.0),
dbstat->locks.latency.max,
dbstat->locks.latency.num);
+ printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
+ "vacuum_latency MIN/AVG/MAX",
+ dbstat->vacuum.latency.min,
+ (dbstat->vacuum.latency.num ?
+ dbstat->vacuum.latency.total /dbstat->vacuum.latency.num :
+ 0.0),
+ dbstat->vacuum.latency.max,
+ dbstat->vacuum.latency.num);
num_hot_keys = 0;
for (i=0; i<dbstat->num_hot_keys; i++) {
if (dbstat->hot_keys[i].count > 0) {
printf("\n");
}
- ctdb_free_dbstat(dbstat);
+ talloc_free(tmp_ctx);
return 0;
}
}
if (options.machinereadable){
- printf(":Current Node Time:Ctdb Start Time:Last Recovery/Failover Time:Last Recovery/IPFailover Duration:\n");
- printf(":%u:%u:%u:%lf\n",
+ printm(":Current Node Time:Ctdb Start Time:Last Recovery/Failover Time:Last Recovery/IPFailover Duration:\n");
+ printm(":%u:%u:%u:%lf\n",
(unsigned int)uptime->current_time.tv_sec,
(unsigned int)uptime->ctdbd_start_time.tv_sec,
(unsigned int)uptime->last_recovery_finished.tv_sec,
struct pnn_node {
- struct pnn_node *next;
- const char *addr;
+ struct pnn_node *next, *prev;
+ ctdb_sock_addr addr;
int pnn;
};
-static struct pnn_node *read_nodes_file(TALLOC_CTX *mem_ctx)
+static struct pnn_node *read_pnn_node_file(TALLOC_CTX *mem_ctx,
+ const char *file)
{
- const char *nodes_list;
int nlines;
char **lines;
int i, pnn;
struct pnn_node *pnn_nodes = NULL;
struct pnn_node *pnn_node;
- struct pnn_node *tmp_node;
- /* read the nodes file */
- nodes_list = getenv("CTDB_NODES");
- if (nodes_list == NULL) {
- nodes_list = "/etc/ctdb/nodes";
- }
- lines = file_lines_load(nodes_list, &nlines, mem_ctx);
+ lines = file_lines_load(file, &nlines, 0, mem_ctx);
if (lines == NULL) {
return NULL;
}
- while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
- nlines--;
- }
for (i=0, pnn=0; i<nlines; i++) {
char *node;
}
pnn_node = talloc(mem_ctx, struct pnn_node);
pnn_node->pnn = pnn++;
- pnn_node->addr = talloc_strdup(pnn_node, node);
- pnn_node->next = pnn_nodes;
- pnn_nodes = pnn_node;
- }
- /* swap them around so we return them in incrementing order */
- pnn_node = pnn_nodes;
- pnn_nodes = NULL;
- while (pnn_node) {
- tmp_node = pnn_node;
- pnn_node = pnn_node->next;
+ if (!parse_ip(node, NULL, 0, &pnn_node->addr)) {
+ DEBUG(DEBUG_ERR,
+ ("Invalid IP address '%s' in file %s\n",
+ node, file));
+ /* Caller will free mem_ctx */
+ return NULL;
+ }
- tmp_node->next = pnn_nodes;
- pnn_nodes = tmp_node;
+ DLIST_ADD_END(pnn_nodes, pnn_node, NULL);
}
return pnn_nodes;
}
+static struct pnn_node *read_nodes_file(TALLOC_CTX *mem_ctx)
+{
+ const char *nodes_list;
+
+ /* read the nodes file */
+ nodes_list = getenv("CTDB_NODES");
+ if (nodes_list == NULL) {
+ nodes_list = talloc_asprintf(mem_ctx, "%s/nodes",
+ getenv("CTDB_BASE"));
+ if (nodes_list == NULL) {
+ DEBUG(DEBUG_ALERT,(__location__ " Out of memory\n"));
+ exit(1);
+ }
+ }
+
+ return read_pnn_node_file(mem_ctx, nodes_list);
+}
+
/*
show the PNN of the current node
discover the pnn by loading the nodes file and try to bind to all
addresses one at a time until the ip address is found.
*/
-static int control_xpnn(struct ctdb_context *ctdb, int argc, const char **argv)
+static int find_node_xpnn(void)
{
TALLOC_CTX *mem_ctx = talloc_new(NULL);
struct pnn_node *pnn_nodes;
struct pnn_node *pnn_node;
-
- assert_single_node_only();
+ int pnn;
pnn_nodes = read_nodes_file(mem_ctx);
if (pnn_nodes == NULL) {
}
for(pnn_node=pnn_nodes;pnn_node;pnn_node=pnn_node->next) {
- ctdb_sock_addr addr;
-
- if (parse_ip(pnn_node->addr, NULL, 63999, &addr) == 0) {
- DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s' in nodes file\n", pnn_node->addr));
+ if (ctdb_sys_have_ip(&pnn_node->addr)) {
+ pnn = pnn_node->pnn;
talloc_free(mem_ctx);
- return -1;
- }
-
- if (ctdb_sys_have_ip(&addr)) {
- printf("PNN:%d\n", pnn_node->pnn);
- talloc_free(mem_ctx);
- return 0;
+ return pnn;
}
}
return -1;
}
+static int control_xpnn(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+ uint32_t pnn;
+
+ assert_single_node_only();
+
+ pnn = find_node_xpnn();
+ if (pnn == -1) {
+ return -1;
+ }
+
+ printf("PNN:%d\n", pnn);
+ return 0;
+}
+
/* Helpers for ctdb status
*/
-static bool is_partially_online(struct ctdb_node_and_flags *node)
+static bool is_partially_online(struct ctdb_context *ctdb, struct ctdb_node_and_flags *node)
{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
int j;
bool ret = false;
if (node->flags == 0) {
- struct ctdb_ifaces_list *ifaces;
+ struct ctdb_control_get_ifaces *ifaces;
- if (ctdb_getifaces(ctdb_connection, node->pnn, &ifaces)) {
+ if (ctdb_ctrl_get_ifaces(ctdb, TIMELIMIT(), node->pnn,
+ tmp_ctx, &ifaces) == 0) {
for (j=0; j < ifaces->num; j++) {
if (ifaces->ifaces[j].link_state != 0) {
continue;
ret = true;
break;
}
- ctdb_free_ifaces(ifaces);
}
}
+ talloc_free(tmp_ctx);
return ret;
}
static void control_status_header_machine(void)
{
- printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped"
+ printm(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped"
":Inactive:PartiallyOnline:ThisNode:\n");
}
-static int control_status_1_machine(int mypnn, struct ctdb_node_and_flags *node)
+static int control_status_1_machine(struct ctdb_context *ctdb, int mypnn,
+ struct ctdb_node_and_flags *node)
{
- printf(":%d:%s:%d:%d:%d:%d:%d:%d:%d:%c:\n", node->pnn,
+ printm(":%d:%s:%d:%d:%d:%d:%d:%d:%d:%c:\n", node->pnn,
ctdb_addr_to_str(&node->addr),
!!(node->flags&NODE_FLAGS_DISCONNECTED),
!!(node->flags&NODE_FLAGS_BANNED),
!!(node->flags&NODE_FLAGS_UNHEALTHY),
!!(node->flags&NODE_FLAGS_STOPPED),
!!(node->flags&NODE_FLAGS_INACTIVE),
- is_partially_online(node) ? 1 : 0,
+ is_partially_online(ctdb, node) ? 1 : 0,
(node->pnn == mypnn)?'Y':'N');
return node->flags;
}
-static int control_status_1_human(int mypnn, struct ctdb_node_and_flags *node)
+static int control_status_1_human(struct ctdb_context *ctdb, int mypnn,
+ struct ctdb_node_and_flags *node)
{
printf("pnn:%d %-16s %s%s\n", node->pnn,
ctdb_addr_to_str(&node->addr),
- is_partially_online(node) ? "PARTIALLYONLINE" : pretty_print_flags(node->flags),
+ is_partially_online(ctdb, node) ? "PARTIALLYONLINE" : pretty_print_flags(node->flags),
node->pnn == mypnn?" (THIS NODE)":"");
return node->flags;
*/
static int control_status(struct ctdb_context *ctdb, int argc, const char **argv)
{
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
int i;
struct ctdb_vnn_map *vnnmap=NULL;
struct ctdb_node_map *nodemap=NULL;
uint32_t recmode, recmaster, mypnn;
int num_deleted_nodes = 0;
+ int ret;
mypnn = getpnn(ctdb);
- if (!ctdb_getnodemap(ctdb_connection, options.pnn, &nodemap)) {
+ ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &nodemap);
+ if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
+ talloc_free(tmp_ctx);
return -1;
}
if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
continue;
}
- (void) control_status_1_machine(mypnn,
+ (void) control_status_1_machine(ctdb, mypnn,
&nodemap->nodes[i]);
}
+ talloc_free(tmp_ctx);
return 0;
}
if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
continue;
}
- (void) control_status_1_human(mypnn, &nodemap->nodes[i]);
+ (void) control_status_1_human(ctdb, mypnn, &nodemap->nodes[i]);
}
- if (!ctdb_getvnnmap(ctdb_connection, options.pnn, &vnnmap)) {
+ 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 -1;
}
if (vnnmap->generation == INVALID_GENERATION) {
for(i=0;i<vnnmap->size;i++){
printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
}
- ctdb_free_vnnmap(vnnmap);
- if (!ctdb_getrecmode(ctdb_connection, options.pnn, &recmode)) {
+ ret = ctdb_ctrl_getrecmode(ctdb, tmp_ctx, TIMELIMIT(), options.pnn, &recmode);
+ if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to get recmode from node %u\n", options.pnn));
+ talloc_free(tmp_ctx);
return -1;
}
printf("Recovery mode:%s (%d)\n",recmode==CTDB_RECOVERY_NORMAL?"NORMAL":"RECOVERY",recmode);
- if (!ctdb_getrecmaster(ctdb_connection, options.pnn, &recmaster)) {
+ ret = ctdb_ctrl_getrecmaster(ctdb, tmp_ctx, TIMELIMIT(), options.pnn, &recmaster);
+ if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to get recmaster from node %u\n", options.pnn));
+ talloc_free(tmp_ctx);
return -1;
}
printf("Recovery master:%d\n",recmaster);
+ talloc_free(tmp_ctx);
return 0;
}
static int control_nodestatus(struct ctdb_context *ctdb, int argc, const char **argv)
{
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
int i, ret;
struct ctdb_node_map *nodemap=NULL;
uint32_t * nodes;
usage();
}
- if (!parse_nodestring(ctdb, argc == 1 ? argv[0] : NULL,
+ if (!parse_nodestring(ctdb, tmp_ctx, argc == 1 ? argv[0] : NULL,
options.pnn, true, &nodes, &pnn_mode)) {
return -1;
}
mypnn = getpnn(ctdb);
- if (!ctdb_getnodemap(ctdb_connection, options.pnn, &nodemap)) {
+ ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &nodemap);
+ if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
+ talloc_free(tmp_ctx);
return -1;
}
for (i = 0; i < talloc_array_length(nodes); i++) {
if (options.machinereadable) {
- ret |= control_status_1_machine(mypnn,
+ ret |= control_status_1_machine(ctdb, mypnn,
&nodemap->nodes[nodes[i]]);
} else {
- ret |= control_status_1_human(mypnn,
+ ret |= control_status_1_human(ctdb, mypnn,
&nodemap->nodes[nodes[i]]);
}
}
+
+ talloc_free(tmp_ctx);
return ret;
}
-struct natgw_node {
- struct natgw_node *next;
- const char *addr;
-};
+static struct pnn_node *read_natgw_nodes_file(struct ctdb_context *ctdb,
+ TALLOC_CTX *mem_ctx)
+{
+ const char *natgw_list;
+ struct pnn_node *natgw_nodes = NULL;
+
+ natgw_list = getenv("CTDB_NATGW_NODES");
+ if (natgw_list == NULL) {
+ natgw_list = talloc_asprintf(mem_ctx, "%s/natgw_nodes",
+ getenv("CTDB_BASE"));
+ if (natgw_list == NULL) {
+ DEBUG(DEBUG_ALERT,(__location__ " Out of memory\n"));
+ exit(1);
+ }
+ }
+ /* The PNNs will be junk but they're not used */
+ natgw_nodes = read_pnn_node_file(mem_ctx, natgw_list);
+ if (natgw_nodes == NULL) {
+ DEBUG(DEBUG_ERR,
+ ("Failed to load natgw node list '%s'\n", natgw_list));
+ }
+ return natgw_nodes;
+}
+
+
+/* talloc off the existing nodemap... */
+static struct ctdb_node_map *talloc_nodemap(struct ctdb_node_map *nodemap)
+{
+ return talloc_zero_size(nodemap,
+ offsetof(struct ctdb_node_map, nodes) +
+ nodemap->num * sizeof(struct ctdb_node_and_flags));
+}
-static int find_natgw(struct ctdb_context *ctdb,
- struct ctdb_node_map *nodemap, uint32_t flags,
- uint32_t *pnn, const char **ip)
+static struct ctdb_node_map *
+filter_nodemap_by_addrs(struct ctdb_context *ctdb,
+ struct ctdb_node_map *nodemap,
+ struct pnn_node *nodes)
{
int i;
- uint32_t capabilities;
+ struct pnn_node *n;
+ struct ctdb_node_map *ret;
- for (i=0;i<nodemap->num;i++) {
- if (!(nodemap->nodes[i].flags & flags)) {
- if (!ctdb_getcapabilities(ctdb_connection, nodemap->nodes[i].pnn, &capabilities)) {
- DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", nodemap->nodes[i].pnn));
- return -1;
- }
- if (!(capabilities&CTDB_CAP_NATGW)) {
- continue;
+ ret = talloc_nodemap(nodemap);
+ CTDB_NO_MEMORY_NULL(ctdb, ret);
+
+ ret->num = 0;
+
+ for (i = 0; i < nodemap->num; i++) {
+ for(n = nodes; n != NULL ; n = n->next) {
+ if (ctdb_same_ip(&n->addr,
+ &nodemap->nodes[i].addr)) {
+ break;
}
- *pnn = nodemap->nodes[i].pnn;
- *ip = ctdb_addr_to_str(&nodemap->nodes[i].addr);
- return 0;
+ }
+ if (n == NULL) {
+ continue;
+ }
+
+ ret->nodes[ret->num] = nodemap->nodes[i];
+ ret->num++;
+ }
+
+ return ret;
+}
+
+static struct ctdb_node_map *
+filter_nodemap_by_capabilities(struct ctdb_context *ctdb,
+ struct ctdb_node_map *nodemap,
+ uint32_t required_capabilities,
+ bool first_only)
+{
+ int i;
+ uint32_t capabilities;
+ struct ctdb_node_map *ret;
+
+ ret = talloc_nodemap(nodemap);
+ CTDB_NO_MEMORY_NULL(ctdb, ret);
+
+ ret->num = 0;
+
+ for (i = 0; i < nodemap->num; i++) {
+ int res;
+
+ /* Disconnected nodes have no capabilities! */
+ if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+ continue;
+ }
+
+ res = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(),
+ nodemap->nodes[i].pnn,
+ &capabilities);
+ if (res != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n",
+ nodemap->nodes[i].pnn));
+ talloc_free(ret);
+ return NULL;
+ }
+ if (!(capabilities & required_capabilities)) {
+ continue;
+ }
+
+ ret->nodes[ret->num] = nodemap->nodes[i];
+ ret->num++;
+ if (first_only) {
+ break;
}
}
- return 2; /* matches ENOENT */
+ return ret;
+}
+
+static struct ctdb_node_map *
+filter_nodemap_by_flags(struct ctdb_context *ctdb,
+ struct ctdb_node_map *nodemap,
+ uint32_t flags_mask)
+{
+ int i;
+ struct ctdb_node_map *ret;
+
+ ret = talloc_nodemap(nodemap);
+ CTDB_NO_MEMORY_NULL(ctdb, ret);
+
+ ret->num = 0;
+
+ for (i = 0; i < nodemap->num; i++) {
+ if (nodemap->nodes[i].flags & flags_mask) {
+ continue;
+ }
+
+ ret->nodes[ret->num] = nodemap->nodes[i];
+ ret->num++;
+ }
+
+ return ret;
}
/*
*/
static int control_natgwlist(struct ctdb_context *ctdb, int argc, const char **argv)
{
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
int i, ret;
- const char *natgw_list;
- int nlines;
- char **lines;
- struct natgw_node *natgw_nodes = NULL;
- struct natgw_node *natgw_node;
- struct ctdb_node_map *nodemap=NULL;
+ struct pnn_node *natgw_nodes = NULL;
+ struct ctdb_node_map *orig_nodemap=NULL;
+ struct ctdb_node_map *nodemap;
uint32_t mypnn, pnn;
const char *ip;
};
/* read the natgw nodes file into a linked list */
- natgw_list = getenv("CTDB_NATGW_NODES");
- if (natgw_list == NULL) {
- natgw_list = "/etc/ctdb/natgw_nodes";
- }
- lines = file_lines_load(natgw_list, &nlines, ctdb);
- if (lines == NULL) {
- ctdb_set_error(ctdb, "Failed to load natgw node list '%s'\n", natgw_list);
- return -1;
- }
- for (i=0;i<nlines;i++) {
- char *node;
-
- node = lines[i];
- /* strip leading spaces */
- while((*node == ' ') || (*node == '\t')) {
- node++;
- }
- if (*node == '#') {
- continue;
- }
- if (strcmp(node, "") == 0) {
- continue;
- }
- natgw_node = talloc(ctdb, struct natgw_node);
- natgw_node->addr = talloc_strdup(natgw_node, node);
- CTDB_NO_MEMORY(ctdb, natgw_node->addr);
- natgw_node->next = natgw_nodes;
- natgw_nodes = natgw_node;
+ natgw_nodes = read_natgw_nodes_file(ctdb, tmp_ctx);
+ if (natgw_nodes == NULL) {
+ ret = -1;
+ goto done;
}
- if (!ctdb_getnodemap(ctdb_connection, CTDB_CURRENT_NODE, &nodemap)) {
+ ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE,
+ tmp_ctx, &orig_nodemap);
+ if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node.\n"));
+ talloc_free(tmp_ctx);
return -1;
}
- /* Trim the nodemap so it only includes connected nodes in the
- * current natgw group.
- */
- i=0;
- while(i<nodemap->num) {
- for(natgw_node=natgw_nodes;natgw_node;natgw_node=natgw_node->next) {
- if (!strcmp(natgw_node->addr, ctdb_addr_to_str(&nodemap->nodes[i].addr))) {
- break;
- }
- }
-
- /* this node was not in the natgw so we just remove it from
- * the list
- */
- if ((natgw_node == NULL)
- || (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) ) {
- int j;
-
- for (j=i+1; j<nodemap->num; j++) {
- nodemap->nodes[j-1] = nodemap->nodes[j];
- }
- nodemap->num--;
- continue;
- }
-
- i++;
+ /* Get a nodemap that includes only the nodes in the NATGW
+ * group */
+ nodemap = filter_nodemap_by_addrs(ctdb, orig_nodemap, natgw_nodes);
+ if (nodemap == NULL) {
+ ret = -1;
+ goto done;
}
ret = 2; /* matches ENOENT */
pnn = -1;
ip = "0.0.0.0";
+ /* For each flag mask... */
for (i = 0; exclude_flags[i] != 0; i++) {
- ret = find_natgw(ctdb, nodemap,
- exclude_flags[i],
- &pnn, &ip);
- if (ret == -1) {
+ /* ... get a nodemap that excludes nodes with with
+ * masked flags... */
+ struct ctdb_node_map *t =
+ filter_nodemap_by_flags(ctdb, nodemap,
+ exclude_flags[i]);
+ if (t == NULL) {
+ /* No memory */
+ ret = -1;
goto done;
}
- if (ret == 0) {
- break;
+ if (t->num > 0) {
+ /* ... and find the first node with the NATGW
+ * capability */
+ struct ctdb_node_map *n;
+ n = filter_nodemap_by_capabilities(ctdb, t,
+ CTDB_CAP_NATGW,
+ true);
+ if (n == NULL) {
+ /* No memory */
+ ret = -1;
+ goto done;
+ }
+ if (n->num > 0) {
+ ret = 0;
+ pnn = n->nodes[0].pnn;
+ ip = ctdb_addr_to_str(&n->nodes[0].addr);
+ break;
+ }
}
+ talloc_free(t);
}
if (options.machinereadable) {
- printf(":Node:IP:\n");
- printf(":%d:%s:\n", pnn, ip);
+ printm(":Node:IP:\n");
+ printm(":%d:%s:\n", pnn, ip);
} else {
printf("%d %s\n", pnn, ip);
}
continue;
}
if (options.machinereadable) {
- control_status_1_machine(mypnn, &(nodemap->nodes[i]));
+ control_status_1_machine(ctdb, mypnn, &(nodemap->nodes[i]));
} else {
- control_status_1_human(mypnn, &(nodemap->nodes[i]));
+ control_status_1_human(ctdb, mypnn, &(nodemap->nodes[i]));
}
}
done:
- ctdb_free_nodemap(nodemap);
+ talloc_free(tmp_ctx);
return ret;
}
}
if (!options.machinereadable) {
+ int num_run = 0;
+ for (i=0; i<script_status->num_scripts; i++) {
+ if (script_status->scripts[i].status != -ENOEXEC) {
+ num_run++;
+ }
+ }
printf("%d scripts were executed last %s cycle\n",
- script_status->num_scripts,
+ num_run,
ctdb_eventscript_call_names[type]);
}
for (i=0; i<script_status->num_scripts; i++) {
break;
}
if (options.machinereadable) {
- printf(":%s:%s:%i:%s:%lu.%06lu:%lu.%06lu:%s:\n",
+ printm(":%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,
}
if (options.machinereadable) {
- printf(":Type:Name:Code:Status:Start:End:Error Output...:\n");
+ printm(":Type:Name:Code:Status:Start:End:Error Output...:\n");
}
for (type = min; type < max; type++) {
static int control_recmaster(struct ctdb_context *ctdb, int argc, const char **argv)
{
uint32_t recmaster;
+ int ret;
- if (!ctdb_getrecmaster(ctdb_connection, options.pnn, &recmaster)) {
+ ret = ctdb_ctrl_getrecmaster(ctdb, ctdb, TIMELIMIT(), options.pnn, &recmaster);
+ if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to get recmaster from node %u\n", options.pnn));
return -1;
}
}
if (options.machinereadable){
- printf(":source ip:port:destination ip:port:\n");
+ printm(":source ip:port:destination ip:port:\n");
for (i=0;i<list->tickles.num;i++) {
if (port && port != ntohs(list->tickles.connections[i].dst_addr.ip.sin_port)) {
continue;
}
- printf(":%s:%u", ctdb_addr_to_str(&list->tickles.connections[i].src_addr), ntohs(list->tickles.connections[i].src_addr.ip.sin_port));
- printf(":%s:%u:\n", ctdb_addr_to_str(&list->tickles.connections[i].dst_addr), ntohs(list->tickles.connections[i].dst_addr.ip.sin_port));
+ printm(":%s:%u", ctdb_addr_to_str(&list->tickles.connections[i].src_addr), ntohs(list->tickles.connections[i].src_addr.ip.sin_port));
+ printm(":%s:%u:\n", ctdb_addr_to_str(&list->tickles.connections[i].dst_addr), ntohs(list->tickles.connections[i].dst_addr.ip.sin_port));
}
} else {
printf("Tickles for ip:%s\n", ctdb_addr_to_str(&list->addr));
struct ctdb_all_public_ips *ips;
struct ctdb_node_map *nodemap=NULL;
int i, j, ret;
+ int pnn;
ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap);
if (ret != 0) {
for (j=0;j<ips->num;j++) {
if (ctdb_same_ip(addr, &ips->ips[j].addr)) {
+ pnn = nodemap->nodes[i].pnn;
talloc_free(tmp_ctx);
- return nodemap->nodes[i].pnn;
+ return pnn;
}
}
talloc_free(ips);
static int rebalance_node(struct ctdb_context *ctdb, uint32_t pnn)
{
- uint32_t recmaster;
TDB_DATA data;
- if (ctdb_ctrl_getrecmaster(ctdb, ctdb, TIMELIMIT(), pnn, &recmaster) != 0) {
- DEBUG(DEBUG_ERR, ("Unable to get recmaster from node %u\n", pnn));
- return -1;
- }
-
data.dptr = (uint8_t *)&pnn;
data.dsize = sizeof(uint32_t);
- if (ctdb_client_send_message(ctdb, recmaster, CTDB_SRVID_REBALANCE_NODE, data) != 0) {
- DEBUG(DEBUG_ERR,("Failed to send message to force node reallocation\n"));
+ if (ctdb_client_send_message(ctdb, CTDB_BROADCAST_CONNECTED, CTDB_SRVID_REBALANCE_NODE, data) != 0) {
+ DEBUG(DEBUG_ERR,
+ ("Failed to send message to force node %u to be a rebalancing target\n",
+ pnn));
return -1;
}
*/
static int control_rebalancenode(struct ctdb_context *ctdb, int argc, const char **argv)
{
- switch (options.pnn) {
- case CTDB_BROADCAST_ALL:
- case CTDB_CURRENT_NODE:
- DEBUG(DEBUG_ERR,("You must specify a node number with -n <pnn> for the node to rebalance\n"));
- return -1;
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+ uint32_t *nodes;
+ uint32_t pnn_mode;
+ int i, ret;
+
+ assert_single_node_only();
+
+ if (argc > 1) {
+ usage();
}
- return rebalance_node(ctdb, options.pnn);
-}
+ /* Determine the nodes where IPs need to be reloaded */
+ if (!parse_nodestring(ctdb, tmp_ctx, argc == 1 ? argv[0] : NULL,
+ options.pnn, true, &nodes, &pnn_mode)) {
+ ret = -1;
+ goto done;
+ }
+
+ for (i = 0; i < talloc_array_length(nodes); i++) {
+ if (!rebalance_node(ctdb, nodes[i])) {
+ ret = -1;
+ }
+ }
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
static int rebalance_ip(struct ctdb_context *ctdb, ctdb_sock_addr *addr)
{
* pass in the srvid_request structure - pass 0 if this isn't needed.
*/
static int srvid_broadcast(struct ctdb_context *ctdb,
- uint64_t srvid, uint32_t arg,
+ uint64_t srvid, uint32_t *arg,
const char *srvid_str, bool wait_for_all)
{
int ret;
TDB_DATA data;
+ uint32_t pnn;
+ uint64_t reply_srvid;
struct srvid_request request;
+ struct srvid_request_data request_data;
struct srvid_reply_handler_data reply_data;
struct timeval tv;
timeval_current_ofs(1, 0),
ctdb_every_second, ctdb);
- request.pnn = ctdb_get_pnn(ctdb);
- request.srvid = getpid();
- request.data = arg;
+ pnn = ctdb_get_pnn(ctdb);
+ reply_srvid = getpid();
+
+ if (arg == NULL) {
+ request.pnn = pnn;
+ request.srvid = reply_srvid;
+
+ data.dptr = (uint8_t *)&request;
+ data.dsize = sizeof(request);
+ } else {
+ request_data.pnn = pnn;
+ request_data.srvid = reply_srvid;
+ request_data.data = *arg;
+
+ data.dptr = (uint8_t *)&request_data;
+ data.dsize = sizeof(request_data);
+ }
/* Register message port for reply from recovery master */
- ctdb_client_set_message_handler(ctdb, request.srvid,
+ ctdb_client_set_message_handler(ctdb, reply_srvid,
srvid_broadcast_reply_handler,
&reply_data);
- data.dptr = (uint8_t *)&request;
- data.dsize = sizeof(request);
-
reply_data.wait_for_all = wait_for_all;
reply_data.nodes = NULL;
reply_data.srvid_str = srvid_str;
goto again;
}
- ctdb_client_remove_message_handler(ctdb, request.srvid, &reply_data);
+ ctdb_client_remove_message_handler(ctdb, reply_srvid, &reply_data);
talloc_free(reply_data.nodes);
static int ipreallocate(struct ctdb_context *ctdb)
{
- return srvid_broadcast(ctdb, CTDB_SRVID_TAKEOVER_RUN, 0,
+ return srvid_broadcast(ctdb, CTDB_SRVID_TAKEOVER_RUN, NULL,
"IP reallocation", false);
}
if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
continue;
}
- if (ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, tmp_ctx, &ips) != 0) {
+ 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 %d\n", nodemap->nodes[i].pnn));
continue;
}
if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
continue;
}
- if (ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, tmp_ctx, &ips) != 0) {
+ 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 %d\n", nodemap->nodes[i].pnn));
continue;
}
ids[i] = strtoull(argv[i], NULL, 0);
}
- if (!ctdb_check_message_handlers(ctdb_connection,
- options.pnn, argc, ids, result)) {
+ if (!ctdb_client_check_message_handlers(ctdb, ids, argc, result)) {
DEBUG(DEBUG_ERR, ("Unable to check server_id from node %u\n",
options.pnn));
talloc_free(tmp_ctx);
}
if (options.machinereadable){
- printf(":Public IP:Node:");
+ printm(":Public IP:Node:");
if (options.verbose){
- printf("ActiveInterface:AvailableInterfaces:ConfiguredInterfaces:");
+ printm("ActiveInterface:AvailableInterfaces:ConfiguredInterfaces:");
}
- printf("\n");
+ printm("\n");
} else {
if (options.pnn == CTDB_BROADCAST_ALL) {
printf("Public IPs on ALL nodes\n");
}
if (options.machinereadable){
- printf(":%s:%d:",
+ printm(":%s:%d:",
ctdb_addr_to_str(&ips->ips[ips->num-i].addr),
ips->ips[ips->num-i].pnn);
if (options.verbose){
- printf("%s:%s:%s:",
+ printm("%s:%s:%s:",
aciface?aciface:"",
avifaces?avifaces:"",
cifaces?cifaces:"");
*/
static int control_ifaces(struct ctdb_context *ctdb, int argc, const char **argv)
{
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
int i;
- struct ctdb_ifaces_list *ifaces;
+ struct ctdb_control_get_ifaces *ifaces;
+ int ret;
/* read the public ip list from this node */
- if (!ctdb_getifaces(ctdb_connection, options.pnn, &ifaces)) {
+ 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 -1;
}
if (options.machinereadable){
- printf(":Name:LinkStatus:References:\n");
+ printm(":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",
+ printm(":%s:%s:%u:\n",
ifaces->ifaces[i].name,
ifaces->ifaces[i].link_state?"1":"0",
(unsigned int)ifaces->ifaces[i].references);
}
}
- ctdb_free_ifaces(ifaces);
+ talloc_free(tmp_ctx);
return 0;
}
{
struct ctdb_node_map *nodemap = NULL;
bool flag_is_set;
+ int ret;
/* Check if the node is already in the desired state */
- if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap) != 0) {
+ ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
+ if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
exit(10);
}
* Even if the above control/hanlder timed out then it
* could still have worked!
*/
- if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE,
- ctdb, &nodemap) != 0) {
+ ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE,
+ ctdb, &nodemap);
+ if (ret != 0) {
DEBUG(DEBUG_WARNING,
("Unable to get nodemap from local node, try again\n"));
}
/* Administratively disable a node */
static bool update_flags_disabled(struct ctdb_context *ctdb, void *data)
{
- return ctdb_ctrl_modflags(ctdb, TIMELIMIT(), options.pnn,
- NODE_FLAGS_PERMANENTLY_DISABLED, 0) == 0;
+ int ret;
+
+ ret = ctdb_ctrl_modflags(ctdb, TIMELIMIT(), options.pnn,
+ NODE_FLAGS_PERMANENTLY_DISABLED, 0);
+ return ret == 0;
}
static int control_disable(struct ctdb_context *ctdb, int argc, const char **argv)
/* Administratively re-enable a node */
static bool update_flags_not_disabled(struct ctdb_context *ctdb, void *data)
{
- return ctdb_ctrl_modflags(ctdb, TIMELIMIT(), options.pnn,
- 0, NODE_FLAGS_PERMANENTLY_DISABLED) == 0;
+ int ret;
+
+ ret = ctdb_ctrl_modflags(ctdb, TIMELIMIT(), options.pnn,
+ 0, NODE_FLAGS_PERMANENTLY_DISABLED);
+ return ret == 0;
}
static int control_enable(struct ctdb_context *ctdb, int argc, const char **argv)
/* Stop a node */
static bool update_flags_stopped(struct ctdb_context *ctdb, void *data)
{
- return ctdb_ctrl_stop_node(ctdb, TIMELIMIT(), options.pnn) == 0;
+ int ret;
+
+ ret = ctdb_ctrl_stop_node(ctdb, TIMELIMIT(), options.pnn);
+
+ return ret == 0;
}
static int control_stop(struct ctdb_context *ctdb, int argc, const char **argv)
/* Continue a stopped node */
static bool update_flags_not_stopped(struct ctdb_context *ctdb, void *data)
{
- return ctdb_ctrl_continue_node(ctdb, TIMELIMIT(), options.pnn) == 0;
+ int ret;
+
+ ret = ctdb_ctrl_continue_node(ctdb, TIMELIMIT(), options.pnn);
+
+ return ret == 0;
}
static int control_continue(struct ctdb_context *ctdb, int argc, const char **argv)
static uint32_t get_generation(struct ctdb_context *ctdb)
{
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
struct ctdb_vnn_map *vnnmap=NULL;
int ret;
+ uint32_t generation;
/* wait until the recmaster is not in recovery mode */
while (1) {
}
/* get the recmaster */
- if (!ctdb_getrecmaster(ctdb_connection, CTDB_CURRENT_NODE, &recmaster)) {
+ ret = ctdb_ctrl_getrecmaster(ctdb, tmp_ctx, TIMELIMIT(), CTDB_CURRENT_NODE, &recmaster);
+ if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to get recmaster from node %u\n", options.pnn));
+ talloc_free(tmp_ctx);
exit(10);
}
/* get recovery mode */
- if (!ctdb_getrecmode(ctdb_connection, recmaster, &recmode)) {
+ ret = ctdb_ctrl_getrecmode(ctdb, tmp_ctx, TIMELIMIT(), recmaster, &recmode);
+ if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to get recmode from node %u\n", options.pnn));
+ talloc_free(tmp_ctx);
exit(10);
}
/* get the current generation number */
- ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), recmaster, ctdb, &vnnmap);
+ ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), recmaster, tmp_ctx, &vnnmap);
if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to get vnnmap from recmaster (%u)\n", recmaster));
+ talloc_free(tmp_ctx);
exit(10);
}
- if ((recmode == CTDB_RECOVERY_NORMAL)
- && (vnnmap->generation != 1)){
- return vnnmap->generation;
+ if ((recmode == CTDB_RECOVERY_NORMAL) && (vnnmap->generation != 1)) {
+ generation = vnnmap->generation;
+ talloc_free(tmp_ctx);
+ return generation;
}
sleep(1);
}
static bool update_state_banned(struct ctdb_context *ctdb, void *data)
{
struct ctdb_ban_time *bantime = (struct ctdb_ban_time *)data;
- return ctdb_ctrl_set_ban(ctdb, TIMELIMIT(), options.pnn, bantime) == 0;
+ int ret;
+
+ ret = ctdb_ctrl_set_ban(ctdb, TIMELIMIT(), options.pnn, bantime);
+
+ return ret == 0;
}
static int control_ban(struct ctdb_context *ctdb, int argc, const char **argv)
bantime.pnn = options.pnn;
bantime.time = strtoul(argv[0], NULL, 0);
+ if (bantime.time == 0) {
+ DEBUG(DEBUG_ERR, ("Invalid ban time specified - must be >0\n"));
+ return -1;
+ }
+
return update_flags_and_ipreallocate(ctdb, &bantime,
update_state_banned,
NODE_FLAGS_BANNED,
{
int ret;
uint32_t generation, next_generation;
- bool force;
-
- /* "force" option ignores freeze failure and forces recovery */
- force = (argc == 1) && (strcasecmp(argv[0], "force") == 0);
/* record the current generation number */
generation = get_generation(ctdb);
- ret = ctdb_ctrl_freeze_priority(ctdb, TIMELIMIT(), options.pnn, 1);
- if (ret != 0) {
- if (!force) {
- DEBUG(DEBUG_ERR, ("Unable to freeze node\n"));
- return ret;
- }
- DEBUG(DEBUG_WARNING, ("Unable to freeze node but proceeding because \"force\" option given\n"));
- }
-
ret = ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE);
if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to set recovery mode\n"));
if (!options.machinereadable){
printf("Monitoring mode:%s (%d)\n",monmode==CTDB_MONITORING_ACTIVE?"ACTIVE":"DISABLED",monmode);
} else {
- printf(":mode:\n");
- printf(":%d:\n",monmode);
+ printm(":mode:\n");
+ printm(":%d:\n",monmode);
}
return 0;
}
static int control_getcapabilities(struct ctdb_context *ctdb, int argc, const char **argv)
{
uint32_t capabilities;
+ int ret;
- if (!ctdb_getcapabilities(ctdb_connection, options.pnn, &capabilities)) {
+ ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), options.pnn, &capabilities);
+ if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", options.pnn));
return -1;
}
printf("LVS: %s\n", (capabilities&CTDB_CAP_LVS)?"YES":"NO");
printf("NATGW: %s\n", (capabilities&CTDB_CAP_NATGW)?"YES":"NO");
} else {
- printf(":RECMASTER:LMASTER:LVS:NATGW:\n");
- printf(":%d:%d:%d:%d:\n",
+ printm(":RECMASTER:LMASTER:LVS:NATGW:\n");
+ printm(":%d:%d:%d:%d:\n",
!!(capabilities&CTDB_CAP_RECMASTER),
!!(capabilities&CTDB_CAP_LMASTER),
!!(capabilities&CTDB_CAP_LVS),
/*
display lvs configuration
*/
+
+static uint32_t lvs_exclude_flags[] = {
+ /* Look for a nice healthy node */
+ NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
+ /* If not found, an UNHEALTHY node will do */
+ NODE_FLAGS_INACTIVE|NODE_FLAGS_PERMANENTLY_DISABLED,
+ 0,
+};
+
static int control_lvs(struct ctdb_context *ctdb, int argc, const char **argv)
{
- uint32_t *capabilities;
- struct ctdb_node_map *nodemap=NULL;
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+ struct ctdb_node_map *orig_nodemap=NULL;
+ struct ctdb_node_map *nodemap;
int i, ret;
- int healthy_count = 0;
- if (!ctdb_getnodemap(ctdb_connection, options.pnn, &nodemap)) {
+ ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn,
+ tmp_ctx, &orig_nodemap);
+ if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
+ talloc_free(tmp_ctx);
return -1;
}
- capabilities = talloc_array(ctdb, uint32_t, nodemap->num);
- CTDB_NO_MEMORY(ctdb, capabilities);
-
+ nodemap = filter_nodemap_by_capabilities(ctdb, orig_nodemap,
+ CTDB_CAP_LVS, false);
+ if (nodemap == NULL) {
+ /* No memory */
+ ret = -1;
+ goto done;
+ }
+
ret = 0;
- /* collect capabilities for all connected nodes */
- for (i=0; i<nodemap->num; i++) {
- if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
- continue;
- }
- if (nodemap->nodes[i].flags & NODE_FLAGS_PERMANENTLY_DISABLED) {
- continue;
- }
-
- if (!ctdb_getcapabilities(ctdb_connection, i, &capabilities[i])) {
- DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", i));
+ for (i = 0; lvs_exclude_flags[i] != 0; i++) {
+ struct ctdb_node_map *t =
+ filter_nodemap_by_flags(ctdb, nodemap,
+ lvs_exclude_flags[i]);
+ if (t == NULL) {
+ /* No memory */
ret = -1;
goto done;
}
-
- if (!(capabilities[i] & CTDB_CAP_LVS)) {
- continue;
- }
-
- if (!(nodemap->nodes[i].flags & NODE_FLAGS_UNHEALTHY)) {
- healthy_count++;
- }
- }
-
- /* Print all LVS nodes */
- for (i=0; i<nodemap->num; i++) {
- if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
- continue;
- }
- if (nodemap->nodes[i].flags & NODE_FLAGS_PERMANENTLY_DISABLED) {
- continue;
- }
- if (!(capabilities[i] & CTDB_CAP_LVS)) {
- continue;
- }
-
- if (healthy_count != 0) {
- if (nodemap->nodes[i].flags & NODE_FLAGS_UNHEALTHY) {
- continue;
+ if (t->num > 0) {
+ /* At least 1 node without excluded flags */
+ int j;
+ for (j = 0; j < t->num; j++) {
+ printf("%d:%s\n", t->nodes[j].pnn,
+ ctdb_addr_to_str(&t->nodes[j].addr));
}
+ goto done;
}
-
- printf("%d:%s\n", i,
- ctdb_addr_to_str(&nodemap->nodes[i].addr));
+ talloc_free(t);
}
-
done:
- ctdb_free_nodemap(nodemap);
+ talloc_free(tmp_ctx);
return ret;
}
*/
static int control_lvsmaster(struct ctdb_context *ctdb, int argc, const char **argv)
{
- uint32_t *capabilities;
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
struct ctdb_node_map *nodemap=NULL;
int i, ret;
- int healthy_count = 0;
- if (!ctdb_getnodemap(ctdb_connection, options.pnn, &nodemap)) {
+ ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn,
+ tmp_ctx, &nodemap);
+ if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
+ talloc_free(tmp_ctx);
return -1;
}
- capabilities = talloc_array(ctdb, uint32_t, nodemap->num);
- CTDB_NO_MEMORY(ctdb, capabilities);
-
- ret = -1;
-
- /* collect capabilities for all connected nodes */
- for (i=0; i<nodemap->num; i++) {
- if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
- continue;
- }
- if (nodemap->nodes[i].flags & NODE_FLAGS_PERMANENTLY_DISABLED) {
- continue;
- }
-
- if (!ctdb_getcapabilities(ctdb_connection, i, &capabilities[i])) {
- DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", i));
+ for (i = 0; lvs_exclude_flags[i] != 0; i++) {
+ struct ctdb_node_map *t =
+ filter_nodemap_by_flags(ctdb, nodemap,
+ lvs_exclude_flags[i]);
+ if (t == NULL) {
+ /* No memory */
ret = -1;
goto done;
}
-
- if (!(capabilities[i] & CTDB_CAP_LVS)) {
- continue;
- }
-
- if (!(nodemap->nodes[i].flags & NODE_FLAGS_UNHEALTHY)) {
- healthy_count++;
- }
- }
-
- /* find and show the lvsmaster */
- for (i=0; i<nodemap->num; i++) {
- if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
- continue;
- }
- if (nodemap->nodes[i].flags & NODE_FLAGS_PERMANENTLY_DISABLED) {
- continue;
- }
- if (!(capabilities[i] & CTDB_CAP_LVS)) {
- continue;
- }
-
- if (healthy_count != 0) {
- if (nodemap->nodes[i].flags & NODE_FLAGS_UNHEALTHY) {
- continue;
+ if (t->num > 0) {
+ struct ctdb_node_map *n;
+ n = filter_nodemap_by_capabilities(ctdb,
+ t,
+ CTDB_CAP_LVS,
+ true);
+ if (n == NULL) {
+ /* No memory */
+ ret = -1;
+ goto done;
+ }
+ if (n->num > 0) {
+ ret = 0;
+ if (options.machinereadable) {
+ printm("%d\n", n->nodes[0].pnn);
+ } else {
+ printf("Node %d is LVS master\n", n->nodes[0].pnn);
+ }
+ goto done;
}
}
-
- if (options.machinereadable){
- printf("%d\n", i);
- } else {
- printf("Node %d is LVS master\n", i);
- }
- ret = 0;
- goto done;
+ talloc_free(t);
}
printf("There is no LVS master\n");
+ ret = 255;
done:
- ctdb_free_nodemap(nodemap);
+ talloc_free(tmp_ctx);
return ret;
}
usage();
}
- db_name = argv[0];
-
- if (!db_exists(ctdb, db_name, NULL, &flags)) {
+ if (!db_exists(ctdb, argv[0], NULL, &db_name, &flags)) {
return -1;
}
usage();
}
- db_name = argv[0];
-
- if (!db_exists(ctdb, db_name, NULL, &flags)) {
+ if (!db_exists(ctdb, argv[0], NULL, &db_name, &flags)) {
return -1;
}
usage();
}
- db_name = argv[0];
-
- if (!db_exists(ctdb, db_name, NULL, &flags)) {
+ if (!db_exists(ctdb, argv[0], NULL, &db_name, &flags)) {
return -1;
}
exit(10);
}
- printf("Data: size:%d ptr:[%s]\n", (int)data.dsize, data.dptr);
+ printf("Data: size:%d ptr:[%.*s]\n", (int)data.dsize, (int)data.dsize, data.dptr);
- talloc_free(ctdb_db);
talloc_free(tmp_ctx);
+ talloc_free(ctdb_db);
return 0;
}
usage();
}
- db_name = argv[0];
-
- if (!db_exists(ctdb, db_name, NULL, &flags)) {
+ if (!db_exists(ctdb, argv[0], NULL, &db_name, &flags)) {
return -1;
}
}
talloc_free(h);
- talloc_free(ctdb_db);
talloc_free(tmp_ctx);
+ talloc_free(ctdb_db);
return 0;
}
usage();
}
- db_name = argv[0];
-
- if (!db_exists(ctdb, db_name, NULL, &flags)) {
+ if (!db_exists(ctdb, argv[0], NULL, &db_name, &flags)) {
talloc_free(tmp_ctx);
return -1;
}
talloc_free(tmp_ctx);
return -1;
}
- write(fd, data.dptr, data.dsize);
+ sys_write(fd, data.dptr, data.dsize);
close(fd);
} else {
- write(1, data.dptr, data.dsize);
+ sys_write(1, data.dptr, data.dsize);
}
/* abort the transaction */
return -1;
}
if (options.verbose){
- write(fd, data.dptr, data.dsize);
+ sys_write(fd, data.dptr, data.dsize);
} else {
- write(fd, data.dptr+sizeof(struct ctdb_ltdb_header), data.dsize-sizeof(struct ctdb_ltdb_header));
+ sys_write(fd, data.dptr+sizeof(struct ctdb_ltdb_header), data.dsize-sizeof(struct ctdb_ltdb_header));
}
close(fd);
} else {
if (options.verbose){
- write(1, data.dptr, data.dsize);
+ sys_write(1, data.dptr, data.dsize);
} else {
- write(1, data.dptr+sizeof(struct ctdb_ltdb_header), data.dsize-sizeof(struct ctdb_ltdb_header));
+ sys_write(1, data.dptr+sizeof(struct ctdb_ltdb_header), data.dsize-sizeof(struct ctdb_ltdb_header));
}
}
{
const char *tdb_file;
TDB_CONTEXT *tdb;
- TDB_DATA key, data;
+ TDB_DATA key, value, data;
TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ struct ctdb_ltdb_header header;
if (argc < 3) {
usage();
}
if (!strncmp(argv[2], "0x", 2)) {
- data = hextodata(tmp_ctx, argv[2] + 2);
- if (data.dsize == 0) {
+ value = hextodata(tmp_ctx, argv[2] + 2);
+ if (value.dsize == 0) {
printf("Failed to convert \"%s\" into a TDB_DATA\n", argv[2]);
return -1;
}
} else {
- data.dptr = discard_const(argv[2]);
- data.dsize = strlen(argv[2]);
+ value.dptr = discard_const(argv[2]);
+ value.dsize = strlen(argv[2]);
+ }
+
+ ZERO_STRUCT(header);
+ if (argc > 3) {
+ header.rsn = atoll(argv[3]);
+ }
+ if (argc > 4) {
+ header.dmaster = atoi(argv[4]);
+ }
+ if (argc > 5) {
+ header.flags = atoi(argv[5]);
}
- if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
- printf("Not enough data. You must specify the full ctdb_ltdb_header too when storing\n");
+ data.dsize = sizeof(struct ctdb_ltdb_header) + value.dsize;
+ data.dptr = talloc_size(tmp_ctx, data.dsize);
+ if (data.dptr == NULL) {
+ printf("Failed to allocate header+value\n");
return -1;
}
+
+ *(struct ctdb_ltdb_header *)data.dptr = header;
+ memcpy(data.dptr + sizeof(struct ctdb_ltdb_header), value.dptr, value.dsize);
+
if (tdb_store(tdb, key, data, TDB_REPLACE) != 0) {
printf("Failed to write record %s to tdb %s\n", argv[1], tdb_file);
tdb_close(tdb);
talloc_free(tmp_ctx);
return -1;
}
- ret = read(fd, data.dptr, data.dsize);
+ ret = sys_read(fd, data.dptr, data.dsize);
if (ret != data.dsize) {
DEBUG(DEBUG_ERR,("Failed to read %d bytes of record data\n", (int)data.dsize));
close(fd);
usage();
}
- db_name = argv[0];
-
- if (!db_exists(ctdb, db_name, NULL, &flags)) {
+ if (!db_exists(ctdb, argv[0], NULL, &db_name, &flags)) {
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;
+ 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;
+}
+
+static const char *ptrans_parse_string(TALLOC_CTX *mem_ctx, const char *s,
+ TDB_DATA *data)
+{
+ const char *t;
+ size_t n;
+ const char *ret; /* Next byte after successfully parsed value */
+
+ /* Error, unless someone says otherwise */
+ ret = NULL;
+ /* Indicates no value to parse */
+ *data = tdb_null;
+
+ /* Skip whitespace */
+ n = strspn(s, " \t");
+ t = s + n;
+
+ if (t[0] == '"') {
+ /* Quoted ASCII string - no wide characters! */
+ t++;
+ n = strcspn(t, "\"");
+ if (t[n] == '"') {
+ if (n > 0) {
+ data->dsize = n;
+ data->dptr = talloc_memdup(mem_ctx, t, n);
+ CTDB_NOMEM_ABORT(data->dptr);
+ }
+ ret = t + n + 1;
+ } else {
+ DEBUG(DEBUG_WARNING,("Unmatched \" in input %s\n", s));
+ }
+ } else {
+ DEBUG(DEBUG_WARNING,("Unsupported input format in %s\n", s));
+ }
+
+ return ret;
+}
+
+static bool ptrans_get_key_value(TALLOC_CTX *mem_ctx, FILE *file,
+ TDB_DATA *key, TDB_DATA *value)
+{
+ char line [1024]; /* FIXME: make this more flexible? */
+ const char *t;
+ char *ptr;
+
+ ptr = fgets(line, sizeof(line), file);
+
+ if (ptr == NULL) {
+ return false;
+ }
+
+ /* Get key */
+ t = ptrans_parse_string(mem_ctx, line, key);
+ if (t == NULL || key->dptr == NULL) {
+ /* Line Ignored but not EOF */
+ return true;
+ }
+
+ /* Get value */
+ t = ptrans_parse_string(mem_ctx, t, value);
+ if (t == NULL) {
+ /* Line Ignored but not EOF */
+ talloc_free(key->dptr);
+ *key = tdb_null;
+ return true;
+ }
+
+ return true;
+}
+
+/*
+ * Update a persistent database as per file/stdin
+ */
+static int control_ptrans(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, value;
+ FILE *file;
+ int ret;
+
+ if (argc < 1) {
+ talloc_free(tmp_ctx);
+ usage();
+ }
+
+ file = stdin;
+ if (argc == 2) {
+ file = fopen(argv[1], "r");
+ if (file == NULL) {
+ DEBUG(DEBUG_ERR,("Unable to open file for reading '%s'\n", argv[1]));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+ }
+
+ db_name = argv[0];
+
+ ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, true, 0);
+ if (ctdb_db == NULL) {
+ DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name));
+ goto error;
}
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;
+ DEBUG(DEBUG_ERR,("Failed to start transaction on database %s\n", db_name));
+ goto error;
}
- 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;
+ while (ptrans_get_key_value(tmp_ctx, file, &key, &value)) {
+ if (key.dsize != 0) {
+ ret = ctdb_transaction_store(h, key, value);
+ /* Minimise memory use */
+ talloc_free(key.dptr);
+ if (value.dptr != NULL) {
+ talloc_free(value.dptr);
+ }
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR,("Failed to store record\n"));
+ ctdb_transaction_cancel(h);
+ goto error;
+ }
+ }
}
ret = ctdb_transaction_commit(h);
if (ret != 0) {
- DEBUG(DEBUG_ERR, ("Failed to commit transaction\n"));
- talloc_free(tmp_ctx);
- return -1;
+ DEBUG(DEBUG_ERR,("Failed to commit transaction\n"));
+ goto error;
}
+ if (file != stdin) {
+ fclose(file);
+ }
talloc_free(tmp_ctx);
return 0;
+
+error:
+ if (file != stdin) {
+ fclose(file);
+ }
+
+ talloc_free(tmp_ctx);
+ return -1;
}
/*
static int control_chktcpport(struct ctdb_context *ctdb, int argc, const char **argv)
{
int s, ret;
- unsigned v;
+ int v;
int port;
struct sockaddr_in sin;
}
v = fcntl(s, F_GETFL, 0);
- fcntl(s, F_SETFL, v | O_NONBLOCK);
+ if (v == -1 || fcntl(s, F_SETFL, v | O_NONBLOCK) != 0) {
+ printf("Unable to set socket non-blocking: %s\n", strerror(errno));
+ }
bzero(&sin, sizeof(sin));
sin.sin_family = PF_INET;
return 0;
}
-
-static uint32_t reloadips_finished;
-
-static void reloadips_handler(struct ctdb_context *ctdb, uint64_t srvid,
- TDB_DATA data, void *private_data)
+/* Reload public IPs on a specified nodes */
+static int control_reloadips(struct ctdb_context *ctdb, int argc, const char **argv)
{
- reloadips_finished = 1;
-}
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+ uint32_t *nodes;
+ uint32_t pnn_mode;
+ uint32_t timeout;
+ int ret;
-static int reloadips_all(struct ctdb_context *ctdb)
-{
- struct reloadips_all_reply rips;
- struct ctdb_node_map *nodemap=NULL;
- TDB_DATA data;
- uint32_t recmaster;
- int ret, i;
+ assert_single_node_only();
- /* check that there are valid nodes available */
- if (ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, 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 != 0) {
- DEBUG(DEBUG_ERR,("reloadips -n all can only be used when all nodes are up and healthy. Aborting due to problem with node %d\n", i));
- return 1;
- }
+ if (argc > 1) {
+ usage();
}
- rips.pnn = ctdb_get_pnn(ctdb);
- rips.srvid = getpid();
-
- /* register a message port for receiveing the reply so that we
- can receive the reply
- */
- ctdb_client_set_message_handler(ctdb, rips.srvid, reloadips_handler, NULL);
-
- if (!ctdb_getrecmaster(ctdb_connection, CTDB_CURRENT_NODE, &recmaster)) {
- DEBUG(DEBUG_ERR, ("Unable to get recmaster from node\n"));
- return -1;
+ /* Determine the nodes where IPs need to be reloaded */
+ if (!parse_nodestring(ctdb, tmp_ctx, argc == 1 ? argv[0] : NULL,
+ options.pnn, true, &nodes, &pnn_mode)) {
+ ret = -1;
+ goto done;
}
+again:
+ /* Disable takeover runs on all connected nodes. A reply
+ * indicating success is needed from each node so all nodes
+ * will need to be active. This will retry until maxruntime
+ * is exceeded, hence no error handling.
+ *
+ * A check could be added to not allow reloading of IPs when
+ * there are disconnected nodes. However, this should
+ * probably be left up to the administrator.
+ */
+ timeout = LONGTIMEOUT;
+ srvid_broadcast(ctdb, CTDB_SRVID_DISABLE_TAKEOVER_RUNS, &timeout,
+ "Disable takeover runs", true);
- data.dptr = (uint8_t *)&rips;
- data.dsize = sizeof(rips);
-
- ret = ctdb_client_send_message(ctdb, recmaster, CTDB_SRVID_RELOAD_ALL_IPS, data);
- if (ret != 0) {
- DEBUG(DEBUG_ERR,("Failed to send reload all ips request message to %u\n", options.pnn));
- return 1;
- }
-
- reloadips_finished = 0;
- while (reloadips_finished == 0) {
- event_loop_once(ctdb->ev);
+ /* Now tell all the desired nodes to reload their public IPs.
+ * Keep trying this until it succeeds. This assumes all
+ * failures are transient, which might not be true...
+ */
+ if (ctdb_client_async_control(ctdb, CTDB_CONTROL_RELOAD_PUBLIC_IPS,
+ nodes, 0, LONGTIMELIMIT(),
+ false, tdb_null,
+ NULL, NULL, NULL) != 0) {
+ DEBUG(DEBUG_ERR,
+ ("Unable to reload IPs on some nodes, try again.\n"));
+ goto again;
}
- return 0;
-}
-
-/*
- reload public ips on a specific node
- */
-static int control_reloadips(struct ctdb_context *ctdb, int argc, const char **argv)
-{
- int ret;
- int32_t res;
- char *errmsg;
- TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
-
- if (options.pnn == CTDB_BROADCAST_ALL) {
- return reloadips_all(ctdb);
- }
+ /* It isn't strictly necessary to wait until takeover runs are
+ * re-enabled but doing so can't hurt.
+ */
+ timeout = 0;
+ srvid_broadcast(ctdb, CTDB_SRVID_DISABLE_TAKEOVER_RUNS, &timeout,
+ "Enable takeover runs", true);
- ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_RELOAD_PUBLIC_IPS,
- 0, tdb_null, tmp_ctx, NULL, &res, NULL, &errmsg);
- if (ret != 0 || res != 0) {
- DEBUG(DEBUG_ERR,("Failed to reload ips\n"));
- talloc_free(tmp_ctx);
- return -1;
- }
+ ipreallocate(ctdb);
+ ret = 0;
+done:
talloc_free(tmp_ctx);
- return 0;
+ return ret;
}
/*
}
if(options.machinereadable){
- printf(":ID:Name:Path:Persistent:Sticky:Unhealthy:ReadOnly:\n");
+ printm(":ID:Name:Path:Persistent:Sticky:Unhealthy:ReadOnly:\n");
for(i=0;i<dbmap->num;i++){
const char *path;
const char *name;
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(":0x%08X:%s:%s:%d:%d:%d:%d:\n",
+ printm(":0x%08X:%s:%s:%d:%d:%d:%d:\n",
dbmap->dbs[i].dbid, name, path,
!!(persistent), !!(sticky),
!!(health), !!(readonly));
usage();
}
- db_name = argv[0];
-
- if (!db_exists(ctdb, db_name, &db_id, &flags)) {
+ if (!db_exists(ctdb, argv[0], &db_id, &db_name, &flags)) {
return -1;
}
static int control_isnotrecmaster(struct ctdb_context *ctdb, int argc, const char **argv)
{
uint32_t mypnn, recmaster;
+ int ret;
assert_single_node_only();
mypnn = getpnn(ctdb);
- if (!ctdb_getrecmaster(ctdb_connection, options.pnn, &recmaster)) {
+ ret = ctdb_ctrl_getrecmaster(ctdb, ctdb, TIMELIMIT(), options.pnn, &recmaster);
+ if (ret != 0) {
printf("Failed to get the recmaster\n");
return 1;
}
DEBUG(DEBUG_ERR, ("Unable to set tunable variable '%s'\n", name));
return -1;
}
+ if (ret == 1) {
+ DEBUG(DEBUG_WARNING,
+ ("Setting obsolete tunable variable '%s'\n",
+ name));
+ }
return 0;
}
return ret;
} else {
if (options.machinereadable){
- printf(":Name:Level:\n");
- printf(":%s:%d:\n",get_debug_by_level(level),level);
+ printm(":Name:Level:\n");
+ printm(":%s:%d:\n",get_debug_by_level(level),level);
} else {
printf("Node %u is at debug level %s (%d)\n", options.pnn, get_debug_by_level(level), level);
}
} else {
if (options.machinereadable){
if (reclock != NULL) {
- printf("%s", reclock);
+ printm("%s", reclock);
}
} else {
if (reclock == NULL) {
return 0;
}
+/*
+ * detach from a database
+ */
+static int control_detach(struct ctdb_context *ctdb, int argc,
+ const char **argv)
+{
+ uint32_t db_id;
+ uint8_t flags;
+ int ret, i, status = 0;
+ struct ctdb_node_map *nodemap = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+ uint32_t recmode;
+
+ if (argc < 1) {
+ usage();
+ }
+
+ assert_single_node_only();
+
+ ret = ctdb_ctrl_getrecmode(ctdb, tmp_ctx, TIMELIMIT(), options.pnn,
+ &recmode);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Database cannot be detached "
+ "when recovery is active\n"));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx,
+ &nodemap);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n",
+ options.pnn));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ for (i=0; i<nodemap->num; i++) {
+ uint32_t value;
+
+ if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+ continue;
+ }
+
+ if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
+ continue;
+ }
+
+ if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
+ DEBUG(DEBUG_ERR, ("Database cannot be detached on "
+ "inactive (stopped or banned) node "
+ "%u\n", nodemap->nodes[i].pnn));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ ret = ctdb_ctrl_get_tunable(ctdb, TIMELIMIT(),
+ nodemap->nodes[i].pnn,
+ "AllowClientDBAttach",
+ &value);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to get tunable "
+ "AllowClientDBAttach from node %u\n",
+ nodemap->nodes[i].pnn));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ if (value == 1) {
+ DEBUG(DEBUG_ERR, ("Database access is still active on "
+ "node %u. Set AllowClientDBAttach=0 "
+ "on all nodes.\n",
+ nodemap->nodes[i].pnn));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+ }
+
+ talloc_free(tmp_ctx);
+
+ for (i=0; i<argc; i++) {
+ if (!db_exists(ctdb, argv[i], &db_id, NULL, &flags)) {
+ continue;
+ }
+
+ if (flags & CTDB_DB_FLAGS_PERSISTENT) {
+ DEBUG(DEBUG_ERR, ("Persistent database '%s' "
+ "cannot be detached\n", argv[i]));
+ status = -1;
+ continue;
+ }
+
+ ret = ctdb_detach(ctdb, db_id);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Database '%s' detach failed\n",
+ argv[i]));
+ status = ret;
+ }
+ }
+
+ return status;
+}
+
/*
set db priority
*/
usage();
}
- if (!db_exists(ctdb, argv[0], &db_id, NULL)) {
+ if (!db_exists(ctdb, argv[0], &db_id, NULL, NULL)) {
return -1;
}
usage();
}
- if (!db_exists(ctdb, argv[0], &db_id, NULL)) {
+ if (!db_exists(ctdb, argv[0], &db_id, NULL, NULL)) {
return -1;
}
usage();
}
- if (!db_exists(ctdb, argv[0], &db_id, NULL)) {
+ if (!db_exists(ctdb, argv[0], &db_id, NULL, NULL)) {
return -1;
}
*/
static int control_getdbseqnum(struct ctdb_context *ctdb, int argc, const char **argv)
{
- bool ret;
uint32_t db_id;
uint64_t seqnum;
+ int ret;
if (argc < 1) {
usage();
}
- if (!db_exists(ctdb, argv[0], &db_id, NULL)) {
+ if (!db_exists(ctdb, argv[0], &db_id, NULL, NULL)) {
return -1;
}
- ret = ctdb_getdbseqnum(ctdb_connection, options.pnn, db_id, &seqnum);
- if (!ret) {
+ ret = ctdb_ctrl_getdbseqnum(ctdb, TIMELIMIT(), options.pnn, db_id, &seqnum);
+ if (ret != 0) {
DEBUG(DEBUG_ERR, ("Unable to get seqnum from node."));
return -1;
}
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)
{
+ const char *db_name;
int ret;
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
struct db_file_header dbhdr;
return -1;
}
- if (!db_exists(ctdb, argv[0], &db_id, &flags)) {
+ if (!db_exists(ctdb, argv[0], &db_id, &db_name, &flags)) {
return -1;
}
allow_unhealthy));
}
- ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), argv[0], flags & CTDB_DB_FLAGS_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", argv[0]));
talloc_free(tmp_ctx);
return -1;
}
+ ZERO_STRUCT(dbhdr);
dbhdr.version = DB_VERSION;
dbhdr.timestamp = time(NULL);
dbhdr.persistent = flags & CTDB_DB_FLAGS_PERSISTENT;
DEBUG(DEBUG_ERR,("Too long dbname\n"));
goto done;
}
- strncpy(discard_const(dbhdr.name), argv[0], MAX_DB_NAME);
- ret = write(fh, &dbhdr, sizeof(dbhdr));
+ strncpy(discard_const(dbhdr.name), argv[0], MAX_DB_NAME-1);
+ ret = sys_write(fh, &dbhdr, sizeof(dbhdr));
if (ret == -1) {
DEBUG(DEBUG_ERR,("write failed: %s\n", strerror(errno)));
goto done;
}
- ret = write(fh, bd->records, bd->len);
+ ret = sys_write(fh, bd->records, bd->len);
if (ret == -1) {
DEBUG(DEBUG_ERR,("write failed: %s\n", strerror(errno)));
goto done;
return -1;
}
- read(fh, &dbhdr, sizeof(dbhdr));
+ sys_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));
+ close(fh);
talloc_free(tmp_ctx);
return -1;
}
talloc_free(tmp_ctx);
return -1;
}
- read(fh, outdata.dptr, outdata.dsize);
+ sys_read(fh, outdata.dptr, outdata.dsize);
close(fh);
tm = localtime(&dbhdr.timestamp);
return -1;
}
- read(fh, &dbhdr, sizeof(dbhdr));
+ sys_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));
+ close(fh);
talloc_free(tmp_ctx);
return -1;
}
talloc_free(tmp_ctx);
return -1;
}
- read(fh, outdata.dptr, outdata.dsize);
+ sys_read(fh, outdata.dptr, outdata.dsize);
close(fh);
m = (struct ctdb_marshall_buffer *)outdata.dptr;
static int control_wipedb(struct ctdb_context *ctdb, int argc,
const char **argv)
{
+ const char *db_name;
int ret;
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
TDB_DATA data;
return -1;
}
- if (!db_exists(ctdb, argv[0], NULL, &flags)) {
+ if (!db_exists(ctdb, argv[0], NULL, &db_name, &flags)) {
return -1;
}
- ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), argv[0], flags & CTDB_DB_FLAGS_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",
argv[0]));
talloc_free(tmp_ctx);
return -1;
}
- write(1, data.dptr, data.dsize);
+ sys_write(1, data.dptr, data.dsize);
talloc_free(tmp_ctx);
return 0;
}
static void mem_dump_handler(struct ctdb_context *ctdb, uint64_t srvid,
TDB_DATA data, void *private_data)
{
- write(1, data.dptr, data.dsize);
+ sys_write(1, data.dptr, data.dsize);
exit(0);
}
}
for(pnn_node=pnn_nodes;pnn_node;pnn_node=pnn_node->next) {
- ctdb_sock_addr addr;
- if (parse_ip(pnn_node->addr, NULL, 63999, &addr) == 0) {
- DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s' in nodes file\n", pnn_node->addr));
- talloc_free(mem_ctx);
- return -1;
- }
+ const char *addr = ctdb_addr_to_str(&pnn_node->addr);
if (options.machinereadable){
- printf(":%d:%s:\n", pnn_node->pnn, pnn_node->addr);
+ printm(":%d:%s:\n", pnn_node->pnn, addr);
} else {
- printf("%s\n", pnn_node->addr);
+ printf("%s\n", addr);
}
}
talloc_free(mem_ctx);
{ "getlog", control_getlog, true, false, "get the log data from the in memory ringbuffer", "[<level>] [recoverd]" },
{ "clearlog", control_clearlog, true, false, "clear the log data from the in memory ringbuffer", "[recoverd]" },
{ "attach", control_attach, true, false, "attach to a database", "<dbname> [persistent]" },
+ { "detach", control_detach, false, false, "detach from a database", "<dbname|dbid> [<dbname|dbid> ...]" },
{ "dumpmemory", control_dumpmemory, true, false, "dump memory map to stdout" },
{ "rddumpmemory", control_rddumpmemory, true, false, "dump memory map from the recovery daemon to stdout" },
{ "getpid", control_getpid, true, false, "get ctdbd process ID" },
{ "enable", control_enable, true, false, "enable a nodes public IP" },
{ "stop", control_stop, true, false, "stop a node" },
{ "continue", control_continue, true, false, "re-start a stopped node" },
- { "ban", control_ban, true, false, "ban a node from the cluster", "<bantime|0>"},
+ { "ban", control_ban, true, false, "ban a node from the cluster", "<bantime>"},
{ "unban", control_unban, true, false, "unban a node" },
{ "showban", control_showban, true, false, "show ban information"},
{ "shutdown", control_shutdown, true, false, "shutdown ctdbd" },
{ "chksrvid", chksrvid, false, false, "check if a server id exists", "<pnn> <type> <id>" },
{ "getsrvids", getsrvids, false, false, "get a list of all server ids"},
{ "check_srvids", check_srvids, false, false, "check if a srvid exists", "<id>+" },
- { "vacuum", ctdb_vacuum, false, true, "vacuum the databases of empty records", "[max_records]"},
{ "repack", ctdb_repack, false, false, "repack all databases", "[max_freelist]"},
{ "listnodes", control_listnodes, false, true, "list all nodes in the cluster"},
{ "reloadnodes", control_reload_nodes_file, false, false, "reload the nodes file and restart the transport on all nodes"},
{ "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>" },
+ { "ptrans", control_ptrans, false, false, "update a persistent database (from stdin)", "<dbname|dbid>" },
{ "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>" },
+ { "tstore", control_tstore, false, true, "store a record (including ltdb header)", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
+ { "readkey", control_readkey, true, false, "read the content off a database key", "<dbname|dbid> <key>" },
+ { "writekey", control_writekey, true, false, "write to a database key", "<dbname|dbid> <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>"},
+ { "rebalancenode", control_rebalancenode, false, false, "mark nodes as forced IP rebalancing targets", "[<pnn-list>]"},
{ "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" },
+ { "nodestatus", control_nodestatus, true, false, "show and return node status", "[<pnn-list>]" },
{ "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, false, true, "Find which interface an ip address is hsoted on", "<ip>" },
+ { "reloadips", control_reloadips, false, false, "reload the public addresses file on specified nodes" , "[<pnn-list>]" },
+ { "ipiface", control_ipiface, false, true, "Find which interface an ip address is hosted on", "<ip>" },
};
/*
"Usage: ctdb [options] <control>\n" \
"Options:\n" \
" -n <node> choose node number, or 'all' (defaults to local node)\n"
-" -Y generate machinereadable output\n"
+" -Y generate machine readable output\n"
+" -x <char> specify delimiter for machine readable output\n"
" -v generate verbose output\n"
" -t <timelimit> set timelimit for control in seconds (default %u)\n", options.timelimit);
printf("Controls:\n");
{
struct ctdb_context *ctdb;
char *nodestring = NULL;
+ int machineparsable = 0;
struct poptOption popt_options[] = {
POPT_AUTOHELP
POPT_CTDB_CMDLINE
{ "timelimit", 't', POPT_ARG_INT, &options.timelimit, 0, "timelimit", "integer" },
{ "node", 'n', POPT_ARG_STRING, &nodestring, 0, "node", "integer|all" },
- { "machinereadable", 'Y', POPT_ARG_NONE, &options.machinereadable, 0, "enable machinereadable output", NULL },
+ { "machinereadable", 'Y', POPT_ARG_NONE, &options.machinereadable, 0, "enable machine readable output", NULL },
+ { NULL, 'x', POPT_ARG_STRING, &options.machineseparator, 0, "specify separator for machine readable output", "char" },
+ { NULL, 'X', POPT_ARG_NONE, &machineparsable, 0, "enable machine parsable output with separator |", NULL },
{ "verbose", 'v', POPT_ARG_NONE, &options.verbose, 0, "enable verbose output", NULL },
{ "maxruntime", 'T', POPT_ARG_INT, &options.maxruntime, 0, "die if runtime exceeds this limit (in seconds)", "integer" },
{ "print-emptyrecords", 0, POPT_ARG_NONE, &options.printemptyrecords, 0, "print the empty records when dumping databases (catdb, cattdb, dumpdbbackup)", NULL },
poptContext pc;
struct event_context *ev;
const char *control;
- const char *socket_name;
setlinebuf(stdout);
}
}
+ if (machineparsable) {
+ options.machineseparator = "|";
+ }
+ if (options.machineseparator != NULL) {
+ if (strlen(options.machineseparator) != 1) {
+ printf("Invalid separator \"%s\" - "
+ "must be single character\n",
+ options.machineseparator);
+ exit(1);
+ }
+
+ /* -x implies -Y */
+ options.machinereadable = true;
+ } else if (options.machinereadable) {
+ options.machineseparator = ":";
+ }
+
signal(SIGALRM, ctdb_alarm);
alarm(options.maxruntime);
control = extra_argv[0];
+ /* Default value for CTDB_BASE - don't override */
+ setenv("CTDB_BASE", ETCDIR "/ctdb", 0);
+
ev = event_context_init(NULL);
if (!ev) {
DEBUG(DEBUG_ERR, ("Failed to initialize event system\n"));
DEBUG(DEBUG_ERR, ("Can't specify node(s) with \"ctdb %s\"\n", control));
exit(1);
}
- close(2);
return ctdb_commands[i].fn(NULL, extra_argc-1, extra_argv+1);
}
ctdb = ctdb_cmdline_client(ev, TIMELIMIT());
if (ctdb == NULL) {
+ uint32_t pnn;
DEBUG(DEBUG_ERR, ("Failed to init ctdb\n"));
- exit(1);
- }
- /* initialize a libctdb connection as well */
- socket_name = ctdb_get_socketname(ctdb);
- ctdb_connection = ctdb_connect(socket_name,
- ctdb_log_file, stderr);
- if (ctdb_connection == NULL) {
- DEBUG(DEBUG_ERR, ("Failed to connect to daemon from libctdb\n"));
+ pnn = find_node_xpnn();
+ if (pnn == -1) {
+ DEBUG(DEBUG_ERR,
+ ("Is this node part of a CTDB cluster?\n"));
+ }
exit(1);
- }
+ }
/* setup the node number(s) to contact */
- if (!parse_nodestring(ctdb, nodestring, CTDB_CURRENT_NODE, false,
+ if (!parse_nodestring(ctdb, ctdb, nodestring, CTDB_CURRENT_NODE, false,
&options.nodes, &options.pnn)) {
usage();
}
ret = ctdb_commands[i].fn(ctdb, extra_argc-1, extra_argv+1);
}
- ctdb_disconnect(ctdb_connection);
talloc_free(ctdb);
talloc_free(ev);
(void)poptFreeContext(pc);