4 Copyright (C) Andrew Tridgell 2007
5 Copyright (C) Ronnie Sahlberg 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "lib/tevent/tevent.h"
23 #include "system/time.h"
24 #include "system/filesys.h"
25 #include "system/network.h"
26 #include "system/locale.h"
29 #include "../include/ctdb.h"
30 #include "../include/ctdb_client.h"
31 #include "../include/ctdb_private.h"
32 #include "../common/rb_tree.h"
35 #define ERR_TIMEOUT 20 /* timed out trying to reach node */
36 #define ERR_NONODE 21 /* node does not exist */
37 #define ERR_DISNODE 22 /* node is disconnected */
39 struct ctdb_connection
*ctdb_connection
;
41 static void usage(void);
49 int printemptyrecords
;
53 #define TIMELIMIT() timeval_current_ofs(options.timelimit, 0)
54 #define LONGTIMELIMIT() timeval_current_ofs(options.timelimit*10, 0)
57 static int control_version(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
60 #define XSTR(x) STR(x)
61 printf("CTDB version: %s\n", XSTR(CTDB_VERS
));
68 verify that a node exists and is reachable
70 static void verify_node(struct ctdb_context
*ctdb
)
73 struct ctdb_node_map
*nodemap
=NULL
;
75 if (options
.pnn
== CTDB_CURRENT_NODE
) {
78 if (options
.pnn
== CTDB_BROADCAST_ALL
) {
82 /* verify the node exists */
83 if (ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
, ctdb
, &nodemap
) != 0) {
84 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from local node\n"));
87 if (options
.pnn
>= nodemap
->num
) {
88 DEBUG(DEBUG_ERR
, ("Node %u does not exist\n", options
.pnn
));
91 if (nodemap
->nodes
[options
.pnn
].flags
& NODE_FLAGS_DELETED
) {
92 DEBUG(DEBUG_ERR
, ("Node %u is DELETED\n", options
.pnn
));
95 if (nodemap
->nodes
[options
.pnn
].flags
& NODE_FLAGS_DISCONNECTED
) {
96 DEBUG(DEBUG_ERR
, ("Node %u is DISCONNECTED\n", options
.pnn
));
100 /* verify we can access the node */
101 ret
= ctdb_ctrl_getpnn(ctdb
, TIMELIMIT(), options
.pnn
);
103 DEBUG(DEBUG_ERR
,("Can not access node. Node is not operational.\n"));
109 check if a database exists
111 static int db_exists(struct ctdb_context
*ctdb
, const char *db_name
, bool *persistent
)
114 struct ctdb_dbid_map
*dbmap
=NULL
;
116 ret
= ctdb_ctrl_getdbmap(ctdb
, TIMELIMIT(), options
.pnn
, ctdb
, &dbmap
);
118 DEBUG(DEBUG_ERR
, ("Unable to get dbids from node %u\n", options
.pnn
));
122 for(i
=0;i
<dbmap
->num
;i
++){
125 ctdb_ctrl_getdbname(ctdb
, TIMELIMIT(), options
.pnn
, dbmap
->dbs
[i
].dbid
, ctdb
, &name
);
126 if (!strcmp(name
, db_name
)) {
128 *persistent
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_PERSISTENT
;
138 see if a process exists
140 static int control_process_exists(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
148 if (sscanf(argv
[0], "%u:%u", &pnn
, &pid
) != 2) {
149 DEBUG(DEBUG_ERR
, ("Badly formed pnn:pid\n"));
153 ret
= ctdb_ctrl_process_exists(ctdb
, pnn
, pid
);
155 printf("%u:%u exists\n", pnn
, pid
);
157 printf("%u:%u does not exist\n", pnn
, pid
);
163 display statistics structure
165 static void show_statistics(struct ctdb_statistics
*s
, int show_header
)
167 TALLOC_CTX
*tmp_ctx
= talloc_new(NULL
);
169 const char *prefix
=NULL
;
171 int tmp
, days
, hours
, minutes
, seconds
;
176 #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
177 STATISTICS_FIELD(num_clients
),
178 STATISTICS_FIELD(frozen
),
179 STATISTICS_FIELD(recovering
),
180 STATISTICS_FIELD(num_recoveries
),
181 STATISTICS_FIELD(client_packets_sent
),
182 STATISTICS_FIELD(client_packets_recv
),
183 STATISTICS_FIELD(node_packets_sent
),
184 STATISTICS_FIELD(node_packets_recv
),
185 STATISTICS_FIELD(keepalive_packets_sent
),
186 STATISTICS_FIELD(keepalive_packets_recv
),
187 STATISTICS_FIELD(node
.req_call
),
188 STATISTICS_FIELD(node
.reply_call
),
189 STATISTICS_FIELD(node
.req_dmaster
),
190 STATISTICS_FIELD(node
.reply_dmaster
),
191 STATISTICS_FIELD(node
.reply_error
),
192 STATISTICS_FIELD(node
.req_message
),
193 STATISTICS_FIELD(node
.req_control
),
194 STATISTICS_FIELD(node
.reply_control
),
195 STATISTICS_FIELD(client
.req_call
),
196 STATISTICS_FIELD(client
.req_message
),
197 STATISTICS_FIELD(client
.req_control
),
198 STATISTICS_FIELD(timeouts
.call
),
199 STATISTICS_FIELD(timeouts
.control
),
200 STATISTICS_FIELD(timeouts
.traverse
),
201 STATISTICS_FIELD(total_calls
),
202 STATISTICS_FIELD(pending_calls
),
203 STATISTICS_FIELD(lockwait_calls
),
204 STATISTICS_FIELD(pending_lockwait_calls
),
205 STATISTICS_FIELD(childwrite_calls
),
206 STATISTICS_FIELD(pending_childwrite_calls
),
207 STATISTICS_FIELD(memory_used
),
208 STATISTICS_FIELD(max_hop_count
),
210 tmp
= s
->statistics_current_time
.tv_sec
- s
->statistics_start_time
.tv_sec
;
219 if (options
.machinereadable
){
221 printf("CTDB version:");
222 printf("Current time of statistics:");
223 printf("Statistics collected since:");
224 for (i
=0;i
<ARRAY_SIZE(fields
);i
++) {
225 printf("%s:", fields
[i
].name
);
227 printf("num_reclock_ctdbd_latency:");
228 printf("min_reclock_ctdbd_latency:");
229 printf("avg_reclock_ctdbd_latency:");
230 printf("max_reclock_ctdbd_latency:");
232 printf("num_reclock_recd_latency:");
233 printf("min_reclock_recd_latency:");
234 printf("avg_reclock_recd_latency:");
235 printf("max_reclock_recd_latency:");
237 printf("num_call_latency:");
238 printf("min_call_latency:");
239 printf("avg_call_latency:");
240 printf("max_call_latency:");
242 printf("num_lockwait_latency:");
243 printf("min_lockwait_latency:");
244 printf("avg_lockwait_latency:");
245 printf("max_lockwait_latency:");
247 printf("num_childwrite_latency:");
248 printf("min_childwrite_latency:");
249 printf("avg_childwrite_latency:");
250 printf("max_childwrite_latency:");
253 printf("%d:", CTDB_VERSION
);
254 printf("%d:", (int)s
->statistics_current_time
.tv_sec
);
255 printf("%d:", (int)s
->statistics_start_time
.tv_sec
);
256 for (i
=0;i
<ARRAY_SIZE(fields
);i
++) {
257 printf("%d:", *(uint32_t *)(fields
[i
].offset
+(uint8_t *)s
));
259 printf("%d:", s
->reclock
.ctdbd
.num
);
260 printf("%.6f:", s
->reclock
.ctdbd
.min
);
261 printf("%.6f:", s
->reclock
.ctdbd
.num
?s
->reclock
.ctdbd
.total
/s
->reclock
.ctdbd
.num
:0.0);
262 printf("%.6f:", s
->reclock
.ctdbd
.max
);
264 printf("%d:", s
->reclock
.recd
.num
);
265 printf("%.6f:", s
->reclock
.recd
.min
);
266 printf("%.6f:", s
->reclock
.recd
.num
?s
->reclock
.recd
.total
/s
->reclock
.recd
.num
:0.0);
267 printf("%.6f:", s
->reclock
.recd
.max
);
269 printf("%d:", s
->call_latency
.num
);
270 printf("%.6f:", s
->call_latency
.min
);
271 printf("%.6f:", s
->call_latency
.num
?s
->call_latency
.total
/s
->call_latency
.num
:0.0);
272 printf("%.6f:", s
->call_latency
.max
);
274 printf("%d:", s
->lockwait_latency
.num
);
275 printf("%.6f:", s
->lockwait_latency
.min
);
276 printf("%.6f:", s
->lockwait_latency
.num
?s
->lockwait_latency
.total
/s
->lockwait_latency
.num
:0.0);
277 printf("%.6f:", s
->lockwait_latency
.max
);
279 printf("%d:", s
->childwrite_latency
.num
);
280 printf("%.6f:", s
->childwrite_latency
.min
);
281 printf("%.6f:", s
->childwrite_latency
.num
?s
->childwrite_latency
.total
/s
->childwrite_latency
.num
:0.0);
282 printf("%.6f:", s
->childwrite_latency
.max
);
285 printf("CTDB version %u\n", CTDB_VERSION
);
286 printf("Current time of statistics : %s", ctime(&s
->statistics_current_time
.tv_sec
));
287 printf("Statistics collected since : (%03d %02d:%02d:%02d) %s", days
, hours
, minutes
, seconds
, ctime(&s
->statistics_start_time
.tv_sec
));
289 for (i
=0;i
<ARRAY_SIZE(fields
);i
++) {
290 if (strchr(fields
[i
].name
, '.')) {
291 preflen
= strcspn(fields
[i
].name
, ".")+1;
292 if (!prefix
|| strncmp(prefix
, fields
[i
].name
, preflen
) != 0) {
293 prefix
= fields
[i
].name
;
294 printf(" %*.*s\n", preflen
-1, preflen
-1, fields
[i
].name
);
299 printf(" %*s%-22s%*s%10u\n",
301 fields
[i
].name
+preflen
,
303 *(uint32_t *)(fields
[i
].offset
+(uint8_t *)s
));
305 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n", "reclock_ctdbd MIN/AVG/MAX", s
->reclock
.ctdbd
.min
, s
->reclock
.ctdbd
.num
?s
->reclock
.ctdbd
.total
/s
->reclock
.ctdbd
.num
:0.0, s
->reclock
.ctdbd
.max
, s
->reclock
.ctdbd
.num
);
307 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n", "reclock_recd MIN/AVG/MAX", s
->reclock
.recd
.min
, s
->reclock
.recd
.num
?s
->reclock
.recd
.total
/s
->reclock
.recd
.num
:0.0, s
->reclock
.recd
.max
, s
->reclock
.recd
.num
);
309 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n", "call_latency MIN/AVG/MAX", s
->call_latency
.min
, s
->call_latency
.num
?s
->call_latency
.total
/s
->call_latency
.num
:0.0, s
->call_latency
.max
, s
->call_latency
.num
);
310 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n", "lockwait_latency MIN/AVG/MAX", s
->lockwait_latency
.min
, s
->lockwait_latency
.num
?s
->lockwait_latency
.total
/s
->lockwait_latency
.num
:0.0, s
->lockwait_latency
.max
, s
->lockwait_latency
.num
);
311 printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n", "childwrite_latency MIN/AVG/MAX", s
->childwrite_latency
.min
, s
->childwrite_latency
.num
?s
->childwrite_latency
.total
/s
->childwrite_latency
.num
:0.0, s
->childwrite_latency
.max
, s
->childwrite_latency
.num
);
314 talloc_free(tmp_ctx
);
318 display remote ctdb statistics combined from all nodes
320 static int control_statistics_all(struct ctdb_context
*ctdb
)
323 struct ctdb_statistics statistics
;
327 nodes
= ctdb_get_connected_nodes(ctdb
, TIMELIMIT(), ctdb
, &num_nodes
);
328 CTDB_NO_MEMORY(ctdb
, nodes
);
330 ZERO_STRUCT(statistics
);
332 for (i
=0;i
<num_nodes
;i
++) {
333 struct ctdb_statistics s1
;
335 uint32_t *v1
= (uint32_t *)&s1
;
336 uint32_t *v2
= (uint32_t *)&statistics
;
338 offsetof(struct ctdb_statistics
, __last_counter
) / sizeof(uint32_t);
339 ret
= ctdb_ctrl_statistics(ctdb
, nodes
[i
], &s1
);
341 DEBUG(DEBUG_ERR
, ("Unable to get statistics from node %u\n", nodes
[i
]));
344 for (j
=0;j
<num_ints
;j
++) {
347 statistics
.max_hop_count
=
348 MAX(statistics
.max_hop_count
, s1
.max_hop_count
);
349 statistics
.call_latency
.max
=
350 MAX(statistics
.call_latency
.max
, s1
.call_latency
.max
);
351 statistics
.lockwait_latency
.max
=
352 MAX(statistics
.lockwait_latency
.max
, s1
.lockwait_latency
.max
);
355 printf("Gathered statistics for %u nodes\n", num_nodes
);
356 show_statistics(&statistics
, 1);
361 display remote ctdb statistics
363 static int control_statistics(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
366 struct ctdb_statistics statistics
;
368 if (options
.pnn
== CTDB_BROADCAST_ALL
) {
369 return control_statistics_all(ctdb
);
372 ret
= ctdb_ctrl_statistics(ctdb
, options
.pnn
, &statistics
);
374 DEBUG(DEBUG_ERR
, ("Unable to get statistics from node %u\n", options
.pnn
));
377 show_statistics(&statistics
, 1);
383 reset remote ctdb statistics
385 static int control_statistics_reset(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
389 ret
= ctdb_statistics_reset(ctdb
, options
.pnn
);
391 DEBUG(DEBUG_ERR
, ("Unable to reset statistics on node %u\n", options
.pnn
));
399 display remote ctdb rolling statistics
401 static int control_stats(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
404 struct ctdb_statistics_wire
*stats
;
405 int i
, num_records
= -1;
408 num_records
= atoi(argv
[0]) - 1;
411 ret
= ctdb_ctrl_getstathistory(ctdb
, TIMELIMIT(), options
.pnn
, ctdb
, &stats
);
413 DEBUG(DEBUG_ERR
, ("Unable to get rolling statistics from node %u\n", options
.pnn
));
416 for (i
=0;i
<stats
->num
;i
++) {
417 if (stats
->stats
[i
].statistics_start_time
.tv_sec
== 0) {
420 show_statistics(&stats
->stats
[i
], i
==0);
421 if (i
== num_records
) {
430 display uptime of remote node
432 static int control_uptime(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
435 struct ctdb_uptime
*uptime
= NULL
;
436 int tmp
, days
, hours
, minutes
, seconds
;
438 ret
= ctdb_ctrl_uptime(ctdb
, ctdb
, TIMELIMIT(), options
.pnn
, &uptime
);
440 DEBUG(DEBUG_ERR
, ("Unable to get uptime from node %u\n", options
.pnn
));
444 if (options
.machinereadable
){
445 printf(":Current Node Time:Ctdb Start Time:Last Recovery/Failover Time:Last Recovery/IPFailover Duration:\n");
446 printf(":%u:%u:%u:%lf\n",
447 (unsigned int)uptime
->current_time
.tv_sec
,
448 (unsigned int)uptime
->ctdbd_start_time
.tv_sec
,
449 (unsigned int)uptime
->last_recovery_finished
.tv_sec
,
450 timeval_delta(&uptime
->last_recovery_finished
,
451 &uptime
->last_recovery_started
)
456 printf("Current time of node : %s", ctime(&uptime
->current_time
.tv_sec
));
458 tmp
= uptime
->current_time
.tv_sec
- uptime
->ctdbd_start_time
.tv_sec
;
466 printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s", days
, hours
, minutes
, seconds
, ctime(&uptime
->ctdbd_start_time
.tv_sec
));
468 tmp
= uptime
->current_time
.tv_sec
- uptime
->last_recovery_finished
.tv_sec
;
476 printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s", days
, hours
, minutes
, seconds
, ctime(&uptime
->last_recovery_finished
.tv_sec
));
478 printf("Duration of last recovery/failover: %lf seconds\n",
479 timeval_delta(&uptime
->last_recovery_finished
,
480 &uptime
->last_recovery_started
));
486 show the PNN of the current node
488 static int control_pnn(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
493 ret
= ctdb_getpnn(ctdb_connection
, options
.pnn
, &mypnn
);
495 DEBUG(DEBUG_ERR
, ("Unable to get pnn from node."));
499 printf("PNN:%d\n", mypnn
);
505 struct pnn_node
*next
;
510 static struct pnn_node
*read_nodes_file(TALLOC_CTX
*mem_ctx
)
512 const char *nodes_list
;
516 struct pnn_node
*pnn_nodes
= NULL
;
517 struct pnn_node
*pnn_node
;
518 struct pnn_node
*tmp_node
;
520 /* read the nodes file */
521 nodes_list
= getenv("CTDB_NODES");
522 if (nodes_list
== NULL
) {
523 nodes_list
= "/etc/ctdb/nodes";
525 lines
= file_lines_load(nodes_list
, &nlines
, mem_ctx
);
529 while (nlines
> 0 && strcmp(lines
[nlines
-1], "") == 0) {
532 for (i
=0, pnn
=0; i
<nlines
; i
++) {
536 /* strip leading spaces */
537 while((*node
== ' ') || (*node
== '\t')) {
544 if (strcmp(node
, "") == 0) {
547 pnn_node
= talloc(mem_ctx
, struct pnn_node
);
548 pnn_node
->pnn
= pnn
++;
549 pnn_node
->addr
= talloc_strdup(pnn_node
, node
);
550 pnn_node
->next
= pnn_nodes
;
551 pnn_nodes
= pnn_node
;
554 /* swap them around so we return them in incrementing order */
555 pnn_node
= pnn_nodes
;
559 pnn_node
= pnn_node
->next
;
561 tmp_node
->next
= pnn_nodes
;
562 pnn_nodes
= tmp_node
;
569 show the PNN of the current node
570 discover the pnn by loading the nodes file and try to bind to all
571 addresses one at a time until the ip address is found.
573 static int control_xpnn(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
575 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
576 struct pnn_node
*pnn_nodes
;
577 struct pnn_node
*pnn_node
;
579 pnn_nodes
= read_nodes_file(mem_ctx
);
580 if (pnn_nodes
== NULL
) {
581 DEBUG(DEBUG_ERR
,("Failed to read nodes file\n"));
582 talloc_free(mem_ctx
);
586 for(pnn_node
=pnn_nodes
;pnn_node
;pnn_node
=pnn_node
->next
) {
589 if (parse_ip(pnn_node
->addr
, NULL
, 63999, &addr
) == 0) {
590 DEBUG(DEBUG_ERR
,("Wrongly formed ip address '%s' in nodes file\n", pnn_node
->addr
));
591 talloc_free(mem_ctx
);
595 if (ctdb_sys_have_ip(&addr
)) {
596 printf("PNN:%d\n", pnn_node
->pnn
);
597 talloc_free(mem_ctx
);
602 printf("Failed to detect which PNN this node is\n");
603 talloc_free(mem_ctx
);
608 display remote ctdb status
610 static int control_status(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
613 struct ctdb_vnn_map
*vnnmap
=NULL
;
614 struct ctdb_node_map
*nodemap
=NULL
;
615 uint32_t recmode
, recmaster
;
618 mypnn
= ctdb_ctrl_getpnn(ctdb
, TIMELIMIT(), options
.pnn
);
623 ret
= ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), options
.pnn
, ctdb
, &nodemap
);
625 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from node %u\n", options
.pnn
));
629 if (options
.machinereadable
) {
630 printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped"
631 ":Inactive:PartiallyOnline:ThisNode:\n");
632 for (i
=0;i
<nodemap
->num
;i
++) {
633 int partially_online
= 0;
636 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_DELETED
) {
639 if (nodemap
->nodes
[i
].flags
== 0) {
640 struct ctdb_control_get_ifaces
*ifaces
;
642 ret
= ctdb_ctrl_get_ifaces(ctdb
, TIMELIMIT(),
643 nodemap
->nodes
[i
].pnn
,
646 for (j
=0; j
< ifaces
->num
; j
++) {
647 if (ifaces
->ifaces
[j
].link_state
!= 0) {
650 partially_online
= 1;
656 printf(":%d:%s:%d:%d:%d:%d:%d:%d:%d:%c:\n", nodemap
->nodes
[i
].pnn
,
657 ctdb_addr_to_str(&nodemap
->nodes
[i
].addr
),
658 !!(nodemap
->nodes
[i
].flags
&NODE_FLAGS_DISCONNECTED
),
659 !!(nodemap
->nodes
[i
].flags
&NODE_FLAGS_BANNED
),
660 !!(nodemap
->nodes
[i
].flags
&NODE_FLAGS_PERMANENTLY_DISABLED
),
661 !!(nodemap
->nodes
[i
].flags
&NODE_FLAGS_UNHEALTHY
),
662 !!(nodemap
->nodes
[i
].flags
&NODE_FLAGS_STOPPED
),
663 !!(nodemap
->nodes
[i
].flags
&NODE_FLAGS_INACTIVE
),
665 (nodemap
->nodes
[i
].pnn
== mypnn
)?'Y':'N');
670 printf("Number of nodes:%d\n", nodemap
->num
);
671 for(i
=0;i
<nodemap
->num
;i
++){
672 static const struct {
676 { NODE_FLAGS_DISCONNECTED
, "DISCONNECTED" },
677 { NODE_FLAGS_PERMANENTLY_DISABLED
, "DISABLED" },
678 { NODE_FLAGS_BANNED
, "BANNED" },
679 { NODE_FLAGS_UNHEALTHY
, "UNHEALTHY" },
680 { NODE_FLAGS_DELETED
, "DELETED" },
681 { NODE_FLAGS_STOPPED
, "STOPPED" },
682 { NODE_FLAGS_INACTIVE
, "INACTIVE" },
684 char *flags_str
= NULL
;
687 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_DELETED
) {
690 if (nodemap
->nodes
[i
].flags
== 0) {
691 struct ctdb_control_get_ifaces
*ifaces
;
693 ret
= ctdb_ctrl_get_ifaces(ctdb
, TIMELIMIT(),
694 nodemap
->nodes
[i
].pnn
,
697 for (j
=0; j
< ifaces
->num
; j
++) {
698 if (ifaces
->ifaces
[j
].link_state
!= 0) {
701 flags_str
= talloc_strdup(ctdb
, "PARTIALLYONLINE");
707 for (j
=0;j
<ARRAY_SIZE(flag_names
);j
++) {
708 if (nodemap
->nodes
[i
].flags
& flag_names
[j
].flag
) {
709 if (flags_str
== NULL
) {
710 flags_str
= talloc_strdup(ctdb
, flag_names
[j
].name
);
712 flags_str
= talloc_asprintf_append(flags_str
, "|%s",
715 CTDB_NO_MEMORY_FATAL(ctdb
, flags_str
);
718 if (flags_str
== NULL
) {
719 flags_str
= talloc_strdup(ctdb
, "OK");
720 CTDB_NO_MEMORY_FATAL(ctdb
, flags_str
);
722 printf("pnn:%d %-16s %s%s\n", nodemap
->nodes
[i
].pnn
,
723 ctdb_addr_to_str(&nodemap
->nodes
[i
].addr
),
725 nodemap
->nodes
[i
].pnn
== mypnn
?" (THIS NODE)":"");
726 talloc_free(flags_str
);
729 ret
= ctdb_ctrl_getvnnmap(ctdb
, TIMELIMIT(), options
.pnn
, ctdb
, &vnnmap
);
731 DEBUG(DEBUG_ERR
, ("Unable to get vnnmap from node %u\n", options
.pnn
));
734 if (vnnmap
->generation
== INVALID_GENERATION
) {
735 printf("Generation:INVALID\n");
737 printf("Generation:%d\n",vnnmap
->generation
);
739 printf("Size:%d\n",vnnmap
->size
);
740 for(i
=0;i
<vnnmap
->size
;i
++){
741 printf("hash:%d lmaster:%d\n", i
, vnnmap
->map
[i
]);
744 if (!ctdb_getrecmode(ctdb_connection
, options
.pnn
, &recmode
)) {
745 DEBUG(DEBUG_ERR
, ("Unable to get recmode from node %u\n", options
.pnn
));
748 printf("Recovery mode:%s (%d)\n",recmode
==CTDB_RECOVERY_NORMAL
?"NORMAL":"RECOVERY",recmode
);
750 if (!ctdb_getrecmaster(ctdb_connection
, options
.pnn
, &recmaster
)) {
751 DEBUG(DEBUG_ERR
, ("Unable to get recmaster from node %u\n", options
.pnn
));
754 printf("Recovery master:%d\n",recmaster
);
761 struct natgw_node
*next
;
766 display the list of nodes belonging to this natgw configuration
768 static int control_natgwlist(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
771 uint32_t capabilities
;
772 const char *natgw_list
;
775 struct natgw_node
*natgw_nodes
= NULL
;
776 struct natgw_node
*natgw_node
;
777 struct ctdb_node_map
*nodemap
=NULL
;
780 /* read the natgw nodes file into a linked list */
781 natgw_list
= getenv("NATGW_NODES");
782 if (natgw_list
== NULL
) {
783 natgw_list
= "/etc/ctdb/natgw_nodes";
785 lines
= file_lines_load(natgw_list
, &nlines
, ctdb
);
787 ctdb_set_error(ctdb
, "Failed to load natgw node list '%s'\n", natgw_list
);
790 while (nlines
> 0 && strcmp(lines
[nlines
-1], "") == 0) {
793 for (i
=0;i
<nlines
;i
++) {
797 /* strip leading spaces */
798 while((*node
== ' ') || (*node
== '\t')) {
804 if (strcmp(node
, "") == 0) {
807 natgw_node
= talloc(ctdb
, struct natgw_node
);
808 natgw_node
->addr
= talloc_strdup(natgw_node
, node
);
809 CTDB_NO_MEMORY(ctdb
, natgw_node
->addr
);
810 natgw_node
->next
= natgw_nodes
;
811 natgw_nodes
= natgw_node
;
814 ret
= ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
, ctdb
, &nodemap
);
816 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from local node.\n"));
821 while(i
<nodemap
->num
) {
822 for(natgw_node
=natgw_nodes
;natgw_node
;natgw_node
=natgw_node
->next
) {
823 if (!strcmp(natgw_node
->addr
, ctdb_addr_to_str(&nodemap
->nodes
[i
].addr
))) {
828 /* this node was not in the natgw so we just remove it from
831 if ((natgw_node
== NULL
)
832 || (nodemap
->nodes
[i
].flags
& NODE_FLAGS_DISCONNECTED
) ) {
835 for (j
=i
+1; j
<nodemap
->num
; j
++) {
836 nodemap
->nodes
[j
-1] = nodemap
->nodes
[j
];
845 /* pick a node to be natgwmaster
846 * we dont allow STOPPED, DELETED, BANNED or UNHEALTHY nodes to become the natgwmaster
848 for(i
=0;i
<nodemap
->num
;i
++){
849 if (!(nodemap
->nodes
[i
].flags
& (NODE_FLAGS_DISCONNECTED
|NODE_FLAGS_STOPPED
|NODE_FLAGS_DELETED
|NODE_FLAGS_BANNED
|NODE_FLAGS_UNHEALTHY
))) {
850 ret
= ctdb_ctrl_getcapabilities(ctdb
, TIMELIMIT(), nodemap
->nodes
[i
].pnn
, &capabilities
);
852 DEBUG(DEBUG_ERR
, ("Unable to get capabilities from node %u\n", nodemap
->nodes
[i
].pnn
));
855 if (!(capabilities
&CTDB_CAP_NATGW
)) {
858 printf("%d %s\n", nodemap
->nodes
[i
].pnn
,ctdb_addr_to_str(&nodemap
->nodes
[i
].addr
));
862 /* we couldnt find any healthy node, try unhealthy ones */
863 if (i
== nodemap
->num
) {
864 for(i
=0;i
<nodemap
->num
;i
++){
865 if (!(nodemap
->nodes
[i
].flags
& (NODE_FLAGS_DISCONNECTED
|NODE_FLAGS_STOPPED
|NODE_FLAGS_DELETED
))) {
866 ret
= ctdb_ctrl_getcapabilities(ctdb
, TIMELIMIT(), nodemap
->nodes
[i
].pnn
, &capabilities
);
868 DEBUG(DEBUG_ERR
, ("Unable to get capabilities from node %u\n", nodemap
->nodes
[i
].pnn
));
871 if (!(capabilities
&CTDB_CAP_NATGW
)) {
874 printf("%d %s\n", nodemap
->nodes
[i
].pnn
,ctdb_addr_to_str(&nodemap
->nodes
[i
].addr
));
879 /* unless all nodes are STOPPED, when we pick one anyway */
880 if (i
== nodemap
->num
) {
881 for(i
=0;i
<nodemap
->num
;i
++){
882 if (!(nodemap
->nodes
[i
].flags
& (NODE_FLAGS_DISCONNECTED
|NODE_FLAGS_DELETED
))) {
883 ret
= ctdb_ctrl_getcapabilities(ctdb
, TIMELIMIT(), nodemap
->nodes
[i
].pnn
, &capabilities
);
885 DEBUG(DEBUG_ERR
, ("Unable to get capabilities from node %u\n", nodemap
->nodes
[i
].pnn
));
888 if (!(capabilities
&CTDB_CAP_NATGW
)) {
891 printf("%d %s\n", nodemap
->nodes
[i
].pnn
, ctdb_addr_to_str(&nodemap
->nodes
[i
].addr
));
895 /* or if we still can not find any */
896 if (i
== nodemap
->num
) {
897 printf("-1 0.0.0.0\n");
898 ret
= 2; /* matches ENOENT */
902 /* print the pruned list of nodes belonging to this natgw list */
903 for(i
=0;i
<nodemap
->num
;i
++){
904 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_DELETED
) {
907 printf(":%d:%s:%d:%d:%d:%d:%d\n", nodemap
->nodes
[i
].pnn
,
908 ctdb_addr_to_str(&nodemap
->nodes
[i
].addr
),
909 !!(nodemap
->nodes
[i
].flags
&NODE_FLAGS_DISCONNECTED
),
910 !!(nodemap
->nodes
[i
].flags
&NODE_FLAGS_BANNED
),
911 !!(nodemap
->nodes
[i
].flags
&NODE_FLAGS_PERMANENTLY_DISABLED
),
912 !!(nodemap
->nodes
[i
].flags
&NODE_FLAGS_UNHEALTHY
),
913 !!(nodemap
->nodes
[i
].flags
&NODE_FLAGS_STOPPED
));
920 display the status of the scripts for monitoring (or other events)
922 static int control_one_scriptstatus(struct ctdb_context
*ctdb
,
923 enum ctdb_eventscript_call type
)
925 struct ctdb_scripts_wire
*script_status
;
928 ret
= ctdb_ctrl_getscriptstatus(ctdb
, TIMELIMIT(), options
.pnn
, ctdb
, type
, &script_status
);
930 DEBUG(DEBUG_ERR
, ("Unable to get script status from node %u\n", options
.pnn
));
934 if (script_status
== NULL
) {
935 if (!options
.machinereadable
) {
936 printf("%s cycle never run\n",
937 ctdb_eventscript_call_names
[type
]);
942 if (!options
.machinereadable
) {
943 printf("%d scripts were executed last %s cycle\n",
944 script_status
->num_scripts
,
945 ctdb_eventscript_call_names
[type
]);
947 for (i
=0; i
<script_status
->num_scripts
; i
++) {
948 const char *status
= NULL
;
950 switch (script_status
->scripts
[i
].status
) {
961 if (script_status
->scripts
[i
].status
> 0)
965 if (options
.machinereadable
) {
966 printf(":%s:%s:%i:%s:%lu.%06lu:%lu.%06lu:%s:\n",
967 ctdb_eventscript_call_names
[type
],
968 script_status
->scripts
[i
].name
,
969 script_status
->scripts
[i
].status
,
971 (long)script_status
->scripts
[i
].start
.tv_sec
,
972 (long)script_status
->scripts
[i
].start
.tv_usec
,
973 (long)script_status
->scripts
[i
].finished
.tv_sec
,
974 (long)script_status
->scripts
[i
].finished
.tv_usec
,
975 script_status
->scripts
[i
].output
);
979 printf("%-20s Status:%s ",
980 script_status
->scripts
[i
].name
, status
);
982 /* Some other error, eg from stat. */
983 printf("%-20s Status:CANNOT RUN (%s)",
984 script_status
->scripts
[i
].name
,
985 strerror(-script_status
->scripts
[i
].status
));
987 if (script_status
->scripts
[i
].status
>= 0) {
988 printf("Duration:%.3lf ",
989 timeval_delta(&script_status
->scripts
[i
].finished
,
990 &script_status
->scripts
[i
].start
));
992 if (script_status
->scripts
[i
].status
!= -ENOEXEC
) {
994 ctime(&script_status
->scripts
[i
].start
.tv_sec
));
995 if (script_status
->scripts
[i
].status
!= 0) {
996 printf(" OUTPUT:%s\n",
997 script_status
->scripts
[i
].output
);
1007 static int control_scriptstatus(struct ctdb_context
*ctdb
,
1008 int argc
, const char **argv
)
1011 enum ctdb_eventscript_call type
, min
, max
;
1015 DEBUG(DEBUG_ERR
, ("Unknown arguments to scriptstatus\n"));
1020 arg
= ctdb_eventscript_call_names
[CTDB_EVENT_MONITOR
];
1024 for (type
= 0; type
< CTDB_EVENT_MAX
; type
++) {
1025 if (strcmp(arg
, ctdb_eventscript_call_names
[type
]) == 0) {
1031 if (type
== CTDB_EVENT_MAX
) {
1032 if (strcmp(arg
, "all") == 0) {
1034 max
= CTDB_EVENT_MAX
;
1036 DEBUG(DEBUG_ERR
, ("Unknown event type %s\n", argv
[0]));
1041 if (options
.machinereadable
) {
1042 printf(":Type:Name:Code:Status:Start:End:Error Output...:\n");
1045 for (type
= min
; type
< max
; type
++) {
1046 ret
= control_one_scriptstatus(ctdb
, type
);
1056 enable an eventscript
1058 static int control_enablescript(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
1066 ret
= ctdb_ctrl_enablescript(ctdb
, TIMELIMIT(), options
.pnn
, argv
[0]);
1068 DEBUG(DEBUG_ERR
, ("Unable to enable script %s on node %u\n", argv
[0], options
.pnn
));
1076 disable an eventscript
1078 static int control_disablescript(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
1086 ret
= ctdb_ctrl_disablescript(ctdb
, TIMELIMIT(), options
.pnn
, argv
[0]);
1088 DEBUG(DEBUG_ERR
, ("Unable to disable script %s on node %u\n", argv
[0], options
.pnn
));
1096 display the pnn of the recovery master
1098 static int control_recmaster(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
1102 if (!ctdb_getrecmaster(ctdb_connection
, options
.pnn
, &recmaster
)) {
1103 DEBUG(DEBUG_ERR
, ("Unable to get recmaster from node %u\n", options
.pnn
));
1106 printf("%d\n",recmaster
);
1112 add a tickle to a public address
1114 static int control_add_tickle(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
1116 struct ctdb_tcp_connection t
;
1124 if (parse_ip_port(argv
[0], &t
.src_addr
) == 0) {
1125 DEBUG(DEBUG_ERR
,("Wrongly formed ip address '%s'\n", argv
[0]));
1128 if (parse_ip_port(argv
[1], &t
.dst_addr
) == 0) {
1129 DEBUG(DEBUG_ERR
,("Wrongly formed ip address '%s'\n", argv
[1]));
1133 data
.dptr
= (uint8_t *)&t
;
1134 data
.dsize
= sizeof(t
);
1136 /* tell all nodes about this tcp connection */
1137 ret
= ctdb_control(ctdb
, options
.pnn
, 0, CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE
,
1138 0, data
, ctdb
, NULL
, NULL
, NULL
, NULL
);
1140 DEBUG(DEBUG_ERR
,("Failed to add tickle\n"));
1149 delete a tickle from a node
1151 static int control_del_tickle(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
1153 struct ctdb_tcp_connection t
;
1161 if (parse_ip_port(argv
[0], &t
.src_addr
) == 0) {
1162 DEBUG(DEBUG_ERR
,("Wrongly formed ip address '%s'\n", argv
[0]));
1165 if (parse_ip_port(argv
[1], &t
.dst_addr
) == 0) {
1166 DEBUG(DEBUG_ERR
,("Wrongly formed ip address '%s'\n", argv
[1]));
1170 data
.dptr
= (uint8_t *)&t
;
1171 data
.dsize
= sizeof(t
);
1173 /* tell all nodes about this tcp connection */
1174 ret
= ctdb_control(ctdb
, options
.pnn
, 0, CTDB_CONTROL_TCP_REMOVE
,
1175 0, data
, ctdb
, NULL
, NULL
, NULL
, NULL
);
1177 DEBUG(DEBUG_ERR
,("Failed to remove tickle\n"));
1186 get a list of all tickles for this pnn
1188 static int control_get_tickles(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
1190 struct ctdb_control_tcp_tickle_list
*list
;
1191 ctdb_sock_addr addr
;
1200 port
= atoi(argv
[1]);
1203 if (parse_ip(argv
[0], NULL
, 0, &addr
) == 0) {
1204 DEBUG(DEBUG_ERR
,("Wrongly formed ip address '%s'\n", argv
[0]));
1208 ret
= ctdb_ctrl_get_tcp_tickles(ctdb
, TIMELIMIT(), options
.pnn
, ctdb
, &addr
, &list
);
1210 DEBUG(DEBUG_ERR
, ("Unable to list tickles\n"));
1214 if (options
.machinereadable
){
1215 printf(":source ip:port:destination ip:port:\n");
1216 for (i
=0;i
<list
->tickles
.num
;i
++) {
1217 if (port
&& port
!= ntohs(list
->tickles
.connections
[i
].dst_addr
.ip
.sin_port
)) {
1220 printf(":%s:%u", ctdb_addr_to_str(&list
->tickles
.connections
[i
].src_addr
), ntohs(list
->tickles
.connections
[i
].src_addr
.ip
.sin_port
));
1221 printf(":%s:%u:\n", ctdb_addr_to_str(&list
->tickles
.connections
[i
].dst_addr
), ntohs(list
->tickles
.connections
[i
].dst_addr
.ip
.sin_port
));
1224 printf("Tickles for ip:%s\n", ctdb_addr_to_str(&list
->addr
));
1225 printf("Num tickles:%u\n", list
->tickles
.num
);
1226 for (i
=0;i
<list
->tickles
.num
;i
++) {
1227 if (port
&& port
!= ntohs(list
->tickles
.connections
[i
].dst_addr
.ip
.sin_port
)) {
1230 printf("SRC: %s:%u ", ctdb_addr_to_str(&list
->tickles
.connections
[i
].src_addr
), ntohs(list
->tickles
.connections
[i
].src_addr
.ip
.sin_port
));
1231 printf("DST: %s:%u\n", ctdb_addr_to_str(&list
->tickles
.connections
[i
].dst_addr
), ntohs(list
->tickles
.connections
[i
].dst_addr
.ip
.sin_port
));
1241 static int move_ip(struct ctdb_context
*ctdb
, ctdb_sock_addr
*addr
, uint32_t pnn
)
1243 struct ctdb_all_public_ips
*ips
;
1244 struct ctdb_public_ip ip
;
1247 uint32_t disable_time
;
1249 struct ctdb_node_map
*nodemap
=NULL
;
1250 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
1253 data
.dptr
= (uint8_t*)&disable_time
;
1254 data
.dsize
= sizeof(disable_time
);
1255 ret
= ctdb_client_send_message(ctdb
, CTDB_BROADCAST_CONNECTED
, CTDB_SRVID_DISABLE_IP_CHECK
, data
);
1257 DEBUG(DEBUG_ERR
,("Failed to send message to disable ipcheck\n"));
1263 /* read the public ip list from the node */
1264 ret
= ctdb_ctrl_get_public_ips(ctdb
, TIMELIMIT(), pnn
, ctdb
, &ips
);
1266 DEBUG(DEBUG_ERR
, ("Unable to get public ip list from node %u\n", pnn
));
1267 talloc_free(tmp_ctx
);
1271 for (i
=0;i
<ips
->num
;i
++) {
1272 if (ctdb_same_ip(addr
, &ips
->ips
[i
].addr
)) {
1277 DEBUG(DEBUG_ERR
, ("Node %u can not host ip address '%s'\n",
1278 pnn
, ctdb_addr_to_str(addr
)));
1279 talloc_free(tmp_ctx
);
1286 data
.dptr
= (uint8_t *)&ip
;
1287 data
.dsize
= sizeof(ip
);
1289 ret
= ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), options
.pnn
, tmp_ctx
, &nodemap
);
1291 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from node %u\n", options
.pnn
));
1292 talloc_free(tmp_ctx
);
1296 nodes
= list_of_active_nodes_except_pnn(ctdb
, nodemap
, tmp_ctx
, pnn
);
1297 ret
= ctdb_client_async_control(ctdb
, CTDB_CONTROL_RELEASE_IP
,
1304 DEBUG(DEBUG_ERR
,("Failed to release IP on nodes\n"));
1305 talloc_free(tmp_ctx
);
1309 ret
= ctdb_ctrl_takeover_ip(ctdb
, LONGTIMELIMIT(), pnn
, &ip
);
1311 DEBUG(DEBUG_ERR
,("Failed to take over IP on node %d\n", pnn
));
1312 talloc_free(tmp_ctx
);
1316 /* update the recovery daemon so it now knows to expect the new
1317 node assignment for this ip.
1319 ret
= ctdb_client_send_message(ctdb
, CTDB_BROADCAST_CONNECTED
, CTDB_SRVID_RECD_UPDATE_IP
, data
);
1321 DEBUG(DEBUG_ERR
,("Failed to send message to update the ip on the recovery master.\n"));
1325 talloc_free(tmp_ctx
);
1330 move/failover an ip address to a specific node
1332 static int control_moveip(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
1335 int ret
, retries
= 0;
1336 ctdb_sock_addr addr
;
1343 if (parse_ip(argv
[0], NULL
, 0, &addr
) == 0) {
1344 DEBUG(DEBUG_ERR
,("Wrongly formed ip address '%s'\n", argv
[0]));
1349 if (sscanf(argv
[1], "%u", &pnn
) != 1) {
1350 DEBUG(DEBUG_ERR
, ("Badly formed pnn\n"));
1355 ret
= move_ip(ctdb
, &addr
, pnn
);
1357 DEBUG(DEBUG_ERR
,("Failed to move ip to node %d. Wait 3 second and try again.\n", pnn
));
1361 } while (retries
< 5 && ret
!= 0);
1363 DEBUG(DEBUG_ERR
,("Failed to move ip to node %d. Giving up.\n", pnn
));
1370 static int getips_store_callback(void *param
, void *data
)
1372 struct ctdb_public_ip
*node_ip
= (struct ctdb_public_ip
*)data
;
1373 struct ctdb_all_public_ips
*ips
= param
;
1377 ips
->ips
[i
].pnn
= node_ip
->pnn
;
1378 ips
->ips
[i
].addr
= node_ip
->addr
;
1382 static int getips_count_callback(void *param
, void *data
)
1384 uint32_t *count
= param
;
1391 static uint32_t *ip_key(ctdb_sock_addr
*ip
)
1393 static uint32_t key
[IP_KEYLEN
];
1395 bzero(key
, sizeof(key
));
1397 switch (ip
->sa
.sa_family
) {
1399 key
[0] = ip
->ip
.sin_addr
.s_addr
;
1402 key
[0] = ip
->ip6
.sin6_addr
.s6_addr32
[3];
1403 key
[1] = ip
->ip6
.sin6_addr
.s6_addr32
[2];
1404 key
[2] = ip
->ip6
.sin6_addr
.s6_addr32
[1];
1405 key
[3] = ip
->ip6
.sin6_addr
.s6_addr32
[0];
1408 DEBUG(DEBUG_ERR
, (__location__
" ERROR, unknown family passed :%u\n", ip
->sa
.sa_family
));
1415 static void *add_ip_callback(void *parm
, void *data
)
1421 control_get_all_public_ips(struct ctdb_context
*ctdb
, TALLOC_CTX
*tmp_ctx
, struct ctdb_all_public_ips
**ips
)
1423 struct ctdb_all_public_ips
*tmp_ips
;
1424 struct ctdb_node_map
*nodemap
=NULL
;
1425 trbt_tree_t
*ip_tree
;
1429 ret
= ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
, tmp_ctx
, &nodemap
);
1431 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from node %u\n", options
.pnn
));
1435 ip_tree
= trbt_create(tmp_ctx
, 0);
1437 for(i
=0;i
<nodemap
->num
;i
++){
1438 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_DELETED
) {
1441 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_DISCONNECTED
) {
1445 /* read the public ip list from this node */
1446 ret
= ctdb_ctrl_get_public_ips(ctdb
, TIMELIMIT(), nodemap
->nodes
[i
].pnn
, tmp_ctx
, &tmp_ips
);
1448 DEBUG(DEBUG_ERR
, ("Unable to get public ip list from node %u\n", nodemap
->nodes
[i
].pnn
));
1452 for (j
=0; j
<tmp_ips
->num
;j
++) {
1453 struct ctdb_public_ip
*node_ip
;
1455 node_ip
= talloc(tmp_ctx
, struct ctdb_public_ip
);
1456 node_ip
->pnn
= tmp_ips
->ips
[j
].pnn
;
1457 node_ip
->addr
= tmp_ips
->ips
[j
].addr
;
1459 trbt_insertarray32_callback(ip_tree
,
1460 IP_KEYLEN
, ip_key(&tmp_ips
->ips
[j
].addr
),
1464 talloc_free(tmp_ips
);
1469 trbt_traversearray32(ip_tree
, IP_KEYLEN
, getips_count_callback
, &count
);
1471 len
= offsetof(struct ctdb_all_public_ips
, ips
) +
1472 count
*sizeof(struct ctdb_public_ip
);
1473 tmp_ips
= talloc_zero_size(tmp_ctx
, len
);
1474 trbt_traversearray32(ip_tree
, IP_KEYLEN
, getips_store_callback
, tmp_ips
);
1483 * scans all other nodes and returns a pnn for another node that can host this
1487 find_other_host_for_public_ip(struct ctdb_context
*ctdb
, ctdb_sock_addr
*addr
)
1489 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
1490 struct ctdb_all_public_ips
*ips
;
1491 struct ctdb_node_map
*nodemap
=NULL
;
1494 ret
= ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
, tmp_ctx
, &nodemap
);
1496 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from node %u\n", options
.pnn
));
1497 talloc_free(tmp_ctx
);
1501 for(i
=0;i
<nodemap
->num
;i
++){
1502 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_INACTIVE
) {
1505 if (nodemap
->nodes
[i
].pnn
== options
.pnn
) {
1509 /* read the public ip list from this node */
1510 ret
= ctdb_ctrl_get_public_ips(ctdb
, TIMELIMIT(), nodemap
->nodes
[i
].pnn
, tmp_ctx
, &ips
);
1512 DEBUG(DEBUG_ERR
, ("Unable to get public ip list from node %u\n", nodemap
->nodes
[i
].pnn
));
1516 for (j
=0;j
<ips
->num
;j
++) {
1517 if (ctdb_same_ip(addr
, &ips
->ips
[j
].addr
)) {
1518 talloc_free(tmp_ctx
);
1519 return nodemap
->nodes
[i
].pnn
;
1525 talloc_free(tmp_ctx
);
1529 static uint32_t ipreallocate_finished
;
1532 handler for receiving the response to ipreallocate
1534 static void ip_reallocate_handler(struct ctdb_context
*ctdb
, uint64_t srvid
,
1535 TDB_DATA data
, void *private_data
)
1537 ipreallocate_finished
= 1;
1540 static void ctdb_every_second(struct event_context
*ev
, struct timed_event
*te
, struct timeval t
, void *p
)
1542 struct ctdb_context
*ctdb
= talloc_get_type(p
, struct ctdb_context
);
1544 event_add_timed(ctdb
->ev
, ctdb
,
1545 timeval_current_ofs(1, 0),
1546 ctdb_every_second
, ctdb
);
1550 ask the recovery daemon on the recovery master to perform a ip reallocation
1552 static int control_ipreallocate(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
1556 struct takeover_run_reply rd
;
1558 struct ctdb_node_map
*nodemap
=NULL
;
1560 struct timeval tv
= timeval_current();
1562 /* we need some events to trigger so we can timeout and restart
1565 event_add_timed(ctdb
->ev
, ctdb
,
1566 timeval_current_ofs(1, 0),
1567 ctdb_every_second
, ctdb
);
1569 rd
.pnn
= ctdb_ctrl_getpnn(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
);
1571 DEBUG(DEBUG_ERR
, ("Failed to get pnn of local node\n"));
1574 rd
.srvid
= getpid();
1576 /* register a message port for receiveing the reply so that we
1577 can receive the reply
1579 ctdb_client_set_message_handler(ctdb
, rd
.srvid
, ip_reallocate_handler
, NULL
);
1581 data
.dptr
= (uint8_t *)&rd
;
1582 data
.dsize
= sizeof(rd
);
1585 /* check that there are valid nodes available */
1586 if (ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), options
.pnn
, ctdb
, &nodemap
) != 0) {
1587 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from local node\n"));
1590 for (i
=0; i
<nodemap
->num
;i
++) {
1591 if ((nodemap
->nodes
[i
].flags
& (NODE_FLAGS_DELETED
|NODE_FLAGS_BANNED
|NODE_FLAGS_STOPPED
)) == 0) {
1595 if (i
==nodemap
->num
) {
1596 DEBUG(DEBUG_ERR
,("No recmaster available, no need to wait for cluster convergence\n"));
1601 if (!ctdb_getrecmaster(ctdb_connection
, options
.pnn
, &recmaster
)) {
1602 DEBUG(DEBUG_ERR
, ("Unable to get recmaster from node %u\n", options
.pnn
));
1606 /* verify the node exists */
1607 if (ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), recmaster
, ctdb
, &nodemap
) != 0) {
1608 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from local node\n"));
1613 /* check tha there are nodes available that can act as a recmaster */
1614 for (i
=0; i
<nodemap
->num
; i
++) {
1615 if (nodemap
->nodes
[i
].flags
& (NODE_FLAGS_DELETED
|NODE_FLAGS_BANNED
|NODE_FLAGS_STOPPED
)) {
1620 if (i
== nodemap
->num
) {
1621 DEBUG(DEBUG_ERR
,("No possible nodes to host addresses.\n"));
1625 /* verify the recovery master is not STOPPED, nor BANNED */
1626 if (nodemap
->nodes
[recmaster
].flags
& (NODE_FLAGS_DELETED
|NODE_FLAGS_BANNED
|NODE_FLAGS_STOPPED
)) {
1627 DEBUG(DEBUG_ERR
,("No suitable recmaster found. Try again\n"));
1633 /* verify the recovery master is not STOPPED, nor BANNED */
1634 if (nodemap
->nodes
[recmaster
].flags
& (NODE_FLAGS_DELETED
|NODE_FLAGS_BANNED
|NODE_FLAGS_STOPPED
)) {
1635 DEBUG(DEBUG_ERR
,("No suitable recmaster found. Try again\n"));
1641 ipreallocate_finished
= 0;
1642 ret
= ctdb_client_send_message(ctdb
, recmaster
, CTDB_SRVID_TAKEOVER_RUN
, data
);
1644 DEBUG(DEBUG_ERR
,("Failed to send ip takeover run request message to %u\n", options
.pnn
));
1648 tv
= timeval_current();
1649 /* this loop will terminate when we have received the reply */
1650 while (timeval_elapsed(&tv
) < 5.0 && ipreallocate_finished
== 0) {
1651 event_loop_once(ctdb
->ev
);
1653 if (ipreallocate_finished
== 1) {
1666 add a public ip address to a node
1668 static int control_addip(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
1671 int len
, retries
= 0;
1673 ctdb_sock_addr addr
;
1674 struct ctdb_control_ip_iface
*pub
;
1675 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
1676 struct ctdb_all_public_ips
*ips
;
1680 talloc_free(tmp_ctx
);
1684 if (!parse_ip_mask(argv
[0], argv
[1], &addr
, &mask
)) {
1685 DEBUG(DEBUG_ERR
, ("Badly formed ip/mask : %s\n", argv
[0]));
1686 talloc_free(tmp_ctx
);
1690 /* read the public ip list from the node */
1691 ret
= ctdb_ctrl_get_public_ips(ctdb
, TIMELIMIT(), options
.pnn
, tmp_ctx
, &ips
);
1693 DEBUG(DEBUG_ERR
, ("Unable to get public ip list from node %u\n", options
.pnn
));
1694 talloc_free(tmp_ctx
);
1697 for (i
=0;i
<ips
->num
;i
++) {
1698 if (ctdb_same_ip(&addr
, &ips
->ips
[i
].addr
)) {
1699 DEBUG(DEBUG_ERR
,("Can not add ip to node. Node already hosts this ip\n"));
1706 /* Dont timeout. This command waits for an ip reallocation
1707 which sometimes can take wuite a while if there has
1708 been a recent recovery
1712 len
= offsetof(struct ctdb_control_ip_iface
, iface
) + strlen(argv
[1]) + 1;
1713 pub
= talloc_size(tmp_ctx
, len
);
1714 CTDB_NO_MEMORY(ctdb
, pub
);
1718 pub
->len
= strlen(argv
[1])+1;
1719 memcpy(&pub
->iface
[0], argv
[1], strlen(argv
[1])+1);
1722 ret
= ctdb_ctrl_add_public_ip(ctdb
, TIMELIMIT(), options
.pnn
, pub
);
1724 DEBUG(DEBUG_ERR
, ("Unable to add public ip to node %u. Wait 3 seconds and try again.\n", options
.pnn
));
1728 } while (retries
< 5 && ret
!= 0);
1730 DEBUG(DEBUG_ERR
, ("Unable to add public ip to node %u. Giving up.\n", options
.pnn
));
1731 talloc_free(tmp_ctx
);
1736 ret
= control_ipreallocate(ctdb
, argc
, argv
);
1738 DEBUG(DEBUG_ERR
, ("IP Reallocate failed on node %u. Wait 3 seconds and try again.\n", options
.pnn
));
1742 } while (retries
< 5 && ret
!= 0);
1744 DEBUG(DEBUG_ERR
, ("IP Reallocate failed on node %u. Giving up.\n", options
.pnn
));
1745 talloc_free(tmp_ctx
);
1749 talloc_free(tmp_ctx
);
1753 static int control_delip(struct ctdb_context
*ctdb
, int argc
, const char **argv
);
1755 static int control_delip_all(struct ctdb_context
*ctdb
, int argc
, const char **argv
, ctdb_sock_addr
*addr
)
1757 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
1758 struct ctdb_node_map
*nodemap
=NULL
;
1759 struct ctdb_all_public_ips
*ips
;
1762 ret
= ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
, tmp_ctx
, &nodemap
);
1764 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from current node\n"));
1768 /* remove it from the nodes that are not hosting the ip currently */
1769 for(i
=0;i
<nodemap
->num
;i
++){
1770 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_INACTIVE
) {
1773 if (ctdb_ctrl_get_public_ips(ctdb
, TIMELIMIT(), nodemap
->nodes
[i
].pnn
, tmp_ctx
, &ips
) != 0) {
1774 DEBUG(DEBUG_ERR
, ("Unable to get public ip list from node %d\n", nodemap
->nodes
[i
].pnn
));
1778 for (j
=0;j
<ips
->num
;j
++) {
1779 if (ctdb_same_ip(addr
, &ips
->ips
[j
].addr
)) {
1787 if (ips
->ips
[j
].pnn
== nodemap
->nodes
[i
].pnn
) {
1791 options
.pnn
= nodemap
->nodes
[i
].pnn
;
1792 control_delip(ctdb
, argc
, argv
);
1796 /* remove it from every node (also the one hosting it) */
1797 for(i
=0;i
<nodemap
->num
;i
++){
1798 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_INACTIVE
) {
1801 if (ctdb_ctrl_get_public_ips(ctdb
, TIMELIMIT(), nodemap
->nodes
[i
].pnn
, tmp_ctx
, &ips
) != 0) {
1802 DEBUG(DEBUG_ERR
, ("Unable to get public ip list from node %d\n", nodemap
->nodes
[i
].pnn
));
1806 for (j
=0;j
<ips
->num
;j
++) {
1807 if (ctdb_same_ip(addr
, &ips
->ips
[j
].addr
)) {
1815 options
.pnn
= nodemap
->nodes
[i
].pnn
;
1816 control_delip(ctdb
, argc
, argv
);
1819 talloc_free(tmp_ctx
);
1824 delete a public ip address from a node
1826 static int control_delip(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
1830 ctdb_sock_addr addr
;
1831 struct ctdb_control_ip_iface pub
;
1832 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
1833 struct ctdb_all_public_ips
*ips
;
1836 talloc_free(tmp_ctx
);
1840 if (parse_ip(argv
[0], NULL
, 0, &addr
) == 0) {
1841 DEBUG(DEBUG_ERR
,("Wrongly formed ip address '%s'\n", argv
[0]));
1845 if (options
.pnn
== CTDB_BROADCAST_ALL
) {
1846 return control_delip_all(ctdb
, argc
, argv
, &addr
);
1853 ret
= ctdb_ctrl_get_public_ips(ctdb
, TIMELIMIT(), options
.pnn
, tmp_ctx
, &ips
);
1855 DEBUG(DEBUG_ERR
, ("Unable to get public ip list from cluster\n"));
1856 talloc_free(tmp_ctx
);
1860 for (i
=0;i
<ips
->num
;i
++) {
1861 if (ctdb_same_ip(&addr
, &ips
->ips
[i
].addr
)) {
1867 DEBUG(DEBUG_ERR
, ("This node does not support this public address '%s'\n",
1868 ctdb_addr_to_str(&addr
)));
1869 talloc_free(tmp_ctx
);
1873 if (ips
->ips
[i
].pnn
== options
.pnn
) {
1874 ret
= find_other_host_for_public_ip(ctdb
, &addr
);
1877 ret
= move_ip(ctdb
, &addr
, ret
);
1879 DEBUG(DEBUG_ERR
,("Failed to move ip to node %d. Wait 3 seconds and try again.\n", options
.pnn
));
1883 } while (retries
< 5 && ret
!= 0);
1885 DEBUG(DEBUG_ERR
,("Failed to move ip to node %d. Giving up.\n", options
.pnn
));
1891 ret
= ctdb_ctrl_del_public_ip(ctdb
, TIMELIMIT(), options
.pnn
, &pub
);
1893 DEBUG(DEBUG_ERR
, ("Unable to del public ip from node %u\n", options
.pnn
));
1894 talloc_free(tmp_ctx
);
1898 talloc_free(tmp_ctx
);
1903 kill a tcp connection
1905 static int kill_tcp(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
1908 struct ctdb_control_killtcp killtcp
;
1914 if (!parse_ip_port(argv
[0], &killtcp
.src_addr
)) {
1915 DEBUG(DEBUG_ERR
, ("Bad IP:port '%s'\n", argv
[0]));
1919 if (!parse_ip_port(argv
[1], &killtcp
.dst_addr
)) {
1920 DEBUG(DEBUG_ERR
, ("Bad IP:port '%s'\n", argv
[1]));
1924 ret
= ctdb_ctrl_killtcp(ctdb
, TIMELIMIT(), options
.pnn
, &killtcp
);
1926 DEBUG(DEBUG_ERR
, ("Unable to killtcp from node %u\n", options
.pnn
));
1937 static int control_gratious_arp(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
1940 ctdb_sock_addr addr
;
1946 if (!parse_ip(argv
[0], NULL
, 0, &addr
)) {
1947 DEBUG(DEBUG_ERR
, ("Bad IP '%s'\n", argv
[0]));
1951 ret
= ctdb_ctrl_gratious_arp(ctdb
, TIMELIMIT(), options
.pnn
, &addr
, argv
[1]);
1953 DEBUG(DEBUG_ERR
, ("Unable to send gratious_arp from node %u\n", options
.pnn
));
1961 register a server id
1963 static int regsrvid(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
1966 struct ctdb_server_id server_id
;
1972 server_id
.pnn
= strtoul(argv
[0], NULL
, 0);
1973 server_id
.type
= strtoul(argv
[1], NULL
, 0);
1974 server_id
.server_id
= strtoul(argv
[2], NULL
, 0);
1976 ret
= ctdb_ctrl_register_server_id(ctdb
, TIMELIMIT(), &server_id
);
1978 DEBUG(DEBUG_ERR
, ("Unable to register server_id from node %u\n", options
.pnn
));
1981 DEBUG(DEBUG_ERR
,("Srvid registered. Sleeping for 999 seconds\n"));
1987 unregister a server id
1989 static int unregsrvid(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
1992 struct ctdb_server_id server_id
;
1998 server_id
.pnn
= strtoul(argv
[0], NULL
, 0);
1999 server_id
.type
= strtoul(argv
[1], NULL
, 0);
2000 server_id
.server_id
= strtoul(argv
[2], NULL
, 0);
2002 ret
= ctdb_ctrl_unregister_server_id(ctdb
, TIMELIMIT(), &server_id
);
2004 DEBUG(DEBUG_ERR
, ("Unable to unregister server_id from node %u\n", options
.pnn
));
2011 check if a server id exists
2013 static int chksrvid(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2017 struct ctdb_server_id server_id
;
2023 server_id
.pnn
= strtoul(argv
[0], NULL
, 0);
2024 server_id
.type
= strtoul(argv
[1], NULL
, 0);
2025 server_id
.server_id
= strtoul(argv
[2], NULL
, 0);
2027 ret
= ctdb_ctrl_check_server_id(ctdb
, TIMELIMIT(), options
.pnn
, &server_id
, &status
);
2029 DEBUG(DEBUG_ERR
, ("Unable to check server_id from node %u\n", options
.pnn
));
2034 printf("Server id %d:%d:%d EXISTS\n", server_id
.pnn
, server_id
.type
, server_id
.server_id
);
2036 printf("Server id %d:%d:%d does NOT exist\n", server_id
.pnn
, server_id
.type
, server_id
.server_id
);
2042 get a list of all server ids that are registered on a node
2044 static int getsrvids(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2047 struct ctdb_server_id_list
*server_ids
;
2049 ret
= ctdb_ctrl_get_server_id_list(ctdb
, ctdb
, TIMELIMIT(), options
.pnn
, &server_ids
);
2051 DEBUG(DEBUG_ERR
, ("Unable to get server_id list from node %u\n", options
.pnn
));
2055 for (i
=0; i
<server_ids
->num
; i
++) {
2056 printf("Server id %d:%d:%d\n",
2057 server_ids
->server_ids
[i
].pnn
,
2058 server_ids
->server_ids
[i
].type
,
2059 server_ids
->server_ids
[i
].server_id
);
2066 send a tcp tickle ack
2068 static int tickle_tcp(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2071 ctdb_sock_addr src
, dst
;
2077 if (!parse_ip_port(argv
[0], &src
)) {
2078 DEBUG(DEBUG_ERR
, ("Bad IP:port '%s'\n", argv
[0]));
2082 if (!parse_ip_port(argv
[1], &dst
)) {
2083 DEBUG(DEBUG_ERR
, ("Bad IP:port '%s'\n", argv
[1]));
2087 ret
= ctdb_sys_send_tcp(&src
, &dst
, 0, 0, 0);
2091 DEBUG(DEBUG_ERR
, ("Error while sending tickle ack\n"));
2098 display public ip status
2100 static int control_ip(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2103 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
2104 struct ctdb_all_public_ips
*ips
;
2106 if (options
.pnn
== CTDB_BROADCAST_ALL
) {
2107 /* read the list of public ips from all nodes */
2108 ret
= control_get_all_public_ips(ctdb
, tmp_ctx
, &ips
);
2110 /* read the public ip list from this node */
2111 ret
= ctdb_ctrl_get_public_ips(ctdb
, TIMELIMIT(), options
.pnn
, tmp_ctx
, &ips
);
2114 DEBUG(DEBUG_ERR
, ("Unable to get public ips from node %u\n", options
.pnn
));
2115 talloc_free(tmp_ctx
);
2119 if (options
.machinereadable
){
2120 printf(":Public IP:Node:");
2121 if (options
.verbose
){
2122 printf("ActiveInterface:AvailableInterfaces:ConfiguredInterfaces:");
2126 if (options
.pnn
== CTDB_BROADCAST_ALL
) {
2127 printf("Public IPs on ALL nodes\n");
2129 printf("Public IPs on node %u\n", options
.pnn
);
2133 for (i
=1;i
<=ips
->num
;i
++) {
2134 struct ctdb_control_public_ip_info
*info
= NULL
;
2136 char *aciface
= NULL
;
2137 char *avifaces
= NULL
;
2138 char *cifaces
= NULL
;
2140 if (options
.pnn
== CTDB_BROADCAST_ALL
) {
2141 pnn
= ips
->ips
[ips
->num
-i
].pnn
;
2147 ret
= ctdb_ctrl_get_public_ip_info(ctdb
, TIMELIMIT(), pnn
, ctdb
,
2148 &ips
->ips
[ips
->num
-i
].addr
, &info
);
2155 for (j
=0; j
< info
->num
; j
++) {
2156 if (cifaces
== NULL
) {
2157 cifaces
= talloc_strdup(info
,
2158 info
->ifaces
[j
].name
);
2160 cifaces
= talloc_asprintf_append(cifaces
,
2162 info
->ifaces
[j
].name
);
2165 if (info
->active_idx
== j
) {
2166 aciface
= info
->ifaces
[j
].name
;
2169 if (info
->ifaces
[j
].link_state
== 0) {
2173 if (avifaces
== NULL
) {
2174 avifaces
= talloc_strdup(info
, info
->ifaces
[j
].name
);
2176 avifaces
= talloc_asprintf_append(avifaces
,
2178 info
->ifaces
[j
].name
);
2183 if (options
.machinereadable
){
2185 ctdb_addr_to_str(&ips
->ips
[ips
->num
-i
].addr
),
2186 ips
->ips
[ips
->num
-i
].pnn
);
2187 if (options
.verbose
){
2190 avifaces
?avifaces
:"",
2191 cifaces
?cifaces
:"");
2195 if (options
.verbose
) {
2196 printf("%s node[%d] active[%s] available[%s] configured[%s]\n",
2197 ctdb_addr_to_str(&ips
->ips
[ips
->num
-i
].addr
),
2198 ips
->ips
[ips
->num
-i
].pnn
,
2200 avifaces
?avifaces
:"",
2201 cifaces
?cifaces
:"");
2204 ctdb_addr_to_str(&ips
->ips
[ips
->num
-i
].addr
),
2205 ips
->ips
[ips
->num
-i
].pnn
);
2211 talloc_free(tmp_ctx
);
2218 static int control_ipinfo(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2221 ctdb_sock_addr addr
;
2222 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
2223 struct ctdb_control_public_ip_info
*info
;
2226 talloc_free(tmp_ctx
);
2230 if (parse_ip(argv
[0], NULL
, 0, &addr
) == 0) {
2231 DEBUG(DEBUG_ERR
,("Wrongly formed ip address '%s'\n", argv
[0]));
2235 /* read the public ip info from this node */
2236 ret
= ctdb_ctrl_get_public_ip_info(ctdb
, TIMELIMIT(), options
.pnn
,
2237 tmp_ctx
, &addr
, &info
);
2239 DEBUG(DEBUG_ERR
, ("Unable to get public ip[%s]info from node %u\n",
2240 argv
[0], options
.pnn
));
2241 talloc_free(tmp_ctx
);
2245 printf("Public IP[%s] info on node %u\n",
2246 ctdb_addr_to_str(&info
->ip
.addr
),
2249 printf("IP:%s\nCurrentNode:%d\nNumInterfaces:%u\n",
2250 ctdb_addr_to_str(&info
->ip
.addr
),
2251 info
->ip
.pnn
, info
->num
);
2253 for (i
=0; i
<info
->num
; i
++) {
2254 info
->ifaces
[i
].name
[CTDB_IFACE_SIZE
] = '\0';
2256 printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
2257 i
+1, info
->ifaces
[i
].name
,
2258 info
->ifaces
[i
].link_state
?"up":"down",
2259 (unsigned int)info
->ifaces
[i
].references
,
2260 (i
==info
->active_idx
)?" (active)":"");
2263 talloc_free(tmp_ctx
);
2268 display interfaces status
2270 static int control_ifaces(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2273 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
2274 struct ctdb_control_get_ifaces
*ifaces
;
2276 /* read the public ip list from this node */
2277 ret
= ctdb_ctrl_get_ifaces(ctdb
, TIMELIMIT(), options
.pnn
,
2280 DEBUG(DEBUG_ERR
, ("Unable to get interfaces from node %u\n",
2282 talloc_free(tmp_ctx
);
2286 if (options
.machinereadable
){
2287 printf(":Name:LinkStatus:References:\n");
2289 printf("Interfaces on node %u\n", options
.pnn
);
2292 for (i
=0; i
<ifaces
->num
; i
++) {
2293 if (options
.machinereadable
){
2294 printf(":%s:%s:%u\n",
2295 ifaces
->ifaces
[i
].name
,
2296 ifaces
->ifaces
[i
].link_state
?"1":"0",
2297 (unsigned int)ifaces
->ifaces
[i
].references
);
2299 printf("name:%s link:%s references:%u\n",
2300 ifaces
->ifaces
[i
].name
,
2301 ifaces
->ifaces
[i
].link_state
?"up":"down",
2302 (unsigned int)ifaces
->ifaces
[i
].references
);
2306 talloc_free(tmp_ctx
);
2312 set link status of an interface
2314 static int control_setifacelink(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2317 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
2318 struct ctdb_control_iface_info info
;
2326 if (strlen(argv
[0]) > CTDB_IFACE_SIZE
) {
2327 DEBUG(DEBUG_ERR
, ("interfaces name '%s' too long\n",
2329 talloc_free(tmp_ctx
);
2332 strcpy(info
.name
, argv
[0]);
2334 if (strcmp(argv
[1], "up") == 0) {
2335 info
.link_state
= 1;
2336 } else if (strcmp(argv
[1], "down") == 0) {
2337 info
.link_state
= 0;
2339 DEBUG(DEBUG_ERR
, ("link state invalid '%s' should be 'up' or 'down'\n",
2341 talloc_free(tmp_ctx
);
2345 /* read the public ip list from this node */
2346 ret
= ctdb_ctrl_set_iface_link(ctdb
, TIMELIMIT(), options
.pnn
,
2349 DEBUG(DEBUG_ERR
, ("Unable to set link state for interfaces %s node %u\n",
2350 argv
[0], options
.pnn
));
2351 talloc_free(tmp_ctx
);
2355 talloc_free(tmp_ctx
);
2360 display pid of a ctdb daemon
2362 static int control_getpid(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2367 ret
= ctdb_ctrl_getpid(ctdb
, TIMELIMIT(), options
.pnn
, &pid
);
2369 DEBUG(DEBUG_ERR
, ("Unable to get daemon pid from node %u\n", options
.pnn
));
2372 printf("Pid:%d\n", pid
);
2378 disable a remote node
2380 static int control_disable(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2383 struct ctdb_node_map
*nodemap
=NULL
;
2385 /* check if the node is already disabled */
2386 if (ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
, ctdb
, &nodemap
) != 0) {
2387 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from local node\n"));
2390 if (nodemap
->nodes
[options
.pnn
].flags
& NODE_FLAGS_PERMANENTLY_DISABLED
) {
2391 DEBUG(DEBUG_ERR
,("Node %d is already disabled.\n", options
.pnn
));
2396 ret
= ctdb_ctrl_modflags(ctdb
, TIMELIMIT(), options
.pnn
, NODE_FLAGS_PERMANENTLY_DISABLED
, 0);
2398 DEBUG(DEBUG_ERR
, ("Unable to disable node %u\n", options
.pnn
));
2404 /* read the nodemap and verify the change took effect */
2405 if (ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
, ctdb
, &nodemap
) != 0) {
2406 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from local node\n"));
2410 } while (!(nodemap
->nodes
[options
.pnn
].flags
& NODE_FLAGS_PERMANENTLY_DISABLED
));
2411 ret
= control_ipreallocate(ctdb
, argc
, argv
);
2413 DEBUG(DEBUG_ERR
, ("IP Reallocate failed on node %u\n", options
.pnn
));
2421 enable a disabled remote node
2423 static int control_enable(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2427 struct ctdb_node_map
*nodemap
=NULL
;
2430 /* check if the node is already enabled */
2431 if (ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
, ctdb
, &nodemap
) != 0) {
2432 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from local node\n"));
2435 if (!(nodemap
->nodes
[options
.pnn
].flags
& NODE_FLAGS_PERMANENTLY_DISABLED
)) {
2436 DEBUG(DEBUG_ERR
,("Node %d is already enabled.\n", options
.pnn
));
2441 ret
= ctdb_ctrl_modflags(ctdb
, TIMELIMIT(), options
.pnn
, 0, NODE_FLAGS_PERMANENTLY_DISABLED
);
2443 DEBUG(DEBUG_ERR
, ("Unable to enable node %u\n", options
.pnn
));
2449 /* read the nodemap and verify the change took effect */
2450 if (ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
, ctdb
, &nodemap
) != 0) {
2451 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from local node\n"));
2455 } while (nodemap
->nodes
[options
.pnn
].flags
& NODE_FLAGS_PERMANENTLY_DISABLED
);
2457 ret
= control_ipreallocate(ctdb
, argc
, argv
);
2459 DEBUG(DEBUG_ERR
, ("IP Reallocate failed on node %u\n", options
.pnn
));
2469 static int control_stop(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2472 struct ctdb_node_map
*nodemap
=NULL
;
2475 ret
= ctdb_ctrl_stop_node(ctdb
, TIMELIMIT(), options
.pnn
);
2477 DEBUG(DEBUG_ERR
, ("Unable to stop node %u try again\n", options
.pnn
));
2482 /* read the nodemap and verify the change took effect */
2483 if (ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
, ctdb
, &nodemap
) != 0) {
2484 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from local node\n"));
2488 } while (!(nodemap
->nodes
[options
.pnn
].flags
& NODE_FLAGS_STOPPED
));
2489 ret
= control_ipreallocate(ctdb
, argc
, argv
);
2491 DEBUG(DEBUG_ERR
, ("IP Reallocate failed on node %u\n", options
.pnn
));
2499 restart a stopped remote node
2501 static int control_continue(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2505 struct ctdb_node_map
*nodemap
=NULL
;
2508 ret
= ctdb_ctrl_continue_node(ctdb
, TIMELIMIT(), options
.pnn
);
2510 DEBUG(DEBUG_ERR
, ("Unable to continue node %u\n", options
.pnn
));
2516 /* read the nodemap and verify the change took effect */
2517 if (ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
, ctdb
, &nodemap
) != 0) {
2518 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from local node\n"));
2522 } while (nodemap
->nodes
[options
.pnn
].flags
& NODE_FLAGS_STOPPED
);
2523 ret
= control_ipreallocate(ctdb
, argc
, argv
);
2525 DEBUG(DEBUG_ERR
, ("IP Reallocate failed on node %u\n", options
.pnn
));
2532 static uint32_t get_generation(struct ctdb_context
*ctdb
)
2534 struct ctdb_vnn_map
*vnnmap
=NULL
;
2537 /* wait until the recmaster is not in recovery mode */
2539 uint32_t recmode
, recmaster
;
2541 if (vnnmap
!= NULL
) {
2542 talloc_free(vnnmap
);
2546 /* get the recmaster */
2547 if (!ctdb_getrecmaster(ctdb_connection
, CTDB_CURRENT_NODE
, &recmaster
)) {
2548 DEBUG(DEBUG_ERR
, ("Unable to get recmaster from node %u\n", options
.pnn
));
2552 /* get recovery mode */
2553 if (!ctdb_getrecmode(ctdb_connection
, recmaster
, &recmode
)) {
2554 DEBUG(DEBUG_ERR
, ("Unable to get recmode from node %u\n", options
.pnn
));
2558 /* get the current generation number */
2559 ret
= ctdb_ctrl_getvnnmap(ctdb
, TIMELIMIT(), recmaster
, ctdb
, &vnnmap
);
2561 DEBUG(DEBUG_ERR
, ("Unable to get vnnmap from recmaster (%u)\n", recmaster
));
2565 if ((recmode
== CTDB_RECOVERY_NORMAL
)
2566 && (vnnmap
->generation
!= 1)){
2567 return vnnmap
->generation
;
2574 ban a node from the cluster
2576 static int control_ban(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2579 struct ctdb_node_map
*nodemap
=NULL
;
2580 struct ctdb_ban_time bantime
;
2586 /* verify the node exists */
2587 ret
= ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
, ctdb
, &nodemap
);
2589 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from local node\n"));
2593 if (nodemap
->nodes
[options
.pnn
].flags
& NODE_FLAGS_BANNED
) {
2594 DEBUG(DEBUG_ERR
,("Node %u is already banned.\n", options
.pnn
));
2598 bantime
.pnn
= options
.pnn
;
2599 bantime
.time
= strtoul(argv
[0], NULL
, 0);
2601 ret
= ctdb_ctrl_set_ban(ctdb
, TIMELIMIT(), options
.pnn
, &bantime
);
2603 DEBUG(DEBUG_ERR
,("Banning node %d for %d seconds failed.\n", bantime
.pnn
, bantime
.time
));
2607 ret
= control_ipreallocate(ctdb
, argc
, argv
);
2609 DEBUG(DEBUG_ERR
, ("IP Reallocate failed on node %u\n", options
.pnn
));
2618 unban a node from the cluster
2620 static int control_unban(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2623 struct ctdb_node_map
*nodemap
=NULL
;
2624 struct ctdb_ban_time bantime
;
2626 /* verify the node exists */
2627 ret
= ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
, ctdb
, &nodemap
);
2629 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from local node\n"));
2633 if (!(nodemap
->nodes
[options
.pnn
].flags
& NODE_FLAGS_BANNED
)) {
2634 DEBUG(DEBUG_ERR
,("Node %u is not banned.\n", options
.pnn
));
2638 bantime
.pnn
= options
.pnn
;
2641 ret
= ctdb_ctrl_set_ban(ctdb
, TIMELIMIT(), options
.pnn
, &bantime
);
2643 DEBUG(DEBUG_ERR
,("Unbanning node %d failed.\n", bantime
.pnn
));
2647 ret
= control_ipreallocate(ctdb
, argc
, argv
);
2649 DEBUG(DEBUG_ERR
, ("IP Reallocate failed on node %u\n", options
.pnn
));
2658 show ban information for a node
2660 static int control_showban(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2663 struct ctdb_node_map
*nodemap
=NULL
;
2664 struct ctdb_ban_time
*bantime
;
2666 /* verify the node exists */
2667 ret
= ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
, ctdb
, &nodemap
);
2669 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from local node\n"));
2673 ret
= ctdb_ctrl_get_ban(ctdb
, TIMELIMIT(), options
.pnn
, ctdb
, &bantime
);
2675 DEBUG(DEBUG_ERR
,("Showing ban info for node %d failed.\n", options
.pnn
));
2679 if (bantime
->time
== 0) {
2680 printf("Node %u is not banned\n", bantime
->pnn
);
2682 printf("Node %u is banned banned for %d seconds\n", bantime
->pnn
, bantime
->time
);
2691 static int control_shutdown(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2695 ret
= ctdb_ctrl_shutdown(ctdb
, TIMELIMIT(), options
.pnn
);
2697 DEBUG(DEBUG_ERR
, ("Unable to shutdown node %u\n", options
.pnn
));
2707 static int control_recover(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2710 uint32_t generation
, next_generation
;
2712 /* record the current generation number */
2713 generation
= get_generation(ctdb
);
2715 ret
= ctdb_ctrl_freeze_priority(ctdb
, TIMELIMIT(), options
.pnn
, 1);
2717 DEBUG(DEBUG_ERR
, ("Unable to freeze node\n"));
2721 ret
= ctdb_ctrl_setrecmode(ctdb
, TIMELIMIT(), options
.pnn
, CTDB_RECOVERY_ACTIVE
);
2723 DEBUG(DEBUG_ERR
, ("Unable to set recovery mode\n"));
2727 /* wait until we are in a new generation */
2729 next_generation
= get_generation(ctdb
);
2730 if (next_generation
!= generation
) {
2741 display monitoring mode of a remote node
2743 static int control_getmonmode(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2748 ret
= ctdb_ctrl_getmonmode(ctdb
, TIMELIMIT(), options
.pnn
, &monmode
);
2750 DEBUG(DEBUG_ERR
, ("Unable to get monmode from node %u\n", options
.pnn
));
2753 if (!options
.machinereadable
){
2754 printf("Monitoring mode:%s (%d)\n",monmode
==CTDB_MONITORING_ACTIVE
?"ACTIVE":"DISABLED",monmode
);
2757 printf(":%d:\n",monmode
);
2764 display capabilities of a remote node
2766 static int control_getcapabilities(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2768 uint32_t capabilities
;
2771 ret
= ctdb_ctrl_getcapabilities(ctdb
, TIMELIMIT(), options
.pnn
, &capabilities
);
2773 DEBUG(DEBUG_ERR
, ("Unable to get capabilities from node %u\n", options
.pnn
));
2777 if (!options
.machinereadable
){
2778 printf("RECMASTER: %s\n", (capabilities
&CTDB_CAP_RECMASTER
)?"YES":"NO");
2779 printf("LMASTER: %s\n", (capabilities
&CTDB_CAP_LMASTER
)?"YES":"NO");
2780 printf("LVS: %s\n", (capabilities
&CTDB_CAP_LVS
)?"YES":"NO");
2781 printf("NATGW: %s\n", (capabilities
&CTDB_CAP_NATGW
)?"YES":"NO");
2783 printf(":RECMASTER:LMASTER:LVS:NATGW:\n");
2784 printf(":%d:%d:%d:%d:\n",
2785 !!(capabilities
&CTDB_CAP_RECMASTER
),
2786 !!(capabilities
&CTDB_CAP_LMASTER
),
2787 !!(capabilities
&CTDB_CAP_LVS
),
2788 !!(capabilities
&CTDB_CAP_NATGW
));
2794 display lvs configuration
2796 static int control_lvs(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2798 uint32_t *capabilities
;
2799 struct ctdb_node_map
*nodemap
=NULL
;
2801 int healthy_count
= 0;
2803 ret
= ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), options
.pnn
, ctdb
, &nodemap
);
2805 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from node %u\n", options
.pnn
));
2809 capabilities
= talloc_array(ctdb
, uint32_t, nodemap
->num
);
2810 CTDB_NO_MEMORY(ctdb
, capabilities
);
2812 /* collect capabilities for all connected nodes */
2813 for (i
=0; i
<nodemap
->num
; i
++) {
2814 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_INACTIVE
) {
2817 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_PERMANENTLY_DISABLED
) {
2821 ret
= ctdb_ctrl_getcapabilities(ctdb
, TIMELIMIT(), i
, &capabilities
[i
]);
2823 DEBUG(DEBUG_ERR
, ("Unable to get capabilities from node %u\n", i
));
2827 if (!(capabilities
[i
] & CTDB_CAP_LVS
)) {
2831 if (!(nodemap
->nodes
[i
].flags
& NODE_FLAGS_UNHEALTHY
)) {
2836 /* Print all LVS nodes */
2837 for (i
=0; i
<nodemap
->num
; i
++) {
2838 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_INACTIVE
) {
2841 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_PERMANENTLY_DISABLED
) {
2844 if (!(capabilities
[i
] & CTDB_CAP_LVS
)) {
2848 if (healthy_count
!= 0) {
2849 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_UNHEALTHY
) {
2854 printf("%d:%s\n", i
,
2855 ctdb_addr_to_str(&nodemap
->nodes
[i
].addr
));
2862 display who is the lvs master
2864 static int control_lvsmaster(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2866 uint32_t *capabilities
;
2867 struct ctdb_node_map
*nodemap
=NULL
;
2869 int healthy_count
= 0;
2871 ret
= ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), options
.pnn
, ctdb
, &nodemap
);
2873 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from node %u\n", options
.pnn
));
2877 capabilities
= talloc_array(ctdb
, uint32_t, nodemap
->num
);
2878 CTDB_NO_MEMORY(ctdb
, capabilities
);
2880 /* collect capabilities for all connected nodes */
2881 for (i
=0; i
<nodemap
->num
; i
++) {
2882 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_INACTIVE
) {
2885 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_PERMANENTLY_DISABLED
) {
2889 ret
= ctdb_ctrl_getcapabilities(ctdb
, TIMELIMIT(), i
, &capabilities
[i
]);
2891 DEBUG(DEBUG_ERR
, ("Unable to get capabilities from node %u\n", i
));
2895 if (!(capabilities
[i
] & CTDB_CAP_LVS
)) {
2899 if (!(nodemap
->nodes
[i
].flags
& NODE_FLAGS_UNHEALTHY
)) {
2904 /* find and show the lvsmaster */
2905 for (i
=0; i
<nodemap
->num
; i
++) {
2906 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_INACTIVE
) {
2909 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_PERMANENTLY_DISABLED
) {
2912 if (!(capabilities
[i
] & CTDB_CAP_LVS
)) {
2916 if (healthy_count
!= 0) {
2917 if (nodemap
->nodes
[i
].flags
& NODE_FLAGS_UNHEALTHY
) {
2922 if (options
.machinereadable
){
2925 printf("Node %d is LVS master\n", i
);
2930 printf("There is no LVS master\n");
2935 disable monitoring on a node
2937 static int control_disable_monmode(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2942 ret
= ctdb_ctrl_disable_monmode(ctdb
, TIMELIMIT(), options
.pnn
);
2944 DEBUG(DEBUG_ERR
, ("Unable to disable monmode on node %u\n", options
.pnn
));
2947 printf("Monitoring mode:%s\n","DISABLED");
2953 enable monitoring on a node
2955 static int control_enable_monmode(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2960 ret
= ctdb_ctrl_enable_monmode(ctdb
, TIMELIMIT(), options
.pnn
);
2962 DEBUG(DEBUG_ERR
, ("Unable to enable monmode on node %u\n", options
.pnn
));
2965 printf("Monitoring mode:%s\n","ACTIVE");
2971 display remote list of keys/data for a db
2973 static int control_catdb(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
2975 const char *db_name
;
2976 struct ctdb_db_context
*ctdb_db
;
2979 struct ctdb_dump_db_context c
;
2988 if (db_exists(ctdb
, db_name
, &persistent
)) {
2989 DEBUG(DEBUG_ERR
,("Database '%s' does not exist\n", db_name
));
2993 ctdb_db
= ctdb_attach(ctdb
, TIMELIMIT(), db_name
, persistent
, 0);
2995 if (ctdb_db
== NULL
) {
2996 DEBUG(DEBUG_ERR
,("Unable to attach to database '%s'\n", db_name
));
3002 c
.printemptyrecords
= (bool)options
.printemptyrecords
;
3003 c
.printdatasize
= (bool)options
.printdatasize
;
3005 /* traverse and dump the cluster tdb */
3006 ret
= ctdb_dump_db(ctdb_db
, &c
);
3008 DEBUG(DEBUG_ERR
, ("Unable to dump database\n"));
3009 DEBUG(DEBUG_ERR
, ("Maybe try 'ctdb getdbstatus %s'"
3010 " and 'ctdb getvar AllowUnhealthyDBRead'\n",
3014 talloc_free(ctdb_db
);
3016 printf("Dumped %d records\n", ret
);
3020 struct cattdb_data
{
3021 struct ctdb_context
*ctdb
;
3025 static int cattdb_traverse(struct tdb_context
*tdb
, TDB_DATA key
, TDB_DATA data
, void *private_data
)
3027 struct cattdb_data
*d
= private_data
;
3028 struct ctdb_dump_db_context c
;
3034 c
.printemptyrecords
= (bool)options
.printemptyrecords
;
3035 c
.printdatasize
= (bool)options
.printdatasize
;
3037 return ctdb_dumpdb_record(d
->ctdb
, key
, data
, &c
);
3041 cat the local tdb database using same format as catdb
3043 static int control_cattdb(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3045 const char *db_name
;
3046 struct ctdb_db_context
*ctdb_db
;
3047 struct cattdb_data d
;
3057 if (db_exists(ctdb
, db_name
, &persistent
)) {
3058 DEBUG(DEBUG_ERR
,("Database '%s' does not exist\n", db_name
));
3062 ctdb_db
= ctdb_attach(ctdb
, TIMELIMIT(), db_name
, false, 0);
3064 if (ctdb_db
== NULL
) {
3065 DEBUG(DEBUG_ERR
,("Unable to attach to database '%s'\n", db_name
));
3069 /* traverse the local tdb */
3072 if (tdb_traverse_read(ctdb_db
->ltdb
->tdb
, cattdb_traverse
, &d
) == -1) {
3073 printf("Failed to cattdb data\n");
3076 talloc_free(ctdb_db
);
3078 printf("Dumped %d records\n", d
.count
);
3083 display the content of a database key
3085 static int control_readkey(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3087 const char *db_name
;
3088 struct ctdb_db_context
*ctdb_db
;
3089 struct ctdb_record_handle
*h
;
3090 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
3101 if (db_exists(ctdb
, db_name
, &persistent
)) {
3102 DEBUG(DEBUG_ERR
,("Database '%s' does not exist\n", db_name
));
3106 ctdb_db
= ctdb_attach(ctdb
, TIMELIMIT(), db_name
, persistent
, 0);
3108 if (ctdb_db
== NULL
) {
3109 DEBUG(DEBUG_ERR
,("Unable to attach to database '%s'\n", db_name
));
3113 key
.dptr
= discard_const(argv
[1]);
3114 key
.dsize
= strlen((char *)key
.dptr
);
3116 h
= ctdb_fetch_lock(ctdb_db
, tmp_ctx
, key
, &data
);
3118 printf("Failed to fetch record '%s' on node %d\n",
3119 (const char *)key
.dptr
, ctdb_get_pnn(ctdb
));
3120 talloc_free(tmp_ctx
);
3124 printf("Data: size:%d ptr:[%s]\n", (int)data
.dsize
, data
.dptr
);
3126 talloc_free(ctdb_db
);
3127 talloc_free(tmp_ctx
);
3132 display the content of a database key
3134 static int control_writekey(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3136 const char *db_name
;
3137 struct ctdb_db_context
*ctdb_db
;
3138 struct ctdb_record_handle
*h
;
3139 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
3150 if (db_exists(ctdb
, db_name
, &persistent
)) {
3151 DEBUG(DEBUG_ERR
,("Database '%s' does not exist\n", db_name
));
3155 ctdb_db
= ctdb_attach(ctdb
, TIMELIMIT(), db_name
, persistent
, 0);
3157 if (ctdb_db
== NULL
) {
3158 DEBUG(DEBUG_ERR
,("Unable to attach to database '%s'\n", db_name
));
3162 key
.dptr
= discard_const(argv
[1]);
3163 key
.dsize
= strlen((char *)key
.dptr
);
3165 h
= ctdb_fetch_lock(ctdb_db
, tmp_ctx
, key
, &data
);
3167 printf("Failed to fetch record '%s' on node %d\n",
3168 (const char *)key
.dptr
, ctdb_get_pnn(ctdb
));
3169 talloc_free(tmp_ctx
);
3173 data
.dptr
= discard_const(argv
[2]);
3174 data
.dsize
= strlen((char *)data
.dptr
);
3176 if (ctdb_record_store(h
, data
) != 0) {
3177 printf("Failed to store record\n");
3181 talloc_free(ctdb_db
);
3182 talloc_free(tmp_ctx
);
3187 fetch a record from a persistent database
3189 static int control_pfetch(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3191 const char *db_name
;
3192 struct ctdb_db_context
*ctdb_db
;
3193 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
3194 struct ctdb_transaction_handle
*h
;
3200 talloc_free(tmp_ctx
);
3207 if (db_exists(ctdb
, db_name
, &persistent
)) {
3208 DEBUG(DEBUG_ERR
,("Database '%s' does not exist\n", db_name
));
3209 talloc_free(tmp_ctx
);
3214 DEBUG(DEBUG_ERR
,("Database '%s' is not persistent\n", db_name
));
3215 talloc_free(tmp_ctx
);
3219 ctdb_db
= ctdb_attach(ctdb
, TIMELIMIT(), db_name
, persistent
, 0);
3221 if (ctdb_db
== NULL
) {
3222 DEBUG(DEBUG_ERR
,("Unable to attach to database '%s'\n", db_name
));
3223 talloc_free(tmp_ctx
);
3227 h
= ctdb_transaction_start(ctdb_db
, tmp_ctx
);
3229 DEBUG(DEBUG_ERR
,("Failed to start transaction on database %s\n", db_name
));
3230 talloc_free(tmp_ctx
);
3234 key
.dptr
= discard_const(argv
[1]);
3235 key
.dsize
= strlen(argv
[1]);
3236 ret
= ctdb_transaction_fetch(h
, tmp_ctx
, key
, &data
);
3238 DEBUG(DEBUG_ERR
,("Failed to fetch record\n"));
3239 talloc_free(tmp_ctx
);
3243 if (data
.dsize
== 0 || data
.dptr
== NULL
) {
3244 DEBUG(DEBUG_ERR
,("Record is empty\n"));
3245 talloc_free(tmp_ctx
);
3250 fd
= open(argv
[2], O_WRONLY
|O_CREAT
|O_TRUNC
, 0600);
3252 DEBUG(DEBUG_ERR
,("Failed to open output file %s\n", argv
[2]));
3253 talloc_free(tmp_ctx
);
3256 write(fd
, data
.dptr
, data
.dsize
);
3259 write(1, data
.dptr
, data
.dsize
);
3262 /* abort the transaction */
3266 talloc_free(tmp_ctx
);
3271 fetch a record from a tdb-file
3273 static int control_tfetch(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3275 const char *tdb_file
;
3286 tdb
= tdb_open(tdb_file
, 0, 0, O_RDONLY
, 0);
3288 DEBUG(DEBUG_ERR
,("Failed to open TDB file %s\n", tdb_file
));
3292 key
.dptr
= discard_const(argv
[1]);
3293 key
.dsize
= strlen(argv
[1]);
3294 data
= tdb_fetch(tdb
, key
);
3295 if (data
.dptr
== NULL
|| data
.dsize
< sizeof(struct ctdb_ltdb_header
)) {
3296 DEBUG(DEBUG_ERR
,("Failed to read record %s from tdb %s\n", argv
[1], tdb_file
));
3304 fd
= open(argv
[2], O_WRONLY
|O_CREAT
|O_TRUNC
, 0600);
3306 DEBUG(DEBUG_ERR
,("Failed to open output file %s\n", argv
[2]));
3309 write(fd
, data
.dptr
+sizeof(struct ctdb_ltdb_header
), data
.dsize
-sizeof(struct ctdb_ltdb_header
));
3312 write(1, data
.dptr
+sizeof(struct ctdb_ltdb_header
), data
.dsize
-sizeof(struct ctdb_ltdb_header
));
3319 write a record to a persistent database
3321 static int control_pstore(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3323 const char *db_name
;
3324 struct ctdb_db_context
*ctdb_db
;
3325 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
3326 struct ctdb_transaction_handle
*h
;
3332 talloc_free(tmp_ctx
);
3336 fd
= open(argv
[2], O_RDONLY
);
3338 DEBUG(DEBUG_ERR
,("Failed to open file containing record data : %s %s\n", argv
[2], strerror(errno
)));
3339 talloc_free(tmp_ctx
);
3343 ret
= fstat(fd
, &st
);
3345 DEBUG(DEBUG_ERR
,("fstat of file %s failed: %s\n", argv
[2], strerror(errno
)));
3347 talloc_free(tmp_ctx
);
3351 if (!S_ISREG(st
.st_mode
)) {
3352 DEBUG(DEBUG_ERR
,("Not a regular file %s\n", argv
[2]));
3354 talloc_free(tmp_ctx
);
3358 data
.dsize
= st
.st_size
;
3359 if (data
.dsize
== 0) {
3362 data
.dptr
= talloc_size(tmp_ctx
, data
.dsize
);
3363 if (data
.dptr
== NULL
) {
3364 DEBUG(DEBUG_ERR
,("Failed to talloc %d of memory to store record data\n", (int)data
.dsize
));
3366 talloc_free(tmp_ctx
);
3369 ret
= read(fd
, data
.dptr
, data
.dsize
);
3370 if (ret
!= data
.dsize
) {
3371 DEBUG(DEBUG_ERR
,("Failed to read %d bytes of record data\n", (int)data
.dsize
));
3373 talloc_free(tmp_ctx
);
3382 ctdb_db
= ctdb_attach(ctdb
, TIMELIMIT(), db_name
, true, 0);
3383 if (ctdb_db
== NULL
) {
3384 DEBUG(DEBUG_ERR
,("Unable to attach to database '%s'\n", db_name
));
3385 talloc_free(tmp_ctx
);
3389 h
= ctdb_transaction_start(ctdb_db
, tmp_ctx
);
3391 DEBUG(DEBUG_ERR
,("Failed to start transaction on database %s\n", db_name
));
3392 talloc_free(tmp_ctx
);
3396 key
.dptr
= discard_const(argv
[1]);
3397 key
.dsize
= strlen(argv
[1]);
3398 ret
= ctdb_transaction_store(h
, key
, data
);
3400 DEBUG(DEBUG_ERR
,("Failed to store record\n"));
3401 talloc_free(tmp_ctx
);
3405 ret
= ctdb_transaction_commit(h
);
3407 DEBUG(DEBUG_ERR
,("Failed to commit transaction\n"));
3408 talloc_free(tmp_ctx
);
3413 talloc_free(tmp_ctx
);
3418 check if a service is bound to a port or not
3420 static int control_chktcpport(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3425 struct sockaddr_in sin
;
3428 printf("Use: ctdb chktcport <port>\n");
3432 port
= atoi(argv
[0]);
3434 s
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
3436 printf("Failed to open local socket\n");
3440 v
= fcntl(s
, F_GETFL
, 0);
3441 fcntl(s
, F_SETFL
, v
| O_NONBLOCK
);
3443 bzero(&sin
, sizeof(sin
));
3444 sin
.sin_family
= PF_INET
;
3445 sin
.sin_port
= htons(port
);
3446 ret
= bind(s
, (struct sockaddr
*)&sin
, sizeof(sin
));
3449 printf("Failed to bind to local socket: %d %s\n", errno
, strerror(errno
));
3458 static void log_handler(struct ctdb_context
*ctdb
, uint64_t srvid
,
3459 TDB_DATA data
, void *private_data
)
3461 DEBUG(DEBUG_ERR
,("Log data received\n"));
3462 if (data
.dsize
> 0) {
3463 printf("%s", data
.dptr
);
3470 display a list of log messages from the in memory ringbuffer
3472 static int control_getlog(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3476 struct ctdb_get_log_addr log_addr
;
3478 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
3483 DEBUG(DEBUG_ERR
,("Invalid arguments\n"));
3484 talloc_free(tmp_ctx
);
3488 log_addr
.pnn
= ctdb_ctrl_getpnn(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
);
3489 log_addr
.srvid
= getpid();
3490 if (isalpha(argv
[0][0]) || argv
[0][0] == '-') {
3491 log_addr
.level
= get_debug_by_desc(argv
[0]);
3493 log_addr
.level
= strtol(argv
[0], NULL
, 0);
3497 data
.dptr
= (unsigned char *)&log_addr
;
3498 data
.dsize
= sizeof(log_addr
);
3500 DEBUG(DEBUG_ERR
, ("Pulling logs from node %u\n", options
.pnn
));
3502 ctdb_client_set_message_handler(ctdb
, log_addr
.srvid
, log_handler
, NULL
);
3505 DEBUG(DEBUG_ERR
,("Listen for response on %d\n", (int)log_addr
.srvid
));
3507 ret
= ctdb_control(ctdb
, options
.pnn
, 0, CTDB_CONTROL_GET_LOG
,
3508 0, data
, tmp_ctx
, NULL
, &res
, NULL
, &errmsg
);
3509 if (ret
!= 0 || res
!= 0) {
3510 DEBUG(DEBUG_ERR
,("Failed to get logs - %s\n", errmsg
));
3511 talloc_free(tmp_ctx
);
3516 tv
= timeval_current();
3517 /* this loop will terminate when we have received the reply */
3518 while (timeval_elapsed(&tv
) < 3.0) {
3519 event_loop_once(ctdb
->ev
);
3522 DEBUG(DEBUG_INFO
,("Timed out waiting for log data.\n"));
3524 talloc_free(tmp_ctx
);
3529 clear the in memory log area
3531 static int control_clearlog(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3536 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
3538 ret
= ctdb_control(ctdb
, options
.pnn
, 0, CTDB_CONTROL_CLEAR_LOG
,
3539 0, tdb_null
, tmp_ctx
, NULL
, &res
, NULL
, &errmsg
);
3540 if (ret
!= 0 || res
!= 0) {
3541 DEBUG(DEBUG_ERR
,("Failed to clear logs\n"));
3542 talloc_free(tmp_ctx
);
3546 talloc_free(tmp_ctx
);
3553 display a list of the databases on a remote ctdb
3555 static int control_getdbmap(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3558 struct ctdb_dbid_map
*dbmap
=NULL
;
3560 ret
= ctdb_ctrl_getdbmap(ctdb
, TIMELIMIT(), options
.pnn
, ctdb
, &dbmap
);
3562 DEBUG(DEBUG_ERR
, ("Unable to get dbids from node %u\n", options
.pnn
));
3566 if(options
.machinereadable
){
3567 printf(":ID:Name:Path:Persistent:Unhealthy:ReadOnly:\n");
3568 for(i
=0;i
<dbmap
->num
;i
++){
3575 ctdb_ctrl_getdbpath(ctdb
, TIMELIMIT(), options
.pnn
,
3576 dbmap
->dbs
[i
].dbid
, ctdb
, &path
);
3577 ctdb_ctrl_getdbname(ctdb
, TIMELIMIT(), options
.pnn
,
3578 dbmap
->dbs
[i
].dbid
, ctdb
, &name
);
3579 ctdb_ctrl_getdbhealth(ctdb
, TIMELIMIT(), options
.pnn
,
3580 dbmap
->dbs
[i
].dbid
, ctdb
, &health
);
3581 persistent
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_PERSISTENT
;
3582 readonly
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_READONLY
;
3583 printf(":0x%08X:%s:%s:%d:%d:%d:\n",
3584 dbmap
->dbs
[i
].dbid
, name
, path
,
3585 !!(persistent
), !!(health
), !!(readonly
));
3590 printf("Number of databases:%d\n", dbmap
->num
);
3591 for(i
=0;i
<dbmap
->num
;i
++){
3598 ctdb_ctrl_getdbpath(ctdb
, TIMELIMIT(), options
.pnn
, dbmap
->dbs
[i
].dbid
, ctdb
, &path
);
3599 ctdb_ctrl_getdbname(ctdb
, TIMELIMIT(), options
.pnn
, dbmap
->dbs
[i
].dbid
, ctdb
, &name
);
3600 ctdb_ctrl_getdbhealth(ctdb
, TIMELIMIT(), options
.pnn
, dbmap
->dbs
[i
].dbid
, ctdb
, &health
);
3601 persistent
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_PERSISTENT
;
3602 readonly
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_READONLY
;
3603 printf("dbid:0x%08x name:%s path:%s%s%s%s\n",
3604 dbmap
->dbs
[i
].dbid
, name
, path
,
3605 persistent
?" PERSISTENT":"",
3606 readonly
?" READONLY":"",
3607 health
?" UNHEALTHY":"");
3614 display the status of a database on a remote ctdb
3616 static int control_getdbstatus(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3619 struct ctdb_dbid_map
*dbmap
=NULL
;
3620 const char *db_name
;
3628 ret
= ctdb_ctrl_getdbmap(ctdb
, TIMELIMIT(), options
.pnn
, ctdb
, &dbmap
);
3630 DEBUG(DEBUG_ERR
, ("Unable to get dbids from node %u\n", options
.pnn
));
3634 for(i
=0;i
<dbmap
->num
;i
++){
3641 ctdb_ctrl_getdbname(ctdb
, TIMELIMIT(), options
.pnn
, dbmap
->dbs
[i
].dbid
, ctdb
, &name
);
3642 if (strcmp(name
, db_name
) != 0) {
3646 ctdb_ctrl_getdbpath(ctdb
, TIMELIMIT(), options
.pnn
, dbmap
->dbs
[i
].dbid
, ctdb
, &path
);
3647 ctdb_ctrl_getdbhealth(ctdb
, TIMELIMIT(), options
.pnn
, dbmap
->dbs
[i
].dbid
, ctdb
, &health
);
3648 persistent
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_PERSISTENT
;
3649 readonly
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_READONLY
;
3650 printf("dbid: 0x%08x\nname: %s\npath: %s\nPERSISTENT: %s\nREADONLY: %s\nHEALTH: %s\n",
3651 dbmap
->dbs
[i
].dbid
, name
, path
,
3652 persistent
?"yes":"no",
3653 readonly
?"yes":"no",
3654 health
?health
:"OK");
3658 DEBUG(DEBUG_ERR
, ("db %s doesn't exist on node %u\n", db_name
, options
.pnn
));
3663 check if the local node is recmaster or not
3664 it will return 1 if this node is the recmaster and 0 if it is not
3665 or if the local ctdb daemon could not be contacted
3667 static int control_isnotrecmaster(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3669 uint32_t mypnn
, recmaster
;
3671 mypnn
= ctdb_ctrl_getpnn(ctdb
, TIMELIMIT(), options
.pnn
);
3673 printf("Failed to get pnn of node\n");
3677 if (!ctdb_getrecmaster(ctdb_connection
, options
.pnn
, &recmaster
)) {
3678 printf("Failed to get the recmaster\n");
3682 if (recmaster
!= mypnn
) {
3683 printf("this node is not the recmaster\n");
3687 printf("this node is the recmaster\n");
3694 static int control_ping(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3697 struct timeval tv
= timeval_current();
3698 ret
= ctdb_ctrl_ping(ctdb
, options
.pnn
);
3700 printf("Unable to get ping response from node %u\n", options
.pnn
);
3703 printf("response from %u time=%.6f sec (%d clients)\n",
3704 options
.pnn
, timeval_elapsed(&tv
), ret
);
3713 static int control_getvar(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3724 ret
= ctdb_ctrl_get_tunable(ctdb
, TIMELIMIT(), options
.pnn
, name
, &value
);
3726 DEBUG(DEBUG_ERR
, ("Unable to get tunable variable '%s'\n", name
));
3730 printf("%-19s = %u\n", name
, value
);
3737 static int control_setvar(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3748 value
= strtoul(argv
[1], NULL
, 0);
3750 ret
= ctdb_ctrl_set_tunable(ctdb
, TIMELIMIT(), options
.pnn
, name
, value
);
3752 DEBUG(DEBUG_ERR
, ("Unable to set tunable variable '%s'\n", name
));
3761 static int control_listvars(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3767 ret
= ctdb_ctrl_list_tunables(ctdb
, TIMELIMIT(), options
.pnn
, ctdb
, &list
, &count
);
3769 DEBUG(DEBUG_ERR
, ("Unable to list tunable variables\n"));
3773 for (i
=0;i
<count
;i
++) {
3774 control_getvar(ctdb
, 1, &list
[i
]);
3783 display debug level on a node
3785 static int control_getdebug(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3790 ret
= ctdb_ctrl_get_debuglevel(ctdb
, options
.pnn
, &level
);
3792 DEBUG(DEBUG_ERR
, ("Unable to get debuglevel response from node %u\n", options
.pnn
));
3795 if (options
.machinereadable
){
3796 printf(":Name:Level:\n");
3797 printf(":%s:%d:\n",get_debug_by_level(level
),level
);
3799 printf("Node %u is at debug level %s (%d)\n", options
.pnn
, get_debug_by_level(level
), level
);
3806 display reclock file of a node
3808 static int control_getreclock(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3811 const char *reclock
;
3813 ret
= ctdb_ctrl_getreclock(ctdb
, TIMELIMIT(), options
.pnn
, ctdb
, &reclock
);
3815 DEBUG(DEBUG_ERR
, ("Unable to get reclock file from node %u\n", options
.pnn
));
3818 if (options
.machinereadable
){
3819 if (reclock
!= NULL
) {
3820 printf("%s", reclock
);
3823 if (reclock
== NULL
) {
3824 printf("No reclock file used.\n");
3826 printf("Reclock file:%s\n", reclock
);
3834 set the reclock file of a node
3836 static int control_setreclock(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3839 const char *reclock
;
3843 } else if (argc
== 1) {
3849 ret
= ctdb_ctrl_setreclock(ctdb
, TIMELIMIT(), options
.pnn
, reclock
);
3851 DEBUG(DEBUG_ERR
, ("Unable to get reclock file from node %u\n", options
.pnn
));
3858 set the natgw state on/off
3860 static int control_setnatgwstate(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3863 uint32_t natgwstate
;
3869 if (!strcmp(argv
[0], "on")) {
3871 } else if (!strcmp(argv
[0], "off")) {
3877 ret
= ctdb_ctrl_setnatgwstate(ctdb
, TIMELIMIT(), options
.pnn
, natgwstate
);
3879 DEBUG(DEBUG_ERR
, ("Unable to set the natgw state for node %u\n", options
.pnn
));
3887 set the lmaster role on/off
3889 static int control_setlmasterrole(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3892 uint32_t lmasterrole
;
3898 if (!strcmp(argv
[0], "on")) {
3900 } else if (!strcmp(argv
[0], "off")) {
3906 ret
= ctdb_ctrl_setlmasterrole(ctdb
, TIMELIMIT(), options
.pnn
, lmasterrole
);
3908 DEBUG(DEBUG_ERR
, ("Unable to set the lmaster role for node %u\n", options
.pnn
));
3916 set the recmaster role on/off
3918 static int control_setrecmasterrole(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3921 uint32_t recmasterrole
;
3927 if (!strcmp(argv
[0], "on")) {
3929 } else if (!strcmp(argv
[0], "off")) {
3935 ret
= ctdb_ctrl_setrecmasterrole(ctdb
, TIMELIMIT(), options
.pnn
, recmasterrole
);
3937 DEBUG(DEBUG_ERR
, ("Unable to set the recmaster role for node %u\n", options
.pnn
));
3945 set debug level on a node or all nodes
3947 static int control_setdebug(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3953 printf("You must specify the debug level. Valid levels are:\n");
3954 for (i
=0; debug_levels
[i
].description
!= NULL
; i
++) {
3955 printf("%s (%d)\n", debug_levels
[i
].description
, debug_levels
[i
].level
);
3961 if (isalpha(argv
[0][0]) || argv
[0][0] == '-') {
3962 level
= get_debug_by_desc(argv
[0]);
3964 level
= strtol(argv
[0], NULL
, 0);
3967 for (i
=0; debug_levels
[i
].description
!= NULL
; i
++) {
3968 if (level
== debug_levels
[i
].level
) {
3972 if (debug_levels
[i
].description
== NULL
) {
3973 printf("Invalid debug level, must be one of\n");
3974 for (i
=0; debug_levels
[i
].description
!= NULL
; i
++) {
3975 printf("%s (%d)\n", debug_levels
[i
].description
, debug_levels
[i
].level
);
3980 ret
= ctdb_ctrl_set_debuglevel(ctdb
, options
.pnn
, level
);
3982 DEBUG(DEBUG_ERR
, ("Unable to set debug level on node %u\n", options
.pnn
));
3991 static int control_thaw(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
3997 priority
= strtol(argv
[0], NULL
, 0);
4001 DEBUG(DEBUG_ERR
,("Thaw by priority %u\n", priority
));
4003 ret
= ctdb_ctrl_thaw_priority(ctdb
, TIMELIMIT(), options
.pnn
, priority
);
4005 DEBUG(DEBUG_ERR
, ("Unable to thaw node %u\n", options
.pnn
));
4012 attach to a database
4014 static int control_attach(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
4016 const char *db_name
;
4017 struct ctdb_db_context
*ctdb_db
;
4018 bool persistent
= false;
4028 if (strcmp(argv
[1], "persistent") != 0) {
4034 ctdb_db
= ctdb_attach(ctdb
, TIMELIMIT(), db_name
, persistent
, 0);
4035 if (ctdb_db
== NULL
) {
4036 DEBUG(DEBUG_ERR
,("Unable to attach to database '%s'\n", db_name
));
4046 static int control_setdbprio(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
4048 struct ctdb_db_priority db_prio
;
4055 db_prio
.db_id
= strtoul(argv
[0], NULL
, 0);
4056 db_prio
.priority
= strtoul(argv
[1], NULL
, 0);
4058 ret
= ctdb_ctrl_set_db_priority(ctdb
, TIMELIMIT(), options
.pnn
, &db_prio
);
4060 DEBUG(DEBUG_ERR
,("Unable to set db prio\n"));
4070 static int control_getdbprio(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
4072 uint32_t db_id
, priority
;
4079 db_id
= strtoul(argv
[0], NULL
, 0);
4081 ret
= ctdb_ctrl_get_db_priority(ctdb
, TIMELIMIT(), options
.pnn
, db_id
, &priority
);
4083 DEBUG(DEBUG_ERR
,("Unable to get db prio\n"));
4087 DEBUG(DEBUG_ERR
,("Priority:%u\n", priority
));
4093 set the readonly capability for a database
4095 static int control_setdbreadonly(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
4104 db_id
= strtoul(argv
[0], NULL
, 0);
4106 ret
= ctdb_ctrl_set_db_readonly(ctdb
, options
.pnn
, db_id
);
4108 DEBUG(DEBUG_ERR
,("Unable to set db to support readonly\n"));
4116 run an eventscript on a node
4118 static int control_eventscript(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
4124 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
4127 DEBUG(DEBUG_ERR
,("Invalid arguments\n"));
4131 data
.dptr
= (unsigned char *)discard_const(argv
[0]);
4132 data
.dsize
= strlen((char *)data
.dptr
) + 1;
4134 DEBUG(DEBUG_ERR
, ("Running eventscripts with arguments \"%s\" on node %u\n", data
.dptr
, options
.pnn
));
4136 ret
= ctdb_control(ctdb
, options
.pnn
, 0, CTDB_CONTROL_RUN_EVENTSCRIPTS
,
4137 0, data
, tmp_ctx
, NULL
, &res
, NULL
, &errmsg
);
4138 if (ret
!= 0 || res
!= 0) {
4139 DEBUG(DEBUG_ERR
,("Failed to run eventscripts - %s\n", errmsg
));
4140 talloc_free(tmp_ctx
);
4143 talloc_free(tmp_ctx
);
4147 #define DB_VERSION 1
4148 #define MAX_DB_NAME 64
4149 struct db_file_header
{
4150 unsigned long version
;
4152 unsigned long persistent
;
4154 const char name
[MAX_DB_NAME
];
4157 struct backup_data
{
4158 struct ctdb_marshall_buffer
*records
;
4161 bool traverse_error
;
4164 static int backup_traverse(struct tdb_context
*tdb
, TDB_DATA key
, TDB_DATA data
, void *private)
4166 struct backup_data
*bd
= talloc_get_type(private, struct backup_data
);
4167 struct ctdb_rec_data
*rec
;
4169 /* add the record */
4170 rec
= ctdb_marshall_record(bd
->records
, 0, key
, NULL
, data
);
4172 bd
->traverse_error
= true;
4173 DEBUG(DEBUG_ERR
,("Failed to marshall record\n"));
4176 bd
->records
= talloc_realloc_size(NULL
, bd
->records
, rec
->length
+ bd
->len
);
4177 if (bd
->records
== NULL
) {
4178 DEBUG(DEBUG_ERR
,("Failed to expand marshalling buffer\n"));
4179 bd
->traverse_error
= true;
4182 bd
->records
->count
++;
4183 memcpy(bd
->len
+(uint8_t *)bd
->records
, rec
, rec
->length
);
4184 bd
->len
+= rec
->length
;
4192 * backup a database to a file
4194 static int control_backupdb(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
4197 struct ctdb_dbid_map
*dbmap
=NULL
;
4198 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
4199 struct db_file_header dbhdr
;
4200 struct ctdb_db_context
*ctdb_db
;
4201 struct backup_data
*bd
;
4204 const char *reason
= NULL
;
4207 DEBUG(DEBUG_ERR
,("Invalid arguments\n"));
4211 ret
= ctdb_ctrl_getdbmap(ctdb
, TIMELIMIT(), options
.pnn
, tmp_ctx
, &dbmap
);
4213 DEBUG(DEBUG_ERR
, ("Unable to get dbids from node %u\n", options
.pnn
));
4217 for(i
=0;i
<dbmap
->num
;i
++){
4220 ctdb_ctrl_getdbname(ctdb
, TIMELIMIT(), options
.pnn
, dbmap
->dbs
[i
].dbid
, tmp_ctx
, &name
);
4221 if(!strcmp(argv
[0], name
)){
4222 talloc_free(discard_const(name
));
4225 talloc_free(discard_const(name
));
4227 if (i
== dbmap
->num
) {
4228 DEBUG(DEBUG_ERR
,("No database with name '%s' found\n", argv
[0]));
4229 talloc_free(tmp_ctx
);
4233 ret
= ctdb_ctrl_getdbhealth(ctdb
, TIMELIMIT(), options
.pnn
,
4234 dbmap
->dbs
[i
].dbid
, tmp_ctx
, &reason
);
4236 DEBUG(DEBUG_ERR
,("Unable to get dbhealth for database '%s'\n",
4238 talloc_free(tmp_ctx
);
4242 uint32_t allow_unhealthy
= 0;
4244 ctdb_ctrl_get_tunable(ctdb
, TIMELIMIT(), options
.pnn
,
4245 "AllowUnhealthyDBRead",
4248 if (allow_unhealthy
!= 1) {
4249 DEBUG(DEBUG_ERR
,("database '%s' is unhealthy: %s\n",
4252 DEBUG(DEBUG_ERR
,("disallow backup : tunable AllowUnhealthyDBRead = %u\n",
4254 talloc_free(tmp_ctx
);
4258 DEBUG(DEBUG_WARNING
,("WARNING database '%s' is unhealthy - see 'ctdb getdbstatus %s'\n",
4260 DEBUG(DEBUG_WARNING
,("WARNING! allow backup of unhealthy database: "
4261 "tunnable AllowUnhealthyDBRead = %u\n",
4265 ctdb_db
= ctdb_attach(ctdb
, TIMELIMIT(), argv
[0], dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_PERSISTENT
, 0);
4266 if (ctdb_db
== NULL
) {
4267 DEBUG(DEBUG_ERR
,("Unable to attach to database '%s'\n", argv
[0]));
4268 talloc_free(tmp_ctx
);
4273 ret
= tdb_transaction_start(ctdb_db
->ltdb
->tdb
);
4275 DEBUG(DEBUG_ERR
,("Failed to start transaction\n"));
4276 talloc_free(tmp_ctx
);
4281 bd
= talloc_zero(tmp_ctx
, struct backup_data
);
4283 DEBUG(DEBUG_ERR
,("Failed to allocate backup_data\n"));
4284 talloc_free(tmp_ctx
);
4288 bd
->records
= talloc_zero(bd
, struct ctdb_marshall_buffer
);
4289 if (bd
->records
== NULL
) {
4290 DEBUG(DEBUG_ERR
,("Failed to allocate ctdb_marshall_buffer\n"));
4291 talloc_free(tmp_ctx
);
4295 bd
->len
= offsetof(struct ctdb_marshall_buffer
, data
);
4296 bd
->records
->db_id
= ctdb_db
->db_id
;
4297 /* traverse the database collecting all records */
4298 if (tdb_traverse_read(ctdb_db
->ltdb
->tdb
, backup_traverse
, bd
) == -1 ||
4299 bd
->traverse_error
) {
4300 DEBUG(DEBUG_ERR
,("Traverse error\n"));
4301 talloc_free(tmp_ctx
);
4305 tdb_transaction_cancel(ctdb_db
->ltdb
->tdb
);
4308 fh
= open(argv
[1], O_RDWR
|O_CREAT
, 0600);
4310 DEBUG(DEBUG_ERR
,("Failed to open file '%s'\n", argv
[1]));
4311 talloc_free(tmp_ctx
);
4315 dbhdr
.version
= DB_VERSION
;
4316 dbhdr
.timestamp
= time(NULL
);
4317 dbhdr
.persistent
= dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_PERSISTENT
;
4318 dbhdr
.size
= bd
->len
;
4319 if (strlen(argv
[0]) >= MAX_DB_NAME
) {
4320 DEBUG(DEBUG_ERR
,("Too long dbname\n"));
4323 strncpy(discard_const(dbhdr
.name
), argv
[0], MAX_DB_NAME
);
4324 ret
= write(fh
, &dbhdr
, sizeof(dbhdr
));
4326 DEBUG(DEBUG_ERR
,("write failed: %s\n", strerror(errno
)));
4329 ret
= write(fh
, bd
->records
, bd
->len
);
4331 DEBUG(DEBUG_ERR
,("write failed: %s\n", strerror(errno
)));
4340 DEBUG(DEBUG_ERR
,("close failed: %s\n", strerror(errno
)));
4344 DEBUG(DEBUG_ERR
,("Database backed up to %s\n", argv
[1]));
4346 talloc_free(tmp_ctx
);
4351 * restore a database from a file
4353 static int control_restoredb(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
4356 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
4359 struct db_file_header dbhdr
;
4360 struct ctdb_db_context
*ctdb_db
;
4361 struct ctdb_node_map
*nodemap
=NULL
;
4362 struct ctdb_vnn_map
*vnnmap
=NULL
;
4364 struct ctdb_control_wipe_database w
;
4366 uint32_t generation
;
4371 if (argc
< 1 || argc
> 2) {
4372 DEBUG(DEBUG_ERR
,("Invalid arguments\n"));
4376 fh
= open(argv
[0], O_RDONLY
);
4378 DEBUG(DEBUG_ERR
,("Failed to open file '%s'\n", argv
[0]));
4379 talloc_free(tmp_ctx
);
4383 read(fh
, &dbhdr
, sizeof(dbhdr
));
4384 if (dbhdr
.version
!= DB_VERSION
) {
4385 DEBUG(DEBUG_ERR
,("Invalid version of database dump. File is version %lu but expected version was %u\n", dbhdr
.version
, DB_VERSION
));
4386 talloc_free(tmp_ctx
);
4390 dbname
= discard_const(dbhdr
.name
);
4392 dbname
= discard_const(argv
[1]);
4395 outdata
.dsize
= dbhdr
.size
;
4396 outdata
.dptr
= talloc_size(tmp_ctx
, outdata
.dsize
);
4397 if (outdata
.dptr
== NULL
) {
4398 DEBUG(DEBUG_ERR
,("Failed to allocate data of size '%lu'\n", dbhdr
.size
));
4400 talloc_free(tmp_ctx
);
4403 read(fh
, outdata
.dptr
, outdata
.dsize
);
4406 tm
= localtime(&dbhdr
.timestamp
);
4407 strftime(tbuf
,sizeof(tbuf
)-1,"%Y/%m/%d %H:%M:%S", tm
);
4408 printf("Restoring database '%s' from backup @ %s\n",
4412 ctdb_db
= ctdb_attach(ctdb
, TIMELIMIT(), dbname
, dbhdr
.persistent
, 0);
4413 if (ctdb_db
== NULL
) {
4414 DEBUG(DEBUG_ERR
,("Unable to attach to database '%s'\n", dbname
));
4415 talloc_free(tmp_ctx
);
4419 ret
= ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), options
.pnn
, ctdb
, &nodemap
);
4421 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from node %u\n", options
.pnn
));
4422 talloc_free(tmp_ctx
);
4427 ret
= ctdb_ctrl_getvnnmap(ctdb
, TIMELIMIT(), options
.pnn
, tmp_ctx
, &vnnmap
);
4429 DEBUG(DEBUG_ERR
, ("Unable to get vnnmap from node %u\n", options
.pnn
));
4430 talloc_free(tmp_ctx
);
4434 /* freeze all nodes */
4435 nodes
= list_of_active_nodes(ctdb
, nodemap
, tmp_ctx
, true);
4436 for (i
=1; i
<=NUM_DB_PRIORITIES
; i
++) {
4437 if (ctdb_client_async_control(ctdb
, CTDB_CONTROL_FREEZE
,
4443 DEBUG(DEBUG_ERR
, ("Unable to freeze nodes.\n"));
4444 ctdb_ctrl_setrecmode(ctdb
, TIMELIMIT(), options
.pnn
, CTDB_RECOVERY_ACTIVE
);
4445 talloc_free(tmp_ctx
);
4450 generation
= vnnmap
->generation
;
4451 data
.dptr
= (void *)&generation
;
4452 data
.dsize
= sizeof(generation
);
4454 /* start a cluster wide transaction */
4455 nodes
= list_of_active_nodes(ctdb
, nodemap
, tmp_ctx
, true);
4456 if (ctdb_client_async_control(ctdb
, CTDB_CONTROL_TRANSACTION_START
,
4458 TIMELIMIT(), false, data
,
4461 DEBUG(DEBUG_ERR
, ("Unable to start cluster wide transactions.\n"));
4466 w
.db_id
= ctdb_db
->db_id
;
4467 w
.transaction_id
= generation
;
4469 data
.dptr
= (void *)&w
;
4470 data
.dsize
= sizeof(w
);
4472 /* wipe all the remote databases. */
4473 nodes
= list_of_active_nodes(ctdb
, nodemap
, tmp_ctx
, true);
4474 if (ctdb_client_async_control(ctdb
, CTDB_CONTROL_WIPE_DATABASE
,
4476 TIMELIMIT(), false, data
,
4479 DEBUG(DEBUG_ERR
, ("Unable to wipe database.\n"));
4480 ctdb_ctrl_setrecmode(ctdb
, TIMELIMIT(), options
.pnn
, CTDB_RECOVERY_ACTIVE
);
4481 talloc_free(tmp_ctx
);
4485 /* push the database */
4486 nodes
= list_of_active_nodes(ctdb
, nodemap
, tmp_ctx
, true);
4487 if (ctdb_client_async_control(ctdb
, CTDB_CONTROL_PUSH_DB
,
4489 TIMELIMIT(), false, outdata
,
4492 DEBUG(DEBUG_ERR
, ("Failed to push database.\n"));
4493 ctdb_ctrl_setrecmode(ctdb
, TIMELIMIT(), options
.pnn
, CTDB_RECOVERY_ACTIVE
);
4494 talloc_free(tmp_ctx
);
4498 data
.dptr
= (void *)&ctdb_db
->db_id
;
4499 data
.dsize
= sizeof(ctdb_db
->db_id
);
4501 /* mark the database as healthy */
4502 nodes
= list_of_active_nodes(ctdb
, nodemap
, tmp_ctx
, true);
4503 if (ctdb_client_async_control(ctdb
, CTDB_CONTROL_DB_SET_HEALTHY
,
4505 TIMELIMIT(), false, data
,
4508 DEBUG(DEBUG_ERR
, ("Failed to mark database as healthy.\n"));
4509 ctdb_ctrl_setrecmode(ctdb
, TIMELIMIT(), options
.pnn
, CTDB_RECOVERY_ACTIVE
);
4510 talloc_free(tmp_ctx
);
4514 data
.dptr
= (void *)&generation
;
4515 data
.dsize
= sizeof(generation
);
4517 /* commit all the changes */
4518 if (ctdb_client_async_control(ctdb
, CTDB_CONTROL_TRANSACTION_COMMIT
,
4520 TIMELIMIT(), false, data
,
4523 DEBUG(DEBUG_ERR
, ("Unable to commit databases.\n"));
4524 ctdb_ctrl_setrecmode(ctdb
, TIMELIMIT(), options
.pnn
, CTDB_RECOVERY_ACTIVE
);
4525 talloc_free(tmp_ctx
);
4530 /* thaw all nodes */
4531 nodes
= list_of_active_nodes(ctdb
, nodemap
, tmp_ctx
, true);
4532 if (ctdb_client_async_control(ctdb
, CTDB_CONTROL_THAW
,
4538 DEBUG(DEBUG_ERR
, ("Unable to thaw nodes.\n"));
4539 ctdb_ctrl_setrecmode(ctdb
, TIMELIMIT(), options
.pnn
, CTDB_RECOVERY_ACTIVE
);
4540 talloc_free(tmp_ctx
);
4545 talloc_free(tmp_ctx
);
4550 * dump a database backup from a file
4552 static int control_dumpdbbackup(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
4554 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
4556 struct db_file_header dbhdr
;
4560 struct ctdb_rec_data
*rec
= NULL
;
4561 struct ctdb_marshall_buffer
*m
;
4562 struct ctdb_dump_db_context c
;
4565 DEBUG(DEBUG_ERR
,("Invalid arguments\n"));
4569 fh
= open(argv
[0], O_RDONLY
);
4571 DEBUG(DEBUG_ERR
,("Failed to open file '%s'\n", argv
[0]));
4572 talloc_free(tmp_ctx
);
4576 read(fh
, &dbhdr
, sizeof(dbhdr
));
4577 if (dbhdr
.version
!= DB_VERSION
) {
4578 DEBUG(DEBUG_ERR
,("Invalid version of database dump. File is version %lu but expected version was %u\n", dbhdr
.version
, DB_VERSION
));
4579 talloc_free(tmp_ctx
);
4583 outdata
.dsize
= dbhdr
.size
;
4584 outdata
.dptr
= talloc_size(tmp_ctx
, outdata
.dsize
);
4585 if (outdata
.dptr
== NULL
) {
4586 DEBUG(DEBUG_ERR
,("Failed to allocate data of size '%lu'\n", dbhdr
.size
));
4588 talloc_free(tmp_ctx
);
4591 read(fh
, outdata
.dptr
, outdata
.dsize
);
4593 m
= (struct ctdb_marshall_buffer
*)outdata
.dptr
;
4595 tm
= localtime(&dbhdr
.timestamp
);
4596 strftime(tbuf
,sizeof(tbuf
)-1,"%Y/%m/%d %H:%M:%S", tm
);
4597 printf("Backup of database name:'%s' dbid:0x%x08x from @ %s\n",
4598 dbhdr
.name
, m
->db_id
, tbuf
);
4602 c
.printemptyrecords
= (bool)options
.printemptyrecords
;
4603 c
.printdatasize
= (bool)options
.printdatasize
;
4605 for (i
=0; i
< m
->count
; i
++) {
4609 /* we do not want the header splitted, so we pass NULL*/
4610 rec
= ctdb_marshall_loop_next(m
, rec
, &reqid
,
4613 ctdb_dumpdb_record(ctdb
, key
, data
, &c
);
4616 printf("Dumped %d records\n", i
);
4617 talloc_free(tmp_ctx
);
4622 * wipe a database from a file
4624 static int control_wipedb(struct ctdb_context
*ctdb
, int argc
,
4628 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
4630 struct ctdb_db_context
*ctdb_db
;
4631 struct ctdb_node_map
*nodemap
= NULL
;
4632 struct ctdb_vnn_map
*vnnmap
= NULL
;
4634 struct ctdb_control_wipe_database w
;
4636 uint32_t generation
;
4637 struct ctdb_dbid_map
*dbmap
= NULL
;
4640 DEBUG(DEBUG_ERR
,("Invalid arguments\n"));
4644 ret
= ctdb_ctrl_getdbmap(ctdb
, TIMELIMIT(), options
.pnn
, tmp_ctx
,
4647 DEBUG(DEBUG_ERR
, ("Unable to get dbids from node %u\n",
4652 for(i
=0;i
<dbmap
->num
;i
++){
4655 ctdb_ctrl_getdbname(ctdb
, TIMELIMIT(), options
.pnn
,
4656 dbmap
->dbs
[i
].dbid
, tmp_ctx
, &name
);
4657 if(!strcmp(argv
[0], name
)){
4658 talloc_free(discard_const(name
));
4661 talloc_free(discard_const(name
));
4663 if (i
== dbmap
->num
) {
4664 DEBUG(DEBUG_ERR
, ("No database with name '%s' found\n",
4666 talloc_free(tmp_ctx
);
4670 ctdb_db
= ctdb_attach(ctdb
, TIMELIMIT(), argv
[0], dbmap
->dbs
[i
].flags
& CTDB_DB_FLAGS_PERSISTENT
, 0);
4671 if (ctdb_db
== NULL
) {
4672 DEBUG(DEBUG_ERR
, ("Unable to attach to database '%s'\n",
4674 talloc_free(tmp_ctx
);
4678 ret
= ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), options
.pnn
, ctdb
,
4681 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from node %u\n",
4683 talloc_free(tmp_ctx
);
4687 ret
= ctdb_ctrl_getvnnmap(ctdb
, TIMELIMIT(), options
.pnn
, tmp_ctx
,
4690 DEBUG(DEBUG_ERR
, ("Unable to get vnnmap from node %u\n",
4692 talloc_free(tmp_ctx
);
4696 /* freeze all nodes */
4697 nodes
= list_of_active_nodes(ctdb
, nodemap
, tmp_ctx
, true);
4698 for (i
=1; i
<=NUM_DB_PRIORITIES
; i
++) {
4699 ret
= ctdb_client_async_control(ctdb
, CTDB_CONTROL_FREEZE
,
4706 DEBUG(DEBUG_ERR
, ("Unable to freeze nodes.\n"));
4707 ctdb_ctrl_setrecmode(ctdb
, TIMELIMIT(), options
.pnn
,
4708 CTDB_RECOVERY_ACTIVE
);
4709 talloc_free(tmp_ctx
);
4714 generation
= vnnmap
->generation
;
4715 data
.dptr
= (void *)&generation
;
4716 data
.dsize
= sizeof(generation
);
4718 /* start a cluster wide transaction */
4719 nodes
= list_of_active_nodes(ctdb
, nodemap
, tmp_ctx
, true);
4720 ret
= ctdb_client_async_control(ctdb
, CTDB_CONTROL_TRANSACTION_START
,
4722 TIMELIMIT(), false, data
,
4726 DEBUG(DEBUG_ERR
, ("Unable to start cluster wide "
4727 "transactions.\n"));
4731 w
.db_id
= ctdb_db
->db_id
;
4732 w
.transaction_id
= generation
;
4734 data
.dptr
= (void *)&w
;
4735 data
.dsize
= sizeof(w
);
4737 /* wipe all the remote databases. */
4738 nodes
= list_of_active_nodes(ctdb
, nodemap
, tmp_ctx
, true);
4739 if (ctdb_client_async_control(ctdb
, CTDB_CONTROL_WIPE_DATABASE
,
4741 TIMELIMIT(), false, data
,
4744 DEBUG(DEBUG_ERR
, ("Unable to wipe database.\n"));
4745 ctdb_ctrl_setrecmode(ctdb
, TIMELIMIT(), options
.pnn
, CTDB_RECOVERY_ACTIVE
);
4746 talloc_free(tmp_ctx
);
4750 data
.dptr
= (void *)&ctdb_db
->db_id
;
4751 data
.dsize
= sizeof(ctdb_db
->db_id
);
4753 /* mark the database as healthy */
4754 nodes
= list_of_active_nodes(ctdb
, nodemap
, tmp_ctx
, true);
4755 if (ctdb_client_async_control(ctdb
, CTDB_CONTROL_DB_SET_HEALTHY
,
4757 TIMELIMIT(), false, data
,
4760 DEBUG(DEBUG_ERR
, ("Failed to mark database as healthy.\n"));
4761 ctdb_ctrl_setrecmode(ctdb
, TIMELIMIT(), options
.pnn
, CTDB_RECOVERY_ACTIVE
);
4762 talloc_free(tmp_ctx
);
4766 data
.dptr
= (void *)&generation
;
4767 data
.dsize
= sizeof(generation
);
4769 /* commit all the changes */
4770 if (ctdb_client_async_control(ctdb
, CTDB_CONTROL_TRANSACTION_COMMIT
,
4772 TIMELIMIT(), false, data
,
4775 DEBUG(DEBUG_ERR
, ("Unable to commit databases.\n"));
4776 ctdb_ctrl_setrecmode(ctdb
, TIMELIMIT(), options
.pnn
, CTDB_RECOVERY_ACTIVE
);
4777 talloc_free(tmp_ctx
);
4781 /* thaw all nodes */
4782 nodes
= list_of_active_nodes(ctdb
, nodemap
, tmp_ctx
, true);
4783 if (ctdb_client_async_control(ctdb
, CTDB_CONTROL_THAW
,
4789 DEBUG(DEBUG_ERR
, ("Unable to thaw nodes.\n"));
4790 ctdb_ctrl_setrecmode(ctdb
, TIMELIMIT(), options
.pnn
, CTDB_RECOVERY_ACTIVE
);
4791 talloc_free(tmp_ctx
);
4795 DEBUG(DEBUG_ERR
, ("Database wiped.\n"));
4797 talloc_free(tmp_ctx
);
4804 static int control_dumpmemory(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
4810 TALLOC_CTX
*tmp_ctx
= talloc_new(ctdb
);
4811 ret
= ctdb_control(ctdb
, options
.pnn
, 0, CTDB_CONTROL_DUMP_MEMORY
,
4812 0, tdb_null
, tmp_ctx
, &data
, &res
, NULL
, &errmsg
);
4813 if (ret
!= 0 || res
!= 0) {
4814 DEBUG(DEBUG_ERR
,("Failed to dump memory - %s\n", errmsg
));
4815 talloc_free(tmp_ctx
);
4818 write(1, data
.dptr
, data
.dsize
);
4819 talloc_free(tmp_ctx
);
4824 handler for memory dumps
4826 static void mem_dump_handler(struct ctdb_context
*ctdb
, uint64_t srvid
,
4827 TDB_DATA data
, void *private_data
)
4829 write(1, data
.dptr
, data
.dsize
);
4834 dump memory usage on the recovery daemon
4836 static int control_rddumpmemory(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
4840 struct rd_memdump_reply rd
;
4842 rd
.pnn
= ctdb_ctrl_getpnn(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
);
4844 DEBUG(DEBUG_ERR
, ("Failed to get pnn of local node\n"));
4847 rd
.srvid
= getpid();
4849 /* register a message port for receiveing the reply so that we
4850 can receive the reply
4852 ctdb_client_set_message_handler(ctdb
, rd
.srvid
, mem_dump_handler
, NULL
);
4855 data
.dptr
= (uint8_t *)&rd
;
4856 data
.dsize
= sizeof(rd
);
4858 ret
= ctdb_client_send_message(ctdb
, options
.pnn
, CTDB_SRVID_MEM_DUMP
, data
);
4860 DEBUG(DEBUG_ERR
,("Failed to send memdump request message to %u\n", options
.pnn
));
4864 /* this loop will terminate when we have received the reply */
4866 event_loop_once(ctdb
->ev
);
4873 send a message to a srvid
4875 static int control_msgsend(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
4877 unsigned long srvid
;
4885 srvid
= strtoul(argv
[0], NULL
, 0);
4887 data
.dptr
= (uint8_t *)discard_const(argv
[1]);
4888 data
.dsize
= strlen(argv
[1]);
4890 ret
= ctdb_client_send_message(ctdb
, CTDB_BROADCAST_CONNECTED
, srvid
, data
);
4892 DEBUG(DEBUG_ERR
,("Failed to send memdump request message to %u\n", options
.pnn
));
4900 handler for msglisten
4902 static void msglisten_handler(struct ctdb_context
*ctdb
, uint64_t srvid
,
4903 TDB_DATA data
, void *private_data
)
4907 printf("Message received: ");
4908 for (i
=0;i
<data
.dsize
;i
++) {
4909 printf("%c", data
.dptr
[i
]);
4915 listen for messages on a messageport
4917 static int control_msglisten(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
4923 /* register a message port and listen for messages
4925 ctdb_client_set_message_handler(ctdb
, srvid
, msglisten_handler
, NULL
);
4926 printf("Listening for messages on srvid:%d\n", (int)srvid
);
4929 event_loop_once(ctdb
->ev
);
4936 list all nodes in the cluster
4937 we parse the nodes file directly
4939 static int control_listnodes(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
4941 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
4942 struct pnn_node
*pnn_nodes
;
4943 struct pnn_node
*pnn_node
;
4945 pnn_nodes
= read_nodes_file(mem_ctx
);
4946 if (pnn_nodes
== NULL
) {
4947 DEBUG(DEBUG_ERR
,("Failed to read nodes file\n"));
4948 talloc_free(mem_ctx
);
4952 for(pnn_node
=pnn_nodes
;pnn_node
;pnn_node
=pnn_node
->next
) {
4953 ctdb_sock_addr addr
;
4954 if (parse_ip(pnn_node
->addr
, NULL
, 63999, &addr
) == 0) {
4955 DEBUG(DEBUG_ERR
,("Wrongly formed ip address '%s' in nodes file\n", pnn_node
->addr
));
4956 talloc_free(mem_ctx
);
4959 if (options
.machinereadable
){
4960 printf(":%d:%s:\n", pnn_node
->pnn
, pnn_node
->addr
);
4962 printf("%s\n", pnn_node
->addr
);
4965 talloc_free(mem_ctx
);
4971 reload the nodes file on the local node
4973 static int control_reload_nodes_file(struct ctdb_context
*ctdb
, int argc
, const char **argv
)
4977 struct ctdb_node_map
*nodemap
=NULL
;
4979 mypnn
= ctdb_ctrl_getpnn(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
);
4981 DEBUG(DEBUG_ERR
, ("Failed to read pnn of local node\n"));
4985 ret
= ctdb_ctrl_getnodemap(ctdb
, TIMELIMIT(), CTDB_CURRENT_NODE
, ctdb
, &nodemap
);
4987 DEBUG(DEBUG_ERR
, ("Unable to get nodemap from local node\n"));
4991 /* reload the nodes file on all remote nodes */
4992 for (i
=0;i
<nodemap
->num
;i
++) {
4993 if (nodemap
->nodes
[i
].pnn
== mypnn
) {
4996 DEBUG(DEBUG_NOTICE
, ("Reloading nodes file on node %u\n", nodemap
->nodes
[i
].pnn
));
4997 ret
= ctdb_ctrl_reload_nodes_file(ctdb
, TIMELIMIT(),
4998 nodemap
->nodes
[i
].pnn
);
5000 DEBUG(DEBUG_ERR
, ("ERROR: Failed to reload nodes file on node %u. You MUST fix that node manually!\n", nodemap
->nodes
[i
].pnn
));
5004 /* reload the nodes file on the local node */
5005 DEBUG(DEBUG_NOTICE
, ("Reloading nodes file on node %u\n", mypnn
));
5006 ret
= ctdb_ctrl_reload_nodes_file(ctdb
, TIMELIMIT(), mypnn
);
5008 DEBUG(DEBUG_ERR
, ("ERROR: Failed to reload nodes file on node %u. You MUST fix that node manually!\n", mypnn
));
5011 /* initiate a recovery */
5012 control_recover(ctdb
, argc
, argv
);
5018 static const struct {
5020 int (*fn
)(struct ctdb_context
*, int, const char **);
5022 bool without_daemon
; /* can be run without daemon running ? */
5025 } ctdb_commands
[] = {
5027 { "version", control_version
, true, false, "show version of ctdb" },
5029 { "status", control_status
, true, false, "show node status" },
5030 { "uptime", control_uptime
, true, false, "show node uptime" },
5031 { "ping", control_ping
, true, false, "ping all nodes" },
5032 { "getvar", control_getvar
, true, false, "get a tunable variable", "<name>"},
5033 { "setvar", control_setvar
, true, false, "set a tunable variable", "<name> <value>"},
5034 { "listvars", control_listvars
, true, false, "list tunable variables"},
5035 { "statistics", control_statistics
, false, false, "show statistics" },
5036 { "statisticsreset", control_statistics_reset
, true, false, "reset statistics"},
5037 { "stats", control_stats
, false, false, "show rolling statistics", "[number of history records]" },
5038 { "ip", control_ip
, false, false, "show which public ip's that ctdb manages" },
5039 { "ipinfo", control_ipinfo
, true, false, "show details about a public ip that ctdb manages", "<ip>" },
5040 { "ifaces", control_ifaces
, true, false, "show which interfaces that ctdb manages" },
5041 { "setifacelink", control_setifacelink
, true, false, "set interface link status", "<iface> <status>" },
5042 { "process-exists", control_process_exists
, true, false, "check if a process exists on a node", "<pid>"},
5043 { "getdbmap", control_getdbmap
, true, false, "show the database map" },
5044 { "getdbstatus", control_getdbstatus
, true, false, "show the status of a database", "<dbname>" },
5045 { "catdb", control_catdb
, true, false, "dump a ctdb database" , "<dbname>"},
5046 { "cattdb", control_cattdb
, true, false, "dump a local tdb database" , "<dbname>"},
5047 { "getmonmode", control_getmonmode
, true, false, "show monitoring mode" },
5048 { "getcapabilities", control_getcapabilities
, true, false, "show node capabilities" },
5049 { "pnn", control_pnn
, true, false, "show the pnn of the currnet node" },
5050 { "lvs", control_lvs
, true, false, "show lvs configuration" },
5051 { "lvsmaster", control_lvsmaster
, true, false, "show which node is the lvs master" },
5052 { "disablemonitor", control_disable_monmode
,true, false, "set monitoring mode to DISABLE" },
5053 { "enablemonitor", control_enable_monmode
, true, false, "set monitoring mode to ACTIVE" },
5054 { "setdebug", control_setdebug
, true, false, "set debug level", "<EMERG|ALERT|CRIT|ERR|WARNING|NOTICE|INFO|DEBUG>" },
5055 { "getdebug", control_getdebug
, true, false, "get debug level" },
5056 { "getlog", control_getlog
, true, false, "get the log data from the in memory ringbuffer", "<level>" },
5057 { "clearlog", control_clearlog
, true, false, "clear the log data from the in memory ringbuffer" },
5058 { "attach", control_attach
, true, false, "attach to a database", "<dbname> [persistent]" },
5059 { "dumpmemory", control_dumpmemory
, true, false, "dump memory map to stdout" },
5060 { "rddumpmemory", control_rddumpmemory
, true, false, "dump memory map from the recovery daemon to stdout" },
5061 { "getpid", control_getpid
, true, false, "get ctdbd process ID" },
5062 { "disable", control_disable
, true, false, "disable a nodes public IP" },
5063 { "enable", control_enable
, true, false, "enable a nodes public IP" },
5064 { "stop", control_stop
, true, false, "stop a node" },
5065 { "continue", control_continue
, true, false, "re-start a stopped node" },
5066 { "ban", control_ban
, true, false, "ban a node from the cluster", "<bantime|0>"},
5067 { "unban", control_unban
, true, false, "unban a node" },
5068 { "showban", control_showban
, true, false, "show ban information"},
5069 { "shutdown", control_shutdown
, true, false, "shutdown ctdbd" },
5070 { "recover", control_recover
, true, false, "force recovery" },
5071 { "sync", control_ipreallocate
, true, false, "wait until ctdbd has synced all state changes" },
5072 { "ipreallocate", control_ipreallocate
, true, false, "force the recovery daemon to perform a ip reallocation procedure" },
5073 { "thaw", control_thaw
, true, false, "thaw databases", "[priority:1-3]" },
5074 { "isnotrecmaster", control_isnotrecmaster
, false, false, "check if the local node is recmaster or not" },
5075 { "killtcp", kill_tcp
, false, false, "kill a tcp connection.", "<srcip:port> <dstip:port>" },
5076 { "gratiousarp", control_gratious_arp
, false, false, "send a gratious arp", "<ip> <interface>" },
5077 { "tickle", tickle_tcp
, false, false, "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
5078 { "gettickles", control_get_tickles
, false, false, "get the list of tickles registered for this ip", "<ip> [<port>]" },
5079 { "addtickle", control_add_tickle
, false, false, "add a tickle for this ip", "<ip>:<port> <ip>:<port>" },
5081 { "deltickle", control_del_tickle
, false, false, "delete a tickle from this ip", "<ip>:<port> <ip>:<port>" },
5083 { "regsrvid", regsrvid
, false, false, "register a server id", "<pnn> <type> <id>" },
5084 { "unregsrvid", unregsrvid
, false, false, "unregister a server id", "<pnn> <type> <id>" },
5085 { "chksrvid", chksrvid
, false, false, "check if a server id exists", "<pnn> <type> <id>" },
5086 { "getsrvids", getsrvids
, false, false, "get a list of all server ids"},
5087 { "vacuum", ctdb_vacuum
, false, false, "vacuum the databases of empty records", "[max_records]"},
5088 { "repack", ctdb_repack
, false, false, "repack all databases", "[max_freelist]"},
5089 { "listnodes", control_listnodes
, false, true, "list all nodes in the cluster"},
5090 { "reloadnodes", control_reload_nodes_file
, false, false, "reload the nodes file and restart the transport on all nodes"},
5091 { "moveip", control_moveip
, false, false, "move/failover an ip address to another node", "<ip> <node>"},
5092 { "addip", control_addip
, true, false, "add a ip address to a node", "<ip/mask> <iface>"},
5093 { "delip", control_delip
, false, false, "delete an ip address from a node", "<ip>"},
5094 { "eventscript", control_eventscript
, true, false, "run the eventscript with the given parameters on a node", "<arguments>"},
5095 { "backupdb", control_backupdb
, false, false, "backup the database into a file.", "<database> <file>"},
5096 { "restoredb", control_restoredb
, false, false, "restore the database from a file.", "<file> [dbname]"},
5097 { "dumpdbbackup", control_dumpdbbackup
, false, true, "dump database backup from a file.", "<file>"},
5098 { "wipedb", control_wipedb
, false, false, "wipe the contents of a database.", "<dbname>"},
5099 { "recmaster", control_recmaster
, false, false, "show the pnn for the recovery master."},
5100 { "scriptstatus", control_scriptstatus
, true, false, "show the status of the monitoring scripts (or all scripts)", "[all]"},
5101 { "enablescript", control_enablescript
, false, false, "enable an eventscript", "<script>"},
5102 { "disablescript", control_disablescript
, false, false, "disable an eventscript", "<script>"},
5103 { "natgwlist", control_natgwlist
, false, false, "show the nodes belonging to this natgw configuration"},
5104 { "xpnn", control_xpnn
, true, true, "find the pnn of the local node without talking to the daemon (unreliable)" },
5105 { "getreclock", control_getreclock
, false, false, "Show the reclock file of a node"},
5106 { "setreclock", control_setreclock
, false, false, "Set/clear the reclock file of a node", "[filename]"},
5107 { "setnatgwstate", control_setnatgwstate
, false, false, "Set NATGW state to on/off", "{on|off}"},
5108 { "setlmasterrole", control_setlmasterrole
, false, false, "Set LMASTER role to on/off", "{on|off}"},
5109 { "setrecmasterrole", control_setrecmasterrole
, false, false, "Set RECMASTER role to on/off", "{on|off}"},
5110 { "setdbprio", control_setdbprio
, false, false, "Set DB priority", "<dbid> <prio:1-3>"},
5111 { "getdbprio", control_getdbprio
, false, false, "Get DB priority", "<dbid>"},
5112 { "setdbreadonly", control_setdbreadonly
, false, false, "Set DB readonly capable", "<dbid>"},
5113 { "msglisten", control_msglisten
, false, false, "Listen on a srvid port for messages", "<msg srvid>"},
5114 { "msgsend", control_msgsend
, false, false, "Send a message to srvid", "<srvid> <message>"},
5115 { "sync", control_ipreallocate
, false, false, "wait until ctdbd has synced all state changes" },
5116 { "pfetch", control_pfetch
, false, false, "fetch a record from a persistent database", "<db> <key> [<file>]" },
5117 { "pstore", control_pstore
, false, false, "write a record to a persistent database", "<db> <key> <file containing record>" },
5118 { "tfetch", control_tfetch
, false, true, "fetch a record from a [c]tdb-file", "<tdb-file> <key> [<file>]" },
5119 { "readkey", control_readkey
, true, false, "read the content off a database key", "<tdb-file> <key>" },
5120 { "writekey", control_writekey
, true, false, "write to a database key", "<tdb-file> <key> <value>" },
5121 { "checktcpport", control_chktcpport
, false, true, "check if a service is bound to a specific tcp port or not", "<port>" },
5127 static void usage(void)
5131 "Usage: ctdb [options] <control>\n" \
5133 " -n <node> choose node number, or 'all' (defaults to local node)\n"
5134 " -Y generate machinereadable output\n"
5135 " -v generate verbose output\n"
5136 " -t <timelimit> set timelimit for control in seconds (default %u)\n", options
.timelimit
);
5137 printf("Controls:\n");
5138 for (i
=0;i
<ARRAY_SIZE(ctdb_commands
);i
++) {
5139 printf(" %-15s %-27s %s\n",
5140 ctdb_commands
[i
].name
,
5141 ctdb_commands
[i
].args
?ctdb_commands
[i
].args
:"",
5142 ctdb_commands
[i
].msg
);
5148 static void ctdb_alarm(int sig
)
5150 printf("Maximum runtime exceeded - exiting\n");
5157 int main(int argc
, const char *argv
[])
5159 struct ctdb_context
*ctdb
;
5160 char *nodestring
= NULL
;
5161 struct poptOption popt_options
[] = {
5164 { "timelimit", 't', POPT_ARG_INT
, &options
.timelimit
, 0, "timelimit", "integer" },
5165 { "node", 'n', POPT_ARG_STRING
, &nodestring
, 0, "node", "integer|all" },
5166 { "machinereadable", 'Y', POPT_ARG_NONE
, &options
.machinereadable
, 0, "enable machinereadable output", NULL
},
5167 { "verbose", 'v', POPT_ARG_NONE
, &options
.verbose
, 0, "enable verbose output", NULL
},
5168 { "maxruntime", 'T', POPT_ARG_INT
, &options
.maxruntime
, 0, "die if runtime exceeds this limit (in seconds)", "integer" },
5169 { "print-emptyrecords", 0, POPT_ARG_NONE
, &options
.printemptyrecords
, 0, "print the empty records when dumping databases (catdb, cattdb, dumpdbbackup)", NULL
},
5170 { "print-datasize", 0, POPT_ARG_NONE
, &options
.printdatasize
, 0, "do not print record data when dumping databases, only the data size", NULL
},
5174 const char **extra_argv
;
5178 struct event_context
*ev
;
5179 const char *control
;
5183 /* set some defaults */
5184 options
.maxruntime
= 0;
5185 options
.timelimit
= 3;
5186 options
.pnn
= CTDB_CURRENT_NODE
;
5188 pc
= poptGetContext(argv
[0], argc
, argv
, popt_options
, POPT_CONTEXT_KEEP_FIRST
);
5190 while ((opt
= poptGetNextOpt(pc
)) != -1) {
5193 DEBUG(DEBUG_ERR
, ("Invalid option %s: %s\n",
5194 poptBadOption(pc
, 0), poptStrerror(opt
)));
5199 /* setup the remaining options for the main program to use */
5200 extra_argv
= poptGetArgs(pc
);
5203 while (extra_argv
[extra_argc
]) extra_argc
++;
5206 if (extra_argc
< 1) {
5210 if (options
.maxruntime
== 0) {
5211 const char *ctdb_timeout
;
5212 ctdb_timeout
= getenv("CTDB_TIMEOUT");
5213 if (ctdb_timeout
!= NULL
) {
5214 options
.maxruntime
= strtoul(ctdb_timeout
, NULL
, 0);
5216 /* default timeout is 120 seconds */
5217 options
.maxruntime
= 120;
5221 signal(SIGALRM
, ctdb_alarm
);
5222 alarm(options
.maxruntime
);
5224 /* setup the node number to contact */
5225 if (nodestring
!= NULL
) {
5226 if (strcmp(nodestring
, "all") == 0) {
5227 options
.pnn
= CTDB_BROADCAST_ALL
;
5229 options
.pnn
= strtoul(nodestring
, NULL
, 0);
5233 control
= extra_argv
[0];
5235 ev
= event_context_init(NULL
);
5237 DEBUG(DEBUG_ERR
, ("Failed to initialize event system\n"));
5240 tevent_loop_allow_nesting(ev
);
5242 for (i
=0;i
<ARRAY_SIZE(ctdb_commands
);i
++) {
5243 if (strcmp(control
, ctdb_commands
[i
].name
) == 0) {
5246 if (ctdb_commands
[i
].without_daemon
== true) {
5250 /* initialise ctdb */
5251 ctdb
= ctdb_cmdline_client(ev
, TIMELIMIT());
5253 if (ctdb_commands
[i
].without_daemon
== false) {
5254 const char *socket_name
;
5257 DEBUG(DEBUG_ERR
, ("Failed to init ctdb\n"));
5261 /* initialize a libctdb connection as well */
5262 socket_name
= ctdb_get_socketname(ctdb
);
5263 ctdb_connection
= ctdb_connect(socket_name
,
5264 ctdb_log_file
, stderr
);
5265 if (ctdb_connection
== NULL
) {
5266 fprintf(stderr
, "Failed to connect to daemon from libctdb\n");
5270 /* verify the node exists */
5273 if (options
.pnn
== CTDB_CURRENT_NODE
) {
5275 pnn
= ctdb_ctrl_getpnn(ctdb
, TIMELIMIT(), options
.pnn
);
5283 if (ctdb_commands
[i
].auto_all
&&
5284 options
.pnn
== CTDB_BROADCAST_ALL
) {
5289 nodes
= ctdb_get_connected_nodes(ctdb
, TIMELIMIT(), ctdb
, &num_nodes
);
5290 CTDB_NO_MEMORY(ctdb
, nodes
);
5292 for (j
=0;j
<num_nodes
;j
++) {
5293 options
.pnn
= nodes
[j
];
5294 ret
|= ctdb_commands
[i
].fn(ctdb
, extra_argc
-1, extra_argv
+1);
5298 ret
= ctdb_commands
[i
].fn(ctdb
, extra_argc
-1, extra_argv
+1);
5304 if (i
== ARRAY_SIZE(ctdb_commands
)) {
5305 DEBUG(DEBUG_ERR
, ("Unknown control '%s'\n", control
));