diff options
Diffstat (limited to 'ctdb/tools/ctdb.c')
-rw-r--r-- | ctdb/tools/ctdb.c | 279 |
1 files changed, 186 insertions, 93 deletions
diff --git a/ctdb/tools/ctdb.c b/ctdb/tools/ctdb.c index 793e98f132..f42ecc5f94 100644 --- a/ctdb/tools/ctdb.c +++ b/ctdb/tools/ctdb.c @@ -43,6 +43,7 @@ static void usage(void); static struct { int timelimit; uint32_t pnn; + uint32_t *nodes; int machinereadable; int verbose; int maxruntime; @@ -66,6 +67,11 @@ static int control_version(struct ctdb_context *ctdb, int argc, const char **arg } #endif +#define CTDB_NOMEM_ABORT(p) do { if (!(p)) { \ + DEBUG(DEBUG_ALERT,("ctdb fatal error: %s\n", \ + "Out of memory in " __location__ )); \ + abort(); \ + }} while (0) /* verify that a node exists and is reachable @@ -108,6 +114,146 @@ static void verify_node(struct ctdb_context *ctdb) } } +/* Pretty print the flags to a static buffer in human-readable format. + * This never returns NULL! + */ +static const char *pretty_print_flags(uint32_t flags) +{ + int j; + static const struct { + uint32_t flag; + const char *name; + } flag_names[] = { + { NODE_FLAGS_DISCONNECTED, "DISCONNECTED" }, + { NODE_FLAGS_PERMANENTLY_DISABLED, "DISABLED" }, + { NODE_FLAGS_BANNED, "BANNED" }, + { NODE_FLAGS_UNHEALTHY, "UNHEALTHY" }, + { NODE_FLAGS_DELETED, "DELETED" }, + { NODE_FLAGS_STOPPED, "STOPPED" }, + { NODE_FLAGS_INACTIVE, "INACTIVE" }, + }; + static char flags_str[512]; /* Big enough to contain all flag names */ + + flags_str[0] = '\0'; + for (j=0;j<ARRAY_SIZE(flag_names);j++) { + if (flags & flag_names[j].flag) { + 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); + } + } + } + if (flags_str[0] == '\0') { + (void) strcpy(flags_str, "OK"); + } + + return flags_str; +} + +/* 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 + * nodes are filtered from the "all" case and cause an error if + * explicitly specified. + */ +static bool parse_nodestring(struct ctdb_context *ctdb, + const char * nodestring, + bool dd_ok, + uint32_t **nodes, + uint32_t *pnn_mode) +{ + int n; + uint32_t i; + struct ctdb_node_map *nodemap; + + *nodes = NULL; + + if (!ctdb_getnodemap(ctdb_connection, CTDB_CURRENT_NODE, &nodemap)) { + DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n")); + exit(10); + } + + if (nodestring != NULL) { + *nodes = talloc_array(ctdb, uint32_t, 0); + CTDB_NOMEM_ABORT(*nodes); + + n = 0; + + if (strcmp(nodestring, "all") == 0) { + *pnn_mode = CTDB_BROADCAST_ALL; + + /* all */ + for (i = 0; i < nodemap->num; i++) { + if ((nodemap->nodes[i].flags & + (NODE_FLAGS_DISCONNECTED | + NODE_FLAGS_DELETED)) && !dd_ok) { + continue; + } + *nodes = talloc_realloc(ctdb, *nodes, + uint32_t, n+1); + CTDB_NOMEM_ABORT(*nodes); + (*nodes)[n] = i; + n++; + } + } else { + /* x{,y...} */ + char *ns, *tok; + + ns = talloc_strdup(ctdb, nodestring); + tok = strtok(ns, ","); + while (tok != NULL) { + uint32_t pnn; + i = (uint32_t)strtoul(tok, NULL, 0); + if (i >= nodemap->num) { + DEBUG(DEBUG_ERR, ("Node %u does not exist\n", i)); + 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))); + exit(ERR_DISNODE); + } + if (!ctdb_getpnn(ctdb_connection, i, &pnn)) { + DEBUG(DEBUG_ERR, ("Can not access node %u. Node is not operational.\n", i)); + exit(10); + } + + *nodes = talloc_realloc(ctdb, *nodes, + uint32_t, n+1); + CTDB_NOMEM_ABORT(*nodes); + + (*nodes)[n] = i; + n++; + + tok = strtok(NULL, ","); + } + talloc_free(ns); + + if (n == 1) { + *pnn_mode = (*nodes)[0]; + } else { + *pnn_mode = CTDB_MULTICAST; + } + } + } else { + /* default - no nodes specified */ + *nodes = talloc_array(ctdb, uint32_t, 1); + CTDB_NOMEM_ABORT(*nodes); + + if (!ctdb_getpnn(ctdb_connection, CTDB_CURRENT_NODE, + &((*nodes)[0]))) { + return false; + } + } + + ctdb_free_nodemap(nodemap); + + return true; +} + /* check if a database exists */ @@ -607,6 +753,31 @@ static int control_xpnn(struct ctdb_context *ctdb, int argc, const char **argv) return -1; } +/* Helpers for ctdb status + */ +static bool is_partially_online(struct ctdb_node_and_flags *node) +{ + int j; + bool ret = false; + + if (node->flags == 0) { + struct ctdb_ifaces_list *ifaces; + + if (ctdb_getifaces(ctdb_connection, node->pnn, &ifaces)) { + for (j=0; j < ifaces->num; j++) { + if (ifaces->ifaces[j].link_state != 0) { + continue; + } + ret = true; + break; + } + ctdb_free_ifaces(ifaces); + } + } + + return ret; +} + /* display remote ctdb status */ @@ -633,29 +804,9 @@ static int control_status(struct ctdb_context *ctdb, int argc, const char **argv printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped" ":Inactive:PartiallyOnline:ThisNode:\n"); for (i=0;i<nodemap->num;i++) { - int partially_online = 0; - int j; - if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) { continue; } - if (nodemap->nodes[i].flags == 0) { - struct ctdb_ifaces_list *ifaces; - - ret = ctdb_getifaces(ctdb_connection, - nodemap->nodes[i].pnn, - &ifaces); - if (ret == 0) { - for (j=0; j < ifaces->num; j++) { - if (ifaces->ifaces[j].link_state != 0) { - continue; - } - partially_online = 1; - break; - } - ctdb_free_ifaces(ifaces); - } - } printf(":%d:%s:%d:%d:%d:%d:%d:%d:%d:%c:\n", nodemap->nodes[i].pnn, ctdb_addr_to_str(&nodemap->nodes[i].addr), !!(nodemap->nodes[i].flags&NODE_FLAGS_DISCONNECTED), @@ -664,7 +815,7 @@ static int control_status(struct ctdb_context *ctdb, int argc, const char **argv !!(nodemap->nodes[i].flags&NODE_FLAGS_UNHEALTHY), !!(nodemap->nodes[i].flags&NODE_FLAGS_STOPPED), !!(nodemap->nodes[i].flags&NODE_FLAGS_INACTIVE), - partially_online, + is_partially_online(&nodemap->nodes[i]) ? 1 : 0, (nodemap->nodes[i].pnn == mypnn)?'Y':'N'); } return 0; @@ -672,61 +823,13 @@ static int control_status(struct ctdb_context *ctdb, int argc, const char **argv printf("Number of nodes:%d\n", nodemap->num); for(i=0;i<nodemap->num;i++){ - static const struct { - uint32_t flag; - const char *name; - } flag_names[] = { - { NODE_FLAGS_DISCONNECTED, "DISCONNECTED" }, - { NODE_FLAGS_PERMANENTLY_DISABLED, "DISABLED" }, - { NODE_FLAGS_BANNED, "BANNED" }, - { NODE_FLAGS_UNHEALTHY, "UNHEALTHY" }, - { NODE_FLAGS_DELETED, "DELETED" }, - { NODE_FLAGS_STOPPED, "STOPPED" }, - { NODE_FLAGS_INACTIVE, "INACTIVE" }, - }; - char *flags_str = NULL; - int j; - if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) { continue; } - if (nodemap->nodes[i].flags == 0) { - struct ctdb_control_get_ifaces *ifaces; - - ret = ctdb_ctrl_get_ifaces(ctdb, TIMELIMIT(), - nodemap->nodes[i].pnn, - ctdb, &ifaces); - if (ret == 0) { - for (j=0; j < ifaces->num; j++) { - if (ifaces->ifaces[j].link_state != 0) { - continue; - } - flags_str = talloc_strdup(ctdb, "PARTIALLYONLINE"); - break; - } - talloc_free(ifaces); - } - } - for (j=0;j<ARRAY_SIZE(flag_names);j++) { - if (nodemap->nodes[i].flags & flag_names[j].flag) { - if (flags_str == NULL) { - flags_str = talloc_strdup(ctdb, flag_names[j].name); - } else { - flags_str = talloc_asprintf_append(flags_str, "|%s", - flag_names[j].name); - } - CTDB_NO_MEMORY_FATAL(ctdb, flags_str); - } - } - if (flags_str == NULL) { - flags_str = talloc_strdup(ctdb, "OK"); - CTDB_NO_MEMORY_FATAL(ctdb, flags_str); - } printf("pnn:%d %-16s %s%s\n", nodemap->nodes[i].pnn, ctdb_addr_to_str(&nodemap->nodes[i].addr), - flags_str, + is_partially_online(&nodemap->nodes[i]) ? "PARTIALLYONLINE" : pretty_print_flags(nodemap->nodes[i].flags), nodemap->nodes[i].pnn == mypnn?" (THIS NODE)":""); - talloc_free(flags_str); } ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), options.pnn, ctdb, &vnnmap); @@ -5356,45 +5459,35 @@ int main(int argc, const char *argv[]) exit(1); } - /* setup the node number to contact */ - if (nodestring != NULL) { - if (strcmp(nodestring, "all") == 0) { - options.pnn = CTDB_BROADCAST_ALL; - } else { - options.pnn = strtoul(nodestring, NULL, 0); - } + /* setup the node number(s) to contact */ + if (!parse_nodestring(ctdb, nodestring, true, + &options.nodes, &options.pnn)) { + usage(); } /* verify the node exists */ verify_node(ctdb); if (options.pnn == CTDB_CURRENT_NODE) { - int pnn; - pnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), options.pnn); - if (pnn == -1) { - return -1; - } - options.pnn = pnn; + options.pnn = options.nodes[0]; } if (ctdb_commands[i].auto_all && - options.pnn == CTDB_BROADCAST_ALL) { - uint32_t *nodes; - uint32_t num_nodes; + ((options.pnn == CTDB_BROADCAST_ALL) || + (options.pnn == CTDB_MULTICAST))) { int j; - ret = 0; - nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes); - CTDB_NO_MEMORY(ctdb, nodes); - - for (j=0;j<num_nodes;j++) { - options.pnn = nodes[j]; + ret = 0; + for (j = 0; j < talloc_array_length(options.nodes); j++) { + options.pnn = options.nodes[j]; ret |= ctdb_commands[i].fn(ctdb, extra_argc-1, extra_argv+1); } - talloc_free(nodes); } else { ret = ctdb_commands[i].fn(ctdb, extra_argc-1, extra_argv+1); } + ctdb_disconnect(ctdb_connection); + talloc_free(ctdb); + return ret; } |