along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "includes.h"
+#include "replace.h"
#include "system/time.h"
#include "system/filesys.h"
#include "system/network.h"
#include "system/locale.h"
-#include "popt.h"
-#include "cmdline.h"
-#include "../include/ctdb_version.h"
-#include "../include/ctdb_client.h"
-#include "../include/ctdb_private.h"
-#include "../common/rb_tree.h"
-#include "db_wrap.h"
+
+#include <popt.h>
+#include <talloc.h>
+/* Allow use of deprecated function tevent_loop_allow_nesting() */
+#define TEVENT_DEPRECATED
+#include <tevent.h>
+#include <tdb.h>
+
+#include "lib/tdb_wrap/tdb_wrap.h"
+#include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+#include "lib/util/substitute.h"
+#include "lib/util/time.h"
+
+#include "ctdb_logging.h"
+#include "ctdb_version.h"
+#include "ctdb_private.h"
+#include "ctdb_client.h"
+
+#include "common/cmdline.h"
+#include "common/rb_tree.h"
+#include "common/system.h"
+#include "common/common.h"
#define ERR_TIMEOUT 20 /* timed out trying to reach node */
#define ERR_NONODE 21 /* node does not exist */
uint32_t pnn;
uint32_t *nodes;
int machinereadable;
+ const char *machineseparator;
int verbose;
int maxruntime;
int printemptyrecords;
#define TIMELIMIT() timeval_current_ofs(options.timelimit, 0)
#define LONGTIMELIMIT() timeval_current_ofs(LONGTIMEOUT, 0)
+static double timeval_delta(struct timeval *tv2, struct timeval *tv)
+{
+ return (tv2->tv_sec - tv->tv_sec) +
+ (tv2->tv_usec - tv->tv_usec)*1.0e-6;
+}
+
static int control_version(struct ctdb_context *ctdb, int argc, const char **argv)
{
printf("CTDB version: %s\n", CTDB_VERSION_STRING);
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__ )); \
}
}
+static void assert_current_node_only(struct ctdb_context *ctdb)
+{
+ if (options.pnn != ctdb_get_pnn(ctdb)) {
+ DEBUG(DEBUG_ERR,
+ ("This control can only be applied to the current node\n"));
+ exit(1);
+ }
+}
+
/* Pretty print the flags to a static buffer in human-readable format.
* This never returns NULL!
*/
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);
}
}
}
return h - '0';
}
-static TDB_DATA hextodata(TALLOC_CTX *mem_ctx, const char *str)
+static TDB_DATA hextodata(TALLOC_CTX *mem_ctx, const char *str, size_t len)
{
- int i, len;
+ int i;
TDB_DATA key = {NULL, 0};
- len = strlen(str);
if (len & 0x01) {
DEBUG(DEBUG_ERR,("Key specified with odd number of hexadecimal digits\n"));
return key;
return key;
}
+static TDB_DATA strtodata(TALLOC_CTX *mem_ctx, const char *str, size_t len)
+{
+ TDB_DATA key;
+
+ if (!strncmp(str, "0x", 2)) {
+ key = hextodata(mem_ctx, str + 2, len - 2);
+ } else {
+ key.dptr = talloc_memdup(mem_ctx, str, len);
+ key.dsize = len;
+ }
+
+ return key;
+}
+
/* Parse a nodestring. Parameter dd_ok controls what happens to nodes
* that are disconnected or deleted. If dd_ok is true those nodes are
* included in the output list of nodes. If dd_ok is false, those
* 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(ctdb);
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
int n;
uint32_t i;
- struct ctdb_node_map *nodemap;
+ struct ctdb_node_map_old *nodemap;
int ret;
*nodes = NULL;
}
if (nodestring != NULL) {
- *nodes = talloc_array(tmp_ctx, uint32_t, 0);
+ *nodes = talloc_array(mem_ctx, uint32_t, 0);
if (*nodes == NULL) {
goto failed;
}
NODE_FLAGS_DELETED)) && !dd_ok) {
continue;
}
- *nodes = talloc_realloc(tmp_ctx, *nodes,
+ *nodes = talloc_realloc(mem_ctx, *nodes,
uint32_t, n+1);
if (*nodes == NULL) {
goto failed;
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(10);
}
- *nodes = talloc_realloc(ctdb, *nodes,
+ *nodes = talloc_realloc(mem_ctx, *nodes,
uint32_t, n+1);
if (*nodes == NULL) {
goto failed;
}
} else {
/* default - no nodes specified */
- *nodes = talloc_array(tmp_ctx, uint32_t, 1);
+ *nodes = talloc_array(mem_ctx, uint32_t, 1);
if (*nodes == NULL) {
goto failed;
}
/*
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;
+ struct ctdb_dbid_map_old *dbmap=NULL;
bool dbid_given = false, found = false;
uint32_t id;
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+ const char *name = NULL;
ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &dbmap);
if (ret != 0) {
for(i=0; i<dbmap->num; i++) {
if (dbid_given) {
- if (id == dbmap->dbs[i].dbid) {
+ if (id == dbmap->dbs[i].db_id) {
found = true;
break;
}
} else {
- const char *name;
- ret = ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, tmp_ctx, &name);
+ ret = ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].db_id, tmp_ctx, &name);
if (ret != 0) {
- DEBUG(DEBUG_ERR, ("Unable to get dbname from dbid %u\n", dbmap->dbs[i].dbid));
+ DEBUG(DEBUG_ERR, ("Unable to get dbname from dbid %u\n", dbmap->dbs[i].db_id));
goto fail;
}
if (strcmp(name, dbarg) == 0) {
- id = dbmap->dbs[i].dbid;
+ id = dbmap->dbs[i].db_id;
found = true;
break;
}
}
}
+ if (found && dbid_given && dbname != NULL) {
+ ret = ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].db_id, tmp_ctx, &name);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to get dbname from dbid %u\n", dbmap->dbs[i].db_id));
+ 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_PROTOCOL);
+ 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("CTDB version %u\n", CTDB_PROTOCOL);
printf("Current time of statistics : %s", ctime(&s->statistics_current_time.tv_sec));
printf("Statistics collected since : (%03d %02d:%02d:%02d) %s", days, hours, minutes, seconds, ctime(&s->statistics_start_time.tv_sec));
static int control_stats(struct ctdb_context *ctdb, int argc, const char **argv)
{
int ret;
- struct ctdb_statistics_wire *stats;
+ struct ctdb_statistics_list_old *stats;
int i, num_records = -1;
assert_single_node_only();
static int control_dbstatistics(struct ctdb_context *ctdb, int argc, const char **argv)
{
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
- struct ctdb_db_statistics *dbstat;
+ struct ctdb_db_statistics_old *dbstat;
int i;
uint32_t db_id;
int num_hot_keys;
usage();
}
- if (!db_exists(ctdb, argv[0], &db_id, NULL)) {
+ if (!db_exists(ctdb, argv[0], &db_id, NULL, NULL)) {
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) {
}
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;
- int pnn;
-};
-
-static struct pnn_node *read_nodes_file(TALLOC_CTX *mem_ctx)
+static struct ctdb_node_map_old *read_nodes_file(TALLOC_CTX *mem_ctx)
{
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);
- if (lines == NULL) {
- return NULL;
- }
- while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
- nlines--;
- }
- for (i=0, pnn=0; i<nlines; i++) {
- char *node;
-
- node = lines[i];
- /* strip leading spaces */
- while((*node == ' ') || (*node == '\t')) {
- node++;
- }
- if (*node == '#') {
- pnn++;
- continue;
- }
- if (strcmp(node, "") == 0) {
- continue;
+ 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);
}
- 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;
-
- tmp_node->next = pnn_nodes;
- pnn_nodes = tmp_node;
}
- return pnn_nodes;
+ return ctdb_read_nodes_file(mem_ctx, nodes_list);
}
/*
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();
+ struct ctdb_node_map_old *node_map;
+ int i, pnn;
- pnn_nodes = read_nodes_file(mem_ctx);
- if (pnn_nodes == NULL) {
- DEBUG(DEBUG_ERR,("Failed to read nodes file\n"));
+ node_map = read_nodes_file(mem_ctx);
+ if (node_map == NULL) {
talloc_free(mem_ctx);
return -1;
}
- 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;
+ for (i = 0; i < node_map->num; i++) {
+ if (node_map->nodes[i].flags & NODE_FLAGS_DELETED) {
+ continue;
}
-
- if (ctdb_sys_have_ip(&addr)) {
- printf("PNN:%d\n", pnn_node->pnn);
+ if (ctdb_sys_have_ip(&node_map->nodes[i].addr)) {
+ pnn = node_map->nodes[i].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_context *ctdb, struct ctdb_node_and_flags *node)
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(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),
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
int i;
struct ctdb_vnn_map *vnnmap=NULL;
- struct ctdb_node_map *nodemap=NULL;
+ struct ctdb_node_map_old *nodemap=NULL;
uint32_t recmode, recmaster, mypnn;
int num_deleted_nodes = 0;
int ret;
{
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
int i, ret;
- struct ctdb_node_map *nodemap=NULL;
+ struct ctdb_node_map_old *nodemap=NULL;
uint32_t * nodes;
uint32_t pnn_mode, mypnn;
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;
}
return ret;
}
-struct natgw_node {
- struct natgw_node *next;
- const char *addr;
-};
+static struct ctdb_node_map_old *read_natgw_nodes_file(struct ctdb_context *ctdb,
+ TALLOC_CTX *mem_ctx)
+{
+ const char *natgw_list;
+ struct ctdb_node_map_old *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/flags will be junk but they're not used */
+ natgw_nodes = ctdb_read_nodes_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;
+}
+
-static int find_natgw(struct ctdb_context *ctdb,
- struct ctdb_node_map *nodemap, uint32_t flags,
- uint32_t *pnn, const char **ip)
+/* talloc off the existing nodemap... */
+static struct ctdb_node_map_old *talloc_nodemap(struct ctdb_node_map_old *nodemap)
{
- int i;
- uint32_t capabilities;
- int ret;
+ return talloc_zero_size(nodemap,
+ offsetof(struct ctdb_node_map_old, nodes) +
+ nodemap->num * sizeof(struct ctdb_node_and_flags));
+}
- for (i=0;i<nodemap->num;i++) {
- if (!(nodemap->nodes[i].flags & flags)) {
- ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(),
- nodemap->nodes[i].pnn,
- &capabilities);
- if (ret != 0) {
- DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n",
- nodemap->nodes[i].pnn));
- return -1;
- }
- if (!(capabilities&CTDB_CAP_NATGW)) {
+static struct ctdb_node_map_old *
+filter_nodemap_by_addrs(struct ctdb_context *ctdb,
+ struct ctdb_node_map_old *nodemap,
+ struct ctdb_node_map_old *natgw_nodes)
+{
+ int i, j;
+ struct ctdb_node_map_old *ret;
+
+ ret = talloc_nodemap(nodemap);
+ CTDB_NO_MEMORY_NULL(ctdb, ret);
+
+ ret->num = 0;
+
+ for (i = 0; i < nodemap->num; i++) {
+ for(j = 0; j < natgw_nodes->num ; j++) {
+ if (nodemap->nodes[j].flags & NODE_FLAGS_DELETED) {
continue;
}
- *pnn = nodemap->nodes[i].pnn;
- *ip = ctdb_addr_to_str(&nodemap->nodes[i].addr);
- return 0;
+ if (ctdb_same_ip(&natgw_nodes->nodes[j].addr,
+ &nodemap->nodes[i].addr)) {
+
+ ret->nodes[ret->num] = nodemap->nodes[i];
+ ret->num++;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static struct ctdb_node_map_old *
+filter_nodemap_by_capabilities(struct ctdb_context *ctdb,
+ struct ctdb_node_map_old *nodemap,
+ uint32_t required_capabilities,
+ bool first_only)
+{
+ int i;
+ uint32_t capabilities;
+ struct ctdb_node_map_old *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 ret;
+}
+
+static struct ctdb_node_map_old *
+filter_nodemap_by_flags(struct ctdb_context *ctdb,
+ struct ctdb_node_map_old *nodemap,
+ uint32_t flags_mask)
+{
+ int i;
+ struct ctdb_node_map_old *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 2; /* matches ENOENT */
+ return ret;
}
/*
{
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 ctdb_node_map_old *natgw_nodes = NULL;
+ struct ctdb_node_map_old *orig_nodemap=NULL;
+ struct ctdb_node_map_old *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);
- talloc_free(tmp_ctx);
- 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;
}
- ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &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_old *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_old *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);
}
display the status of the scripts for monitoring (or other events)
*/
static int control_one_scriptstatus(struct ctdb_context *ctdb,
- enum ctdb_eventscript_call type)
+ enum ctdb_event type)
{
- struct ctdb_scripts_wire *script_status;
+ struct ctdb_script_list_old *script_status;
int ret, i;
ret = ctdb_ctrl_getscriptstatus(ctdb, TIMELIMIT(), options.pnn, ctdb, type, &script_status);
}
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++) {
const char *status = NULL;
+ /* The ETIME status is ignored for certain events.
+ * In that case the status is 0, but endtime is not set.
+ */
+ if (script_status->scripts[i].status == 0 &&
+ timeval_is_zero(&script_status->scripts[i].finished)) {
+ script_status->scripts[i].status = -ETIME;
+ }
+
switch (script_status->scripts[i].status) {
case -ETIME:
status = "TIMEDOUT";
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,
int argc, const char **argv)
{
int ret;
- enum ctdb_eventscript_call type, min, max;
+ enum ctdb_event type, min, max;
const char *arg;
if (argc > 1) {
}
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++) {
}
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));
static int move_ip(struct ctdb_context *ctdb, ctdb_sock_addr *addr, uint32_t pnn)
{
- struct ctdb_all_public_ips *ips;
+ struct ctdb_public_ip_list_old *ips;
struct ctdb_public_ip ip;
int i, ret;
uint32_t *nodes;
uint32_t disable_time;
TDB_DATA data;
- struct ctdb_node_map *nodemap=NULL;
+ struct ctdb_node_map_old *nodemap=NULL;
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
disable_time = 30;
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;
+ struct ctdb_public_ip_list_old *ips;
+ struct ctdb_node_map_old *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);
uint32_t *nodes;
uint32_t disable_time;
TDB_DATA data;
- struct ctdb_node_map *nodemap=NULL;
+ struct ctdb_node_map_old *nodemap=NULL;
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
disable_time = 30;
static int getips_store_callback(void *param, void *data)
{
struct ctdb_public_ip *node_ip = (struct ctdb_public_ip *)data;
- struct ctdb_all_public_ips *ips = param;
+ struct ctdb_public_ip_list_old *ips = param;
int i;
i = ips->num++;
}
static int
-control_get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *tmp_ctx, struct ctdb_all_public_ips **ips)
+control_get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *tmp_ctx, struct ctdb_public_ip_list_old **ips)
{
- struct ctdb_all_public_ips *tmp_ips;
- struct ctdb_node_map *nodemap=NULL;
+ struct ctdb_public_ip_list_old *tmp_ips;
+ struct ctdb_node_map_old *nodemap=NULL;
trbt_tree_t *ip_tree;
int i, j, len, ret;
uint32_t count;
count = 0;
trbt_traversearray32(ip_tree, IP_KEYLEN, getips_count_callback, &count);
- len = offsetof(struct ctdb_all_public_ips, ips) +
+ len = offsetof(struct ctdb_public_ip_list_old, ips) +
count*sizeof(struct ctdb_public_ip);
tmp_ips = talloc_zero_size(tmp_ctx, len);
trbt_traversearray32(ip_tree, IP_KEYLEN, getips_store_callback, tmp_ips);
}
-static void ctdb_every_second(struct event_context *ev, struct timed_event *te, struct timeval t, void *p)
+static void ctdb_every_second(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval t, void *p)
{
struct ctdb_context *ctdb = talloc_get_type(p, struct ctdb_context);
- event_add_timed(ctdb->ev, ctdb,
- timeval_current_ofs(1, 0),
- ctdb_every_second, ctdb);
+ tevent_add_timer(ctdb->ev, ctdb, timeval_current_ofs(1, 0),
+ ctdb_every_second, ctdb);
}
struct srvid_reply_handler_data {
const char *srvid_str;
};
-static void srvid_broadcast_reply_handler(struct ctdb_context *ctdb,
- uint64_t srvid,
- TDB_DATA data,
+static void srvid_broadcast_reply_handler(uint64_t srvid, TDB_DATA data,
void *private_data)
{
struct srvid_reply_handler_data *d =
d->done = true;
for (i = 0; i < talloc_array_length(d->nodes); i++) {
if (d->nodes[i] == ret) {
- DEBUG(DEBUG_INFO,
+ DEBUG(DEBUG_DEBUG,
("%s reply received from node %u\n",
d->srvid_str, ret));
d->nodes[i] = -1;
* 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;
ZERO_STRUCT(request);
/* Time ticks to enable timeouts to be processed */
- event_add_timed(ctdb->ev, ctdb,
- timeval_current_ofs(1, 0),
- ctdb_every_second, ctdb);
+ tevent_add_timer(ctdb->ev, ctdb, timeval_current_ofs(1, 0),
+ ctdb_every_second, ctdb);
+
+ pnn = ctdb_get_pnn(ctdb);
+ reply_srvid = getpid();
+
+ if (arg == NULL) {
+ request.pnn = pnn;
+ request.srvid = reply_srvid;
- request.pnn = ctdb_get_pnn(ctdb);
- request.srvid = getpid();
- request.data = arg;
+ 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;
reply_data.done = false;
if (wait_for_all) {
- struct ctdb_node_map *nodemap;
+ struct ctdb_node_map_old *nodemap;
ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(),
CTDB_CURRENT_NODE, ctdb, &nodemap);
tv = timeval_current();
/* This loop terminates the reply is received */
while (timeval_elapsed(&tv) < 5.0 && !reply_data.done) {
- event_loop_once(ctdb->ev);
+ tevent_loop_once(ctdb->ev);
}
if (!reply_data.done) {
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);
}
ctdb_sock_addr addr;
struct ctdb_control_ip_iface *pub;
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
- struct ctdb_all_public_ips *ips;
+ struct ctdb_public_ip_list_old *ips;
if (argc != 2) {
static int control_ipiface(struct ctdb_context *ctdb, int argc, const char **argv)
{
ctdb_sock_addr addr;
+ char *iface = NULL;
if (argc != 1) {
usage();
return -1;
}
- printf("IP on interface %s\n", ctdb_sys_find_ifname(&addr));
+ iface = ctdb_sys_find_ifname(&addr);
+ if (iface == NULL) {
+ printf("Failed to get interface name for ip: %s", argv[0]);
+ return -1;
+ }
+
+ printf("IP on interface %s\n", iface);
+
+ free(iface);
return 0;
}
static int control_delip_all(struct ctdb_context *ctdb, int argc, const char **argv, ctdb_sock_addr *addr)
{
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
- struct ctdb_node_map *nodemap=NULL;
- struct ctdb_all_public_ips *ips;
+ struct ctdb_node_map_old *nodemap=NULL;
+ struct ctdb_public_ip_list_old *ips;
int ret, i, j;
ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap);
ctdb_sock_addr addr;
struct ctdb_control_ip_iface pub;
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
- struct ctdb_all_public_ips *ips;
+ struct ctdb_public_ip_list_old *ips;
if (argc != 1) {
talloc_free(tmp_ctx);
static int kill_tcp_from_file(struct ctdb_context *ctdb,
int argc, const char **argv)
{
- struct ctdb_control_killtcp *killtcp;
+ struct ctdb_tcp_connection *killtcp;
int max_entries, current, i;
struct timeval timeout;
char line[128], src[128], dst[128];
if (current >= max_entries) {
max_entries += 1024;
killtcp = talloc_realloc(ctdb, killtcp,
- struct ctdb_control_killtcp,
+ struct ctdb_tcp_connection,
max_entries);
CTDB_NO_MEMORY(ctdb, killtcp);
}
for (i = 0; i < current; i++) {
- data.dsize = sizeof(struct ctdb_control_killtcp);
+ data.dsize = sizeof(struct ctdb_tcp_connection);
data.dptr = (unsigned char *)&killtcp[i];
timeout = TIMELIMIT();
static int kill_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
{
int ret;
- struct ctdb_control_killtcp killtcp;
+ struct ctdb_tcp_connection killtcp;
assert_single_node_only();
static int regsrvid(struct ctdb_context *ctdb, int argc, const char **argv)
{
int ret;
- struct ctdb_server_id server_id;
+ struct ctdb_client_id server_id;
if (argc < 3) {
usage();
static int unregsrvid(struct ctdb_context *ctdb, int argc, const char **argv)
{
int ret;
- struct ctdb_server_id server_id;
+ struct ctdb_client_id server_id;
if (argc < 3) {
usage();
*/
static int chksrvid(struct ctdb_context *ctdb, int argc, const char **argv)
{
- uint32_t status;
+ uint32_t status = 0;
int ret;
- struct ctdb_server_id server_id;
+ struct ctdb_client_id server_id;
if (argc < 3) {
usage();
static int getsrvids(struct ctdb_context *ctdb, int argc, const char **argv)
{
int i, ret;
- struct ctdb_server_id_list *server_ids;
+ struct ctdb_client_id_list_old *server_ids;
ret = ctdb_ctrl_get_server_id_list(ctdb, ctdb, TIMELIMIT(), options.pnn, &server_ids);
if (ret != 0) {
{
int i, ret;
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
- struct ctdb_all_public_ips *ips;
+ struct ctdb_public_ip_list_old *ips;
+
+ if (argc == 1 && strcmp(argv[0], "all") == 0) {
+ options.pnn = CTDB_BROADCAST_ALL;
+ }
if (options.pnn == CTDB_BROADCAST_ALL) {
/* read the list of public ips from all nodes */
}
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:"");
}
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);
const char *desc,
bool set_flag)
{
- struct ctdb_node_map *nodemap = NULL;
+ struct ctdb_node_map_old *nodemap = NULL;
bool flag_is_set;
int ret;
static int control_showban(struct ctdb_context *ctdb, int argc, const char **argv)
{
int ret;
- struct ctdb_node_map *nodemap=NULL;
+ struct ctdb_node_map_old *nodemap=NULL;
struct ctdb_ban_time *bantime;
/* verify the node exists */
{
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;
}
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)
{
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
- uint32_t *capabilities;
- struct ctdb_node_map *nodemap=NULL;
+ struct ctdb_node_map_old *orig_nodemap=NULL;
+ struct ctdb_node_map_old *nodemap;
int i, ret;
- int healthy_count = 0;
- ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &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);
-
- ret = 0;
+ nodemap = filter_nodemap_by_capabilities(ctdb, orig_nodemap,
+ CTDB_CAP_LVS, false);
+ if (nodemap == NULL) {
+ /* No memory */
+ ret = -1;
+ goto done;
+ }
- /* 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;
- }
+ ret = 0;
- ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), i, &capabilities[i]);
- if (ret != 0) {
- 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_old *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:
talloc_free(tmp_ctx);
return ret;
static int control_lvsmaster(struct ctdb_context *ctdb, int argc, const char **argv)
{
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
- uint32_t *capabilities;
- struct ctdb_node_map *nodemap=NULL;
+ struct ctdb_node_map_old *nodemap=NULL;
int i, ret;
- int healthy_count = 0;
- ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &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(tmp_ctx, uint32_t, nodemap->num);
- if (capabilities == NULL) {
- talloc_free(tmp_ctx);
- 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;
- }
-
- ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), i, &capabilities[i]);
- if (ret != 0) {
- 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_old *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_old *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:
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;
}
}
ZERO_STRUCT(c);
+ c.ctdb = ctdb;
c.f = stdout;
c.printemptyrecords = (bool)options.printemptyrecords;
c.printdatasize = (bool)options.printdatasize;
d->count++;
ZERO_STRUCT(c);
+ c.ctdb = d->ctdb;
c.f = stdout;
c.printemptyrecords = (bool)options.printemptyrecords;
c.printdatasize = (bool)options.printdatasize;
c.printhash = (bool)options.printhash;
c.printrecordflags = true;
- return ctdb_dumpdb_record(d->ctdb, key, data, &c);
+ return ctdb_dumpdb_record(key, data, &c);
}
/*
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;
}
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 (!strncmp(argv[1], "0x", 2)) {
- key = hextodata(tmp_ctx, argv[1] + 2);
- if (key.dsize == 0) {
- printf("Failed to convert \"%s\" into a TDB_DATA\n", argv[1]);
- return -1;
- }
- } else {
- key.dptr = discard_const(argv[1]);
- key.dsize = strlen(argv[1]);
+ key = strtodata(tmp_ctx, argv[1], strlen(argv[1]));
+ if (key.dptr == NULL) {
+ printf("Failed to convert \"%s\" into a TDB_DATA\n", argv[1]);
+ return -1;
}
data = tdb_fetch(tdb, key);
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();
return -1;
}
- if (!strncmp(argv[1], "0x", 2)) {
- key = hextodata(tmp_ctx, argv[1] + 2);
- if (key.dsize == 0) {
- printf("Failed to convert \"%s\" into a TDB_DATA\n", argv[1]);
- return -1;
- }
- } else {
- key.dptr = discard_const(argv[1]);
- key.dsize = strlen(argv[1]);
+ key = strtodata(tmp_ctx, argv[1], strlen(argv[1]));
+ if (key.dptr == NULL) {
+ printf("Failed to convert \"%s\" into a TDB_DATA\n", argv[1]);
+ return -1;
}
- if (!strncmp(argv[2], "0x", 2)) {
- data = hextodata(tmp_ctx, argv[2] + 2);
- if (data.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 = strtodata(tmp_ctx, argv[2], strlen(argv[2]));
+ if (value.dptr == NULL) {
+ printf("Failed to convert \"%s\" into a TDB_DATA\n", argv[2]);
+ return -1;
+ }
+
+ 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);
return -1;
}
- key.dptr = discard_const(argv[1]);
- key.dsize = strlen(argv[1]);
+ key = strtodata(tmp_ctx, argv[1], strlen(argv[1]));
+ if (key.dptr == NULL) {
+ printf("Failed to convert \"%s\" into a TDB_DATA\n", argv[1]);
+ return -1;
+ }
+
ret = ctdb_transaction_store(h, key, data);
if (ret != 0) {
DEBUG(DEBUG_ERR,("Failed to store record\n"));
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;
}
return -1;
}
- key.dptr = discard_const(argv[1]);
- key.dsize = strlen(argv[1]);
+ key = strtodata(tmp_ctx, argv[1], strlen(argv[1]));
+ if (key.dptr == NULL) {
+ printf("Failed to convert \"%s\" into a TDB_DATA\n", argv[1]);
+ return -1;
+ }
+
ret = ctdb_transaction_store(h, key, tdb_null);
if (ret != 0) {
DEBUG(DEBUG_ERR, ("Failed to delete record\n"));
return 0;
}
-/*
- check if a service is bound to a port or not
- */
-static int control_chktcpport(struct ctdb_context *ctdb, int argc, const char **argv)
+static const char *ptrans_parse_string(TALLOC_CTX *mem_ctx, const char *s,
+ TDB_DATA *data)
{
- int s, ret;
- unsigned v;
- int port;
- struct sockaddr_in sin;
+ const char *t;
+ size_t n;
+ const char *ret; /* Next byte after successfully parsed value */
- if (argc != 1) {
- printf("Use: ctdb chktcport <port>\n");
- return EINVAL;
- }
+ /* Error, unless someone says otherwise */
+ ret = NULL;
+ /* Indicates no value to parse */
+ *data = tdb_null;
- port = atoi(argv[0]);
+ /* Skip whitespace */
+ n = strspn(s, " \t");
+ t = s + n;
- s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (s == -1) {
- printf("Failed to open local socket\n");
- return errno;
+ if (t[0] == '"') {
+ /* Quoted ASCII string - no wide characters! */
+ t++;
+ n = strcspn(t, "\"");
+ if (t[n] == '"') {
+ if (n > 0) {
+ *data = strtodata(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));
}
- v = fcntl(s, F_GETFL, 0);
- fcntl(s, F_SETFL, v | O_NONBLOCK);
+ return ret;
+}
- bzero(&sin, sizeof(sin));
- sin.sin_family = PF_INET;
- sin.sin_port = htons(port);
- ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
- close(s);
- if (ret == -1) {
- printf("Failed to bind to local socket: %d %s\n", errno, strerror(errno));
- return errno;
- }
+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;
- return 0;
-}
+ 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;
+ }
-static void log_handler(struct ctdb_context *ctdb, uint64_t srvid,
- TDB_DATA data, void *private_data)
-{
- DEBUG(DEBUG_ERR,("Log data received\n"));
- if (data.dsize > 0) {
- printf("%s", data.dptr);
+ /* 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;
}
- exit(0);
+ return true;
}
/*
- display a list of log messages from the in memory ringbuffer
+ * Update a persistent database as per file/stdin
*/
-static int control_getlog(struct ctdb_context *ctdb, int argc, const char **argv)
+static int control_ptrans(struct ctdb_context *ctdb,
+ int argc, const char **argv)
{
- int ret, i;
- bool main_daemon;
- struct ctdb_get_log_addr log_addr;
- TDB_DATA data;
- struct timeval tv;
+ 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;
- /* Process options */
- main_daemon = true;
- log_addr.pnn = ctdb_get_pnn(ctdb);
- log_addr.level = DEBUG_NOTICE;
- for (i = 0; i < argc; i++) {
- if (strcmp(argv[i], "recoverd") == 0) {
- main_daemon = false;
- } else {
- if (isalpha(argv[i][0]) || argv[i][0] == '-') {
- log_addr.level = get_debug_by_desc(argv[i]);
- } else {
- log_addr.level = strtol(argv[i], NULL, 0);
- }
- }
+ if (argc < 1) {
+ talloc_free(tmp_ctx);
+ usage();
}
- /* Our message port is our PID */
- log_addr.srvid = getpid();
-
- data.dptr = (unsigned char *)&log_addr;
- data.dsize = sizeof(log_addr);
-
- DEBUG(DEBUG_ERR, ("Pulling logs from node %u\n", options.pnn));
+ 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;
+ }
+ }
- ctdb_client_set_message_handler(ctdb, log_addr.srvid, log_handler, NULL);
- sleep(1);
+ db_name = argv[0];
- DEBUG(DEBUG_ERR,("Listen for response on %d\n", (int)log_addr.srvid));
+ 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;
+ }
- if (main_daemon) {
- int32_t res;
- char *errmsg;
- TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+ h = ctdb_transaction_start(ctdb_db, tmp_ctx);
+ if (h == NULL) {
+ DEBUG(DEBUG_ERR,("Failed to start transaction on database %s\n", db_name));
+ goto error;
+ }
- ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_GET_LOG,
- 0, data, tmp_ctx, NULL, &res, NULL, &errmsg);
- if (ret != 0 || res != 0) {
- DEBUG(DEBUG_ERR,("Failed to get logs - %s\n", errmsg));
- talloc_free(tmp_ctx);
- return -1;
- }
- talloc_free(tmp_ctx);
- } else {
- ret = ctdb_client_send_message(ctdb, options.pnn,
- CTDB_SRVID_GETLOG, data);
- if (ret != 0) {
- DEBUG(DEBUG_ERR,("Failed to send getlog request message to %u\n", options.pnn));
- 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;
+ }
}
}
- tv = timeval_current();
- /* this loop will terminate when we have received the reply */
- while (timeval_elapsed(&tv) < (double)options.timelimit) {
- event_loop_once(ctdb->ev);
+ ret = ctdb_transaction_commit(h);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR,("Failed to commit transaction\n"));
+ goto error;
}
- DEBUG(DEBUG_INFO,("Timed out waiting for log data.\n"));
-
+ if (file != stdin) {
+ fclose(file);
+ }
+ talloc_free(tmp_ctx);
return 0;
+
+error:
+ if (file != stdin) {
+ fclose(file);
+ }
+
+ talloc_free(tmp_ctx);
+ return -1;
}
/*
- clear the in memory log area
+ check if a service is bound to a port or not
*/
-static int control_clearlog(struct ctdb_context *ctdb, int argc, const char **argv)
+static int control_chktcpport(struct ctdb_context *ctdb, int argc, const char **argv)
{
- int ret;
+ int s, ret;
+ int v;
+ int port;
+ struct sockaddr_in sin;
- if (argc == 0 || (argc >= 1 && strcmp(argv[0], "recoverd") != 0)) {
- /* "recoverd" not given - get logs from main daemon */
- int32_t res;
- char *errmsg;
- TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+ if (argc != 1) {
+ printf("Use: ctdb chktcport <port>\n");
+ return EINVAL;
+ }
- ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_CLEAR_LOG,
- 0, tdb_null, tmp_ctx, NULL, &res, NULL, &errmsg);
- if (ret != 0 || res != 0) {
- DEBUG(DEBUG_ERR,("Failed to clear logs\n"));
- talloc_free(tmp_ctx);
- return -1;
- }
+ port = atoi(argv[0]);
- talloc_free(tmp_ctx);
- } else {
- TDB_DATA data; /* unused in recoverd... */
- data.dsize = 0;
+ s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (s == -1) {
+ printf("Failed to open local socket\n");
+ return errno;
+ }
- ret = ctdb_client_send_message(ctdb, options.pnn, CTDB_SRVID_CLEARLOG, data);
- if (ret != 0) {
- DEBUG(DEBUG_ERR,("Failed to send clearlog request message to %u\n", options.pnn));
- return -1;
- }
+ v = fcntl(s, F_GETFL, 0);
+ 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;
+ sin.sin_port = htons(port);
+ ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
+ close(s);
+ if (ret == -1) {
+ printf("Failed to bind to local socket: %d %s\n", errno, strerror(errno));
+ return errno;
}
return 0;
}
+
/* Reload public IPs on a specified nodes */
static int control_reloadips(struct ctdb_context *ctdb, int argc, const char **argv)
{
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
uint32_t *nodes;
uint32_t pnn_mode;
+ uint32_t timeout;
int ret;
assert_single_node_only();
* there are disconnected nodes. However, this should
* probably be left up to the administrator.
*/
- srvid_broadcast(ctdb, CTDB_SRVID_DISABLE_TAKEOVER_RUNS, LONGTIMEOUT,
+ timeout = LONGTIMEOUT;
+ srvid_broadcast(ctdb, CTDB_SRVID_DISABLE_TAKEOVER_RUNS, &timeout,
"Disable takeover runs", true);
/* Now tell all the desired nodes to reload their public IPs.
/* It isn't strictly necessary to wait until takeover runs are
* re-enabled but doing so can't hurt.
*/
- srvid_broadcast(ctdb, CTDB_SRVID_DISABLE_TAKEOVER_RUNS, 0,
+ timeout = 0;
+ srvid_broadcast(ctdb, CTDB_SRVID_DISABLE_TAKEOVER_RUNS, &timeout,
"Enable takeover runs", true);
ipreallocate(ctdb);
static int control_getdbmap(struct ctdb_context *ctdb, int argc, const char **argv)
{
int i, ret;
- struct ctdb_dbid_map *dbmap=NULL;
+ struct ctdb_dbid_map_old *dbmap=NULL;
ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, ctdb, &dbmap);
if (ret != 0) {
}
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;
- const char *health;
+ const char *path = NULL;
+ const char *name = NULL;
+ const char *health = NULL;
bool persistent;
bool readonly;
bool sticky;
ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.pnn,
- dbmap->dbs[i].dbid, ctdb, &path);
+ dbmap->dbs[i].db_id, ctdb, &path);
ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn,
- dbmap->dbs[i].dbid, ctdb, &name);
+ dbmap->dbs[i].db_id, ctdb, &name);
ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn,
- dbmap->dbs[i].dbid, ctdb, &health);
+ dbmap->dbs[i].db_id, 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(":0x%08X:%s:%s:%d:%d:%d:%d:\n",
- dbmap->dbs[i].dbid, name, path,
+ printm(":0x%08X:%s:%s:%d:%d:%d:%d:\n",
+ dbmap->dbs[i].db_id, name, path,
!!(persistent), !!(sticky),
!!(health), !!(readonly));
}
printf("Number of databases:%d\n", dbmap->num);
for(i=0;i<dbmap->num;i++){
- const char *path;
- const char *name;
- const char *health;
+ const char *path = NULL;
+ const char *name = NULL;
+ const char *health = NULL;
bool persistent;
bool readonly;
bool sticky;
- ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &path);
- ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &name);
- ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &health);
+ ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].db_id, ctdb, &path);
+ ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].db_id, ctdb, &name);
+ ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].db_id, 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 name:%s path:%s%s%s%s%s\n",
- dbmap->dbs[i].dbid, name, path,
+ dbmap->dbs[i].db_id, name, path,
persistent?" PERSISTENT":"",
sticky?" STICKY":"",
readonly?" READONLY":"",
const char *db_name;
uint32_t db_id;
uint8_t flags;
- const char *path;
- const char *health;
+ const char *path = NULL;
+ const char *health = NULL;
if (argc < 1) {
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;
}
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;
}
DEBUG(DEBUG_ERR, ("Unable to get debuglevel response from node %u\n", options.pnn));
return ret;
} else {
+ const char *desc = get_debug_by_level(level);
+ if (desc == NULL) {
+ /* This should never happen */
+ desc = "Unknown";
+ }
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", desc, level);
} else {
- printf("Node %u is at debug level %s (%d)\n", options.pnn, get_debug_by_level(level), level);
+ printf("Node %u is at debug level %s (%d)\n",
+ options.pnn, desc, level);
}
}
return 0;
} else {
if (options.machinereadable){
if (reclock != NULL) {
- printf("%s", reclock);
+ printm("%s", reclock);
}
} else {
if (reclock == NULL) {
static int control_setreclock(struct ctdb_context *ctdb, int argc, const char **argv)
{
int ret;
- const char *reclock;
+ const char *reclock = NULL;
if (argc == 0) {
reclock = NULL;
static int control_setnatgwstate(struct ctdb_context *ctdb, int argc, const char **argv)
{
int ret;
- uint32_t natgwstate;
+ uint32_t natgwstate = 0;
if (argc == 0) {
usage();
static int control_setlmasterrole(struct ctdb_context *ctdb, int argc, const char **argv)
{
int ret;
- uint32_t lmasterrole;
+ uint32_t lmasterrole = 0;
if (argc == 0) {
usage();
static int control_setrecmasterrole(struct ctdb_context *ctdb, int argc, const char **argv)
{
int ret;
- uint32_t recmasterrole;
+ uint32_t recmasterrole = 0;
if (argc == 0) {
usage();
*/
static int control_setdebug(struct ctdb_context *ctdb, int argc, const char **argv)
{
- int i, ret;
+ int ret;
int32_t level;
if (argc == 0) {
printf("You must specify the debug level. Valid levels are:\n");
- for (i=0; debug_levels[i].description != NULL; i++) {
- printf("%s (%d)\n", debug_levels[i].description, debug_levels[i].level);
- }
-
+ print_debug_levels(stdout);
return 0;
}
- if (isalpha(argv[0][0]) || argv[0][0] == '-') {
- level = get_debug_by_desc(argv[0]);
- } else {
- level = strtol(argv[0], NULL, 0);
- }
-
- for (i=0; debug_levels[i].description != NULL; i++) {
- if (level == debug_levels[i].level) {
- break;
- }
- }
- if (debug_levels[i].description == NULL) {
+ if (!parse_debug(argv[0], &level)) {
printf("Invalid debug level, must be one of\n");
- for (i=0; debug_levels[i].description != NULL; i++) {
- printf("%s (%d)\n", debug_levels[i].description, debug_levels[i].level);
- }
+ print_debug_levels(stdout);
return -1;
}
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_old *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;
}
usage();
}
- if (!db_exists(ctdb, argv[0], &db_id, NULL)) {
+ if (!db_exists(ctdb, argv[0], &db_id, NULL, NULL)) {
return -1;
}
return 0;
}
-/*
- * set db seqnum
- */
-static int control_setdbseqnum(struct ctdb_context *ctdb, int argc, const char **argv)
-{
- int 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_ctrl_getdbseqnum(ctdb, TIMELIMIT(), options.pnn, db_id, &old_seqnum);
- if (ret != 0) {
- 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
*/
ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_RUN_EVENTSCRIPTS,
0, data, tmp_ctx, NULL, &res, NULL, &errmsg);
if (ret != 0 || res != 0) {
- DEBUG(DEBUG_ERR,("Failed to run eventscripts - %s\n", errmsg));
+ if (errmsg != NULL) {
+ DEBUG(DEBUG_ERR,
+ ("Failed to run eventscripts - %s\n", errmsg));
+ } else {
+ DEBUG(DEBUG_ERR, ("Failed to run eventscripts\n"));
+ }
talloc_free(tmp_ctx);
return -1;
}
static int backup_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private)
{
struct backup_data *bd = talloc_get_type(private, struct backup_data);
- struct ctdb_rec_data *rec;
+ struct ctdb_rec_data_old *rec;
/* add the record */
rec = ctdb_marshall_record(bd->records, 0, key, NULL, data);
*/
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;
TDB_DATA data;
struct db_file_header dbhdr;
struct ctdb_db_context *ctdb_db;
- struct ctdb_node_map *nodemap=NULL;
+ struct ctdb_node_map_old *nodemap=NULL;
struct ctdb_vnn_map *vnnmap=NULL;
int i, fh;
- struct ctdb_control_wipe_database w;
+ struct ctdb_control_transdb w;
uint32_t *nodes;
uint32_t generation;
struct tm *tm;
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);
int i, fh;
struct tm *tm;
char tbuf[100];
- struct ctdb_rec_data *rec = NULL;
+ struct ctdb_rec_data_old *rec = NULL;
struct ctdb_marshall_buffer *m;
struct ctdb_dump_db_context c;
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;
dbhdr.name, m->db_id, tbuf);
ZERO_STRUCT(c);
+ c.ctdb = ctdb;
c.f = stdout;
c.printemptyrecords = (bool)options.printemptyrecords;
c.printdatasize = (bool)options.printdatasize;
rec = ctdb_marshall_loop_next(m, rec, &reqid,
NULL, &key, &data);
- ctdb_dumpdb_record(ctdb, key, data, &c);
+ ctdb_dumpdb_record(key, data, &c);
}
printf("Dumped %d records\n", i);
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;
struct ctdb_db_context *ctdb_db;
- struct ctdb_node_map *nodemap = NULL;
+ struct ctdb_node_map_old *nodemap = NULL;
struct ctdb_vnn_map *vnnmap = NULL;
int i;
- struct ctdb_control_wipe_database w;
+ struct ctdb_control_transdb w;
uint32_t *nodes;
uint32_t generation;
uint8_t flags;
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;
}
/*
handler for memory dumps
*/
-static void mem_dump_handler(struct ctdb_context *ctdb, uint64_t srvid,
- TDB_DATA data, void *private_data)
+static void mem_dump_handler(uint64_t srvid, TDB_DATA data, void *private_data)
{
- write(1, data.dptr, data.dsize);
+ sys_write(1, data.dptr, data.dsize);
exit(0);
}
}
/* this loop will terminate when we have received the reply */
- while (1) {
- event_loop_once(ctdb->ev);
+ while (1) {
+ tevent_loop_once(ctdb->ev);
}
return 0;
/*
handler for msglisten
*/
-static void msglisten_handler(struct ctdb_context *ctdb, uint64_t srvid,
- TDB_DATA data, void *private_data)
+static void msglisten_handler(uint64_t srvid, TDB_DATA data,
+ void *private_data)
{
int i;
ctdb_client_set_message_handler(ctdb, srvid, msglisten_handler, NULL);
printf("Listening for messages on srvid:%d\n", (int)srvid);
- while (1) {
- event_loop_once(ctdb->ev);
+ while (1) {
+ tevent_loop_once(ctdb->ev);
}
return 0;
static int control_listnodes(struct ctdb_context *ctdb, int argc, const char **argv)
{
TALLOC_CTX *mem_ctx = talloc_new(NULL);
- struct pnn_node *pnn_nodes;
- struct pnn_node *pnn_node;
+ struct ctdb_node_map_old *node_map;
+ int i;
assert_single_node_only();
- pnn_nodes = read_nodes_file(mem_ctx);
- if (pnn_nodes == NULL) {
- DEBUG(DEBUG_ERR,("Failed to read nodes file\n"));
+ node_map = read_nodes_file(mem_ctx);
+ if (node_map == NULL) {
talloc_free(mem_ctx);
return -1;
}
- 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;
+ for (i = 0; i < node_map->num; i++) {
+ const char *addr;
+
+ if (node_map->nodes[i].flags & NODE_FLAGS_DELETED) {
+ continue;
}
+ addr = ctdb_addr_to_str(&node_map->nodes[i].addr);
if (options.machinereadable){
- printf(":%d:%s:\n", pnn_node->pnn, pnn_node->addr);
+ printm(":%d:%s:\n", node_map->nodes[i].pnn, addr);
} else {
- printf("%s\n", pnn_node->addr);
+ printf("%s\n", addr);
}
}
talloc_free(mem_ctx);
return 0;
}
+/**********************************************************************/
+/* reload the nodes file on all nodes */
+
+static void get_nodes_files_callback(struct ctdb_context *ctdb,
+ uint32_t node_pnn, int32_t res,
+ TDB_DATA outdata, void *callback_data)
+{
+ struct ctdb_node_map_old **maps =
+ talloc_get_type(callback_data, struct ctdb_node_map_old *);
+
+ if (outdata.dsize < offsetof(struct ctdb_node_map_old, nodes) ||
+ outdata.dptr == NULL) {
+ DEBUG(DEBUG_ERR,
+ (__location__ " Invalid return data: %u %p\n",
+ (unsigned)outdata.dsize, outdata.dptr));
+ return;
+ }
+
+ if (node_pnn >= talloc_array_length(maps)) {
+ DEBUG(DEBUG_ERR,
+ (__location__ " unexpected PNN %u\n", node_pnn));
+ return;
+ }
+
+ maps[node_pnn] = talloc_memdup(maps, outdata.dptr, outdata.dsize);
+}
+
+static void get_nodes_files_fail_callback(struct ctdb_context *ctdb,
+ uint32_t node_pnn, int32_t res,
+ TDB_DATA outdata, void *callback_data)
+{
+ DEBUG(DEBUG_ERR,
+ ("ERROR: Failed to get nodes file from node %u\n", node_pnn));
+}
+
+static struct ctdb_node_map_old **
+ctdb_get_nodes_files(struct ctdb_context *ctdb,
+ TALLOC_CTX *mem_ctx,
+ struct timeval timeout,
+ struct ctdb_node_map_old *nodemap)
+{
+ uint32_t *nodes;
+ int ret;
+ struct ctdb_node_map_old **maps;
+
+ maps = talloc_zero_array(mem_ctx, struct ctdb_node_map_old *, nodemap->num);
+ CTDB_NO_MEMORY_NULL(ctdb, maps);
+
+ nodes = list_of_connected_nodes(ctdb, nodemap, mem_ctx, true);
+
+ ret = ctdb_client_async_control(ctdb, CTDB_CONTROL_GET_NODES_FILE,
+ nodes, 0, TIMELIMIT(),
+ true, tdb_null,
+ get_nodes_files_callback,
+ get_nodes_files_fail_callback,
+ maps);
+ if (ret != 0) {
+ talloc_free(maps);
+ return NULL;
+ }
+
+ return maps;
+}
+
+static bool node_files_are_identical(struct ctdb_node_map_old *nm1,
+ struct ctdb_node_map_old *nm2)
+{
+ int i;
+
+ if (nm1->num != nm2->num) {
+ return false;
+ }
+ for (i = 0; i < nm1->num; i++) {
+ if (memcmp(&nm1->nodes[i], &nm2->nodes[i],
+ sizeof(struct ctdb_node_and_flags)) != 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool check_all_node_files_are_identical(struct ctdb_context *ctdb,
+ TALLOC_CTX *mem_ctx,
+ struct timeval timeout,
+ struct ctdb_node_map_old *nodemap,
+ struct ctdb_node_map_old *file_nodemap)
+{
+ static struct ctdb_node_map_old **maps;
+ int i;
+ bool ret = true;
+
+ maps = ctdb_get_nodes_files(ctdb, mem_ctx, timeout, nodemap);
+ if (maps == NULL) {
+ return false;
+ }
+
+ for (i = 0; i < talloc_array_length(maps); i++) {
+ if (maps[i] == NULL) {
+ continue;
+ }
+ if (!node_files_are_identical(file_nodemap, maps[i])) {
+ DEBUG(DEBUG_ERR,
+ ("ERROR: Node file on node %u differs from current node (%u)\n",
+ i, ctdb_get_pnn(ctdb)));
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
/*
reload the nodes file on the local node
*/
+static bool sanity_check_nodes_file_changes(TALLOC_CTX *mem_ctx,
+ struct ctdb_node_map_old *nodemap,
+ struct ctdb_node_map_old *file_nodemap)
+{
+ int i;
+ bool should_abort = false;
+ bool have_changes = false;
+
+ for (i=0; i<nodemap->num; i++) {
+ if (i >= file_nodemap->num) {
+ DEBUG(DEBUG_ERR,
+ ("ERROR: Node %u (%s) missing from nodes file\n",
+ nodemap->nodes[i].pnn,
+ ctdb_addr_to_str(&nodemap->nodes[i].addr)));
+ should_abort = true;
+ continue;
+ }
+ if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED &&
+ file_nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
+ /* Node remains deleted */
+ DEBUG(DEBUG_INFO,
+ ("Node %u is unchanged (DELETED)\n",
+ nodemap->nodes[i].pnn));
+ } else if (!(nodemap->nodes[i].flags & NODE_FLAGS_DELETED) &&
+ !(file_nodemap->nodes[i].flags & NODE_FLAGS_DELETED)) {
+ /* Node not newly nor previously deleted */
+ if (!ctdb_same_ip(&nodemap->nodes[i].addr,
+ &file_nodemap->nodes[i].addr)) {
+ DEBUG(DEBUG_ERR,
+ ("ERROR: Node %u has changed IP address (was %s, now %s)\n",
+ nodemap->nodes[i].pnn,
+ /* ctdb_addr_to_str() returns a static */
+ talloc_strdup(mem_ctx,
+ ctdb_addr_to_str(&nodemap->nodes[i].addr)),
+ ctdb_addr_to_str(&file_nodemap->nodes[i].addr)));
+ should_abort = true;
+ } else {
+ DEBUG(DEBUG_INFO,
+ ("Node %u is unchanged\n",
+ nodemap->nodes[i].pnn));
+ if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+ DEBUG(DEBUG_WARNING,
+ ("WARNING: Node %u is disconnected. You MUST fix this node manually!\n",
+ nodemap->nodes[i].pnn));
+ }
+ }
+ } else if (file_nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
+ /* Node is being deleted */
+ DEBUG(DEBUG_NOTICE,
+ ("Node %u is DELETED\n",
+ nodemap->nodes[i].pnn));
+ have_changes = true;
+ if (!(nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED)) {
+ DEBUG(DEBUG_ERR,
+ ("ERROR: Node %u is still connected\n",
+ nodemap->nodes[i].pnn));
+ should_abort = true;
+ }
+ } else if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
+ /* Node was previously deleted */
+ DEBUG(DEBUG_NOTICE,
+ ("Node %u is UNDELETED\n", nodemap->nodes[i].pnn));
+ have_changes = true;
+ }
+ }
+
+ if (should_abort) {
+ DEBUG(DEBUG_ERR,
+ ("ERROR: Nodes will not be reloaded due to previous error\n"));
+ talloc_free(mem_ctx);
+ exit(1);
+ }
+
+ /* Leftover nodes in file are NEW */
+ for (; i < file_nodemap->num; i++) {
+ DEBUG(DEBUG_NOTICE, ("Node %u is NEW\n",
+ file_nodemap->nodes[i].pnn));
+ have_changes = true;
+ }
+
+ return have_changes;
+}
+
+static void reload_nodes_fail_callback(struct ctdb_context *ctdb,
+ uint32_t node_pnn, int32_t res,
+ TDB_DATA outdata, void *callback_data)
+{
+ DEBUG(DEBUG_WARNING,
+ ("WARNING: Node %u failed to reload nodes. You MUST fix this node manually!\n",
+ node_pnn));
+}
+
static int control_reload_nodes_file(struct ctdb_context *ctdb, int argc, const char **argv)
{
int i, ret;
- int mypnn;
- struct ctdb_node_map *nodemap=NULL;
+ struct ctdb_node_map_old *nodemap=NULL;
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ struct ctdb_node_map_old *file_nodemap;
+ uint32_t *conn;
+ uint32_t timeout;
- assert_single_node_only();
+ assert_current_node_only(ctdb);
- mypnn = ctdb_get_pnn(ctdb);
+ /* Load both the current nodemap and the contents of the local
+ * nodes file. Compare and sanity check them before doing
+ * anything. */
ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
if (ret != 0) {
return ret;
}
- /* reload the nodes file on all remote nodes */
- for (i=0;i<nodemap->num;i++) {
- if (nodemap->nodes[i].pnn == mypnn) {
- continue;
- }
- DEBUG(DEBUG_NOTICE, ("Reloading nodes file on node %u\n", nodemap->nodes[i].pnn));
- ret = ctdb_ctrl_reload_nodes_file(ctdb, TIMELIMIT(),
- nodemap->nodes[i].pnn);
- if (ret != 0) {
- DEBUG(DEBUG_ERR, ("ERROR: Failed to reload nodes file on node %u. You MUST fix that node manually!\n", nodemap->nodes[i].pnn));
- }
+ file_nodemap = read_nodes_file(tmp_ctx);
+ if (file_nodemap == NULL) {
+ DEBUG(DEBUG_ERR,("Failed to read nodes file\n"));
+ talloc_free(tmp_ctx);
+ return -1;
}
- /* reload the nodes file on the local node */
- DEBUG(DEBUG_NOTICE, ("Reloading nodes file on node %u\n", mypnn));
- ret = ctdb_ctrl_reload_nodes_file(ctdb, TIMELIMIT(), mypnn);
- if (ret != 0) {
- DEBUG(DEBUG_ERR, ("ERROR: Failed to reload nodes file on node %u. You MUST fix that node manually!\n", mypnn));
+ if (!check_all_node_files_are_identical(ctdb, tmp_ctx, TIMELIMIT(),
+ nodemap, file_nodemap)) {
+ return -1;
}
- /* initiate a recovery */
- control_recover(ctdb, argc, argv);
+ if (!sanity_check_nodes_file_changes(tmp_ctx, nodemap, file_nodemap)) {
+ DEBUG(DEBUG_NOTICE,
+ ("No change in nodes file, skipping unnecessary reload\n"));
+ talloc_free(tmp_ctx);
+ return 0;
+ }
+
+ /* Now make the changes */
+ conn = list_of_connected_nodes(ctdb, nodemap, tmp_ctx, true);
+ for (i = 0; i < talloc_array_length(conn); i++) {
+ DEBUG(DEBUG_NOTICE, ("Reloading nodes file on node %u\n",
+ conn[i]));
+ }
+
+ /* Another timeout could be used, such as ReRecoveryTimeout or
+ * a new one for this purpose. However, this is the simplest
+ * option. */
+ timeout = options.timelimit;
+ srvid_broadcast(ctdb, CTDB_SRVID_DISABLE_RECOVERIES, &timeout,
+ "Disable recoveries", true);
+
+
+ ret = ctdb_client_async_control(ctdb, CTDB_CONTROL_RELOAD_NODES_FILE,
+ conn, 0, TIMELIMIT(),
+ true, tdb_null,
+ NULL, reload_nodes_fail_callback,
+ NULL);
+
+ timeout = 0;
+ srvid_broadcast(ctdb, CTDB_SRVID_DISABLE_RECOVERIES, &timeout,
+ "Enable recoveries", true);
+
+ talloc_free(tmp_ctx);
return 0;
}
{ "enablemonitor", control_enable_monmode, true, false, "set monitoring mode to ACTIVE" },
{ "setdebug", control_setdebug, true, false, "set debug level", "<EMERG|ALERT|CRIT|ERR|WARNING|NOTICE|INFO|DEBUG>" },
{ "getdebug", control_getdebug, true, false, "get debug level" },
- { "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>+" },
- { "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"},
{ "moveip", control_moveip, false, false, "move/failover an ip address to another node", "<ip> <node>"},
{ "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, "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", "[<pnn-list>]" },
{ "dbstatistics", control_dbstatistics, false, false, "show db statistics", "<dbname|dbid>" },
{ "reloadips", control_reloadips, false, false, "reload the public addresses file on specified nodes" , "[<pnn-list>]" },
"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 },
int extra_argc = 0;
int ret=-1, i;
poptContext pc;
- struct event_context *ev;
+ struct tevent_context *ev;
const char *control;
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];
- ev = event_context_init(NULL);
+ /* Default value for CTDB_BASE - don't override */
+ setenv("CTDB_BASE", CTDB_ETCDIR, 0);
+
+ ev = tevent_context_init(NULL);
if (!ev) {
DEBUG(DEBUG_ERR, ("Failed to initialize event system\n"));
exit(1);
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"));
+
+ 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();
}