4 Copyright (C) Amitay Isaacs 2015
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "system/network.h"
22 #include "system/filesys.h"
23 #include "system/time.h"
24 #include "system/wait.h"
32 #include "ctdb_version.h"
33 #include "lib/util/debug.h"
34 #include "lib/util/samba_util.h"
36 #include "common/db_hash.h"
37 #include "common/logging.h"
38 #include "protocol/protocol.h"
39 #include "protocol/protocol_api.h"
40 #include "common/system.h"
41 #include "client/client.h"
43 #define TIMEOUT() timeval_current_ofs(options.timelimit, 0)
45 #define SRVID_CTDB_TOOL (CTDB_SRVID_TOOL_RANGE | 0x0001000000000000LL)
46 #define SRVID_CTDB_PUSHDB (CTDB_SRVID_TOOL_RANGE | 0x0002000000000000LL)
50 const char *debuglevelstr;
58 int printemptyrecords;
65 static poptContext pc;
68 struct tevent_context *ev;
69 struct ctdb_client_context *client;
70 struct ctdb_node_map *nodemap;
71 uint32_t pnn, cmd_pnn;
75 static void usage(const char *command);
81 static double timeval_delta(struct timeval *tv2, struct timeval *tv)
83 return (tv2->tv_sec - tv->tv_sec) +
84 (tv2->tv_usec - tv->tv_usec) * 1.0e-6;
87 static struct ctdb_node_and_flags *get_node_by_pnn(
88 struct ctdb_node_map *nodemap,
93 for (i=0; i<nodemap->num; i++) {
94 if (nodemap->node[i].pnn == pnn) {
95 return &nodemap->node[i];
101 static const char *pretty_print_flags(TALLOC_CTX *mem_ctx, uint32_t flags)
103 static const struct {
107 { NODE_FLAGS_DISCONNECTED, "DISCONNECTED" },
108 { NODE_FLAGS_PERMANENTLY_DISABLED, "DISABLED" },
109 { NODE_FLAGS_BANNED, "BANNED" },
110 { NODE_FLAGS_UNHEALTHY, "UNHEALTHY" },
111 { NODE_FLAGS_DELETED, "DELETED" },
112 { NODE_FLAGS_STOPPED, "STOPPED" },
113 { NODE_FLAGS_INACTIVE, "INACTIVE" },
115 char *flags_str = NULL;
118 for (i=0; i<ARRAY_SIZE(flag_names); i++) {
119 if (flags & flag_names[i].flag) {
120 if (flags_str == NULL) {
121 flags_str = talloc_asprintf(mem_ctx,
122 "%s", flag_names[i].name);
124 flags_str = talloc_asprintf_append(flags_str,
125 "|%s", flag_names[i].name);
127 if (flags_str == NULL) {
128 return "OUT-OF-MEMORY";
132 if (flags_str == NULL) {
139 static uint64_t next_srvid(struct ctdb_context *ctdb)
146 * Get consistent nodemap information.
148 * If nodemap is already cached, use that. If not get it.
149 * If the current node is BANNED, then get nodemap from "better" node.
151 static struct ctdb_node_map *get_nodemap(struct ctdb_context *ctdb, bool force)
154 struct ctdb_node_map *nodemap;
155 struct ctdb_node_and_flags *node;
156 uint32_t current_node;
160 TALLOC_FREE(ctdb->nodemap);
163 if (ctdb->nodemap != NULL) {
164 return ctdb->nodemap;
167 tmp_ctx = talloc_new(ctdb);
168 if (tmp_ctx == NULL) {
172 current_node = ctdb->pnn;
174 ret = ctdb_ctrl_get_nodemap(tmp_ctx, ctdb->ev, ctdb->client,
175 current_node, TIMEOUT(), &nodemap);
177 fprintf(stderr, "Failed to get nodemap from node %u\n",
182 node = get_node_by_pnn(nodemap, current_node);
183 if (node->flags & NODE_FLAGS_BANNED) {
186 current_node = (current_node + 1) % nodemap->num;
187 node = get_node_by_pnn(nodemap, current_node);
189 (NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED))) {
192 } while (current_node != ctdb->pnn);
194 if (current_node == ctdb->pnn) {
195 /* Tried all nodes in the cluster */
196 fprintf(stderr, "Warning: All nodes are banned.\n");
203 ctdb->nodemap = talloc_steal(ctdb, nodemap);
207 talloc_free(tmp_ctx);
211 static bool verify_pnn(struct ctdb_context *ctdb, int pnn)
213 struct ctdb_node_map *nodemap;
221 nodemap = get_nodemap(ctdb, false);
222 if (nodemap == NULL) {
227 for (i=0; i<nodemap->num; i++) {
228 if (nodemap->node[i].pnn == pnn) {
234 fprintf(stderr, "Node %u does not exist\n", pnn);
238 if (nodemap->node[i].flags &
239 (NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED)) {
240 fprintf(stderr, "Node %u has status %s\n", pnn,
241 pretty_print_flags(ctdb, nodemap->node[i].flags));
248 static struct ctdb_node_map *talloc_nodemap(TALLOC_CTX *mem_ctx,
249 struct ctdb_node_map *nodemap)
251 struct ctdb_node_map *nodemap2;
253 nodemap2 = talloc_zero(mem_ctx, struct ctdb_node_map);
254 if (nodemap2 == NULL) {
258 nodemap2->node = talloc_array(nodemap2, struct ctdb_node_and_flags,
260 if (nodemap2->node == NULL) {
261 talloc_free(nodemap2);
269 * Get the number and the list of matching nodes
271 * nodestring := NULL | all | pnn,[pnn,...]
273 * If nodestring is NULL, use the current node.
275 static bool parse_nodestring(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
276 const char *nodestring,
277 struct ctdb_node_map **out)
279 struct ctdb_node_map *nodemap, *nodemap2;
280 struct ctdb_node_and_flags *node;
283 nodemap = get_nodemap(ctdb, false);
284 if (nodemap == NULL) {
288 nodemap2 = talloc_nodemap(mem_ctx, nodemap);
289 if (nodemap2 == NULL) {
293 if (nodestring == NULL) {
294 for (i=0; i<nodemap->num; i++) {
295 if (nodemap->node[i].pnn == ctdb->cmd_pnn) {
296 nodemap2->node[0] = nodemap->node[i];
305 if (strcmp(nodestring, "all") == 0) {
306 for (i=0; i<nodemap->num; i++) {
307 nodemap2->node[i] = nodemap->node[i];
309 nodemap2->num = nodemap->num;
315 ns = talloc_strdup(mem_ctx, nodestring);
320 tok = strtok(ns, ",");
321 while (tok != NULL) {
325 pnn = (uint32_t)strtoul(tok, &endptr, 0);
326 if (pnn == 0 && tok == endptr) {
327 fprintf(stderr, "Invalid node %s\n", tok);
331 node = get_node_by_pnn(nodemap, pnn);
333 fprintf(stderr, "Node %u does not exist\n",
338 nodemap2->node[nodemap2->num] = *node;
341 tok = strtok(NULL, ",");
350 /* Compare IP address */
351 static bool ctdb_same_ip(ctdb_sock_addr *ip1, ctdb_sock_addr *ip2)
355 if (ip1->sa.sa_family != ip2->sa.sa_family) {
359 switch (ip1->sa.sa_family) {
361 ret = (memcmp(&ip1->ip.sin_addr, &ip2->ip.sin_addr,
362 sizeof(struct in_addr)) == 0);
366 ret = (memcmp(&ip1->ip6.sin6_addr, &ip2->ip6.sin6_addr,
367 sizeof(struct in6_addr)) == 0);
374 /* Append a node to a node map with given address and flags */
375 static bool node_map_add(struct ctdb_node_map *nodemap,
376 const char *nstr, uint32_t flags)
380 struct ctdb_node_and_flags *n;
382 if (! parse_ip(nstr, NULL, 0, &addr)) {
383 fprintf(stderr, "Invalid IP address %s\n", nstr);
388 nodemap->node = talloc_realloc(nodemap, nodemap->node,
389 struct ctdb_node_and_flags, num+1);
390 if (nodemap->node == NULL) {
394 n = &nodemap->node[num];
399 nodemap->num = num+1;
403 /* Read a nodes file into a node map */
404 static struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
410 struct ctdb_node_map *nodemap;
412 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
413 if (nodemap == NULL) {
417 lines = file_lines_load(nlist, &nlines, 0, mem_ctx);
422 while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
426 for (i=0; i<nlines; i++) {
432 /* strip leading spaces */
433 while((*node == ' ') || (*node == '\t')) {
439 /* strip trailing spaces */
441 ((node[len-1] == ' ') || (node[len-1] == '\t')))
451 /* A "deleted" node is a node that is
452 commented out in the nodes file. This is
453 used instead of removing a line, which
454 would cause subsequent nodes to change
456 flags = NODE_FLAGS_DELETED;
457 node = discard_const("0.0.0.0");
461 if (! node_map_add(nodemap, node, flags)) {
463 TALLOC_FREE(nodemap);
472 static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx, uint32_t pnn)
474 struct ctdb_node_map *nodemap;
476 const char *nodes_list = NULL;
478 if (pnn != CTDB_UNKNOWN_PNN) {
479 nodepath = talloc_asprintf(mem_ctx, "CTDB_NODES_%u", pnn);
480 if (nodepath != NULL) {
481 nodes_list = getenv(nodepath);
484 if (nodes_list == NULL) {
485 nodes_list = getenv("CTDB_NODES");
487 if (nodes_list == NULL) {
488 const char *basedir = getenv("CTDB_BASE");
489 if (basedir == NULL) {
490 basedir = CTDB_ETCDIR;
492 nodes_list = talloc_asprintf(mem_ctx, "%s/nodes", basedir);
493 if (nodes_list == NULL) {
494 fprintf(stderr, "Memory allocation error\n");
499 nodemap = ctdb_read_nodes_file(mem_ctx, nodes_list);
500 if (nodemap == NULL) {
501 fprintf(stderr, "Failed to read nodes file \"%s\"\n",
509 static struct ctdb_dbid *db_find(TALLOC_CTX *mem_ctx,
510 struct ctdb_context *ctdb,
511 struct ctdb_dbid_map *dbmap,
514 struct ctdb_dbid *db = NULL;
518 for (i=0; i<dbmap->num; i++) {
519 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
520 ctdb->pnn, TIMEOUT(),
521 dbmap->dbs[i].db_id, &name);
526 if (strcmp(db_name, name) == 0) {
527 talloc_free(discard_const(name));
536 static bool db_exists(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
537 const char *db_arg, uint32_t *db_id,
538 const char **db_name, uint8_t *db_flags)
540 struct ctdb_dbid_map *dbmap;
541 struct ctdb_dbid *db = NULL;
543 const char *name = NULL;
546 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
547 ctdb->pnn, TIMEOUT(), &dbmap);
552 if (strncmp(db_arg, "0x", 2) == 0) {
553 id = strtoul(db_arg, NULL, 0);
554 for (i=0; i<dbmap->num; i++) {
555 if (id == dbmap->dbs[i].db_id) {
562 db = db_find(mem_ctx, ctdb, dbmap, name);
566 fprintf(stderr, "No database matching '%s' found\n", db_arg);
571 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
572 ctdb->pnn, TIMEOUT(), id, &name);
581 if (db_name != NULL) {
582 *db_name = talloc_strdup(mem_ctx, name);
584 if (db_flags != NULL) {
585 *db_flags = db->flags;
590 static int h2i(char h)
592 if (h >= 'a' && h <= 'f') {
595 if (h >= 'A' && h <= 'F') {
601 static int hex_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
608 fprintf(stderr, "Key (%s) contains odd number of hex digits\n",
613 data.dsize = len / 2;
614 data.dptr = talloc_size(mem_ctx, data.dsize);
615 if (data.dptr == NULL) {
619 for (i=0; i<data.dsize; i++) {
620 data.dptr[i] = h2i(str[i*2]) << 4 | h2i(str[i*2+1]);
627 static int str_to_data(const char *str, size_t len, TALLOC_CTX *mem_ctx,
633 if (strncmp(str, "0x", 2) == 0) {
634 ret = hex_to_data(str+2, len-2, mem_ctx, &data);
636 data.dptr = talloc_memdup(mem_ctx, str, len);
637 if (data.dptr == NULL) {
647 static int run_helper(const char *command, const char *path, const char *arg1)
650 int save_errno, status, ret;
655 fprintf(stderr, "Failed to fork %s (%s) - %s\n",
656 command, path, strerror(save_errno));
661 ret = execl(path, path, arg1, NULL);
665 /* Should not happen */
669 ret = waitpid(pid, &status, 0);
672 fprintf(stderr, "waitpid() failed for %s - %s\n",
673 command, strerror(save_errno));
677 if (WIFEXITED(status)) {
678 ret = WEXITSTATUS(status);
682 if (WIFSIGNALED(status)) {
683 fprintf(stderr, "%s terminated with signal %d\n",
684 command, WTERMSIG(status));
695 static int control_version(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
696 int argc, const char **argv)
698 printf("%s\n", CTDB_VERSION_STRING);
702 static bool partially_online(TALLOC_CTX *mem_ctx,
703 struct ctdb_context *ctdb,
704 struct ctdb_node_and_flags *node)
706 struct ctdb_iface_list *iface_list;
710 if (node->flags != 0) {
714 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
715 node->pnn, TIMEOUT(), &iface_list);
721 for (i=0; i < iface_list->num; i++) {
722 if (iface_list->iface[i].link_state == 0) {
731 static void print_nodemap_machine(TALLOC_CTX *mem_ctx,
732 struct ctdb_context *ctdb,
733 struct ctdb_node_map *nodemap,
736 struct ctdb_node_and_flags *node;
739 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
743 "Disconnected", options.sep,
744 "Banned", options.sep,
745 "Disabled", options.sep,
746 "Unhealthy", options.sep,
747 "Stopped", options.sep,
748 "Inactive", options.sep,
749 "PartiallyOnline", options.sep,
750 "ThisNode", options.sep);
752 for (i=0; i<nodemap->num; i++) {
753 node = &nodemap->node[i];
754 if (node->flags & NODE_FLAGS_DELETED) {
758 printf("%s%u%s%s%s%d%s%d%s%d%s%d%s%d%s%d%s%d%s%c%s\n",
760 node->pnn, options.sep,
761 ctdb_sock_addr_to_string(mem_ctx, &node->addr),
763 !! (node->flags & NODE_FLAGS_DISCONNECTED), options.sep,
764 !! (node->flags & NODE_FLAGS_BANNED), options.sep,
765 !! (node->flags & NODE_FLAGS_PERMANENTLY_DISABLED),
767 !! (node->flags & NODE_FLAGS_UNHEALTHY), options.sep,
768 !! (node->flags & NODE_FLAGS_STOPPED), options.sep,
769 !! (node->flags & NODE_FLAGS_INACTIVE), options.sep,
770 partially_online(mem_ctx, ctdb, node), options.sep,
771 (node->pnn == mypnn)?'Y':'N', options.sep);
776 static void print_nodemap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
777 struct ctdb_node_map *nodemap, uint32_t mypnn)
779 struct ctdb_node_and_flags *node;
780 int num_deleted_nodes = 0;
783 for (i=0; i<nodemap->num; i++) {
784 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
789 if (num_deleted_nodes == 0) {
790 printf("Number of nodes:%d\n", nodemap->num);
792 printf("Number of nodes:%d (including %d deleted nodes)\n",
793 nodemap->num, num_deleted_nodes);
796 for (i=0; i<nodemap->num; i++) {
797 node = &nodemap->node[i];
798 if (node->flags & NODE_FLAGS_DELETED) {
802 printf("pnn:%u %-16s %s%s\n",
804 ctdb_sock_addr_to_string(mem_ctx, &node->addr),
805 partially_online(mem_ctx, ctdb, node) ?
807 pretty_print_flags(mem_ctx, node->flags),
808 node->pnn == mypnn ? " (THIS NODE)" : "");
812 static void print_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
813 struct ctdb_node_map *nodemap, uint32_t mypnn,
814 struct ctdb_vnn_map *vnnmap, int recmode,
819 print_nodemap(mem_ctx, ctdb, nodemap, mypnn);
821 if (vnnmap->generation == INVALID_GENERATION) {
822 printf("Generation:INVALID\n");
824 printf("Generation:%u\n", vnnmap->generation);
826 printf("Size:%d\n", vnnmap->size);
827 for (i=0; i<vnnmap->size; i++) {
828 printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]);
831 printf("Recovery mode:%s (%d)\n",
832 recmode == CTDB_RECOVERY_NORMAL ? "NORMAL" : "RECOVERY",
834 printf("Recovery master:%d\n", recmaster);
837 static int control_status(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
838 int argc, const char **argv)
840 struct ctdb_node_map *nodemap;
841 struct ctdb_vnn_map *vnnmap;
850 nodemap = get_nodemap(ctdb, false);
851 if (nodemap == NULL) {
855 if (options.machinereadable == 1) {
856 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
860 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
861 ctdb->cmd_pnn, TIMEOUT(), &vnnmap);
866 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
867 ctdb->cmd_pnn, TIMEOUT(), &recmode);
872 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
873 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
878 print_status(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn, vnnmap,
883 static int control_uptime(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
884 int argc, const char **argv)
886 struct ctdb_uptime *uptime;
887 int ret, tmp, days, hours, minutes, seconds;
889 ret = ctdb_ctrl_uptime(mem_ctx, ctdb->ev, ctdb->client,
890 ctdb->cmd_pnn, TIMEOUT(), &uptime);
895 printf("Current time of node %-4u : %s",
896 ctdb->cmd_pnn, ctime(&uptime->current_time.tv_sec));
898 tmp = uptime->current_time.tv_sec - uptime->ctdbd_start_time.tv_sec;
899 seconds = tmp % 60; tmp /= 60;
900 minutes = tmp % 60; tmp /= 60;
901 hours = tmp % 24; tmp /= 24;
904 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s",
905 days, hours, minutes, seconds,
906 ctime(&uptime->ctdbd_start_time.tv_sec));
908 tmp = uptime->current_time.tv_sec - uptime->last_recovery_finished.tv_sec;
909 seconds = tmp % 60; tmp /= 60;
910 minutes = tmp % 60; tmp /= 60;
911 hours = tmp % 24; tmp /= 24;
914 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s",
915 days, hours, minutes, seconds,
916 ctime(&uptime->last_recovery_finished.tv_sec));
918 printf("Duration of last recovery/failover: %lf seconds\n",
919 timeval_delta(&uptime->last_recovery_finished,
920 &uptime->last_recovery_started));
925 static int control_ping(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
926 int argc, const char **argv)
929 int ret, num_clients;
931 tv = timeval_current();
932 ret = ctdb_ctrl_ping(mem_ctx, ctdb->ev, ctdb->client,
933 ctdb->cmd_pnn, TIMEOUT(), &num_clients);
938 printf("response from %u time=%.6f sec (%d clients)\n",
939 ctdb->cmd_pnn, timeval_elapsed(&tv), num_clients);
943 const char *runstate_to_string(enum ctdb_runstate runstate);
944 enum ctdb_runstate runstate_from_string(const char *runstate_str);
946 static int control_runstate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
947 int argc, const char **argv)
949 enum ctdb_runstate runstate;
953 ret = ctdb_ctrl_get_runstate(mem_ctx, ctdb->ev, ctdb->client,
954 ctdb->cmd_pnn, TIMEOUT(), &runstate);
960 for (i=0; i<argc; i++) {
961 enum ctdb_runstate t;
964 t = ctdb_runstate_from_string(argv[i]);
965 if (t == CTDB_RUNSTATE_UNKNOWN) {
966 printf("Invalid run state (%s)\n", argv[i]);
977 printf("CTDB not in required run state (got %s)\n",
978 ctdb_runstate_to_string(runstate));
982 printf("%s\n", ctdb_runstate_to_string(runstate));
986 static int control_getvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
987 int argc, const char **argv)
989 struct ctdb_var_list *tun_var_list;
998 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
999 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1002 "Failed to get list of variables from node %u\n",
1008 for (i=0; i<tun_var_list->count; i++) {
1009 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1016 printf("No such tunable %s\n", argv[0]);
1020 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
1021 ctdb->cmd_pnn, TIMEOUT(), argv[0], &value);
1026 printf("%-26s = %u\n", argv[0], value);
1030 static int control_setvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1031 int argc, const char **argv)
1033 struct ctdb_var_list *tun_var_list;
1034 struct ctdb_tunable tunable;
1042 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1043 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1046 "Failed to get list of variables from node %u\n",
1052 for (i=0; i<tun_var_list->count; i++) {
1053 if (strcasecmp(tun_var_list->var[i], argv[0]) == 0) {
1060 printf("No such tunable %s\n", argv[0]);
1064 tunable.name = argv[0];
1065 tunable.value = strtoul(argv[1], NULL, 0);
1067 ret = ctdb_ctrl_set_tunable(mem_ctx, ctdb->ev, ctdb->client,
1068 ctdb->cmd_pnn, TIMEOUT(), &tunable);
1072 "Setting obsolete tunable variable '%s'\n",
1081 static int control_listvars(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1082 int argc, const char **argv)
1084 struct ctdb_var_list *tun_var_list;
1091 ret = ctdb_ctrl_list_tunables(mem_ctx, ctdb->ev, ctdb->client,
1092 ctdb->cmd_pnn, TIMEOUT(), &tun_var_list);
1097 for (i=0; i<tun_var_list->count; i++) {
1098 control_getvar(mem_ctx, ctdb, 1, &tun_var_list->var[i]);
1107 } stats_fields[] = {
1108 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
1109 STATISTICS_FIELD(num_clients),
1110 STATISTICS_FIELD(frozen),
1111 STATISTICS_FIELD(recovering),
1112 STATISTICS_FIELD(num_recoveries),
1113 STATISTICS_FIELD(client_packets_sent),
1114 STATISTICS_FIELD(client_packets_recv),
1115 STATISTICS_FIELD(node_packets_sent),
1116 STATISTICS_FIELD(node_packets_recv),
1117 STATISTICS_FIELD(keepalive_packets_sent),
1118 STATISTICS_FIELD(keepalive_packets_recv),
1119 STATISTICS_FIELD(node.req_call),
1120 STATISTICS_FIELD(node.reply_call),
1121 STATISTICS_FIELD(node.req_dmaster),
1122 STATISTICS_FIELD(node.reply_dmaster),
1123 STATISTICS_FIELD(node.reply_error),
1124 STATISTICS_FIELD(node.req_message),
1125 STATISTICS_FIELD(node.req_control),
1126 STATISTICS_FIELD(node.reply_control),
1127 STATISTICS_FIELD(client.req_call),
1128 STATISTICS_FIELD(client.req_message),
1129 STATISTICS_FIELD(client.req_control),
1130 STATISTICS_FIELD(timeouts.call),
1131 STATISTICS_FIELD(timeouts.control),
1132 STATISTICS_FIELD(timeouts.traverse),
1133 STATISTICS_FIELD(locks.num_calls),
1134 STATISTICS_FIELD(locks.num_current),
1135 STATISTICS_FIELD(locks.num_pending),
1136 STATISTICS_FIELD(locks.num_failed),
1137 STATISTICS_FIELD(total_calls),
1138 STATISTICS_FIELD(pending_calls),
1139 STATISTICS_FIELD(childwrite_calls),
1140 STATISTICS_FIELD(pending_childwrite_calls),
1141 STATISTICS_FIELD(memory_used),
1142 STATISTICS_FIELD(max_hop_count),
1143 STATISTICS_FIELD(total_ro_delegations),
1144 STATISTICS_FIELD(total_ro_revokes),
1147 #define LATENCY_AVG(v) ((v).num ? (v).total / (v).num : 0.0 )
1149 static void print_statistics_machine(struct ctdb_statistics *s,
1155 printf("CTDB version%s", options.sep);
1156 printf("Current time of statistics%s", options.sep);
1157 printf("Statistics collected since%s", options.sep);
1158 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1159 printf("%s%s", stats_fields[i].name, options.sep);
1161 printf("num_reclock_ctdbd_latency%s", options.sep);
1162 printf("min_reclock_ctdbd_latency%s", options.sep);
1163 printf("avg_reclock_ctdbd_latency%s", options.sep);
1164 printf("max_reclock_ctdbd_latency%s", options.sep);
1166 printf("num_reclock_recd_latency%s", options.sep);
1167 printf("min_reclock_recd_latency%s", options.sep);
1168 printf("avg_reclock_recd_latency%s", options.sep);
1169 printf("max_reclock_recd_latency%s", options.sep);
1171 printf("num_call_latency%s", options.sep);
1172 printf("min_call_latency%s", options.sep);
1173 printf("avg_call_latency%s", options.sep);
1174 printf("max_call_latency%s", options.sep);
1176 printf("num_lockwait_latency%s", options.sep);
1177 printf("min_lockwait_latency%s", options.sep);
1178 printf("avg_lockwait_latency%s", options.sep);
1179 printf("max_lockwait_latency%s", options.sep);
1181 printf("num_childwrite_latency%s", options.sep);
1182 printf("min_childwrite_latency%s", options.sep);
1183 printf("avg_childwrite_latency%s", options.sep);
1184 printf("max_childwrite_latency%s", options.sep);
1188 printf("%u%s", CTDB_PROTOCOL, options.sep);
1189 printf("%u%s", (uint32_t)s->statistics_current_time.tv_sec, options.sep);
1190 printf("%u%s", (uint32_t)s->statistics_start_time.tv_sec, options.sep);
1191 for (i=0;i<ARRAY_SIZE(stats_fields);i++) {
1193 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s),
1196 printf("%u%s", s->reclock.ctdbd.num, options.sep);
1197 printf("%.6f%s", s->reclock.ctdbd.min, options.sep);
1198 printf("%.6f%s", LATENCY_AVG(s->reclock.ctdbd), options.sep);
1199 printf("%.6f%s", s->reclock.ctdbd.max, options.sep);
1201 printf("%u%s", s->reclock.recd.num, options.sep);
1202 printf("%.6f%s", s->reclock.recd.min, options.sep);
1203 printf("%.6f%s", LATENCY_AVG(s->reclock.recd), options.sep);
1204 printf("%.6f%s", s->reclock.recd.max, options.sep);
1206 printf("%d%s", s->call_latency.num, options.sep);
1207 printf("%.6f%s", s->call_latency.min, options.sep);
1208 printf("%.6f%s", LATENCY_AVG(s->call_latency), options.sep);
1209 printf("%.6f%s", s->call_latency.max, options.sep);
1211 printf("%d%s", s->childwrite_latency.num, options.sep);
1212 printf("%.6f%s", s->childwrite_latency.min, options.sep);
1213 printf("%.6f%s", LATENCY_AVG(s->childwrite_latency), options.sep);
1214 printf("%.6f%s", s->childwrite_latency.max, options.sep);
1218 static void print_statistics(struct ctdb_statistics *s)
1220 int tmp, days, hours, minutes, seconds;
1222 const char *prefix = NULL;
1225 tmp = s->statistics_current_time.tv_sec -
1226 s->statistics_start_time.tv_sec;
1227 seconds = tmp % 60; tmp /= 60;
1228 minutes = tmp % 60; tmp /= 60;
1229 hours = tmp % 24; tmp /= 24;
1232 printf("CTDB version %u\n", CTDB_PROTOCOL);
1233 printf("Current time of statistics : %s",
1234 ctime(&s->statistics_current_time.tv_sec));
1235 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s",
1236 days, hours, minutes, seconds,
1237 ctime(&s->statistics_start_time.tv_sec));
1239 for (i=0; i<ARRAY_SIZE(stats_fields); i++) {
1240 if (strchr(stats_fields[i].name, '.') != NULL) {
1241 preflen = strcspn(stats_fields[i].name, ".") + 1;
1243 strncmp(prefix, stats_fields[i].name, preflen) != 0) {
1244 prefix = stats_fields[i].name;
1245 printf(" %*.*s\n", preflen-1, preflen-1,
1246 stats_fields[i].name);
1251 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
1252 stats_fields[i].name+preflen, preflen ? 0 : 4, "",
1253 *(uint32_t *)(stats_fields[i].offset+(uint8_t *)s));
1256 printf(" hop_count_buckets:");
1257 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1258 printf(" %d", s->hop_count_bucket[i]);
1261 printf(" lock_buckets:");
1262 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
1263 printf(" %d", s->locks.buckets[i]);
1266 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1267 "locks_latency MIN/AVG/MAX",
1268 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
1269 s->locks.latency.max, s->locks.latency.num);
1271 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1272 "reclock_ctdbd MIN/AVG/MAX",
1273 s->reclock.ctdbd.min, LATENCY_AVG(s->reclock.ctdbd),
1274 s->reclock.ctdbd.max, s->reclock.ctdbd.num);
1276 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1277 "reclock_recd MIN/AVG/MAX",
1278 s->reclock.recd.min, LATENCY_AVG(s->reclock.recd),
1279 s->reclock.recd.max, s->reclock.recd.num);
1281 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1282 "call_latency MIN/AVG/MAX",
1283 s->call_latency.min, LATENCY_AVG(s->call_latency),
1284 s->call_latency.max, s->call_latency.num);
1286 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
1287 "childwrite_latency MIN/AVG/MAX",
1288 s->childwrite_latency.min,
1289 LATENCY_AVG(s->childwrite_latency),
1290 s->childwrite_latency.max, s->childwrite_latency.num);
1293 static int control_statistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1294 int argc, const char **argv)
1296 struct ctdb_statistics *stats;
1300 usage("statistics");
1303 ret = ctdb_ctrl_statistics(mem_ctx, ctdb->ev, ctdb->client,
1304 ctdb->cmd_pnn, TIMEOUT(), &stats);
1309 if (options.machinereadable) {
1310 print_statistics_machine(stats, true);
1312 print_statistics(stats);
1318 static int control_statistics_reset(TALLOC_CTX *mem_ctx,
1319 struct ctdb_context *ctdb,
1320 int argc, const char **argv)
1325 usage("statisticsreset");
1328 ret = ctdb_ctrl_statistics_reset(mem_ctx, ctdb->ev, ctdb->client,
1329 ctdb->cmd_pnn, TIMEOUT());
1337 static int control_stats(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1338 int argc, const char **argv)
1340 struct ctdb_statistics_list *slist;
1341 int ret, count = 0, i;
1342 bool show_header = true;
1349 count = atoi(argv[0]);
1352 ret = ctdb_ctrl_get_stat_history(mem_ctx, ctdb->ev, ctdb->client,
1353 ctdb->cmd_pnn, TIMEOUT(), &slist);
1358 for (i=0; i<slist->num; i++) {
1359 if (slist->stats[i].statistics_start_time.tv_sec == 0) {
1362 if (options.machinereadable == 1) {
1363 print_statistics_machine(&slist->stats[i],
1365 show_header = false;
1367 print_statistics(&slist->stats[i]);
1369 if (count > 0 && i == count) {
1377 static void print_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1378 struct ctdb_public_ip_list *ips,
1379 struct ctdb_public_ip_info **ipinfo,
1383 char *conf, *avail, *active;
1385 if (options.machinereadable == 1) {
1386 printf("%s%s%s%s%s", options.sep,
1387 "Public IP", options.sep,
1388 "Node", options.sep);
1389 if (options.verbose == 1) {
1390 printf("%s%s%s%s%s%s\n",
1391 "ActiveInterfaces", options.sep,
1392 "AvailableInterfaces", options.sep,
1393 "ConfiguredInterfaces", options.sep);
1399 printf("Public IPs on ALL nodes\n");
1401 printf("Public IPs on node %u\n", ctdb->cmd_pnn);
1405 /* IPs are reverse sorted */
1406 for (i=ips->num-1; i>=0; i--) {
1408 if (options.machinereadable == 1) {
1409 printf("%s%s%s%d%s", options.sep,
1410 ctdb_sock_addr_to_string(
1411 mem_ctx, &ips->ip[i].addr),
1413 (int)ips->ip[i].pnn, options.sep);
1415 printf("%s", ctdb_sock_addr_to_string(
1416 mem_ctx, &ips->ip[i].addr));
1419 if (options.verbose == 0) {
1420 if (options.machinereadable == 1) {
1423 printf(" %d\n", (int)ips->ip[i].pnn);
1432 for (j=0; j<ipinfo[i]->ifaces->num; j++) {
1433 struct ctdb_iface *iface;
1435 iface = &ipinfo[i]->ifaces->iface[j];
1437 conf = talloc_strdup(mem_ctx, iface->name);
1439 conf = talloc_asprintf_append(
1440 mem_ctx, ",%s", iface->name);
1443 if (ipinfo[i]->active_idx == j) {
1444 active = iface->name;
1447 if (iface->link_state == 0) {
1451 if (avail == NULL) {
1452 avail = talloc_strdup(mem_ctx, iface->name);
1454 avail = talloc_asprintf_append(
1455 mem_ctx, ",%s", iface->name);
1459 if (options.machinereadable == 1) {
1460 printf("%s%s%s%s%s%s\n",
1461 active ? active : "", options.sep,
1462 avail ? avail : "", options.sep,
1463 conf ? conf : "", options.sep);
1465 printf(" node[%u] active[%s] available[%s] configured[%s]\n",
1466 ips->ip[i].pnn, active ? active : "",
1467 avail ? avail : "", conf ? conf : "");
1472 static int collect_ips(uint8_t *keybuf, size_t keylen, uint8_t *databuf,
1473 size_t datalen, void *private_data)
1475 struct ctdb_public_ip_list *ips = talloc_get_type_abort(
1476 private_data, struct ctdb_public_ip_list);
1477 struct ctdb_public_ip *ip;
1479 ip = (struct ctdb_public_ip *)databuf;
1480 ips->ip[ips->num] = *ip;
1486 static int get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
1487 struct ctdb_public_ip_list **out)
1489 struct ctdb_node_map *nodemap;
1490 struct ctdb_public_ip_list *ips;
1491 struct db_hash_context *ipdb;
1493 int ret, count, i, j;
1495 nodemap = get_nodemap(ctdb, false);
1496 if (nodemap == NULL) {
1500 ret = db_hash_init(mem_ctx, "ips", 101, DB_HASH_COMPLEX, &ipdb);
1505 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
1511 for (i=0; i<count; i++) {
1512 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1513 pnn_list[i], TIMEOUT(), &ips);
1518 for (j=0; j<ips->num; j++) {
1519 struct ctdb_public_ip ip;
1521 ip.pnn = ips->ip[j].pnn;
1522 ip.addr = ips->ip[j].addr;
1524 ret = db_hash_add(ipdb, (uint8_t *)&ip.addr,
1526 (uint8_t *)&ip, sizeof(ip));
1535 talloc_free(pnn_list);
1537 ret = db_hash_traverse(ipdb, NULL, NULL, &count);
1542 ips = talloc_zero(mem_ctx, struct ctdb_public_ip_list);
1547 ips->ip = talloc_array(ips, struct ctdb_public_ip, count);
1548 if (ips->ip == NULL) {
1552 ret = db_hash_traverse(ipdb, collect_ips, ips, &count);
1557 if (count != ips->num) {
1571 static int control_ip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1572 int argc, const char **argv)
1574 struct ctdb_public_ip_list *ips;
1575 struct ctdb_public_ip_info **ipinfo;
1577 bool do_all = false;
1584 if (strcmp(argv[0], "all") == 0) {
1592 ret = get_all_public_ips(ctdb, mem_ctx, &ips);
1594 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
1595 ctdb->cmd_pnn, TIMEOUT(), &ips);
1601 ipinfo = talloc_array(mem_ctx, struct ctdb_public_ip_info *, ips->num);
1602 if (ipinfo == NULL) {
1606 for (i=0; i<ips->num; i++) {
1609 pnn = ips->ip[i].pnn;
1611 pnn = ctdb->cmd_pnn;
1613 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev,
1615 TIMEOUT(), &ips->ip[i].addr,
1622 print_ip(mem_ctx, ctdb, ips, ipinfo, do_all);
1626 static int control_ipinfo(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1627 int argc, const char **argv)
1629 struct ctdb_public_ip_info *ipinfo;
1630 ctdb_sock_addr addr;
1637 if (! parse_ip(argv[0], NULL, 0, &addr)) {
1638 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
1642 ret = ctdb_ctrl_get_public_ip_info(mem_ctx, ctdb->ev, ctdb->client,
1643 ctdb->cmd_pnn, TIMEOUT(), &addr,
1647 printf("Node %u does not know about IP %s\n",
1648 ctdb->cmd_pnn, argv[0]);
1653 printf("Public IP[%s] info on node %u\n",
1654 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr),
1657 printf("IP:%s\nCurrentNode:%u\nNumInterfaces:%u\n",
1658 ctdb_sock_addr_to_string(mem_ctx, &ipinfo->ip.addr),
1659 ipinfo->ip.pnn, ipinfo->ifaces->num);
1661 for (i=0; i<ipinfo->ifaces->num; i++) {
1662 struct ctdb_iface *iface;
1664 iface = &ipinfo->ifaces->iface[i];
1665 iface->name[CTDB_IFACE_SIZE] = '\0';
1666 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
1668 iface->link_state == 0 ? "down" : "up",
1670 (i == ipinfo->active_idx) ? " (active)" : "");
1676 static int control_ifaces(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1677 int argc, const char **argv)
1679 struct ctdb_iface_list *ifaces;
1686 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1687 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1692 if (ifaces->num == 0) {
1693 printf("No interfaces configured on node %u\n",
1698 if (options.machinereadable) {
1699 printf("%s%s%s%s%s%s%s\n", options.sep,
1700 "Name", options.sep,
1701 "LinkStatus", options.sep,
1702 "References", options.sep);
1704 printf("Interfaces on node %u\n", ctdb->cmd_pnn);
1707 for (i=0; i<ifaces->num; i++) {
1708 if (options.machinereadable) {
1709 printf("%s%s%s%u%s%u%s\n", options.sep,
1710 ifaces->iface[i].name, options.sep,
1711 ifaces->iface[i].link_state, options.sep,
1712 ifaces->iface[i].references, options.sep);
1714 printf("name:%s link:%s references:%u\n",
1715 ifaces->iface[i].name,
1716 ifaces->iface[i].link_state ? "up" : "down",
1717 ifaces->iface[i].references);
1724 static int control_setifacelink(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1725 int argc, const char **argv)
1727 struct ctdb_iface_list *ifaces;
1728 struct ctdb_iface *iface;
1732 usage("setifacelink");
1735 if (strlen(argv[0]) > CTDB_IFACE_SIZE) {
1736 fprintf(stderr, "Interface name '%s' too long\n", argv[0]);
1740 ret = ctdb_ctrl_get_ifaces(mem_ctx, ctdb->ev, ctdb->client,
1741 ctdb->cmd_pnn, TIMEOUT(), &ifaces);
1744 "Failed to get interface information from node %u\n",
1750 for (i=0; i<ifaces->num; i++) {
1751 if (strcmp(ifaces->iface[i].name, argv[0]) == 0) {
1752 iface = &ifaces->iface[i];
1757 if (iface == NULL) {
1758 printf("Interface %s not configured on node %u\n",
1759 argv[0], ctdb->cmd_pnn);
1763 if (strcmp(argv[1], "up") == 0) {
1764 iface->link_state = 1;
1765 } else if (strcmp(argv[1], "down") == 0) {
1766 iface->link_state = 0;
1768 usage("setifacelink");
1772 iface->references = 0;
1774 ret = ctdb_ctrl_set_iface_link_state(mem_ctx, ctdb->ev, ctdb->client,
1775 ctdb->cmd_pnn, TIMEOUT(), iface);
1783 static int control_process_exists(TALLOC_CTX *mem_ctx,
1784 struct ctdb_context *ctdb,
1785 int argc, const char **argv)
1791 usage("process-exists");
1794 pid = atoi(argv[0]);
1795 ret = ctdb_ctrl_process_exists(mem_ctx, ctdb->ev, ctdb->client,
1796 ctdb->cmd_pnn, TIMEOUT(), pid, &status);
1802 printf("PID %u exists\n", pid);
1804 printf("PID %u does not exist\n", pid);
1809 static int control_getdbmap(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1810 int argc, const char **argv)
1812 struct ctdb_dbid_map *dbmap;
1819 ret = ctdb_ctrl_get_dbmap(mem_ctx, ctdb->ev, ctdb->client,
1820 ctdb->cmd_pnn, TIMEOUT(), &dbmap);
1825 if (options.machinereadable == 1) {
1826 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
1829 "Name", options.sep,
1830 "Path", options.sep,
1831 "Persistent", options.sep,
1832 "Sticky", options.sep,
1833 "Unhealthy", options.sep,
1834 "Readonly", options.sep);
1836 printf("Number of databases:%d\n", dbmap->num);
1839 for (i=0; i<dbmap->num; i++) {
1848 db_id = dbmap->dbs[i].db_id;
1850 ret = ctdb_ctrl_get_dbname(mem_ctx, ctdb->ev, ctdb->client,
1851 ctdb->cmd_pnn, TIMEOUT(), db_id,
1857 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
1858 ctdb->cmd_pnn, TIMEOUT(), db_id,
1864 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
1865 ctdb->cmd_pnn, TIMEOUT(), db_id,
1871 persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT;
1872 readonly = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY;
1873 sticky = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY;
1875 if (options.machinereadable == 1) {
1876 printf("%s0x%08X%s%s%s%s%s%d%s%d%s%d%s%d%s\n",
1881 !! (persistent), options.sep,
1882 !! (sticky), options.sep,
1883 !! (health), options.sep,
1884 !! (readonly), options.sep);
1886 printf("dbid:0x%08x name:%s path:%s%s%s%s%s\n",
1888 persistent ? " PERSISTENT" : "",
1889 sticky ? " STICKY" : "",
1890 readonly ? " READONLY" : "",
1891 health ? " UNHEALTHY" : "");
1894 talloc_free(discard_const(name));
1895 talloc_free(discard_const(path));
1896 talloc_free(discard_const(health));
1902 static int control_getdbstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
1903 int argc, const char **argv)
1906 const char *db_name, *db_path, *db_health;
1911 usage("getdbstatus");
1914 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
1918 ret = ctdb_ctrl_getdbpath(mem_ctx, ctdb->ev, ctdb->client,
1919 ctdb->cmd_pnn, TIMEOUT(), db_id,
1925 ret = ctdb_ctrl_db_get_health(mem_ctx, ctdb->ev, ctdb->client,
1926 ctdb->cmd_pnn, TIMEOUT(), db_id,
1932 printf("dbid: 0x%08x\nname: %s\npath: %s\n", db_id, db_name, db_path);
1933 printf("PERSISTENT: %s\nSTICKY: %s\nREADONLY: %s\nHEALTH: %s\n",
1934 (db_flags & CTDB_DB_FLAGS_PERSISTENT ? "yes" : "no"),
1935 (db_flags & CTDB_DB_FLAGS_STICKY ? "yes" : "no"),
1936 (db_flags & CTDB_DB_FLAGS_READONLY ? "yes" : "no"),
1937 (db_health ? db_health : "OK"));
1941 struct dump_record_state {
1945 #define ISASCII(x) (isprint(x) && ! strchr("\"\\", (x)))
1947 static void dump_tdb_data(const char *name, TDB_DATA val)
1951 fprintf(stdout, "%s(%zu) = \"", name, val.dsize);
1952 for (i=0; i<val.dsize; i++) {
1953 if (ISASCII(val.dptr[i])) {
1954 fprintf(stdout, "%c", val.dptr[i]);
1956 fprintf(stdout, "\\%02X", val.dptr[i]);
1959 fprintf(stdout, "\"\n");
1962 static void dump_ltdb_header(struct ctdb_ltdb_header *header)
1964 fprintf(stdout, "dmaster: %u\n", header->dmaster);
1965 fprintf(stdout, "rsn: %" PRIu64 "\n", header->rsn);
1966 fprintf(stdout, "flags: 0x%08x", header->flags);
1967 if (header->flags & CTDB_REC_FLAG_MIGRATED_WITH_DATA) {
1968 fprintf(stdout, " MIGRATED_WITH_DATA");
1970 if (header->flags & CTDB_REC_FLAG_VACUUM_MIGRATED) {
1971 fprintf(stdout, " VACUUM_MIGRATED");
1973 if (header->flags & CTDB_REC_FLAG_AUTOMATIC) {
1974 fprintf(stdout, " AUTOMATIC");
1976 if (header->flags & CTDB_REC_RO_HAVE_DELEGATIONS) {
1977 fprintf(stdout, " RO_HAVE_DELEGATIONS");
1979 if (header->flags & CTDB_REC_RO_HAVE_READONLY) {
1980 fprintf(stdout, " RO_HAVE_READONLY");
1982 if (header->flags & CTDB_REC_RO_REVOKING_READONLY) {
1983 fprintf(stdout, " RO_REVOKING_READONLY");
1985 if (header->flags & CTDB_REC_RO_REVOKE_COMPLETE) {
1986 fprintf(stdout, " RO_REVOKE_COMPLETE");
1988 fprintf(stdout, "\n");
1992 static int dump_record(uint32_t reqid, struct ctdb_ltdb_header *header,
1993 TDB_DATA key, TDB_DATA data, void *private_data)
1995 struct dump_record_state *state =
1996 (struct dump_record_state *)private_data;
2000 dump_tdb_data("key", key);
2001 dump_ltdb_header(header);
2002 dump_tdb_data("data", data);
2003 fprintf(stdout, "\n");
2008 struct traverse_state {
2009 TALLOC_CTX *mem_ctx;
2011 ctdb_rec_parser_func_t func;
2012 struct dump_record_state sub_state;
2015 static void traverse_handler(uint64_t srvid, TDB_DATA data, void *private_data)
2017 struct traverse_state *state = (struct traverse_state *)private_data;
2018 struct ctdb_rec_data *rec;
2019 struct ctdb_ltdb_header header;
2022 ret = ctdb_rec_data_pull(data.dptr, data.dsize, state->mem_ctx, &rec);
2027 if (rec->key.dsize == 0 && rec->data.dsize == 0) {
2029 /* end of traverse */
2034 ret = ctdb_ltdb_header_extract(&rec->data, &header);
2040 if (rec->data.dsize == 0) {
2045 ret = state->func(rec->reqid, &header, rec->key, rec->data,
2053 static int control_catdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2054 int argc, const char **argv)
2056 struct ctdb_db_context *db;
2057 const char *db_name;
2060 struct ctdb_traverse_start_ext traverse;
2061 struct traverse_state state;
2068 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2072 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2075 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2080 ZERO_STRUCT(traverse);
2082 traverse.db_id = db_id;
2084 traverse.srvid = next_srvid(ctdb);
2085 traverse.withemptyrecords = false;
2087 state.mem_ctx = mem_ctx;
2089 state.func = dump_record;
2090 state.sub_state.count = 0;
2092 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2094 traverse_handler, &state);
2099 ret = ctdb_ctrl_traverse_start_ext(mem_ctx, ctdb->ev, ctdb->client,
2100 ctdb->cmd_pnn, TIMEOUT(),
2106 ctdb_client_wait(ctdb->ev, &state.done);
2108 printf("Dumped %u records\n", state.sub_state.count);
2110 ret = ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
2111 traverse.srvid, &state);
2119 static int control_cattdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2120 int argc, const char **argv)
2122 struct ctdb_db_context *db;
2123 const char *db_name;
2126 struct dump_record_state state;
2133 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
2137 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2140 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
2145 ret = ctdb_db_traverse(db, true, true, dump_record, &state);
2147 printf("Dumped %u record(s)\n", state.count);
2152 static int control_getmonmode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2153 int argc, const char **argv)
2158 usage("getmonmode");
2161 ret = ctdb_ctrl_get_monmode(mem_ctx, ctdb->ev, ctdb->client,
2162 ctdb->cmd_pnn, TIMEOUT(), &mode);
2168 (mode == CTDB_MONITORING_ENABLED) ? "ENABLED" : "DISABLED");
2172 static int control_getcapabilities(TALLOC_CTX *mem_ctx,
2173 struct ctdb_context *ctdb,
2174 int argc, const char **argv)
2180 usage("getcapabilities");
2183 ret = ctdb_ctrl_get_capabilities(mem_ctx, ctdb->ev, ctdb->client,
2184 ctdb->cmd_pnn, TIMEOUT(), &caps);
2189 if (options.machinereadable == 1) {
2190 printf("%s%s%s%s%s\n",
2192 "RECMASTER", options.sep,
2193 "LMASTER", options.sep);
2194 printf("%s%d%s%d%s\n", options.sep,
2195 !! (caps & CTDB_CAP_RECMASTER), options.sep,
2196 !! (caps & CTDB_CAP_LMASTER), options.sep);
2198 printf("RECMASTER: %s\n",
2199 (caps & CTDB_CAP_RECMASTER) ? "YES" : "NO");
2200 printf("LMASTER: %s\n",
2201 (caps & CTDB_CAP_LMASTER) ? "YES" : "NO");
2207 static int control_pnn(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2208 int argc, const char **argv)
2210 printf("%u\n", ctdb_client_pnn(ctdb->client));
2214 static int control_lvs(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2215 int argc, const char **argv)
2217 char *t, *lvs_helper = NULL;
2223 t = getenv("CTDB_LVS_HELPER");
2225 lvs_helper = talloc_strdup(mem_ctx, t);
2227 lvs_helper = talloc_asprintf(mem_ctx, "%s/ctdb_lvs",
2228 CTDB_HELPER_BINDIR);
2231 if (lvs_helper == NULL) {
2232 fprintf(stderr, "Unable to set LVS helper\n");
2236 return run_helper("LVS helper", lvs_helper, argv[0]);
2239 static int control_disable_monitor(TALLOC_CTX *mem_ctx,
2240 struct ctdb_context *ctdb,
2241 int argc, const char **argv)
2246 usage("disablemonitor");
2249 ret = ctdb_ctrl_disable_monitor(mem_ctx, ctdb->ev, ctdb->client,
2250 ctdb->cmd_pnn, TIMEOUT());
2258 static int control_enable_monitor(TALLOC_CTX *mem_ctx,
2259 struct ctdb_context *ctdb,
2260 int argc, const char **argv)
2265 usage("enablemonitor");
2268 ret = ctdb_ctrl_enable_monitor(mem_ctx, ctdb->ev, ctdb->client,
2269 ctdb->cmd_pnn, TIMEOUT());
2277 static int control_setdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2278 int argc, const char **argv)
2280 enum debug_level log_level;
2288 found = debug_level_parse(argv[0], &log_level);
2291 "Invalid debug level '%s'. Valid levels are:\n",
2293 fprintf(stderr, "\tERROR | WARNING | NOTICE | INFO | DEBUG\n");
2297 ret = ctdb_ctrl_setdebug(mem_ctx, ctdb->ev, ctdb->client,
2298 ctdb->cmd_pnn, TIMEOUT(), log_level);
2306 static int control_getdebug(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2307 int argc, const char **argv)
2309 enum debug_level loglevel;
2310 const char *log_str;
2317 ret = ctdb_ctrl_getdebug(mem_ctx, ctdb->ev, ctdb->client,
2318 ctdb->cmd_pnn, TIMEOUT(), &loglevel);
2323 log_str = debug_level_to_string(loglevel);
2324 printf("%s\n", log_str);
2329 static int control_attach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2330 int argc, const char **argv)
2332 const char *db_name;
2333 uint8_t db_flags = 0;
2336 if (argc < 1 || argc > 2) {
2342 if (strcmp(argv[1], "persistent") == 0) {
2343 db_flags = CTDB_DB_FLAGS_PERSISTENT;
2344 } else if (strcmp(argv[1], "readonly") == 0) {
2345 db_flags = CTDB_DB_FLAGS_READONLY;
2346 } else if (strcmp(argv[1], "sticky") == 0) {
2347 db_flags = CTDB_DB_FLAGS_STICKY;
2353 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
2362 static int control_detach(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2363 int argc, const char **argv)
2365 const char *db_name;
2368 struct ctdb_node_map *nodemap;
2376 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2377 ctdb->cmd_pnn, TIMEOUT(), &recmode);
2382 if (recmode == CTDB_RECOVERY_ACTIVE) {
2383 fprintf(stderr, "Database cannot be detached"
2384 " when recovery is active\n");
2388 nodemap = get_nodemap(ctdb, false);
2389 if (nodemap == NULL) {
2393 for (i=0; i<nodemap->num; i++) {
2396 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
2399 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
2402 if (nodemap->node[i].flags & NODE_FLAGS_INACTIVE) {
2403 fprintf(stderr, "Database cannot be detached on"
2404 " inactive (stopped or banned) node %u\n",
2405 nodemap->node[i].pnn);
2409 ret = ctdb_ctrl_get_tunable(mem_ctx, ctdb->ev, ctdb->client,
2410 nodemap->node[i].pnn, TIMEOUT(),
2411 "AllowClientDBAttach", &value);
2414 "Unable to get tunable AllowClientDBAttach"
2415 " from node %u\n", nodemap->node[i].pnn);
2421 "Database access is still active on node %u."
2422 " Set AllowclientDBAttach=0 on all nodes.\n",
2423 nodemap->node[i].pnn);
2429 for (i=0; i<argc; i++) {
2430 if (! db_exists(mem_ctx, ctdb, argv[i], &db_id, &db_name,
2435 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
2437 "Persistent database %s cannot be detached\n",
2442 ret = ctdb_detach(mem_ctx, ctdb->ev, ctdb->client,
2445 fprintf(stderr, "Database %s detach failed\n", db_name);
2453 static int control_dumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2454 int argc, const char **argv)
2456 const char *mem_str;
2460 ret = ctdb_ctrl_dump_memory(mem_ctx, ctdb->ev, ctdb->client,
2461 ctdb->cmd_pnn, TIMEOUT(), &mem_str);
2466 n = write(1, mem_str, strlen(mem_str)+1);
2467 if (n < 0 || n != strlen(mem_str)+1) {
2468 fprintf(stderr, "Failed to write talloc summary\n");
2475 static void dump_memory(uint64_t srvid, TDB_DATA data, void *private_data)
2477 bool *done = (bool *)private_data;
2480 n = write(1, data.dptr, data.dsize);
2481 if (n < 0 || n != data.dsize) {
2482 fprintf(stderr, "Failed to write talloc summary\n");
2488 static int control_rddumpmemory(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2489 int argc, const char **argv)
2491 struct ctdb_srvid_message msg = { 0 };
2495 msg.pnn = ctdb->pnn;
2496 msg.srvid = next_srvid(ctdb);
2498 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2499 msg.srvid, dump_memory, &done);
2504 ret = ctdb_message_mem_dump(mem_ctx, ctdb->ev, ctdb->client,
2505 ctdb->cmd_pnn, &msg);
2510 ctdb_client_wait(ctdb->ev, &done);
2514 static int control_getpid(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2515 int argc, const char **argv)
2520 ret = ctdb_ctrl_get_pid(mem_ctx, ctdb->ev, ctdb->client,
2521 ctdb->cmd_pnn, TIMEOUT(), &pid);
2526 printf("%u\n", pid);
2530 static int check_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2531 const char *desc, uint32_t flag, bool set_flag)
2533 struct ctdb_node_map *nodemap;
2536 nodemap = get_nodemap(ctdb, false);
2537 if (nodemap == NULL) {
2541 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2542 if (set_flag == flag_is_set) {
2544 fprintf(stderr, "Node %u is already %s\n",
2545 ctdb->cmd_pnn, desc);
2547 fprintf(stderr, "Node %u is not %s\n",
2548 ctdb->cmd_pnn, desc);
2556 static void wait_for_flags(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2557 uint32_t flag, bool set_flag)
2559 struct ctdb_node_map *nodemap;
2563 nodemap = get_nodemap(ctdb, true);
2564 if (nodemap == NULL) {
2566 "Failed to get nodemap, trying again\n");
2571 flag_is_set = nodemap->node[ctdb->cmd_pnn].flags & flag;
2572 if (flag_is_set == set_flag) {
2580 struct ipreallocate_state {
2585 static void ipreallocate_handler(uint64_t srvid, TDB_DATA data,
2588 struct ipreallocate_state *state =
2589 (struct ipreallocate_state *)private_data;
2591 if (data.dsize != sizeof(int)) {
2596 state->status = *(int *)data.dptr;
2600 static int ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb)
2602 struct ctdb_srvid_message msg = { 0 };
2603 struct ipreallocate_state state;
2606 msg.pnn = ctdb->pnn;
2607 msg.srvid = next_srvid(ctdb);
2610 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
2612 ipreallocate_handler, &state);
2618 ret = ctdb_message_takeover_run(mem_ctx, ctdb->ev,
2620 CTDB_BROADCAST_CONNECTED,
2626 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done,
2632 if (state.status >= 0) {
2641 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
2646 static int control_disable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2647 int argc, const char **argv)
2655 ret = check_flags(mem_ctx, ctdb, "disabled",
2656 NODE_FLAGS_PERMANENTLY_DISABLED, true);
2661 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2662 ctdb->cmd_pnn, TIMEOUT(),
2663 NODE_FLAGS_PERMANENTLY_DISABLED, 0);
2666 "Failed to set DISABLED flag on node %u\n",
2671 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, true);
2672 return ipreallocate(mem_ctx, ctdb);
2675 static int control_enable(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2676 int argc, const char **argv)
2684 ret = check_flags(mem_ctx, ctdb, "disabled",
2685 NODE_FLAGS_PERMANENTLY_DISABLED, false);
2690 ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
2691 ctdb->cmd_pnn, TIMEOUT(),
2692 0, NODE_FLAGS_PERMANENTLY_DISABLED);
2694 fprintf(stderr, "Failed to reset DISABLED flag on node %u\n",
2699 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_PERMANENTLY_DISABLED, false);
2700 return ipreallocate(mem_ctx, ctdb);
2703 static int control_stop(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2704 int argc, const char **argv)
2712 ret = check_flags(mem_ctx, ctdb, "stopped",
2713 NODE_FLAGS_STOPPED, true);
2718 ret = ctdb_ctrl_stop_node(mem_ctx, ctdb->ev, ctdb->client,
2719 ctdb->cmd_pnn, TIMEOUT());
2721 fprintf(stderr, "Failed to stop node %u\n", ctdb->cmd_pnn);
2725 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, true);
2726 return ipreallocate(mem_ctx, ctdb);
2729 static int control_continue(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2730 int argc, const char **argv)
2738 ret = check_flags(mem_ctx, ctdb, "stopped",
2739 NODE_FLAGS_STOPPED, false);
2744 ret = ctdb_ctrl_continue_node(mem_ctx, ctdb->ev, ctdb->client,
2745 ctdb->cmd_pnn, TIMEOUT());
2747 fprintf(stderr, "Failed to continue stopped node %u\n",
2752 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_STOPPED, false);
2753 return ipreallocate(mem_ctx, ctdb);
2756 static int control_ban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2757 int argc, const char **argv)
2759 struct ctdb_ban_state ban_state;
2766 ret = check_flags(mem_ctx, ctdb, "banned",
2767 NODE_FLAGS_BANNED, true);
2772 ban_state.pnn = ctdb->cmd_pnn;
2773 ban_state.time = strtoul(argv[0], NULL, 0);
2775 if (ban_state.time == 0) {
2776 fprintf(stderr, "Ban time cannot be zero\n");
2780 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2781 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2783 fprintf(stderr, "Failed to ban node %u\n", ctdb->cmd_pnn);
2787 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, true);
2788 return ipreallocate(mem_ctx, ctdb);
2792 static int control_unban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2793 int argc, const char **argv)
2795 struct ctdb_ban_state ban_state;
2802 ret = check_flags(mem_ctx, ctdb, "banned",
2803 NODE_FLAGS_BANNED, false);
2808 ban_state.pnn = ctdb->cmd_pnn;
2811 ret = ctdb_ctrl_set_ban_state(mem_ctx, ctdb->ev, ctdb->client,
2812 ctdb->cmd_pnn, TIMEOUT(), &ban_state);
2814 fprintf(stderr, "Failed to unban node %u\n", ctdb->cmd_pnn);
2818 wait_for_flags(mem_ctx, ctdb, NODE_FLAGS_BANNED, false);
2819 return ipreallocate(mem_ctx, ctdb);
2823 static int control_shutdown(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2824 int argc, const char **argv)
2832 ret = ctdb_ctrl_shutdown(mem_ctx, ctdb->ev, ctdb->client,
2833 ctdb->cmd_pnn, TIMEOUT());
2835 fprintf(stderr, "Unable to shutdown node %u\n", ctdb->cmd_pnn);
2842 static int get_generation(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2843 uint32_t *generation)
2847 struct ctdb_vnn_map *vnnmap;
2851 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
2852 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
2854 fprintf(stderr, "Failed to find recovery master\n");
2858 ret = ctdb_ctrl_get_recmode(mem_ctx, ctdb->ev, ctdb->client,
2859 recmaster, TIMEOUT(), &recmode);
2861 fprintf(stderr, "Failed to get recovery mode from node %u\n",
2866 if (recmode == CTDB_RECOVERY_ACTIVE) {
2871 ret = ctdb_ctrl_getvnnmap(mem_ctx, ctdb->ev, ctdb->client,
2872 recmaster, TIMEOUT(), &vnnmap);
2874 fprintf(stderr, "Failed to get generation from node %u\n",
2879 if (vnnmap->generation == INVALID_GENERATION) {
2880 talloc_free(vnnmap);
2885 *generation = vnnmap->generation;
2886 talloc_free(vnnmap);
2891 static int control_recover(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2892 int argc, const char **argv)
2894 uint32_t generation, next_generation;
2901 ret = get_generation(mem_ctx, ctdb, &generation);
2906 ret = ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
2907 ctdb->cmd_pnn, TIMEOUT(),
2908 CTDB_RECOVERY_ACTIVE);
2910 fprintf(stderr, "Failed to set recovery mode active\n");
2915 ret = get_generation(mem_ctx, ctdb, &next_generation);
2918 "Failed to confirm end of recovery\n");
2922 if (next_generation != generation) {
2932 static int control_ipreallocate(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2933 int argc, const char **argv)
2936 usage("ipreallocate");
2939 return ipreallocate(mem_ctx, ctdb);
2942 static int control_isnotrecmaster(TALLOC_CTX *mem_ctx,
2943 struct ctdb_context *ctdb,
2944 int argc, const char **argv)
2950 usage("isnotrecmaster");
2953 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
2954 ctdb->pnn, TIMEOUT(), &recmaster);
2956 fprintf(stderr, "Failed to get recmaster\n");
2960 if (recmaster != ctdb->pnn) {
2961 printf("this node is not the recmaster\n");
2965 printf("this node is the recmaster\n");
2969 static int control_gratarp(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2970 int argc, const char **argv)
2972 struct ctdb_addr_info addr_info;
2979 if (! parse_ip(argv[0], NULL, 0, &addr_info.addr)) {
2980 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
2983 addr_info.iface = argv[1];
2985 ret = ctdb_ctrl_send_gratuitous_arp(mem_ctx, ctdb->ev, ctdb->client,
2986 ctdb->cmd_pnn, TIMEOUT(),
2989 fprintf(stderr, "Unable to send gratuitous arp from node %u\n",
2997 static int control_tickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
2998 int argc, const char **argv)
3000 ctdb_sock_addr src, dst;
3003 if (argc != 0 && argc != 2) {
3008 struct ctdb_connection *clist;
3012 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3018 for (i=0; i<count; i++) {
3019 ret = ctdb_sys_send_tcp(&clist[i].src,
3029 if (num_failed > 0) {
3030 fprintf(stderr, "Failed to send %d tickles\n",
3039 if (! parse_ip_port(argv[0], &src)) {
3040 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3044 if (! parse_ip_port(argv[1], &dst)) {
3045 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3049 ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0);
3051 fprintf(stderr, "Failed to send tickle ack\n");
3058 static int control_gettickles(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3059 int argc, const char **argv)
3061 ctdb_sock_addr addr;
3062 struct ctdb_tickle_list *tickles;
3066 if (argc < 1 || argc > 2) {
3067 usage("gettickles");
3071 port = strtoul(argv[1], NULL, 10);
3074 if (! parse_ip(argv[0], NULL, port, &addr)) {
3075 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3079 ret = ctdb_ctrl_get_tcp_tickle_list(mem_ctx, ctdb->ev, ctdb->client,
3080 ctdb->cmd_pnn, TIMEOUT(), &addr,
3083 fprintf(stderr, "Failed to get list of connections\n");
3087 if (options.machinereadable) {
3088 printf("%s%s%s%s%s%s%s%s%s\n",
3090 "Source IP", options.sep,
3091 "Port", options.sep,
3092 "Destiation IP", options.sep,
3093 "Port", options.sep);
3094 for (i=0; i<tickles->num; i++) {
3095 printf("%s%s%s%u%s%s%s%u%s\n", options.sep,
3096 ctdb_sock_addr_to_string(
3097 mem_ctx, &tickles->conn[i].src),
3099 ntohs(tickles->conn[i].src.ip.sin_port),
3101 ctdb_sock_addr_to_string(
3102 mem_ctx, &tickles->conn[i].dst),
3104 ntohs(tickles->conn[i].dst.ip.sin_port),
3108 printf("Connections for IP: %s\n",
3109 ctdb_sock_addr_to_string(mem_ctx, &tickles->addr));
3110 printf("Num connections: %u\n", tickles->num);
3111 for (i=0; i<tickles->num; i++) {
3112 printf("SRC: %s:%u DST: %s:%u\n",
3113 ctdb_sock_addr_to_string(
3114 mem_ctx, &tickles->conn[i].src),
3115 ntohs(tickles->conn[i].src.ip.sin_port),
3116 ctdb_sock_addr_to_string(
3117 mem_ctx, &tickles->conn[i].dst),
3118 ntohs(tickles->conn[i].dst.ip.sin_port));
3122 talloc_free(tickles);
3126 typedef void (*clist_request_func)(struct ctdb_req_control *request,
3127 struct ctdb_connection *conn);
3129 typedef int (*clist_reply_func)(struct ctdb_reply_control *reply);
3131 struct process_clist_state {
3132 struct ctdb_connection *clist;
3134 int num_failed, num_total;
3135 clist_reply_func reply_func;
3138 static void process_clist_done(struct tevent_req *subreq);
3140 static struct tevent_req *process_clist_send(
3141 TALLOC_CTX *mem_ctx,
3142 struct ctdb_context *ctdb,
3143 struct ctdb_connection *clist,
3145 clist_request_func request_func,
3146 clist_reply_func reply_func)
3148 struct tevent_req *req, *subreq;
3149 struct process_clist_state *state;
3150 struct ctdb_req_control request;
3153 req = tevent_req_create(mem_ctx, &state, struct process_clist_state);
3158 state->clist = clist;
3159 state->count = count;
3160 state->reply_func = reply_func;
3162 for (i=0; i<count; i++) {
3163 request_func(&request, &clist[i]);
3164 subreq = ctdb_client_control_send(state, ctdb->ev,
3165 ctdb->client, ctdb->cmd_pnn,
3166 TIMEOUT(), &request);
3167 if (tevent_req_nomem(subreq, req)) {
3168 return tevent_req_post(req, ctdb->ev);
3170 tevent_req_set_callback(subreq, process_clist_done, req);
3176 static void process_clist_done(struct tevent_req *subreq)
3178 struct tevent_req *req = tevent_req_callback_data(
3179 subreq, struct tevent_req);
3180 struct process_clist_state *state = tevent_req_data(
3181 req, struct process_clist_state);
3182 struct ctdb_reply_control *reply;
3186 status = ctdb_client_control_recv(subreq, NULL, state, &reply);
3187 TALLOC_FREE(subreq);
3189 state->num_failed += 1;
3193 ret = state->reply_func(reply);
3195 state->num_failed += 1;
3200 state->num_total += 1;
3201 if (state->num_total == state->count) {
3202 tevent_req_done(req);
3206 static int process_clist_recv(struct tevent_req *req)
3208 struct process_clist_state *state = tevent_req_data(
3209 req, struct process_clist_state);
3211 return state->num_failed;
3214 static int control_addtickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3215 int argc, const char **argv)
3217 struct ctdb_connection conn;
3220 if (argc != 0 && argc != 2) {
3225 struct ctdb_connection *clist;
3226 struct tevent_req *req;
3229 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3237 req = process_clist_send(mem_ctx, ctdb, clist, count,
3238 ctdb_req_control_tcp_add_delayed_update,
3239 ctdb_reply_control_tcp_add_delayed_update);
3245 tevent_req_poll(req, ctdb->ev);
3248 ret = process_clist_recv(req);
3250 fprintf(stderr, "Failed to add %d tickles\n", ret);
3257 if (! parse_ip_port(argv[0], &conn.src)) {
3258 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3261 if (! parse_ip_port(argv[1], &conn.dst)) {
3262 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3266 ret = ctdb_ctrl_tcp_add_delayed_update(mem_ctx, ctdb->ev,
3267 ctdb->client, ctdb->cmd_pnn,
3270 fprintf(stderr, "Failed to register connection\n");
3277 static int control_deltickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3278 int argc, const char **argv)
3280 struct ctdb_connection conn;
3283 if (argc != 0 && argc != 2) {
3288 struct ctdb_connection *clist;
3289 struct tevent_req *req;
3292 ret = ctdb_parse_connections(stdin, mem_ctx, &count, &clist);
3300 req = process_clist_send(mem_ctx, ctdb, clist, count,
3301 ctdb_req_control_tcp_remove,
3302 ctdb_reply_control_tcp_remove);
3308 tevent_req_poll(req, ctdb->ev);
3311 ret = process_clist_recv(req);
3313 fprintf(stderr, "Failed to remove %d tickles\n", ret);
3320 if (! parse_ip_port(argv[0], &conn.src)) {
3321 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3324 if (! parse_ip_port(argv[1], &conn.dst)) {
3325 fprintf(stderr, "Invalid IP address %s\n", argv[1]);
3329 ret = ctdb_ctrl_tcp_remove(mem_ctx, ctdb->ev, ctdb->client,
3330 ctdb->cmd_pnn, TIMEOUT(), &conn);
3332 fprintf(stderr, "Failed to unregister connection\n");
3339 static int control_check_srvids(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3340 int argc, const char **argv)
3347 usage("check_srvids");
3350 srvid = talloc_array(mem_ctx, uint64_t, argc);
3351 if (srvid == NULL) {
3352 fprintf(stderr, "Memory allocation error\n");
3356 for (i=0; i<argc; i++) {
3357 srvid[i] = strtoull(argv[i], NULL, 0);
3360 ret = ctdb_ctrl_check_srvids(mem_ctx, ctdb->ev, ctdb->client,
3361 ctdb->cmd_pnn, TIMEOUT(), srvid, argc,
3364 fprintf(stderr, "Failed to check srvids on node %u\n",
3369 for (i=0; i<argc; i++) {
3370 printf("SRVID 0x%" PRIx64 " %s\n", srvid[i],
3371 (result[i] ? "exists" : "does not exist"));
3377 static int control_listnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3378 int argc, const char **argv)
3380 struct ctdb_node_map *nodemap;
3387 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
3388 if (nodemap == NULL) {
3392 for (i=0; i<nodemap->num; i++) {
3393 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
3397 if (options.machinereadable) {
3398 printf("%s%u%s%s%s\n", options.sep,
3399 nodemap->node[i].pnn, options.sep,
3400 ctdb_sock_addr_to_string(
3401 mem_ctx, &nodemap->node[i].addr),
3405 ctdb_sock_addr_to_string(
3406 mem_ctx, &nodemap->node[i].addr));
3413 static bool nodemap_identical(struct ctdb_node_map *nodemap1,
3414 struct ctdb_node_map *nodemap2)
3418 if (nodemap1->num != nodemap2->num) {
3422 for (i=0; i<nodemap1->num; i++) {
3423 struct ctdb_node_and_flags *n1, *n2;
3425 n1 = &nodemap1->node[i];
3426 n2 = &nodemap2->node[i];
3428 if ((n1->pnn != n2->pnn) ||
3429 (n1->flags != n2->flags) ||
3430 ! ctdb_sock_addr_same_ip(&n1->addr, &n2->addr)) {
3438 static int check_node_file_changes(TALLOC_CTX *mem_ctx,
3439 struct ctdb_node_map *nm,
3440 struct ctdb_node_map *fnm,
3444 bool check_failed = false;
3448 for (i=0; i<nm->num; i++) {
3449 if (i >= fnm->num) {
3451 "Node %u (%s) missing from nodes file\n",
3453 ctdb_sock_addr_to_string(
3454 mem_ctx, &nm->node[i].addr));
3455 check_failed = true;
3458 if (nm->node[i].flags & NODE_FLAGS_DELETED &&
3459 fnm->node[i].flags & NODE_FLAGS_DELETED) {
3460 /* Node remains deleted */
3464 if (! (nm->node[i].flags & NODE_FLAGS_DELETED) &&
3465 ! (fnm->node[i].flags & NODE_FLAGS_DELETED)) {
3466 /* Node not newly nor previously deleted */
3467 if (! ctdb_same_ip(&nm->node[i].addr,
3468 &fnm->node[i].addr)) {
3470 "Node %u has changed IP address"
3471 " (was %s, now %s)\n",
3473 ctdb_sock_addr_to_string(
3474 mem_ctx, &nm->node[i].addr),
3475 ctdb_sock_addr_to_string(
3476 mem_ctx, &fnm->node[i].addr));
3477 check_failed = true;
3479 if (nm->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3481 "WARNING: Node %u is disconnected."
3482 " You MUST fix this node manually!\n",
3489 if (fnm->node[i].flags & NODE_FLAGS_DELETED) {
3490 /* Node is being deleted */
3491 printf("Node %u is DELETED\n", nm->node[i].pnn);
3493 if (! (nm->node[i].flags & NODE_FLAGS_DISCONNECTED)) {
3495 "ERROR: Node %u is still connected\n",
3497 check_failed = true;
3502 if (nm->node[i].flags & NODE_FLAGS_DELETED) {
3503 /* Node was previously deleted */
3504 printf("Node %u is UNDELETED\n", nm->node[i].pnn);
3511 "ERROR: Nodes will not be reloaded due to previous error\n");
3515 /* Leftover nodes in file are NEW */
3516 for (; i < fnm->num; i++) {
3517 printf("Node %u is NEW\n", fnm->node[i].pnn);
3524 struct disable_recoveries_state {
3532 static void disable_recoveries_handler(uint64_t srvid, TDB_DATA data,
3535 struct disable_recoveries_state *state =
3536 (struct disable_recoveries_state *)private_data;
3539 if (data.dsize != sizeof(int)) {
3544 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
3545 ret = *(int *)data.dptr;
3547 state->status = ret;
3551 for (i=0; i<state->node_count; i++) {
3552 if (state->pnn_list[i] == ret) {
3553 state->reply[i] = true;
3559 for (i=0; i<state->node_count; i++) {
3560 if (! state->reply[i]) {
3561 state->done = false;
3567 static int disable_recoveries(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3568 uint32_t timeout, uint32_t *pnn_list, int count)
3570 struct ctdb_disable_message disable = { 0 };
3571 struct disable_recoveries_state state;
3574 disable.pnn = ctdb->pnn;
3575 disable.srvid = next_srvid(ctdb);
3576 disable.timeout = timeout;
3578 state.pnn_list = pnn_list;
3579 state.node_count = count;
3582 state.reply = talloc_zero_array(mem_ctx, bool, count);
3583 if (state.reply == NULL) {
3587 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
3589 disable_recoveries_handler,
3595 for (i=0; i<count; i++) {
3596 ret = ctdb_message_disable_recoveries(mem_ctx, ctdb->ev,
3605 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
3607 fprintf(stderr, "Timed out waiting to disable recoveries\n");
3609 ret = (state.status >= 0 ? 0 : 1);
3613 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
3614 disable.srvid, &state);
3618 static int control_reloadnodes(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3619 int argc, const char **argv)
3621 struct ctdb_node_map *nodemap = NULL;
3622 struct ctdb_node_map *file_nodemap;
3623 struct ctdb_node_map *remote_nodemap;
3624 struct ctdb_req_control request;
3625 struct ctdb_reply_control **reply;
3631 nodemap = get_nodemap(ctdb, false);
3632 if (nodemap == NULL) {
3636 file_nodemap = read_nodes_file(mem_ctx, ctdb->pnn);
3637 if (file_nodemap == NULL) {
3641 for (i=0; i<nodemap->num; i++) {
3642 if (nodemap->node[i].flags & NODE_FLAGS_DISCONNECTED) {
3646 ret = ctdb_ctrl_get_nodes_file(mem_ctx, ctdb->ev, ctdb->client,
3647 nodemap->node[i].pnn, TIMEOUT(),
3651 "ERROR: Failed to get nodes file from node %u\n",
3652 nodemap->node[i].pnn);
3656 if (! nodemap_identical(file_nodemap, remote_nodemap)) {
3658 "ERROR: Nodes file on node %u differs"
3659 " from current node (%u)\n",
3660 nodemap->node[i].pnn, ctdb->pnn);
3665 ret = check_node_file_changes(mem_ctx, nodemap, file_nodemap, &reload);
3671 fprintf(stderr, "No change in nodes file,"
3672 " skipping unnecessary reload\n");
3676 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
3677 mem_ctx, &pnn_list);
3679 fprintf(stderr, "Memory allocation error\n");
3683 ret = disable_recoveries(mem_ctx, ctdb, 2*options.timelimit,
3686 fprintf(stderr, "Failed to disable recoveries\n");
3690 ctdb_req_control_reload_nodes_file(&request);
3691 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3692 pnn_list, count, TIMEOUT(),
3693 &request, NULL, &reply);
3695 bool failed = false;
3697 for (i=0; i<count; i++) {
3698 ret = ctdb_reply_control_reload_nodes_file(reply[i]);
3701 "Node %u failed to reload nodes\n",
3708 "You MUST fix failed nodes manually!\n");
3712 ret = disable_recoveries(mem_ctx, ctdb, 0, pnn_list, count);
3714 fprintf(stderr, "Failed to enable recoveries\n");
3721 static int moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3722 ctdb_sock_addr *addr, uint32_t pnn)
3724 struct ctdb_public_ip_list *pubip_list;
3725 struct ctdb_public_ip pubip;
3726 struct ctdb_node_map *nodemap;
3727 struct ctdb_req_control request;
3731 ret = ctdb_message_disable_ip_check(mem_ctx, ctdb->ev, ctdb->client,
3732 CTDB_BROADCAST_CONNECTED,
3733 2*options.timelimit);
3735 fprintf(stderr, "Failed to disable IP check\n");
3739 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3740 pnn, TIMEOUT(), &pubip_list);
3742 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3747 for (i=0; i<pubip_list->num; i++) {
3748 if (ctdb_same_ip(addr, &pubip_list->ip[i].addr)) {
3753 if (i == pubip_list->num) {
3754 fprintf(stderr, "Node %u CANNOT host IP address %s\n",
3755 pnn, ctdb_sock_addr_to_string(mem_ctx, addr));
3759 nodemap = get_nodemap(ctdb, false);
3760 if (nodemap == NULL) {
3764 count = list_of_active_nodes(nodemap, pnn, mem_ctx, &pnn_list);
3766 fprintf(stderr, "Memory allocation error\n");
3772 ctdb_req_control_release_ip(&request, &pubip);
3774 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3775 pnn_list, count, TIMEOUT(),
3776 &request, NULL, NULL);
3778 fprintf(stderr, "Failed to release IP on nodes\n");
3782 ret = ctdb_ctrl_takeover_ip(mem_ctx, ctdb->ev, ctdb->client,
3783 pnn, TIMEOUT(), &pubip);
3785 fprintf(stderr, "Failed to takeover IP on node %u\n", pnn);
3792 static int control_moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3793 int argc, const char **argv)
3795 ctdb_sock_addr addr;
3797 int ret, retries = 0;
3803 if (! parse_ip(argv[0], NULL, 0, &addr)) {
3804 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3808 pnn = strtoul(argv[1], NULL, 10);
3809 if (pnn == CTDB_UNKNOWN_PNN) {
3810 fprintf(stderr, "Invalid PNN %s\n", argv[1]);
3814 while (retries < 5) {
3815 ret = moveip(mem_ctx, ctdb, &addr, pnn);
3825 fprintf(stderr, "Failed to move IP %s to node %u\n",
3833 static int control_rebalanceip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3834 int argc, const char **argv)
3836 ctdb_sock_addr addr;
3837 struct ctdb_node_map *nodemap;
3838 struct ctdb_public_ip pubip;
3839 struct ctdb_req_control request;
3844 usage("rebalanceip");
3847 if (parse_ip(argv[0], NULL, 0, &addr)) {
3848 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3852 ret = ctdb_message_disable_ip_check(mem_ctx, ctdb->ev, ctdb->client,
3853 CTDB_BROADCAST_CONNECTED,
3854 2*options.timelimit);
3856 fprintf(stderr, "Failed to disable IP check\n");
3860 nodemap = get_nodemap(ctdb, false);
3861 if (nodemap == NULL) {
3865 count = list_of_active_nodes(nodemap, -1, mem_ctx, &pnn_list);
3867 fprintf(stderr, "Memory allocation error\n");
3871 pubip.pnn = CTDB_UNKNOWN_PNN;
3874 ctdb_req_control_release_ip(&request, &pubip);
3875 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
3876 pnn_list, count, TIMEOUT(),
3877 &request, NULL, NULL);
3879 fprintf(stderr, "Failed to release IP from nodes\n");
3883 return ipreallocate(mem_ctx, ctdb);
3886 static int rebalancenode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3891 ret = ctdb_message_rebalance_node(mem_ctx, ctdb->ev, ctdb->client,
3892 CTDB_BROADCAST_CONNECTED, pnn);
3895 "Failed to ask recovery master to distribute IPs\n");
3902 static int control_addip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3903 int argc, const char **argv)
3905 ctdb_sock_addr addr;
3906 struct ctdb_public_ip_list *pubip_list;
3907 struct ctdb_addr_info addr_info;
3909 int ret, i, retries = 0;
3915 if (! parse_ip_mask(argv[0], argv[1], &addr, &mask)) {
3916 fprintf(stderr, "Invalid IP/Mask %s\n", argv[0]);
3920 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3921 ctdb->cmd_pnn, TIMEOUT(), &pubip_list);
3923 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3928 for (i=0; i<pubip_list->num; i++) {
3929 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3930 fprintf(stderr, "Node already knows about IP %s\n",
3931 ctdb_sock_addr_to_string(mem_ctx, &addr));
3936 addr_info.addr = addr;
3937 addr_info.mask = mask;
3938 addr_info.iface = argv[1];
3940 while (retries < 5) {
3941 ret = ctdb_ctrl_add_public_ip(mem_ctx, ctdb->ev, ctdb->client,
3942 ctdb->cmd_pnn, TIMEOUT(),
3953 fprintf(stderr, "Failed to add public IP to node %u."
3954 " Giving up\n", ctdb->cmd_pnn);
3958 ret = rebalancenode(mem_ctx, ctdb, ctdb->cmd_pnn);
3963 return ipreallocate(mem_ctx, ctdb);
3966 static int control_delip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
3967 int argc, const char **argv)
3969 ctdb_sock_addr addr;
3970 struct ctdb_public_ip_list *pubip_list;
3971 struct ctdb_addr_info addr_info;
3978 if (! parse_ip(argv[0], NULL, 0, &addr)) {
3979 fprintf(stderr, "Invalid IP address %s\n", argv[0]);
3983 ret = ctdb_ctrl_get_public_ips(mem_ctx, ctdb->ev, ctdb->client,
3984 ctdb->cmd_pnn, TIMEOUT(), &pubip_list);
3986 fprintf(stderr, "Failed to get Public IPs from node %u\n",
3991 for (i=0; i<pubip_list->num; i++) {
3992 if (ctdb_same_ip(&addr, &pubip_list->ip[i].addr)) {
3997 if (i == pubip_list->num) {
3998 fprintf(stderr, "Node does not know about IP address %s\n",
3999 ctdb_sock_addr_to_string(mem_ctx, &addr));
4003 addr_info.addr = addr;
4005 addr_info.iface = NULL;
4007 ret = ctdb_ctrl_del_public_ip(mem_ctx, ctdb->ev, ctdb->client,
4008 ctdb->cmd_pnn, TIMEOUT(), &addr_info);
4010 fprintf(stderr, "Failed to delete public IP from node %u\n",
4018 static int control_eventscript(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4019 int argc, const char **argv)
4024 usage("eventscript");
4027 if (strcmp(argv[0], "monitor") != 0) {
4028 fprintf(stderr, "Only monitor event can be run\n");
4032 ret = ctdb_ctrl_run_eventscripts(mem_ctx, ctdb->ev, ctdb->client,
4033 ctdb->cmd_pnn, TIMEOUT(), argv[0]);
4035 fprintf(stderr, "Failed to run monitor event on node %u\n",
4043 #define DB_VERSION 3
4044 #define MAX_DB_NAME 64
4045 #define MAX_REC_BUFFER_SIZE (100*1000)
4048 unsigned long version;
4050 unsigned long flags;
4053 char name[MAX_DB_NAME];
4056 struct backup_state {
4057 TALLOC_CTX *mem_ctx;
4058 struct ctdb_rec_buffer *recbuf;
4061 unsigned int nbuf, nrec;
4064 static int backup_handler(uint32_t reqid, struct ctdb_ltdb_header *header,
4065 TDB_DATA key, TDB_DATA data, void *private_data)
4067 struct backup_state *state = (struct backup_state *)private_data;
4071 if (state->recbuf == NULL) {
4072 state->recbuf = ctdb_rec_buffer_init(state->mem_ctx,
4074 if (state->recbuf == NULL) {
4079 ret = ctdb_rec_buffer_add(state->recbuf, state->recbuf, reqid,
4085 len = ctdb_rec_buffer_len(state->recbuf);
4086 if (len < MAX_REC_BUFFER_SIZE) {
4090 ret = ctdb_rec_buffer_write(state->recbuf, state->fd);
4092 fprintf(stderr, "Failed to write records to backup file\n");
4097 state->nrec += state->recbuf->count;
4098 TALLOC_FREE(state->recbuf);
4103 static int control_backupdb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4104 int argc, const char **argv)
4106 const char *db_name;
4107 struct ctdb_db_context *db;
4110 struct backup_state state;
4111 struct db_header db_hdr;
4118 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4122 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4125 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4129 fd = open(argv[1], O_RDWR|O_CREAT, 0600);
4132 fprintf(stderr, "Failed to open file %s for writing\n",
4137 /* Write empty header first */
4138 ZERO_STRUCT(db_hdr);
4139 ret = write(fd, &db_hdr, sizeof(struct db_header));
4143 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4147 state.mem_ctx = mem_ctx;
4148 state.recbuf = NULL;
4153 ret = ctdb_db_traverse(db, true, false, backup_handler, &state);
4155 fprintf(stderr, "Failed to collect records from DB %s\n",
4161 if (state.recbuf != NULL) {
4162 ret = ctdb_rec_buffer_write(state.recbuf, state.fd);
4165 "Failed to write records to backup file\n");
4171 state.nrec += state.recbuf->count;
4172 TALLOC_FREE(state.recbuf);
4175 db_hdr.version = DB_VERSION;
4176 db_hdr.timestamp = time(NULL);
4177 db_hdr.flags = db_flags;
4178 db_hdr.nbuf = state.nbuf;
4179 db_hdr.nrec = state.nrec;
4180 strncpy(db_hdr.name, db_name, MAX_DB_NAME-1);
4182 lseek(fd, 0, SEEK_SET);
4183 ret = write(fd, &db_hdr, sizeof(struct db_header));
4187 fprintf(stderr, "Failed to write header to file %s\n", argv[1]);
4192 printf("Database backed up to %s\n", argv[1]);
4196 static int control_restoredb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4197 int argc, const char **argv)
4199 const char *db_name = NULL;
4200 struct ctdb_db_context *db;
4201 struct db_header db_hdr;
4202 struct ctdb_node_map *nodemap;
4203 struct ctdb_req_control request;
4204 struct ctdb_reply_control **reply;
4205 struct ctdb_transdb wipedb;
4206 struct ctdb_pulldb_ext pulldb;
4207 struct ctdb_rec_buffer *recbuf;
4208 uint32_t generation;
4214 if (argc < 1 || argc > 2) {
4218 fd = open(argv[0], O_RDONLY, 0600);
4221 fprintf(stderr, "Failed to open file %s for reading\n",
4230 ret = read(fd, &db_hdr, sizeof(struct db_header));
4234 fprintf(stderr, "Failed to read db header from file %s\n",
4239 if (db_hdr.version != DB_VERSION) {
4241 "Wrong version of backup file, expected %u, got %lu\n",
4242 DB_VERSION, db_hdr.version);
4247 if (db_name == NULL) {
4248 db_name = db_hdr.name;
4251 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4252 localtime(&db_hdr.timestamp));
4253 printf("Restoring database %s from backup @ %s\n", db_name, timebuf);
4255 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4258 fprintf(stderr, "Failed to attach to DB %s\n", db_hdr.name);
4262 nodemap = get_nodemap(ctdb, false);
4263 if (nodemap == NULL) {
4264 fprintf(stderr, "Failed to get nodemap\n");
4269 ret = get_generation(mem_ctx, ctdb, &generation);
4271 fprintf(stderr, "Failed to get current generation\n");
4276 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4283 wipedb.db_id = ctdb_db_id(db);
4284 wipedb.tid = generation;
4286 ctdb_req_control_db_freeze(&request, wipedb.db_id);
4287 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4288 ctdb->client, pnn_list, count,
4289 TIMEOUT(), &request, NULL, NULL);
4295 ctdb_req_control_db_transaction_start(&request, &wipedb);
4296 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4297 pnn_list, count, TIMEOUT(),
4298 &request, NULL, NULL);
4303 ctdb_req_control_wipe_database(&request, &wipedb);
4304 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4305 pnn_list, count, TIMEOUT(),
4306 &request, NULL, NULL);
4311 pulldb.db_id = ctdb_db_id(db);
4313 pulldb.srvid = SRVID_CTDB_PUSHDB;
4315 ctdb_req_control_db_push_start(&request, &pulldb);
4316 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4317 pnn_list, count, TIMEOUT(),
4318 &request, NULL, NULL);
4323 for (i=0; i<db_hdr.nbuf; i++) {
4324 struct ctdb_req_message message;
4327 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4332 data.dsize = ctdb_rec_buffer_len(recbuf);
4333 data.dptr = talloc_size(mem_ctx, data.dsize);
4334 if (data.dptr == NULL) {
4338 ctdb_rec_buffer_push(recbuf, data.dptr);
4340 message.srvid = pulldb.srvid;
4341 message.data.data = data;
4343 ret = ctdb_client_message_multi(mem_ctx, ctdb->ev,
4351 talloc_free(recbuf);
4352 talloc_free(data.dptr);
4355 ctdb_req_control_db_push_confirm(&request, pulldb.db_id);
4356 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4357 pnn_list, count, TIMEOUT(),
4358 &request, NULL, &reply);
4363 for (i=0; i<count; i++) {
4364 uint32_t num_records;
4366 ret = ctdb_reply_control_db_push_confirm(reply[i],
4369 fprintf(stderr, "Invalid response from node %u\n",
4374 if (num_records != db_hdr.nrec) {
4375 fprintf(stderr, "Node %u received %u of %lu records\n",
4376 pnn_list[i], num_records, db_hdr.nrec);
4381 ctdb_req_control_db_set_healthy(&request, wipedb.db_id);
4382 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4383 pnn_list, count, TIMEOUT(),
4384 &request, NULL, NULL);
4389 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4390 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4391 pnn_list, count, TIMEOUT(),
4392 &request, NULL, NULL);
4397 ctdb_req_control_db_thaw(&request, wipedb.db_id);
4398 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4399 ctdb->client, pnn_list, count,
4400 TIMEOUT(), &request, NULL, NULL);
4405 printf("Database %s restored\n", db_name);
4411 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4412 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4416 struct dumpdbbackup_state {
4417 ctdb_rec_parser_func_t parser;
4418 struct dump_record_state sub_state;
4421 static int dumpdbbackup_handler(uint32_t reqid,
4422 struct ctdb_ltdb_header *header,
4423 TDB_DATA key, TDB_DATA data,
4426 struct dumpdbbackup_state *state =
4427 (struct dumpdbbackup_state *)private_data;
4428 struct ctdb_ltdb_header hdr;
4431 ret = ctdb_ltdb_header_extract(&data, &hdr);
4436 return state->parser(reqid, &hdr, key, data, &state->sub_state);
4439 static int control_dumpdbbackup(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4440 int argc, const char **argv)
4442 struct db_header db_hdr;
4444 struct dumpdbbackup_state state;
4448 usage("dumpbackup");
4451 fd = open(argv[0], O_RDONLY, 0600);
4454 fprintf(stderr, "Failed to open file %s for reading\n",
4459 ret = read(fd, &db_hdr, sizeof(struct db_header));
4463 fprintf(stderr, "Failed to read db header from file %s\n",
4468 if (db_hdr.version != DB_VERSION) {
4470 "Wrong version of backup file, expected %u, got %lu\n",
4471 DB_VERSION, db_hdr.version);
4476 strftime(timebuf, sizeof(timebuf)-1, "%Y/%m/%d %H:%M:%S",
4477 localtime(&db_hdr.timestamp));
4478 printf("Dumping database %s from backup @ %s\n",
4479 db_hdr.name, timebuf);
4481 state.parser = dump_record;
4482 state.sub_state.count = 0;
4484 for (i=0; i<db_hdr.nbuf; i++) {
4485 struct ctdb_rec_buffer *recbuf;
4487 ret = ctdb_rec_buffer_read(fd, mem_ctx, &recbuf);
4489 fprintf(stderr, "Failed to read records\n");
4494 ret = ctdb_rec_buffer_traverse(recbuf, dumpdbbackup_handler,
4497 fprintf(stderr, "Failed to dump records\n");
4504 printf("Dumped %u record(s)\n", state.sub_state.count);
4508 static int control_wipedb(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4509 int argc, const char **argv)
4511 const char *db_name;
4512 struct ctdb_db_context *db;
4515 struct ctdb_node_map *nodemap;
4516 struct ctdb_req_control request;
4517 struct ctdb_transdb wipedb;
4518 uint32_t generation;
4526 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, &db_flags)) {
4530 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
4533 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
4537 nodemap = get_nodemap(ctdb, false);
4538 if (nodemap == NULL) {
4539 fprintf(stderr, "Failed to get nodemap\n");
4543 ret = get_generation(mem_ctx, ctdb, &generation);
4545 fprintf(stderr, "Failed to get current generation\n");
4549 count = list_of_active_nodes(nodemap, CTDB_UNKNOWN_PNN, mem_ctx,
4555 ctdb_req_control_db_freeze(&request, db_id);
4556 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4557 ctdb->client, pnn_list, count,
4558 TIMEOUT(), &request, NULL, NULL);
4563 wipedb.db_id = db_id;
4564 wipedb.tid = generation;
4566 ctdb_req_control_db_transaction_start(&request, &wipedb);
4567 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4568 pnn_list, count, TIMEOUT(),
4569 &request, NULL, NULL);
4574 ctdb_req_control_wipe_database(&request, &wipedb);
4575 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4576 pnn_list, count, TIMEOUT(),
4577 &request, NULL, NULL);
4582 ctdb_req_control_db_set_healthy(&request, db_id);
4583 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4584 pnn_list, count, TIMEOUT(),
4585 &request, NULL, NULL);
4590 ctdb_req_control_db_transaction_commit(&request, &wipedb);
4591 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
4592 pnn_list, count, TIMEOUT(),
4593 &request, NULL, NULL);
4598 ctdb_req_control_db_thaw(&request, db_id);
4599 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev,
4600 ctdb->client, pnn_list, count,
4601 TIMEOUT(), &request, NULL, NULL);
4606 printf("Database %s wiped\n", db_name);
4611 ctdb_ctrl_set_recmode(mem_ctx, ctdb->ev, ctdb->client,
4612 ctdb->pnn, TIMEOUT(), CTDB_RECOVERY_ACTIVE);
4616 static int control_recmaster(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4617 int argc, const char **argv)
4622 ret = ctdb_ctrl_get_recmaster(mem_ctx, ctdb->ev, ctdb->client,
4623 ctdb->cmd_pnn, TIMEOUT(), &recmaster);
4628 printf("%u\n", recmaster);
4632 static void print_scriptstatus_one(struct ctdb_script_list *slist,
4633 const char *event_str)
4638 if (slist == NULL) {
4639 if (! options.machinereadable) {
4640 printf("%s cycle never run\n", event_str);
4645 for (i=0; i<slist->num_scripts; i++) {
4646 if (slist->script[i].status != -ENOEXEC) {
4651 if (! options.machinereadable) {
4652 printf("%d scripts were executed last %s cycle\n",
4653 num_run, event_str);
4656 for (i=0; i<slist->num_scripts; i++) {
4657 const char *status = NULL;
4659 switch (slist->script[i].status) {
4661 status = "TIMEDOUT";
4664 status = "DISABLED";
4670 if (slist->script[i].status > 0) {
4676 if (options.machinereadable) {
4677 printf("%s%s%s%s%s%i%s%s%s%lu.%06lu%s%lu.%06lu%s%s%s\n",
4679 event_str, options.sep,
4680 slist->script[i].name, options.sep,
4681 slist->script[i].status, options.sep,
4682 status, options.sep,
4683 slist->script[i].start.tv_sec,
4684 slist->script[i].start.tv_usec, options.sep,
4685 slist->script[i].finished.tv_sec,
4686 slist->script[i].finished.tv_usec, options.sep,
4687 slist->script[i].output, options.sep);
4692 printf("%-20s Status:%s ",
4693 slist->script[i].name, status);
4695 /* Some other error, eg from stat. */
4696 printf("%-20s Status:CANNOT RUN (%s)",
4697 slist->script[i].name,
4698 strerror(-slist->script[i].status));
4701 if (slist->script[i].status >= 0) {
4702 printf("Duration:%.3lf ",
4703 timeval_delta(&slist->script[i].finished,
4704 &slist->script[i].start));
4706 if (slist->script[i].status != -ENOEXEC) {
4707 printf("%s", ctime(&slist->script[i].start.tv_sec));
4708 if (slist->script[i].status != 0) {
4709 printf(" OUTPUT:%s\n",
4710 slist->script[i].output);
4718 static void print_scriptstatus(struct ctdb_script_list **slist,
4719 int count, const char **event_str)
4723 if (options.machinereadable) {
4724 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
4726 "Type", options.sep,
4727 "Name", options.sep,
4728 "Code", options.sep,
4729 "Status", options.sep,
4730 "Start", options.sep,
4732 "Error Output", options.sep);
4735 for (i=0; i<count; i++) {
4736 print_scriptstatus_one(slist[i], event_str[i]);
4740 static int control_scriptstatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4741 int argc, const char **argv)
4743 struct ctdb_script_list **slist;
4744 const char *event_str;
4745 enum ctdb_event event;
4746 const char *all_events[] = {
4747 "init", "setup", "startup", "monitor",
4748 "takeip", "releaseip", "updateip", "ipreallocated" };
4751 int count, start, end, num;
4754 usage("scriptstatus");
4758 event_str = "monitor";
4760 event_str = argv[0];
4766 for (i=0; i<ARRAY_SIZE(all_events); i++) {
4767 if (strcmp(event_str, all_events[i]) == 0) {
4776 if (strcmp(event_str, "all") == 0) {
4778 count = ARRAY_SIZE(all_events);
4784 fprintf(stderr, "Unknown event name %s\n", argv[0]);
4785 usage("scriptstatus");
4788 slist = talloc_array(mem_ctx, struct ctdb_script_list *, count);
4789 if (slist == NULL) {
4790 fprintf(stderr, "Memory allocation error\n");
4795 for (i=start; i<end; i++) {
4796 event = ctdb_event_from_string(all_events[i]);
4798 ret = ctdb_ctrl_get_event_script_status(mem_ctx, ctdb->ev,
4805 "failed to get script status for %s event\n",
4810 if (slist[num] == NULL) {
4815 /* The ETIME status is ignored for certain events.
4816 * In that case the status is 0, but endtime is not set.
4818 for (j=0; j<slist[num]->num_scripts; j++) {
4819 if (slist[num]->script[j].status == 0 &&
4820 timeval_is_zero(&slist[num]->script[j].finished)) {
4821 slist[num]->script[j].status = -ETIME;
4828 print_scriptstatus(slist, count, &all_events[start]);
4832 static int control_enablescript(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4833 int argc, const char **argv)
4838 usage("enablescript");
4841 ret = ctdb_ctrl_enable_script(mem_ctx, ctdb->ev, ctdb->client,
4842 ctdb->cmd_pnn, TIMEOUT(), argv[0]);
4844 fprintf(stderr, "Failed to enable script %s\n", argv[0]);
4851 static int control_disablescript(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4852 int argc, const char **argv)
4857 usage("disablescript");
4860 ret = ctdb_ctrl_disable_script(mem_ctx, ctdb->ev, ctdb->client,
4861 ctdb->cmd_pnn, TIMEOUT(), argv[0]);
4863 fprintf(stderr, "Failed to disable script %s\n", argv[0]);
4870 static int control_natgw(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4871 int argc, const char **argv)
4873 char *t, *natgw_helper = NULL;
4879 t = getenv("CTDB_NATGW_HELPER");
4881 natgw_helper = talloc_strdup(mem_ctx, t);
4883 natgw_helper = talloc_asprintf(mem_ctx, "%s/ctdb_natgw",
4884 CTDB_HELPER_BINDIR);
4887 if (natgw_helper == NULL) {
4888 fprintf(stderr, "Unable to set NAT gateway helper\n");
4892 return run_helper("NAT gateway helper", natgw_helper, argv[0]);
4895 static int control_natgwlist(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4896 int argc, const char **argv)
4898 char *t, *natgw_helper = NULL;
4904 t = getenv("CTDB_NATGW_HELPER");
4906 natgw_helper = talloc_strdup(mem_ctx, t);
4908 natgw_helper = talloc_asprintf(mem_ctx, "%s/ctdb_natgw",
4909 CTDB_HELPER_BINDIR);
4912 if (natgw_helper == NULL) {
4913 fprintf(stderr, "Unable to set NAT gateway helper\n");
4917 return run_helper("NAT gateway helper", natgw_helper, "natgwlist");
4921 * Find the PNN of the current node
4922 * discover the pnn by loading the nodes file and try to bind
4923 * to all addresses one at a time until the ip address is found.
4925 static bool find_node_xpnn(TALLOC_CTX *mem_ctx, uint32_t *pnn)
4927 struct ctdb_node_map *nodemap;
4930 nodemap = read_nodes_file(mem_ctx, CTDB_UNKNOWN_PNN);
4931 if (nodemap == NULL) {
4935 for (i=0; i<nodemap->num; i++) {
4936 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
4939 if (ctdb_sys_have_ip(&nodemap->node[i].addr)) {
4941 *pnn = nodemap->node[i].pnn;
4943 talloc_free(nodemap);
4948 fprintf(stderr, "Failed to detect PNN of the current node.\n");
4949 talloc_free(nodemap);
4953 static int control_getreclock(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
4954 int argc, const char **argv)
4956 const char *reclock;
4960 usage("getreclock");
4963 ret = ctdb_ctrl_get_reclock_file(mem_ctx, ctdb->ev, ctdb->client,
4964 ctdb->cmd_pnn, TIMEOUT(), &reclock);
4969 if (reclock != NULL) {
4970 printf("%s\n", reclock);
4976 static int control_setlmasterrole(TALLOC_CTX *mem_ctx,
4977 struct ctdb_context *ctdb,
4978 int argc, const char **argv)
4980 uint32_t lmasterrole = 0;
4984 usage("setlmasterrole");
4987 if (strcmp(argv[0], "on") == 0) {
4989 } else if (strcmp(argv[0], "off") == 0) {
4992 usage("setlmasterrole");
4995 ret = ctdb_ctrl_set_lmasterrole(mem_ctx, ctdb->ev, ctdb->client,
4996 ctdb->cmd_pnn, TIMEOUT(), lmasterrole);
5004 static int control_setrecmasterrole(TALLOC_CTX *mem_ctx,
5005 struct ctdb_context *ctdb,
5006 int argc, const char **argv)
5008 uint32_t recmasterrole = 0;
5012 usage("setrecmasterrole");
5015 if (strcmp(argv[0], "on") == 0) {
5017 } else if (strcmp(argv[0], "off") == 0) {
5020 usage("setrecmasterrole");
5023 ret = ctdb_ctrl_set_recmasterrole(mem_ctx, ctdb->ev, ctdb->client,
5024 ctdb->cmd_pnn, TIMEOUT(),
5033 static int control_setdbreadonly(TALLOC_CTX *mem_ctx,
5034 struct ctdb_context *ctdb,
5035 int argc, const char **argv)
5042 usage("setdbreadonly");
5045 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
5049 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
5050 fprintf(stderr, "Cannot set READONLY on persistent DB\n");
5054 ret = ctdb_ctrl_set_db_readonly(mem_ctx, ctdb->ev, ctdb->client,
5055 ctdb->cmd_pnn, TIMEOUT(), db_id);
5063 static int control_setdbsticky(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5064 int argc, const char **argv)
5071 usage("setdbsticky");
5074 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, NULL, &db_flags)) {
5078 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
5079 fprintf(stderr, "Cannot set STICKY on persistent DB\n");
5083 ret = ctdb_ctrl_set_db_sticky(mem_ctx, ctdb->ev, ctdb->client,
5084 ctdb->cmd_pnn, TIMEOUT(), db_id);
5092 static int control_pfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5093 int argc, const char **argv)
5095 const char *db_name;
5096 struct ctdb_db_context *db;
5097 struct ctdb_transaction_handle *h;
5102 if (argc < 2 || argc > 3) {
5106 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5110 if (! (db_flags & CTDB_DB_FLAGS_PERSISTENT)) {
5111 fprintf(stderr, "DB %s is not a persistent database\n",
5116 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5119 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5123 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5125 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5129 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5130 TIMEOUT(), db, true, &h);
5132 fprintf(stderr, "Failed to start transaction on db %s\n",
5137 ret = ctdb_transaction_fetch_record(h, key, mem_ctx, &data);
5139 fprintf(stderr, "Failed to read record for key %s\n",
5141 ctdb_transaction_cancel(h);
5145 printf("%.*s\n", (int)data.dsize, data.dptr);
5147 ctdb_transaction_cancel(h);
5151 static int control_pstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5152 int argc, const char **argv)
5154 const char *db_name;
5155 struct ctdb_db_context *db;
5156 struct ctdb_transaction_handle *h;
5165 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5169 if (! (db_flags & CTDB_DB_FLAGS_PERSISTENT)) {
5170 fprintf(stderr, "DB %s is not a persistent database\n",
5175 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5178 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5182 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5184 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5188 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
5190 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5194 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5195 TIMEOUT(), db, false, &h);
5197 fprintf(stderr, "Failed to start transaction on db %s\n",
5202 ret = ctdb_transaction_store_record(h, key, data);
5204 fprintf(stderr, "Failed to store record for key %s\n",
5206 ctdb_transaction_cancel(h);
5210 ret = ctdb_transaction_commit(h);
5212 fprintf(stderr, "Failed to commit transaction on db %s\n",
5214 ctdb_transaction_cancel(h);
5221 static int control_pdelete(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5222 int argc, const char **argv)
5224 const char *db_name;
5225 struct ctdb_db_context *db;
5226 struct ctdb_transaction_handle *h;
5235 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5239 if (! (db_flags & CTDB_DB_FLAGS_PERSISTENT)) {
5240 fprintf(stderr, "DB %s is not a persistent database\n",
5245 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5248 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5252 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5254 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5258 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5259 TIMEOUT(), db, false, &h);
5261 fprintf(stderr, "Failed to start transaction on db %s\n",
5266 ret = ctdb_transaction_delete_record(h, key);
5268 fprintf(stderr, "Failed to delete record for key %s\n",
5270 ctdb_transaction_cancel(h);
5274 ret = ctdb_transaction_commit(h);
5276 fprintf(stderr, "Failed to commit transaction on db %s\n",
5278 ctdb_transaction_cancel(h);
5285 static int ptrans_parse_string(TALLOC_CTX *mem_ctx, const char **ptr, TDB_DATA *data)
5293 /* Skip whitespace */
5294 n = strspn(*ptr, " \t");
5298 /* Quoted ASCII string - no wide characters! */
5300 n = strcspn(t, "\"");
5303 ret = str_to_data(t, n, mem_ctx, data);
5310 fprintf(stderr, "Unmatched \" in input %s\n", *ptr);
5314 fprintf(stderr, "Unsupported input format in %s\n", *ptr);
5321 #define MAX_LINE_SIZE 1024
5323 static bool ptrans_get_key_value(TALLOC_CTX *mem_ctx, FILE *file,
5324 TDB_DATA *key, TDB_DATA *value)
5326 char line [MAX_LINE_SIZE]; /* FIXME: make this more flexible? */
5330 ptr = fgets(line, MAX_LINE_SIZE, file);
5336 ret = ptrans_parse_string(mem_ctx, &ptr, key);
5337 if (ret != 0 || ptr == NULL || key->dptr == NULL) {
5338 /* Line Ignored but not EOF */
5344 ret = ptrans_parse_string(mem_ctx, &ptr, value);
5346 /* Line Ignored but not EOF */
5347 talloc_free(key->dptr);
5355 static int control_ptrans(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5356 int argc, const char **argv)
5358 const char *db_name;
5359 struct ctdb_db_context *db;
5360 struct ctdb_transaction_handle *h;
5363 TDB_DATA key, value;
5366 if (argc < 1 || argc > 2) {
5370 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5374 if (! (db_flags & CTDB_DB_FLAGS_PERSISTENT)) {
5375 fprintf(stderr, "DB %s is not a persistent database\n",
5381 file = fopen(argv[1], "r");
5383 fprintf(stderr, "Failed to open file %s\n", argv[1]);
5390 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5393 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5397 ret = ctdb_transaction_start(mem_ctx, ctdb->ev, ctdb->client,
5398 TIMEOUT(), db, false, &h);
5400 fprintf(stderr, "Failed to start transaction on db %s\n",
5405 while (ptrans_get_key_value(mem_ctx, file, &key, &value)) {
5406 if (key.dsize != 0) {
5407 ret = ctdb_transaction_store_record(h, key, value);
5409 fprintf(stderr, "Failed to store record\n");
5410 ctdb_transaction_cancel(h);
5413 talloc_free(key.dptr);
5414 talloc_free(value.dptr);
5418 ret = ctdb_transaction_commit(h);
5420 fprintf(stderr, "Failed to commit transaction on db %s\n",
5422 ctdb_transaction_cancel(h);
5426 if (file != stdin) {
5432 static int control_tfetch(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5433 int argc, const char **argv)
5435 struct tdb_context *tdb;
5437 struct ctdb_ltdb_header header;
5440 if (argc < 2 || argc > 3) {
5444 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5446 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5450 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5452 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5457 data = tdb_fetch(tdb, key);
5458 if (data.dptr == NULL) {
5459 fprintf(stderr, "No record for key %s\n", argv[1]);
5464 if (data.dsize < sizeof(struct ctdb_ltdb_header)) {
5465 fprintf(stderr, "Invalid record for key %s\n", argv[1]);
5476 fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0600);
5478 fprintf(stderr, "Failed to open output file %s\n",
5483 nwritten = sys_write(fd, data.dptr, data.dsize);
5484 if (nwritten != data.dsize) {
5485 fprintf(stderr, "Failed to write record to file\n");
5494 ret = ctdb_ltdb_header_extract(&data, &header);
5496 fprintf(stderr, "Failed to parse header from data\n");
5500 dump_ltdb_header(&header);
5501 dump_tdb_data("data", data);
5506 static int control_tstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5507 int argc, const char **argv)
5509 struct tdb_context *tdb;
5510 TDB_DATA key, data, value;
5511 struct ctdb_ltdb_header header;
5515 if (argc < 3 || argc > 5) {
5519 tdb = tdb_open(argv[0], 0, 0, O_RDWR, 0);
5521 fprintf(stderr, "Failed to open TDB file %s\n", argv[0]);
5525 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5527 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5532 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &value);
5534 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5539 ZERO_STRUCT(header);
5542 header.rsn = (uint64_t)strtoull(argv[3], NULL, 0);
5545 header.dmaster = (uint32_t)atol(argv[4]);
5548 header.flags = (uint32_t)atol(argv[5]);
5551 offset = ctdb_ltdb_header_len(&header);
5552 data.dsize = offset + value.dsize;
5553 data.dptr = talloc_size(mem_ctx, data.dsize);
5554 if (data.dptr == NULL) {
5555 fprintf(stderr, "Memory allocation error\n");
5560 ctdb_ltdb_header_push(&header, data.dptr);
5561 memcpy(data.dptr + offset, value.dptr, value.dsize);
5563 ret = tdb_store(tdb, key, data, TDB_REPLACE);
5565 fprintf(stderr, "Failed to write record %s to file %s\n",
5574 static int control_readkey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5575 int argc, const char **argv)
5577 const char *db_name;
5578 struct ctdb_db_context *db;
5579 struct ctdb_record_handle *h;
5582 bool readonly = false;
5585 if (argc < 2 || argc > 3) {
5590 if (strcmp(argv[2], "readonly") == 0) {
5597 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5601 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
5602 fprintf(stderr, "DB %s is not a volatile database\n",
5607 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5610 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5614 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5616 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5620 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5621 db, key, readonly, &h, NULL, &data);
5623 fprintf(stderr, "Failed to read record for key %s\n",
5626 printf("Data: size:%zu ptr:[%.*s]\n", data.dsize,
5627 (int)data.dsize, data.dptr);
5634 static int control_writekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5635 int argc, const char **argv)
5637 const char *db_name;
5638 struct ctdb_db_context *db;
5639 struct ctdb_record_handle *h;
5648 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5652 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
5653 fprintf(stderr, "DB %s is not a volatile database\n",
5658 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5661 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5665 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5667 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5671 ret = str_to_data(argv[2], strlen(argv[2]), mem_ctx, &data);
5673 fprintf(stderr, "Failed to parse value %s\n", argv[2]);
5677 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5678 db, key, false, &h, NULL, NULL);
5680 fprintf(stderr, "Failed to lock record for key %s\n", argv[0]);
5684 ret = ctdb_store_record(h, data);
5686 fprintf(stderr, "Failed to store record for key %s\n",
5694 static int control_deletekey(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5695 int argc, const char **argv)
5697 const char *db_name;
5698 struct ctdb_db_context *db;
5699 struct ctdb_record_handle *h;
5708 if (! db_exists(mem_ctx, ctdb, argv[0], NULL, &db_name, &db_flags)) {
5712 if (db_flags & CTDB_DB_FLAGS_PERSISTENT) {
5713 fprintf(stderr, "DB %s is not a volatile database\n",
5718 ret = ctdb_attach(ctdb->ev, ctdb->client, TIMEOUT(), db_name,
5721 fprintf(stderr, "Failed to attach to DB %s\n", db_name);
5725 ret = str_to_data(argv[1], strlen(argv[1]), mem_ctx, &key);
5727 fprintf(stderr, "Failed to parse key %s\n", argv[1]);
5731 ret = ctdb_fetch_lock(mem_ctx, ctdb->ev, ctdb->client,
5732 db, key, false, &h, NULL, &data);
5734 fprintf(stderr, "Failed to fetch record for key %s\n",
5739 ret = ctdb_delete_record(h);
5741 fprintf(stderr, "Failed to delete record for key %s\n",
5749 static int control_checktcpport(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5750 int argc, const char **argv)
5752 struct sockaddr_in sin;
5758 usage("chktcpport");
5761 port = atoi(argv[0]);
5763 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
5765 fprintf(stderr, "Failed to open local socket\n");
5769 v = fcntl(s, F_GETFL, 0);
5770 if (v == -1 || fcntl(s, F_SETFL, v | O_NONBLOCK)) {
5771 fprintf(stderr, "Unable to set socket non-blocking\n");
5776 bzero(&sin, sizeof(sin));
5777 sin.sin_family = AF_INET;
5778 sin.sin_port = htons(port);
5779 ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
5782 fprintf(stderr, "Failed to bind to TCP port %u\n", port);
5789 static int control_rebalancenode(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5790 int argc, const char **argv)
5793 usage("rebalancenode");
5796 if (! rebalancenode(mem_ctx, ctdb, ctdb->cmd_pnn)) {
5797 fprintf(stderr, "Failed to rebalance IPs on node %u\n",
5805 static int control_getdbseqnum(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5806 int argc, const char **argv)
5809 const char *db_name;
5814 usage("getdbseqnum");
5817 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5821 ret = ctdb_ctrl_get_db_seqnum(mem_ctx, ctdb->ev, ctdb->client,
5822 ctdb->cmd_pnn, TIMEOUT(), db_id,
5825 fprintf(stderr, "Failed to get sequence number for DB %s\n",
5830 printf("0x%"PRIx64"\n", seqnum);
5834 static int control_nodestatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5835 int argc, const char **argv)
5837 const char *nodestring = NULL;
5838 struct ctdb_node_map *nodemap;
5842 usage("nodestatus");
5846 nodestring = argv[0];
5849 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap)) {
5853 nodemap = get_nodemap(ctdb, false);
5854 if (nodemap == NULL) {
5858 if (options.machinereadable) {
5859 print_nodemap_machine(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
5861 print_nodemap(mem_ctx, ctdb, nodemap, ctdb->cmd_pnn);
5865 for (i=0; i<nodemap->num; i++) {
5866 ret |= nodemap->node[i].flags;
5875 } db_stats_fields[] = {
5876 #define DBSTATISTICS_FIELD(n) { #n, offsetof(struct ctdb_db_statistics, n) }
5877 DBSTATISTICS_FIELD(db_ro_delegations),
5878 DBSTATISTICS_FIELD(db_ro_revokes),
5879 DBSTATISTICS_FIELD(locks.num_calls),
5880 DBSTATISTICS_FIELD(locks.num_current),
5881 DBSTATISTICS_FIELD(locks.num_pending),
5882 DBSTATISTICS_FIELD(locks.num_failed),
5883 DBSTATISTICS_FIELD(db_ro_delegations),
5886 static void print_dbstatistics(const char *db_name,
5887 struct ctdb_db_statistics *s)
5890 const char *prefix = NULL;
5893 printf("DB Statistics %s\n", db_name);
5895 for (i=0; i<ARRAY_SIZE(db_stats_fields); i++) {
5896 if (strchr(db_stats_fields[i].name, '.') != NULL) {
5897 preflen = strcspn(db_stats_fields[i].name, ".") + 1;
5899 strncmp(prefix, db_stats_fields[i].name, preflen) != 0) {
5900 prefix = db_stats_fields[i].name;
5901 printf(" %*.*s\n", preflen-1, preflen-1,
5902 db_stats_fields[i].name);
5907 printf(" %*s%-22s%*s%10u\n", preflen ? 4 : 0, "",
5908 db_stats_fields[i].name+preflen, preflen ? 0 : 4, "",
5909 *(uint32_t *)(db_stats_fields[i].offset+(uint8_t *)s));
5912 printf(" hop_count_buckets:");
5913 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5914 printf(" %d", s->hop_count_bucket[i]);
5918 printf(" lock_buckets:");
5919 for (i=0; i<MAX_COUNT_BUCKETS; i++) {
5920 printf(" %d", s->locks.buckets[i]);
5924 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5925 "locks_latency MIN/AVG/MAX",
5926 s->locks.latency.min, LATENCY_AVG(s->locks.latency),
5927 s->locks.latency.max, s->locks.latency.num);
5929 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n",
5930 "vacuum_latency MIN/AVG/MAX",
5931 s->vacuum.latency.min, LATENCY_AVG(s->vacuum.latency),
5932 s->vacuum.latency.max, s->vacuum.latency.num);
5934 printf(" Num Hot Keys: %d\n", s->num_hot_keys);
5935 for (i=0; i<s->num_hot_keys; i++) {
5937 printf(" Count:%d Key:", s->hot_keys[i].count);
5938 for (j=0; j<s->hot_keys[i].key.dsize; j++) {
5939 printf("%02x", s->hot_keys[i].key.dptr[j] & 0xff);
5945 static int control_dbstatistics(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
5946 int argc, const char **argv)
5949 const char *db_name;
5950 struct ctdb_db_statistics *dbstats;
5954 usage("dbstatistics");
5957 if (! db_exists(mem_ctx, ctdb, argv[0], &db_id, &db_name, NULL)) {
5961 ret = ctdb_ctrl_get_db_statistics(mem_ctx, ctdb->ev, ctdb->client,
5962 ctdb->cmd_pnn, TIMEOUT(), db_id,
5965 fprintf(stderr, "Failed to get statistics for DB %s\n",
5970 print_dbstatistics(db_name, dbstats);
5974 struct disable_takeover_runs_state {
5982 static void disable_takeover_run_handler(uint64_t srvid, TDB_DATA data,
5985 struct disable_takeover_runs_state *state =
5986 (struct disable_takeover_runs_state *)private_data;
5989 if (data.dsize != sizeof(int)) {
5994 /* ret will be a PNN (i.e. >=0) on success, or negative on error */
5995 ret = *(int *)data.dptr;
5997 state->status = ret;
6001 for (i=0; i<state->node_count; i++) {
6002 if (state->pnn_list[i] == ret) {
6003 state->reply[i] = true;
6009 for (i=0; i<state->node_count; i++) {
6010 if (! state->reply[i]) {
6011 state->done = false;
6017 static int disable_takeover_runs(TALLOC_CTX *mem_ctx,
6018 struct ctdb_context *ctdb, uint32_t timeout,
6019 uint32_t *pnn_list, int count)
6021 struct ctdb_disable_message disable = { 0 };
6022 struct disable_takeover_runs_state state;
6025 disable.pnn = ctdb->pnn;
6026 disable.srvid = next_srvid(ctdb);
6027 disable.timeout = timeout;
6029 state.pnn_list = pnn_list;
6030 state.node_count = count;
6033 state.reply = talloc_zero_array(mem_ctx, bool, count);
6034 if (state.reply == NULL) {
6038 ret = ctdb_client_set_message_handler(ctdb->ev, ctdb->client,
6040 disable_takeover_run_handler,
6046 for (i=0; i<count; i++) {
6047 ret = ctdb_message_disable_takeover_runs(mem_ctx, ctdb->ev,
6056 ret = ctdb_client_wait_timeout(ctdb->ev, &state.done, TIMEOUT());
6058 fprintf(stderr, "Timed out waiting to disable takeover runs\n");
6060 ret = (state.status >= 0 ? 0 : 1);
6064 ctdb_client_remove_message_handler(ctdb->ev, ctdb->client,
6065 disable.srvid, &state);
6069 static int control_reloadips(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
6070 int argc, const char **argv)
6072 const char *nodestring = NULL;
6073 struct ctdb_node_map *nodemap, *nodemap2;
6074 struct ctdb_req_control request;
6075 uint32_t *pnn_list, *pnn_list2;
6076 int ret, count, count2;
6083 nodestring = argv[0];
6086 nodemap = get_nodemap(ctdb, false);
6087 if (nodemap == NULL) {
6091 if (! parse_nodestring(mem_ctx, ctdb, nodestring, &nodemap2)) {
6095 count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN,
6096 mem_ctx, &pnn_list);
6098 fprintf(stderr, "Memory allocation error\n");
6102 count2 = list_of_active_nodes(nodemap2, CTDB_UNKNOWN_PNN,
6103 mem_ctx, &pnn_list2);
6105 fprintf(stderr, "Memory allocation error\n");
6109 /* Disable takeover runs on all connected nodes. A reply
6110 * indicating success is needed from each node so all nodes
6111 * will need to be active.
6113 * A check could be added to not allow reloading of IPs when
6114 * there are disconnected nodes. However, this should
6115 * probably be left up to the administrator.
6117 ret = disable_takeover_runs(mem_ctx, ctdb, 2*options.timelimit,
6120 fprintf(stderr, "Failed to disable takeover runs\n");
6124 /* Now tell all the desired nodes to reload their public IPs.
6125 * Keep trying this until it succeeds. This assumes all
6126 * failures are transient, which might not be true...
6128 ctdb_req_control_reload_public_ips(&request);
6129 ret = ctdb_client_control_multi(mem_ctx, ctdb->ev, ctdb->client,
6130 pnn_list2, count2, TIMEOUT(),
6131 &request, NULL, NULL);
6133 fprintf(stderr, "Failed to reload IPs on some nodes.\n");
6136 /* It isn't strictly necessary to wait until takeover runs are
6137 * re-enabled but doing so can't hurt.
6139 ret = disable_takeover_runs(mem_ctx, ctdb, 0, pnn_list, count);
6141 fprintf(stderr, "Failed to enable takeover runs\n");
6145 return ipreallocate(mem_ctx, ctdb);
6148 static int control_ipiface(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
6149 int argc, const char **argv)
6151 ctdb_sock_addr addr;
6158 if (! parse_ip(argv[0], NULL, 0, &addr)) {
6159 fprintf(stderr, "Failed to Parse IP %s\n", argv[0]);
6163 iface = ctdb_sys_find_ifname(&addr);
6164 if (iface == NULL) {
6165 fprintf(stderr, "Failed to find interface for IP %s\n",
6175 static const struct ctdb_cmd {
6177 int (*fn)(TALLOC_CTX *, struct ctdb_context *, int, const char **);
6178 bool without_daemon; /* can be run without daemon running ? */
6179 bool remote; /* can be run on remote nodes */
6182 } ctdb_commands[] = {
6183 { "version", control_version, true, false,
6184 "show version of ctdb", NULL },
6185 { "status", control_status, false, true,
6186 "show node status", NULL },
6187 { "uptime", control_uptime, false, true,
6188 "show node uptime", NULL },
6189 { "ping", control_ping, false, true,
6190 "ping all nodes", NULL },
6191 { "runstate", control_runstate, false, true,
6192 "get/check runstate of a node",
6193 "[setup|first_recovery|startup|running]" },
6194 { "getvar", control_getvar, false, true,
6195 "get a tunable variable", "<name>" },
6196 { "setvar", control_setvar, false, true,
6197 "set a tunable variable", "<name> <value>" },
6198 { "listvars", control_listvars, false, true,
6199 "list tunable variables", NULL },
6200 { "statistics", control_statistics, false, true,
6201 "show ctdb statistics", NULL },
6202 { "statisticsreset", control_statistics_reset, false, true,
6203 "reset ctdb statistics", NULL },
6204 { "stats", control_stats, false, true,
6205 "show rolling statistics", "[count]" },
6206 { "ip", control_ip, false, true,
6207 "show public ips", "[all]" },
6208 { "ipinfo", control_ipinfo, false, true,
6209 "show public ip details", "<ip>" },
6210 { "ifaces", control_ifaces, false, true,
6211 "show interfaces", NULL },
6212 { "setifacelink", control_setifacelink, false, true,
6213 "set interface link status", "<iface> up|down" },
6214 { "process-exists", control_process_exists, false, true,
6215 "check if a process exists on a node", "<pid>" },
6216 { "getdbmap", control_getdbmap, false, true,
6217 "show attached databases", NULL },
6218 { "getdbstatus", control_getdbstatus, false, true,
6219 "show database status", "<dbname|dbid>" },
6220 { "catdb", control_catdb, false, false,
6221 "dump cluster-wide ctdb database", "<dbname|dbid>" },
6222 { "cattdb", control_cattdb, false, false,
6223 "dump local ctdb database", "<dbname|dbid>" },
6224 { "getmonmode", control_getmonmode, false, true,
6225 "show monitoring mode", NULL },
6226 { "getcapabilities", control_getcapabilities, false, true,
6227 "show node capabilities", NULL },
6228 { "pnn", control_pnn, false, false,
6229 "show the pnn of the currnet node", NULL },
6230 { "lvs", control_lvs, false, false,
6231 "show lvs configuration", "master|list|status" },
6232 { "disablemonitor", control_disable_monitor, false, true,
6233 "disable monitoring", NULL },
6234 { "enablemonitor", control_enable_monitor, false, true,
6235 "enable monitoring", NULL },
6236 { "setdebug", control_setdebug, false, true,
6237 "set debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
6238 { "getdebug", control_getdebug, false, true,
6239 "get debug level", NULL },
6240 { "attach", control_attach, false, false,
6241 "attach a database", "<dbname> [persistent]" },
6242 { "detach", control_detach, false, false,
6243 "detach database(s)", "<dbname|dbid> ..." },
6244 { "dumpmemory", control_dumpmemory, false, true,
6245 "dump ctdbd memory map", NULL },
6246 { "rddumpmemory", control_rddumpmemory, false, true,
6247 "dump recoverd memory map", NULL },
6248 { "getpid", control_getpid, false, true,
6249 "get ctdbd process ID", NULL },
6250 { "disable", control_disable, false, true,
6251 "disable a node", NULL },
6252 { "enable", control_enable, false, true,
6253 "enable a node", NULL },
6254 { "stop", control_stop, false, true,
6255 "stop a node", NULL },
6256 { "continue", control_continue, false, true,
6257 "continue a stopped node", NULL },
6258 { "ban", control_ban, false, true,
6259 "ban a node", "<bantime>"},
6260 { "unban", control_unban, false, true,
6261 "unban a node", NULL },
6262 { "shutdown", control_shutdown, false, true,
6263 "shutdown ctdb daemon", NULL },
6264 { "recover", control_recover, false, true,
6265 "force recovery", NULL },
6266 { "sync", control_ipreallocate, false, true,
6267 "run ip reallocation (deprecated)", NULL },
6268 { "ipreallocate", control_ipreallocate, false, true,
6269 "run ip reallocation", NULL },
6270 { "isnotrecmaster", control_isnotrecmaster, false, false,
6271 "check if local node is the recmaster", NULL },
6272 { "gratarp", control_gratarp, false, true,
6273 "send a gratuitous arp", "<ip> <interface>" },
6274 { "tickle", control_tickle, true, false,
6275 "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
6276 { "gettickles", control_gettickles, false, true,
6277 "get the list of tickles", "<ip> [<port>]" },
6278 { "addtickle", control_addtickle, false, true,
6279 "add a tickle", "<ip>:<port> <ip>:<port>" },
6280 { "deltickle", control_deltickle, false, true,
6281 "delete a tickle", "<ip>:<port> <ip>:<port>" },
6282 { "check_srvids", control_check_srvids, false, true,
6283 "check if srvid is registered", "<id> [<id> ...]" },
6284 { "listnodes", control_listnodes, true, true,
6285 "list nodes in the cluster", NULL },
6286 { "reloadnodes", control_reloadnodes, false, false,
6287 "reload the nodes file all nodes", NULL },
6288 { "moveip", control_moveip, false, false,
6289 "move an ip address to another node", "<ip> <node>" },
6290 { "rebalanceip", control_rebalanceip, false, false,
6291 "move an ip address optimally to another node", "<ip>" },
6292 { "addip", control_addip, false, true,
6293 "add an ip address to a node", "<ip/mask> <iface>" },
6294 { "delip", control_delip, false, true,
6295 "delete an ip address from a node", "<ip>" },
6296 { "eventscript", control_eventscript, false, true,
6297 "run an event", "monitor" },
6298 { "backupdb", control_backupdb, false, false,
6299 "backup a database into a file", "<dbname|dbid> <file>" },
6300 { "restoredb", control_restoredb, false, false,
6301 "restore a database from a file", "<file> [dbname]" },
6302 { "dumpdbbackup", control_dumpdbbackup, true, false,
6303 "dump database from a backup file", "<file>" },
6304 { "wipedb", control_wipedb, false, false,
6305 "wipe the contents of a database.", "<dbname|dbid>"},
6306 { "recmaster", control_recmaster, false, true,
6307 "show the pnn for the recovery master", NULL },
6308 { "scriptstatus", control_scriptstatus, false, true,
6309 "show event script status",
6310 "[init|setup|startup|monitor|takeip|releaseip|ipreallocated]" },
6311 { "enablescript", control_enablescript, false, true,
6312 "enable an eventscript", "<script>"},
6313 { "disablescript", control_disablescript, false, true,
6314 "disable an eventscript", "<script>"},
6315 { "natgw", control_natgw, false, false,
6316 "show natgw configuration", "master|list|status" },
6317 { "natgwlist", control_natgwlist, false, false,
6318 "show the nodes belonging to this natgw configuration", NULL },
6319 { "getreclock", control_getreclock, false, true,
6320 "get recovery lock file", NULL },
6321 { "setlmasterrole", control_setlmasterrole, false, true,
6322 "set LMASTER role", "on|off" },
6323 { "setrecmasterrole", control_setrecmasterrole, false, true,
6324 "set RECMASTER role", "on|off"},
6325 { "setdbreadonly", control_setdbreadonly, false, true,
6326 "enable readonly records", "<dbname|dbid>" },
6327 { "setdbsticky", control_setdbsticky, false, true,
6328 "enable sticky records", "<dbname|dbid>"},
6329 { "pfetch", control_pfetch, false, false,
6330 "fetch record from persistent database", "<dbname|dbid> <key> [<file>]" },
6331 { "pstore", control_pstore, false, false,
6332 "write record to persistent database", "<dbname|dbid> <key> <value>" },
6333 { "pdelete", control_pdelete, false, false,
6334 "delete record from persistent database", "<dbname|dbid> <key>" },
6335 { "ptrans", control_ptrans, false, false,
6336 "update a persistent database (from file or stdin)", "<dbname|dbid> [<file>]" },
6337 { "tfetch", control_tfetch, false, true,
6338 "fetch a record", "<tdb-file> <key> [<file>]" },
6339 { "tstore", control_tstore, false, true,
6340 "store a record", "<tdb-file> <key> <data> [<rsn> <dmaster> <flags>]" },
6341 { "readkey", control_readkey, false, false,
6342 "read value of a database key", "<dbname|dbid> <key> [readonly]" },
6343 { "writekey", control_writekey, false, false,
6344 "write value for a database key", "<dbname|dbid> <key> <value>" },
6345 { "deletekey", control_deletekey, false, false,
6346 "delete a database key", "<dbname|dbid> <key>" },
6347 { "checktcpport", control_checktcpport, true, false,
6348 "check if a service is bound to a specific tcp port or not", "<port>" },
6349 { "rebalancenode", control_rebalancenode, false, true,
6350 "mark nodes as forced IP rebalancing targets", NULL },
6351 { "getdbseqnum", control_getdbseqnum, false, false,
6352 "get database sequence number", "<dbname|dbid>" },
6353 { "nodestatus", control_nodestatus, false, true,
6354 "show and return node status", "[all|<pnn-list>]" },
6355 { "dbstatistics", control_dbstatistics, false, true,
6356 "show database statistics", "<dbname|dbid>" },
6357 { "reloadips", control_reloadips, false, false,
6358 "reload the public addresses file", "[all|<pnn-list>]" },
6359 { "ipiface", control_ipiface, true, false,
6360 "Find the interface an ip address is hosted on", "<ip>" },
6363 static const struct ctdb_cmd *match_command(const char *command)
6365 const struct ctdb_cmd *cmd;
6368 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6369 cmd = &ctdb_commands[i];
6370 if (strlen(command) == strlen(cmd->name) &&
6371 strncmp(command, cmd->name, strlen(command)) == 0) {
6381 * Show usage message
6383 static void usage_full(void)
6387 poptPrintHelp(pc, stdout, 0);
6388 printf("\nCommands:\n");
6389 for (i=0; i<ARRAY_SIZE(ctdb_commands); i++) {
6390 printf(" %-15s %-27s %s\n",
6391 ctdb_commands[i].name,
6392 ctdb_commands[i].args ? ctdb_commands[i].args : "",
6393 ctdb_commands[i].msg);
6397 static void usage(const char *command)
6399 const struct ctdb_cmd *cmd;
6401 if (command == NULL) {
6406 cmd = match_command(command);
6410 poptPrintUsage(pc, stdout, 0);
6411 printf("\nCommands:\n");
6412 printf(" %-15s %-27s %s\n",
6413 cmd->name, cmd->args ? cmd->args : "", cmd->msg);
6419 struct poptOption cmdline_options[] = {
6421 { "socket", 's', POPT_ARG_STRING, &options.socket, 0,
6422 "CTDB socket path", "filename" },
6423 { "debug", 'd', POPT_ARG_STRING, &options.debuglevelstr, 0,
6425 { "timelimit", 't', POPT_ARG_INT, &options.timelimit, 0,
6426 "timelimit (in seconds)" },
6427 { "node", 'n', POPT_ARG_INT, &options.pnn, 0,
6428 "node specification - integer" },
6429 { NULL, 'Y', POPT_ARG_NONE, &options.machinereadable, 0,
6430 "enable machine readable output", NULL },
6431 { "separator", 'x', POPT_ARG_STRING, &options.sep, 0,
6432 "specify separator for machine readable output", "CHAR" },
6433 { NULL, 'X', POPT_ARG_NONE, &options.machineparsable, 0,
6434 "enable machine parsable output with separator |", NULL },
6435 { "verbose", 'v', POPT_ARG_NONE, &options.verbose, 0,
6436 "enable verbose output", NULL },
6437 { "maxruntime", 'T', POPT_ARG_INT, &options.maxruntime, 0,
6438 "die if runtime exceeds this limit (in seconds)" },
6442 static int process_command(const struct ctdb_cmd *cmd, int argc,
6445 TALLOC_CTX *tmp_ctx;
6446 struct ctdb_context *ctdb;
6449 uint64_t srvid_offset;
6451 tmp_ctx = talloc_new(NULL);
6452 if (tmp_ctx == NULL) {
6453 fprintf(stderr, "Memory allocation error\n");
6457 if (cmd->without_daemon) {
6458 if (options.pnn != -1) {
6460 "Cannot specify node for command %s\n",
6465 ret = cmd->fn(tmp_ctx, NULL, argc-1, argv+1);
6466 talloc_free(tmp_ctx);
6470 ctdb = talloc_zero(tmp_ctx, struct ctdb_context);
6472 fprintf(stderr, "Memory allocation error\n");
6476 ctdb->ev = tevent_context_init(ctdb);
6477 if (ctdb->ev == NULL) {
6478 fprintf(stderr, "Failed to initialize tevent\n");
6482 ret = ctdb_client_init(ctdb, ctdb->ev, options.socket, &ctdb->client);
6484 fprintf(stderr, "Failed to connect to CTDB daemon (%s)\n",
6487 if (!find_node_xpnn(ctdb, NULL)) {
6488 fprintf(stderr, "Is this node part of CTDB cluster?\n");
6493 ctdb->pnn = ctdb_client_pnn(ctdb->client);
6494 srvid_offset = getpid() & 0xFFFF;
6495 ctdb->srvid = SRVID_CTDB_TOOL | (srvid_offset << 16);
6497 if (options.pnn != -1) {
6498 status = verify_pnn(ctdb, options.pnn);
6503 ctdb->cmd_pnn = options.pnn;
6505 ctdb->cmd_pnn = ctdb->pnn;
6508 if (! cmd->remote && ctdb->pnn != ctdb->cmd_pnn) {
6509 fprintf(stderr, "Node cannot be specified for command %s\n",
6514 ret = cmd->fn(tmp_ctx, ctdb, argc-1, argv+1);
6515 talloc_free(tmp_ctx);
6519 talloc_free(tmp_ctx);
6523 static void signal_handler(int sig)
6525 fprintf(stderr, "Maximum runtime exceeded - exiting\n");
6528 static void alarm_handler(int sig)
6530 /* Kill any child processes */
6531 signal(SIGTERM, signal_handler);
6537 int main(int argc, const char *argv[])
6540 const char **extra_argv;
6542 const struct ctdb_cmd *cmd;
6543 const char *ctdb_socket;
6544 enum debug_level loglevel;
6549 /* Set default options */
6550 options.socket = CTDB_SOCKET;
6551 options.debuglevelstr = NULL;
6552 options.timelimit = 10;
6554 options.maxruntime = 0;
6557 ctdb_socket = getenv("CTDB_SOCKET");
6558 if (ctdb_socket != NULL) {
6559 options.socket = ctdb_socket;
6562 pc = poptGetContext(argv[0], argc, argv, cmdline_options,
6563 POPT_CONTEXT_KEEP_FIRST);
6564 while ((opt = poptGetNextOpt(pc)) != -1) {
6565 fprintf(stderr, "Invalid option %s: %s\n",
6566 poptBadOption(pc, 0), poptStrerror(opt));
6570 if (options.maxruntime == 0) {
6571 const char *ctdb_timeout;
6573 ctdb_timeout = getenv("CTDB_TIMEOUT");
6574 if (ctdb_timeout != NULL) {
6575 options.maxruntime = strtoul(ctdb_timeout, NULL, 0);
6577 options.maxruntime = 120;
6580 if (options.maxruntime <= 120) {
6581 /* default timeout is 120 seconds */
6582 options.maxruntime = 120;
6585 if (options.machineparsable) {
6586 options.machinereadable = 1;
6589 /* setup the remaining options for the commands */
6591 extra_argv = poptGetArgs(pc);
6594 while (extra_argv[extra_argc]) extra_argc++;
6597 if (extra_argc < 1) {
6601 cmd = match_command(extra_argv[0]);
6603 fprintf(stderr, "Unknown command '%s'\n", extra_argv[0]);
6607 /* Enable logging */
6608 setup_logging("ctdb", DEBUG_STDERR);
6609 if (debug_level_parse(options.debuglevelstr, &loglevel)) {
6610 DEBUGLEVEL = loglevel;
6612 DEBUGLEVEL = DEBUG_ERR;
6615 signal(SIGALRM, alarm_handler);
6616 alarm(options.maxruntime);
6618 ret = process_command(cmd, extra_argc, extra_argv);
6623 (void)poptFreeContext(pc);