2007-04-26 16:27:49 +04:00
/*
ctdb control tool
Copyright ( C ) Andrew Tridgell 2007
2007-05-31 07:50:53 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
2007-04-26 16:27:49 +04:00
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2007-05-31 07:50:53 +04:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
2007-04-26 16:27:49 +04:00
*/
# include "includes.h"
# include "lib/events/events.h"
# include "system/filesys.h"
2007-06-07 16:26:27 +04:00
# include "system/network.h"
2007-04-26 16:27:49 +04:00
# include "popt.h"
# include "cmdline.h"
2007-05-02 06:43:35 +04:00
# include "../include/ctdb.h"
2007-04-26 16:27:49 +04:00
# include "../include/ctdb_private.h"
2007-05-29 06:16:59 +04:00
static void usage ( void ) ;
2007-04-26 16:27:49 +04:00
2007-05-29 06:16:59 +04:00
static struct {
int timelimit ;
uint32_t vnn ;
2007-06-03 13:50:51 +04:00
int machinereadable ;
2007-05-29 06:16:59 +04:00
} options ;
# define TIMELIMIT() timeval_current_ofs(options.timelimit, 0)
2007-04-26 16:27:49 +04:00
2007-04-27 17:14:36 +04:00
/*
see if a process exists
*/
2007-04-26 16:27:49 +04:00
static int control_process_exists ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2007-04-26 16:51:41 +04:00
uint32_t vnn , pid ;
2007-04-26 16:27:49 +04:00
int ret ;
2007-04-26 16:51:41 +04:00
if ( argc < 1 ) {
2007-04-26 16:27:49 +04:00
usage ( ) ;
}
2007-04-26 16:51:41 +04:00
if ( sscanf ( argv [ 0 ] , " %u:%u " , & vnn , & pid ) ! = 2 ) {
printf ( " Badly formed vnn:pid \n " ) ;
return - 1 ;
}
2007-04-26 16:27:49 +04:00
2007-04-29 18:58:27 +04:00
ret = ctdb_ctrl_process_exists ( ctdb , vnn , pid ) ;
2007-04-26 16:27:49 +04:00
if ( ret = = 0 ) {
2007-04-26 16:51:41 +04:00
printf ( " %u:%u exists \n " , vnn , pid ) ;
2007-04-26 16:27:49 +04:00
} else {
2007-04-26 16:51:41 +04:00
printf ( " %u:%u does not exist \n " , vnn , pid ) ;
2007-04-26 16:27:49 +04:00
}
return ret ;
}
2007-04-26 16:51:41 +04:00
/*
2007-05-29 06:16:59 +04:00
display statistics structure
2007-04-26 16:51:41 +04:00
*/
2007-05-29 06:16:59 +04:00
static void show_statistics ( struct ctdb_statistics * s )
2007-04-26 16:51:41 +04:00
{
2007-05-05 02:11:54 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( NULL ) ;
int i ;
const char * prefix = NULL ;
2007-05-12 15:25:26 +04:00
int preflen = 0 ;
2007-05-05 02:11:54 +04:00
const struct {
const char * name ;
uint32_t offset ;
} fields [ ] = {
2007-05-29 06:16:59 +04:00
# define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) }
STATISTICS_FIELD ( num_clients ) ,
STATISTICS_FIELD ( frozen ) ,
STATISTICS_FIELD ( recovering ) ,
STATISTICS_FIELD ( client_packets_sent ) ,
STATISTICS_FIELD ( client_packets_recv ) ,
STATISTICS_FIELD ( node_packets_sent ) ,
STATISTICS_FIELD ( node_packets_recv ) ,
STATISTICS_FIELD ( keepalive_packets_sent ) ,
STATISTICS_FIELD ( keepalive_packets_recv ) ,
STATISTICS_FIELD ( node . req_call ) ,
STATISTICS_FIELD ( node . reply_call ) ,
STATISTICS_FIELD ( node . req_dmaster ) ,
STATISTICS_FIELD ( node . reply_dmaster ) ,
STATISTICS_FIELD ( node . reply_error ) ,
STATISTICS_FIELD ( node . req_message ) ,
STATISTICS_FIELD ( node . req_control ) ,
STATISTICS_FIELD ( node . reply_control ) ,
STATISTICS_FIELD ( client . req_call ) ,
STATISTICS_FIELD ( client . req_message ) ,
STATISTICS_FIELD ( client . req_control ) ,
STATISTICS_FIELD ( timeouts . call ) ,
STATISTICS_FIELD ( timeouts . control ) ,
STATISTICS_FIELD ( timeouts . traverse ) ,
STATISTICS_FIELD ( total_calls ) ,
STATISTICS_FIELD ( pending_calls ) ,
STATISTICS_FIELD ( lockwait_calls ) ,
STATISTICS_FIELD ( pending_lockwait_calls ) ,
STATISTICS_FIELD ( memory_used ) ,
STATISTICS_FIELD ( max_hop_count ) ,
2007-05-05 02:11:54 +04:00
} ;
2007-04-26 16:51:41 +04:00
printf ( " CTDB version %u \n " , CTDB_VERSION ) ;
2007-05-05 02:11:54 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( fields ) ; i + + ) {
if ( strchr ( fields [ i ] . name , ' . ' ) ) {
preflen = strcspn ( fields [ i ] . name , " . " ) + 1 ;
if ( ! prefix | | strncmp ( prefix , fields [ i ] . name , preflen ) ! = 0 ) {
prefix = fields [ i ] . name ;
printf ( " %*.*s \n " , preflen - 1 , preflen - 1 , fields [ i ] . name ) ;
}
} else {
preflen = 0 ;
}
printf ( " %*s%-22s%*s%10u \n " ,
preflen ? 4 : 0 , " " ,
fields [ i ] . name + preflen ,
preflen ? 0 : 4 , " " ,
* ( uint32_t * ) ( fields [ i ] . offset + ( uint8_t * ) s ) ) ;
}
printf ( " %-30s %.6f sec \n " , " max_call_latency " , s - > max_call_latency ) ;
printf ( " %-30s %.6f sec \n " , " max_lockwait_latency " , s - > max_lockwait_latency ) ;
talloc_free ( tmp_ctx ) ;
2007-04-26 16:51:41 +04:00
}
2007-04-28 19:13:30 +04:00
/*
2007-05-29 06:16:59 +04:00
display remote ctdb statistics combined from all nodes
2007-04-28 19:13:30 +04:00
*/
2007-05-29 06:16:59 +04:00
static int control_statistics_all ( struct ctdb_context * ctdb )
2007-04-28 19:13:30 +04:00
{
int ret , i ;
2007-05-29 06:16:59 +04:00
struct ctdb_statistics statistics ;
2007-04-28 19:42:40 +04:00
uint32_t * nodes ;
uint32_t num_nodes ;
2007-05-29 06:16:59 +04:00
nodes = ctdb_get_connected_nodes ( ctdb , TIMELIMIT ( ) , ctdb , & num_nodes ) ;
2007-04-28 19:42:40 +04:00
CTDB_NO_MEMORY ( ctdb , nodes ) ;
2007-05-29 06:16:59 +04:00
ZERO_STRUCT ( statistics ) ;
2007-04-28 19:13:30 +04:00
2007-04-28 19:42:40 +04:00
for ( i = 0 ; i < num_nodes ; i + + ) {
2007-05-29 06:16:59 +04:00
struct ctdb_statistics s1 ;
2007-04-28 19:13:30 +04:00
int j ;
uint32_t * v1 = ( uint32_t * ) & s1 ;
2007-05-29 06:16:59 +04:00
uint32_t * v2 = ( uint32_t * ) & statistics ;
2007-04-28 19:13:30 +04:00
uint32_t num_ints =
2007-05-29 06:16:59 +04:00
offsetof ( struct ctdb_statistics , __last_counter ) / sizeof ( uint32_t ) ;
ret = ctdb_ctrl_statistics ( ctdb , nodes [ i ] , & s1 ) ;
2007-04-28 19:13:30 +04:00
if ( ret ! = 0 ) {
2007-05-29 06:16:59 +04:00
printf ( " Unable to get statistics from node %u \n " , nodes [ i ] ) ;
2007-04-28 19:13:30 +04:00
return ret ;
}
for ( j = 0 ; j < num_ints ; j + + ) {
v2 [ j ] + = v1 [ j ] ;
}
2007-05-29 06:16:59 +04:00
statistics . max_hop_count =
MAX ( statistics . max_hop_count , s1 . max_hop_count ) ;
statistics . max_call_latency =
MAX ( statistics . max_call_latency , s1 . max_call_latency ) ;
statistics . max_lockwait_latency =
MAX ( statistics . max_lockwait_latency , s1 . max_lockwait_latency ) ;
2007-04-28 19:13:30 +04:00
}
2007-04-28 19:42:40 +04:00
talloc_free ( nodes ) ;
2007-05-29 06:16:59 +04:00
printf ( " Gathered statistics for %u nodes \n " , num_nodes ) ;
show_statistics ( & statistics ) ;
2007-04-28 19:13:30 +04:00
return 0 ;
}
2007-04-27 17:14:36 +04:00
/*
2007-05-29 06:16:59 +04:00
display remote ctdb statistics
2007-04-27 17:14:36 +04:00
*/
2007-05-29 06:16:59 +04:00
static int control_statistics ( struct ctdb_context * ctdb , int argc , const char * * argv )
2007-04-26 16:51:41 +04:00
{
int ret ;
2007-05-29 06:16:59 +04:00
struct ctdb_statistics statistics ;
2007-04-26 16:51:41 +04:00
2007-05-29 06:16:59 +04:00
if ( options . vnn = = CTDB_BROADCAST_ALL ) {
return control_statistics_all ( ctdb ) ;
2007-04-28 19:13:30 +04:00
}
2007-05-29 06:16:59 +04:00
ret = ctdb_ctrl_statistics ( ctdb , options . vnn , & statistics ) ;
2007-04-26 16:51:41 +04:00
if ( ret ! = 0 ) {
2007-05-29 06:16:59 +04:00
printf ( " Unable to get statistics from node %u \n " , options . vnn ) ;
2007-04-26 16:51:41 +04:00
return ret ;
}
2007-05-29 06:16:59 +04:00
show_statistics ( & statistics ) ;
2007-04-26 16:51:41 +04:00
return 0 ;
}
2007-04-28 21:13:36 +04:00
/*
2007-05-29 06:16:59 +04:00
reset remote ctdb statistics
2007-04-28 21:13:36 +04:00
*/
2007-05-29 06:16:59 +04:00
static int control_statistics_reset ( struct ctdb_context * ctdb , int argc , const char * * argv )
2007-04-28 21:13:36 +04:00
{
int ret ;
2007-05-29 06:16:59 +04:00
ret = ctdb_statistics_reset ( ctdb , options . vnn ) ;
2007-04-28 21:13:36 +04:00
if ( ret ! = 0 ) {
2007-05-29 06:16:59 +04:00
printf ( " Unable to reset statistics on node %u \n " , options . vnn ) ;
2007-04-28 21:13:36 +04:00
return ret ;
}
return 0 ;
}
2007-05-02 04:20:34 +04:00
2007-04-27 17:14:36 +04:00
/*
2007-05-29 06:16:59 +04:00
display remote ctdb status
2007-04-27 17:14:36 +04:00
*/
2007-05-29 06:16:59 +04:00
static int control_status ( struct ctdb_context * ctdb , int argc , const char * * argv )
2007-04-27 14:56:10 +04:00
{
int i , ret ;
2007-05-03 05:06:24 +04:00
struct ctdb_vnn_map * vnnmap = NULL ;
2007-05-29 06:16:59 +04:00
struct ctdb_node_map * nodemap = NULL ;
uint32_t recmode , recmaster ;
uint32_t myvnn ;
2007-05-30 05:12:50 +04:00
myvnn = ctdb_ctrl_getvnn ( ctdb , TIMELIMIT ( ) , options . vnn ) ;
2007-05-29 06:16:59 +04:00
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , options . vnn , ctdb , & nodemap ) ;
if ( ret ! = 0 ) {
printf ( " Unable to get nodemap from node %u \n " , options . vnn ) ;
return ret ;
2007-04-27 14:56:10 +04:00
}
2007-06-03 13:50:51 +04:00
if ( options . machinereadable ) {
2007-06-07 09:18:55 +04:00
printf ( " :Node:IP:Disonnected:Disabled:Permanently Disabled: \n " ) ;
2007-06-03 13:50:51 +04:00
for ( i = 0 ; i < nodemap - > num ; i + + ) {
2007-06-07 03:27:51 +04:00
printf ( " :%d:%s:%d:%d:%d: \n " , nodemap - > nodes [ i ] . vnn ,
2007-06-04 07:26:07 +04:00
inet_ntoa ( nodemap - > nodes [ i ] . sin . sin_addr ) ,
2007-06-07 09:18:55 +04:00
! ! ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_DISCONNECTED ) ,
! ! ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_UNHEALTHY ) ,
! ! ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_PERMANENTLY_DISABLED ) ) ;
2007-06-03 13:50:51 +04:00
}
return 0 ;
}
2007-05-29 06:16:59 +04:00
printf ( " Number of nodes:%d \n " , nodemap - > num ) ;
for ( i = 0 ; i < nodemap - > num ; i + + ) {
2007-06-07 10:34:33 +04:00
static const struct {
uint32_t flag ;
const char * name ;
} flag_names [ ] = {
{ NODE_FLAGS_DISCONNECTED , " DISCONNECTED " } ,
{ NODE_FLAGS_PERMANENTLY_DISABLED , " DISABLED " } ,
{ NODE_FLAGS_BANNED , " BANNED " } ,
{ NODE_FLAGS_UNHEALTHY , " UNHEALTHY " } ,
} ;
char * flags_str = NULL ;
int j ;
for ( j = 0 ; j < ARRAY_SIZE ( flag_names ) ; j + + ) {
if ( nodemap - > nodes [ i ] . flags & flag_names [ j ] . flag ) {
if ( flags_str = = NULL ) {
flags_str = talloc_strdup ( ctdb , flag_names [ j ] . name ) ;
} else {
flags_str = talloc_asprintf_append ( flags_str , " |%s " ,
flag_names [ j ] . name ) ;
}
CTDB_NO_MEMORY_FATAL ( ctdb , flags_str ) ;
}
}
if ( flags_str = = NULL ) {
flags_str = talloc_strdup ( ctdb , " OK " ) ;
CTDB_NO_MEMORY_FATAL ( ctdb , flags_str ) ;
2007-06-06 04:25:46 +04:00
}
2007-06-04 09:09:03 +04:00
printf ( " vnn:%d %-16s %s%s \n " , nodemap - > nodes [ i ] . vnn ,
2007-06-06 04:25:46 +04:00
inet_ntoa ( nodemap - > nodes [ i ] . sin . sin_addr ) ,
flags_str ,
nodemap - > nodes [ i ] . vnn = = myvnn ? " (THIS NODE) " : " " ) ;
2007-06-07 10:34:33 +04:00
talloc_free ( flags_str ) ;
2007-05-29 06:16:59 +04:00
}
2007-04-27 14:56:10 +04:00
2007-05-29 06:16:59 +04:00
ret = ctdb_ctrl_getvnnmap ( ctdb , TIMELIMIT ( ) , options . vnn , ctdb , & vnnmap ) ;
2007-04-27 14:56:10 +04:00
if ( ret ! = 0 ) {
2007-05-29 06:16:59 +04:00
printf ( " Unable to get vnnmap from node %u \n " , options . vnn ) ;
2007-04-27 14:56:10 +04:00
return ret ;
}
printf ( " Generation:%d \n " , vnnmap - > generation ) ;
printf ( " Size:%d \n " , vnnmap - > size ) ;
for ( i = 0 ; i < vnnmap - > size ; i + + ) {
2007-05-29 06:16:59 +04:00
printf ( " hash:%d lmaster:%d \n " , i , vnnmap - > map [ i ] ) ;
2007-05-05 22:31:22 +04:00
}
2007-05-29 06:16:59 +04:00
ret = ctdb_ctrl_getrecmode ( ctdb , TIMELIMIT ( ) , options . vnn , & recmode ) ;
2007-05-05 22:31:22 +04:00
if ( ret ! = 0 ) {
2007-05-29 06:16:59 +04:00
printf ( " Unable to get recmode from node %u \n " , options . vnn ) ;
2007-05-05 22:31:22 +04:00
return ret ;
}
2007-05-29 06:16:59 +04:00
printf ( " Recovery mode:%s (%d) \n " , recmode = = CTDB_RECOVERY_NORMAL ? " NORMAL " : " RECOVERY " , recmode ) ;
2007-05-17 04:45:31 +04:00
2007-05-29 06:16:59 +04:00
ret = ctdb_ctrl_getrecmaster ( ctdb , TIMELIMIT ( ) , options . vnn , & recmaster ) ;
2007-05-17 04:45:31 +04:00
if ( ret ! = 0 ) {
2007-05-29 06:16:59 +04:00
printf ( " Unable to get recmaster from node %u \n " , options . vnn ) ;
2007-05-17 04:45:31 +04:00
return ret ;
}
2007-05-29 06:16:59 +04:00
printf ( " Recovery master:%d \n " , recmaster ) ;
2007-05-17 04:45:31 +04:00
return 0 ;
}
2007-07-04 08:14:48 +04:00
/*
kill a tcp connection
*/
static int kill_tcp ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int i , ret ;
struct sockaddr_in src , dst ;
2007-07-04 10:51:13 +04:00
if ( argc < 2 ) {
2007-07-04 08:14:48 +04:00
usage ( ) ;
}
2007-07-04 10:51:13 +04:00
if ( ! parse_ip_port ( argv [ 0 ] , & src ) ) {
printf ( " Bad IP:port '%s' \n " , argv [ 1 ] ) ;
return - 1 ;
}
2007-07-04 08:14:48 +04:00
2007-07-04 10:51:13 +04:00
if ( ! parse_ip_port ( argv [ 1 ] , & dst ) ) {
printf ( " Bad IP:port '%s' \n " , argv [ 1 ] ) ;
return - 1 ;
}
2007-07-04 08:14:48 +04:00
for ( i = 0 ; i < 5 ; i + + ) {
ret = ctdb_sys_kill_tcp ( ctdb - > ev , & src , & dst ) ;
printf ( " ret:%d \n " , ret ) ;
if ( ret = = 0 ) {
return 0 ;
}
}
return - 1 ;
}
2007-07-05 02:56:02 +04:00
/*
send a tcp tickle ack
*/
static int tickle_tcp ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
struct sockaddr_in src , dst ;
if ( argc < 2 ) {
usage ( ) ;
}
if ( ! parse_ip_port ( argv [ 0 ] , & src ) ) {
printf ( " Bad IP:port '%s' \n " , argv [ 1 ] ) ;
return - 1 ;
}
if ( ! parse_ip_port ( argv [ 1 ] , & dst ) ) {
printf ( " Bad IP:port '%s' \n " , argv [ 1 ] ) ;
return - 1 ;
}
ret = ctdb_sys_send_tcp ( & src , & dst , 0 , 0 , 0 ) ;
if ( ret = = 0 ) {
return 0 ;
}
printf ( " Error while sending tickle ack \n " ) ;
return - 1 ;
}
2007-06-04 15:11:51 +04:00
/*
display public ip status
*/
static int control_ip ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int i , ret ;
struct ctdb_all_public_ips * ips ;
uint32_t myvnn ;
myvnn = ctdb_ctrl_getvnn ( ctdb , TIMELIMIT ( ) , options . vnn ) ;
ret = ctdb_ctrl_get_public_ips ( ctdb , TIMELIMIT ( ) , options . vnn , ctdb , & ips ) ;
if ( ret ! = 0 ) {
printf ( " Unable to get public ips from node %u \n " , options . vnn ) ;
return ret ;
}
2007-06-05 12:32:06 +04:00
if ( options . machinereadable ) {
printf ( " :Public IP:Node: \n " ) ;
for ( i = 0 ; i < ips - > num ; i + + ) {
printf ( " :%s:%d: \n " ,
inet_ntoa ( ips - > ips [ i ] . sin . sin_addr ) ,
ips - > ips [ i ] . takeover_vnn ) ;
}
return 0 ;
}
2007-06-04 15:11:51 +04:00
printf ( " Number of nodes:%d \n " , ips - > num ) ;
for ( i = 0 ; i < ips - > num ; i + + ) {
printf ( " %-16s %d \n " ,
inet_ntoa ( ips - > ips [ i ] . sin . sin_addr ) ,
ips - > ips [ i ] . takeover_vnn ) ;
}
return 0 ;
}
2007-05-25 07:05:25 +04:00
/*
2007-05-29 06:16:59 +04:00
display pid of a ctdb daemon
2007-05-25 07:05:25 +04:00
*/
2007-05-29 06:16:59 +04:00
static int control_getpid ( struct ctdb_context * ctdb , int argc , const char * * argv )
2007-05-25 07:05:25 +04:00
{
2007-05-29 06:16:59 +04:00
uint32_t pid ;
2007-05-25 07:05:25 +04:00
int ret ;
2007-05-29 06:16:59 +04:00
ret = ctdb_ctrl_getpid ( ctdb , TIMELIMIT ( ) , options . vnn , & pid ) ;
2007-05-25 07:05:25 +04:00
if ( ret ! = 0 ) {
2007-05-29 06:16:59 +04:00
printf ( " Unable to get daemon pid from node %u \n " , options . vnn ) ;
2007-05-25 07:05:25 +04:00
return ret ;
}
2007-05-29 06:16:59 +04:00
printf ( " Pid:%d \n " , pid ) ;
2007-05-25 07:05:25 +04:00
return 0 ;
}
2007-06-07 03:16:17 +04:00
/*
disable a remote node
*/
static int control_disable ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
2007-06-07 09:18:55 +04:00
ret = ctdb_ctrl_modflags ( ctdb , TIMELIMIT ( ) , options . vnn , NODE_FLAGS_PERMANENTLY_DISABLED , 0 ) ;
2007-06-07 03:16:17 +04:00
if ( ret ! = 0 ) {
printf ( " Unable to disable node %u \n " , options . vnn ) ;
return ret ;
}
return 0 ;
}
/*
enable a disabled remote node
*/
static int control_enable ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
2007-06-07 09:18:55 +04:00
ret = ctdb_ctrl_modflags ( ctdb , TIMELIMIT ( ) , options . vnn , 0 , NODE_FLAGS_PERMANENTLY_DISABLED ) ;
2007-06-07 03:16:17 +04:00
if ( ret ! = 0 ) {
printf ( " Unable to enable node %u \n " , options . vnn ) ;
return ret ;
}
return 0 ;
}
2007-06-07 10:34:33 +04:00
/*
ban a node from the cluster
*/
static int control_ban ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
uint32_t recmaster ;
struct ctdb_ban_info b ;
TDB_DATA data ;
uint32_t ban_time ;
if ( argc < 1 ) {
usage ( ) ;
}
ban_time = strtoul ( argv [ 0 ] , NULL , 0 ) ;
ret = ctdb_ctrl_getrecmaster ( ctdb , TIMELIMIT ( ) , options . vnn , & recmaster ) ;
if ( ret ! = 0 ) {
DEBUG ( 0 , ( " Failed to find the recmaster \n " ) ) ;
return - 1 ;
}
b . vnn = options . vnn ;
b . ban_time = ban_time ;
data . dptr = ( uint8_t * ) & b ;
data . dsize = sizeof ( b ) ;
ret = ctdb_send_message ( ctdb , recmaster , CTDB_SRVID_BAN_NODE , data ) ;
if ( ret ! = 0 ) {
DEBUG ( 0 , ( " Failed to tell the recmaster to ban node %u \n " , options . vnn ) ) ;
return - 1 ;
}
return 0 ;
}
/*
unban a node from the cluster
*/
static int control_unban ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
uint32_t recmaster ;
TDB_DATA data ;
ret = ctdb_ctrl_getrecmaster ( ctdb , TIMELIMIT ( ) , options . vnn , & recmaster ) ;
if ( ret ! = 0 ) {
DEBUG ( 0 , ( " Failed to find the recmaster \n " ) ) ;
return - 1 ;
}
data . dptr = ( uint8_t * ) & options . vnn ;
data . dsize = sizeof ( uint32_t ) ;
ret = ctdb_send_message ( ctdb , recmaster , CTDB_SRVID_UNBAN_NODE , data ) ;
if ( ret ! = 0 ) {
DEBUG ( 0 , ( " Failed to tell the recmaster to unban node %u \n " , options . vnn ) ) ;
return - 1 ;
}
return 0 ;
}
2007-05-25 07:05:25 +04:00
/*
2007-05-29 06:16:59 +04:00
shutdown a daemon
2007-05-25 07:05:25 +04:00
*/
2007-05-29 06:16:59 +04:00
static int control_shutdown ( struct ctdb_context * ctdb , int argc , const char * * argv )
2007-05-25 07:05:25 +04:00
{
int ret ;
2007-06-05 11:43:19 +04:00
ret = ctdb_ctrl_shutdown ( ctdb , TIMELIMIT ( ) , options . vnn ) ;
2007-05-25 07:05:25 +04:00
if ( ret ! = 0 ) {
2007-05-29 06:16:59 +04:00
printf ( " Unable to shutdown node %u \n " , options . vnn ) ;
2007-05-25 07:05:25 +04:00
return ret ;
}
return 0 ;
}
2007-05-24 02:08:45 +04:00
/*
trigger a recovery
*/
2007-05-29 06:16:59 +04:00
static int control_recover ( struct ctdb_context * ctdb , int argc , const char * * argv )
2007-05-24 02:08:45 +04:00
{
int ret ;
2007-05-29 06:16:59 +04:00
ret = ctdb_ctrl_freeze ( ctdb , TIMELIMIT ( ) , options . vnn ) ;
2007-05-24 02:08:45 +04:00
if ( ret ! = 0 ) {
printf ( " Unable to freeze node \n " ) ;
return ret ;
}
2007-04-29 16:51:56 +04:00
2007-05-29 06:16:59 +04:00
ret = ctdb_ctrl_setrecmode ( ctdb , TIMELIMIT ( ) , options . vnn , CTDB_RECOVERY_ACTIVE ) ;
2007-04-29 16:51:56 +04:00
if ( ret ! = 0 ) {
2007-05-29 06:16:59 +04:00
printf ( " Unable to set recovery mode \n " ) ;
2007-04-29 16:51:56 +04:00
return ret ;
}
return 0 ;
}
2007-05-21 03:24:34 +04:00
/*
display monitoring mode of a remote node
*/
static int control_getmonmode ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2007-05-29 06:16:59 +04:00
uint32_t monmode ;
2007-05-21 03:24:34 +04:00
int ret ;
2007-05-29 06:16:59 +04:00
ret = ctdb_ctrl_getmonmode ( ctdb , TIMELIMIT ( ) , options . vnn , & monmode ) ;
2007-05-21 03:24:34 +04:00
if ( ret ! = 0 ) {
2007-05-29 06:16:59 +04:00
printf ( " Unable to get monmode from node %u \n " , options . vnn ) ;
2007-05-21 03:24:34 +04:00
return ret ;
}
printf ( " Monitoring mode:%s (%d) \n " , monmode = = CTDB_MONITORING_ACTIVE ? " ACTIVE " : " DISABLED " , monmode ) ;
return 0 ;
}
/*
set the monitoring mode of a remote node
*/
static int control_setmonmode ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2007-05-29 06:16:59 +04:00
uint32_t monmode ;
2007-05-07 00:51:58 +04:00
int ret ;
if ( argc < 1 ) {
usage ( ) ;
}
2007-05-29 06:16:59 +04:00
monmode = strtoul ( argv [ 0 ] , NULL , 0 ) ;
2007-05-07 00:51:58 +04:00
2007-05-29 06:16:59 +04:00
ret = ctdb_ctrl_setmonmode ( ctdb , TIMELIMIT ( ) , options . vnn , monmode ) ;
2007-05-07 00:51:58 +04:00
if ( ret ! = 0 ) {
2007-05-29 06:16:59 +04:00
printf ( " Unable to set monmode on node %u \n " , options . vnn ) ;
2007-05-07 00:51:58 +04:00
return ret ;
}
return 0 ;
}
2007-04-28 23:47:13 +04:00
/*
2007-05-04 06:18:39 +04:00
display remote list of keys / data for a db
2007-04-28 23:47:13 +04:00
*/
2007-04-29 18:58:27 +04:00
static int control_catdb ( struct ctdb_context * ctdb , int argc , const char * * argv )
2007-04-28 23:47:13 +04:00
{
2007-05-04 07:25:30 +04:00
const char * db_name ;
2007-05-04 06:18:39 +04:00
struct ctdb_db_context * ctdb_db ;
int ret ;
2007-04-28 23:47:13 +04:00
2007-05-04 06:18:39 +04:00
if ( argc < 1 ) {
2007-04-28 23:47:13 +04:00
usage ( ) ;
}
2007-05-04 07:25:30 +04:00
db_name = argv [ 0 ] ;
ctdb_db = ctdb_attach ( ctdb , db_name ) ;
2007-05-29 06:16:59 +04:00
2007-05-04 06:18:39 +04:00
if ( ctdb_db = = NULL ) {
2007-05-04 07:25:30 +04:00
DEBUG ( 0 , ( " Unable to attach to database '%s' \n " , db_name ) ) ;
2007-05-04 06:18:39 +04:00
return - 1 ;
2007-04-28 23:47:13 +04:00
}
2007-05-04 06:18:39 +04:00
2007-05-29 06:16:59 +04:00
/* traverse and dump the cluster tdb */
ret = ctdb_dump_db ( ctdb_db , stdout ) ;
if ( ret = = - 1 ) {
printf ( " Unable to dump database \n " ) ;
return - 1 ;
2007-05-05 23:53:15 +04:00
}
2007-05-04 07:25:30 +04:00
talloc_free ( ctdb_db ) ;
2007-05-04 06:18:39 +04:00
printf ( " Dumped %d records \n " , ret ) ;
2007-04-28 23:47:13 +04:00
return 0 ;
}
2007-04-29 18:58:27 +04:00
2007-04-28 14:00:50 +04:00
/*
display a list of the databases on a remote ctdb
*/
static int control_getdbmap ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int i , ret ;
2007-05-03 07:07:34 +04:00
struct ctdb_dbid_map * dbmap = NULL ;
2007-04-28 14:00:50 +04:00
2007-05-29 06:16:59 +04:00
ret = ctdb_ctrl_getdbmap ( ctdb , TIMELIMIT ( ) , options . vnn , ctdb , & dbmap ) ;
2007-04-28 14:00:50 +04:00
if ( ret ! = 0 ) {
2007-05-29 06:16:59 +04:00
printf ( " Unable to get dbids from node %u \n " , options . vnn ) ;
2007-04-28 14:00:50 +04:00
return ret ;
}
2007-05-03 07:07:34 +04:00
printf ( " Number of databases:%d \n " , dbmap - > num ) ;
for ( i = 0 ; i < dbmap - > num ; i + + ) {
2007-04-28 14:00:50 +04:00
const char * path ;
2007-05-05 23:53:15 +04:00
const char * name ;
2007-04-28 14:00:50 +04:00
2007-05-29 06:16:59 +04:00
ctdb_ctrl_getdbpath ( ctdb , TIMELIMIT ( ) , options . vnn , dbmap - > dbids [ i ] , ctdb , & path ) ;
ctdb_ctrl_getdbname ( ctdb , TIMELIMIT ( ) , options . vnn , dbmap - > dbids [ i ] , ctdb , & name ) ;
2007-05-05 23:53:15 +04:00
printf ( " dbid:0x%08x name:%s path:%s \n " , dbmap - > dbids [ i ] , name , path ) ;
2007-04-28 14:00:50 +04:00
}
2007-05-02 04:20:34 +04:00
2007-04-28 14:00:50 +04:00
return 0 ;
}
2007-04-28 14:40:26 +04:00
/*
2007-05-29 06:16:59 +04:00
ping a node
2007-04-27 17:14:36 +04:00
*/
2007-04-26 21:27:07 +04:00
static int control_ping ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2007-06-11 16:25:26 +04:00
int ret ;
struct timeval tv = timeval_current ( ) ;
ret = ctdb_ctrl_ping ( ctdb , options . vnn ) ;
if ( ret = = - 1 ) {
printf ( " Unable to get ping response from node %u \n " , options . vnn ) ;
} else {
printf ( " response from %u time=%.6f sec (%d clients) \n " ,
options . vnn , timeval_elapsed ( & tv ) , ret ) ;
2007-04-26 21:27:07 +04:00
}
return 0 ;
}
2007-04-27 17:14:36 +04:00
2007-06-04 13:53:19 +04:00
/*
get a tunable
*/
static int control_getvar ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
const char * name ;
uint32_t value ;
int ret ;
if ( argc < 1 ) {
usage ( ) ;
}
name = argv [ 0 ] ;
ret = ctdb_ctrl_get_tunable ( ctdb , TIMELIMIT ( ) , options . vnn , name , & value ) ;
if ( ret = = - 1 ) {
printf ( " Unable to get tunable variable '%s' \n " , name ) ;
return - 1 ;
}
2007-06-07 09:18:55 +04:00
printf ( " %-19s = %u \n " , name , value ) ;
2007-06-04 13:53:19 +04:00
return 0 ;
}
/*
set a tunable
*/
static int control_setvar ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
const char * name ;
uint32_t value ;
int ret ;
if ( argc < 2 ) {
usage ( ) ;
}
name = argv [ 0 ] ;
value = strtoul ( argv [ 1 ] , NULL , 0 ) ;
ret = ctdb_ctrl_set_tunable ( ctdb , TIMELIMIT ( ) , options . vnn , name , value ) ;
if ( ret = = - 1 ) {
printf ( " Unable to set tunable variable '%s' \n " , name ) ;
return - 1 ;
}
return 0 ;
}
/*
list all tunables
*/
static int control_listvars ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t count ;
const char * * list ;
int ret , i ;
ret = ctdb_ctrl_list_tunables ( ctdb , TIMELIMIT ( ) , options . vnn , ctdb , & list , & count ) ;
if ( ret = = - 1 ) {
printf ( " Unable to list tunable variables \n " ) ;
return - 1 ;
}
for ( i = 0 ; i < count ; i + + ) {
control_getvar ( ctdb , 1 , & list [ i ] ) ;
}
talloc_free ( list ) ;
return 0 ;
}
2007-04-27 17:14:36 +04:00
/*
2007-05-29 06:16:59 +04:00
display debug level on a node
2007-04-27 17:14:36 +04:00
*/
2007-05-29 06:16:59 +04:00
static int control_getdebug ( struct ctdb_context * ctdb , int argc , const char * * argv )
2007-04-27 17:14:36 +04:00
{
2007-06-11 16:25:26 +04:00
int ret ;
2007-05-29 06:16:59 +04:00
uint32_t level ;
2007-04-28 19:42:40 +04:00
2007-06-11 16:25:26 +04:00
ret = ctdb_ctrl_get_debuglevel ( ctdb , options . vnn , & level ) ;
if ( ret ! = 0 ) {
printf ( " Unable to get debuglevel response from node %u \n " ,
options . vnn ) ;
} else {
printf ( " Node %u is at debug level %u \n " , options . vnn , level ) ;
2007-04-27 17:14:36 +04:00
}
return 0 ;
}
2007-05-29 06:16:59 +04:00
2007-04-27 17:14:36 +04:00
/*
2007-05-29 06:16:59 +04:00
set debug level on a node or all nodes
2007-04-27 17:14:36 +04:00
*/
2007-05-29 06:16:59 +04:00
static int control_setdebug ( struct ctdb_context * ctdb , int argc , const char * * argv )
2007-04-27 17:14:36 +04:00
{
int ret ;
2007-06-11 16:25:26 +04:00
uint32_t level ;
2007-04-27 17:14:36 +04:00
2007-05-29 06:16:59 +04:00
if ( argc < 1 ) {
2007-04-27 17:14:36 +04:00
usage ( ) ;
}
2007-05-29 06:16:59 +04:00
level = strtoul ( argv [ 0 ] , NULL , 0 ) ;
2007-04-27 17:14:36 +04:00
2007-06-11 16:25:26 +04:00
ret = ctdb_ctrl_set_debuglevel ( ctdb , options . vnn , level ) ;
if ( ret ! = 0 ) {
printf ( " Unable to set debug level on node %u \n " , options . vnn ) ;
2007-04-27 17:14:36 +04:00
}
return 0 ;
}
2007-04-30 17:54:06 +04:00
2007-05-12 09:15:27 +04:00
/*
freeze a node
*/
static int control_freeze ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2007-06-11 16:25:26 +04:00
int ret ;
2007-05-12 09:15:27 +04:00
2007-06-11 16:25:26 +04:00
ret = ctdb_ctrl_freeze ( ctdb , TIMELIMIT ( ) , options . vnn ) ;
if ( ret ! = 0 ) {
printf ( " Unable to freeze node %u \n " , options . vnn ) ;
}
2007-05-12 09:15:27 +04:00
return 0 ;
}
/*
thaw a node
*/
static int control_thaw ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2007-06-11 16:25:26 +04:00
int ret ;
2007-05-12 09:15:27 +04:00
2007-06-11 16:25:26 +04:00
ret = ctdb_ctrl_thaw ( ctdb , TIMELIMIT ( ) , options . vnn ) ;
if ( ret ! = 0 ) {
printf ( " Unable to thaw node %u \n " , options . vnn ) ;
}
2007-05-12 09:15:27 +04:00
return 0 ;
}
2007-04-30 17:54:06 +04:00
/*
attach to a database
*/
static int control_attach ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
const char * db_name ;
struct ctdb_db_context * ctdb_db ;
2007-05-29 06:16:59 +04:00
2007-04-30 17:54:06 +04:00
if ( argc < 1 ) {
usage ( ) ;
}
db_name = argv [ 0 ] ;
ctdb_db = ctdb_attach ( ctdb , db_name ) ;
if ( ctdb_db = = NULL ) {
DEBUG ( 0 , ( " Unable to attach to database '%s' \n " , db_name ) ) ;
return - 1 ;
}
return 0 ;
}
2007-05-05 05:03:10 +04:00
/*
dump memory usage
*/
static int control_dumpmemory ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2007-05-29 06:16:59 +04:00
return ctdb_control ( ctdb , options . vnn , 0 , CTDB_CONTROL_DUMP_MEMORY ,
CTDB_CTRL_FLAG_NOREPLY , tdb_null , NULL , NULL , NULL , NULL , NULL ) ;
}
static const struct {
const char * name ;
int ( * fn ) ( struct ctdb_context * , int , const char * * ) ;
2007-06-11 16:25:26 +04:00
bool auto_all ;
2007-05-29 06:16:59 +04:00
const char * msg ;
const char * args ;
} ctdb_commands [ ] = {
2007-06-11 16:25:26 +04:00
{ " status " , control_status , true , " show node status " } ,
{ " ping " , control_ping , true , " ping all nodes " } ,
{ " getvar " , control_getvar , true , " get a tunable variable " , " <name> " } ,
{ " setvar " , control_setvar , true , " set a tunable variable " , " <name> <value> " } ,
{ " listvars " , control_listvars , true , " list tunable variables " } ,
{ " statistics " , control_statistics , false , " show statistics " } ,
{ " statisticsreset " , control_statistics_reset , true , " reset statistics " } ,
{ " ip " , control_ip , true , " show which public ip's that ctdb manages " } ,
{ " process-exists " , control_process_exists , true , " check if a process exists on a node " , " <pid> " } ,
{ " getdbmap " , control_getdbmap , true , " show the database map " } ,
{ " catdb " , control_catdb , true , " dump a database " , " <dbname> " } ,
{ " getmonmode " , control_getmonmode , true , " show monitoring mode " } ,
{ " setmonmode " , control_setmonmode , true , " set monitoring mode " , " <0|1> " } ,
{ " setdebug " , control_setdebug , true , " set debug level " , " <debuglevel> " } ,
{ " getdebug " , control_getdebug , true , " get debug level " } ,
{ " attach " , control_attach , true , " attach to a database " , " <dbname> " } ,
{ " dumpmemory " , control_dumpmemory , true , " dump memory map to logs " } ,
{ " getpid " , control_getpid , true , " get ctdbd process ID " } ,
{ " disable " , control_disable , true , " disable a nodes public IP " } ,
{ " enable " , control_enable , true , " enable a nodes public IP " } ,
{ " ban " , control_ban , true , " ban a node from the cluster " , " <bantime|0> " } ,
{ " unban " , control_unban , true , " unban a node from the cluster " } ,
{ " shutdown " , control_shutdown , true , " shutdown ctdbd " } ,
{ " recover " , control_recover , true , " force recovery " } ,
{ " freeze " , control_freeze , true , " freeze all databases " } ,
{ " thaw " , control_thaw , true , " thaw all databases " } ,
2007-07-04 10:51:13 +04:00
{ " killtcp " , kill_tcp , false , " kill a tcp connection " , " <srcip:port> <dstip:port> " } ,
2007-07-05 02:56:02 +04:00
{ " tickle " , tickle_tcp , false , " send a tcp tickle ack " , " <srcip:port> <dstip:port> " } ,
2007-05-29 06:16:59 +04:00
} ;
2007-05-05 05:03:10 +04:00
2007-05-29 06:16:59 +04:00
/*
show usage message
*/
static void usage ( void )
{
int i ;
printf (
" Usage: ctdb [options] <control> \n " \
" Options: \n " \
" -n <node> choose node number, or 'all' (defaults to local node) \n "
2007-06-03 13:50:51 +04:00
" -Y generate machinereadable output \n "
2007-05-29 06:16:59 +04:00
" -t <timelimit> set timelimit for control in seconds (default %u) \n " , options . timelimit ) ;
printf ( " Controls: \n " ) ;
for ( i = 0 ; i < ARRAY_SIZE ( ctdb_commands ) ; i + + ) {
printf ( " %-15s %-20s %s \n " ,
ctdb_commands [ i ] . name ,
ctdb_commands [ i ] . args ? ctdb_commands [ i ] . args : " " ,
ctdb_commands [ i ] . msg ) ;
2007-05-05 05:03:10 +04:00
}
2007-05-29 06:16:59 +04:00
exit ( 1 ) ;
2007-05-05 05:03:10 +04:00
}
2007-05-29 06:16:59 +04:00
2007-04-26 16:27:49 +04:00
/*
main program
*/
int main ( int argc , const char * argv [ ] )
{
struct ctdb_context * ctdb ;
2007-05-29 06:16:59 +04:00
char * nodestring = NULL ;
2007-04-26 16:27:49 +04:00
struct poptOption popt_options [ ] = {
POPT_AUTOHELP
POPT_CTDB_CMDLINE
2007-05-29 06:16:59 +04:00
{ " timelimit " , ' t ' , POPT_ARG_INT , & options . timelimit , 0 , " timelimit " , " integer " } ,
{ " node " , ' n ' , POPT_ARG_STRING , & nodestring , 0 , " node " , " integer|all " } ,
2007-06-03 13:50:51 +04:00
{ " machinereadable " , ' Y ' , POPT_ARG_NONE , & options . machinereadable , 0 , " enable machinereadable output " , NULL } ,
2007-04-26 16:27:49 +04:00
POPT_TABLEEND
} ;
int opt ;
const char * * extra_argv ;
int extra_argc = 0 ;
2007-05-29 10:02:02 +04:00
int ret = - 1 , i ;
2007-04-26 16:27:49 +04:00
poptContext pc ;
struct event_context * ev ;
const char * control ;
2007-05-29 06:16:59 +04:00
/* set some defaults */
options . timelimit = 3 ;
options . vnn = CTDB_CURRENT_NODE ;
2007-04-26 16:27:49 +04:00
pc = poptGetContext ( argv [ 0 ] , argc , argv , popt_options , POPT_CONTEXT_KEEP_FIRST ) ;
while ( ( opt = poptGetNextOpt ( pc ) ) ! = - 1 ) {
switch ( opt ) {
default :
fprintf ( stderr , " Invalid option %s: %s \n " ,
poptBadOption ( pc , 0 ) , poptStrerror ( opt ) ) ;
exit ( 1 ) ;
}
}
/* setup the remaining options for the main program to use */
extra_argv = poptGetArgs ( pc ) ;
if ( extra_argv ) {
extra_argv + + ;
while ( extra_argv [ extra_argc ] ) extra_argc + + ;
}
if ( extra_argc < 1 ) {
usage ( ) ;
}
2007-05-29 06:16:59 +04:00
/* setup the node number to contact */
if ( nodestring ! = NULL ) {
if ( strcmp ( nodestring , " all " ) = = 0 ) {
options . vnn = CTDB_BROADCAST_ALL ;
} else {
options . vnn = strtoul ( nodestring , NULL , 0 ) ;
}
}
2007-04-26 16:27:49 +04:00
control = extra_argv [ 0 ] ;
ev = event_context_init ( NULL ) ;
/* initialise ctdb */
ctdb = ctdb_cmdline_client ( ev ) ;
if ( ctdb = = NULL ) {
printf ( " Failed to init ctdb \n " ) ;
exit ( 1 ) ;
}
2007-05-29 06:16:59 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( ctdb_commands ) ; i + + ) {
if ( strcmp ( control , ctdb_commands [ i ] . name ) = = 0 ) {
2007-06-11 16:25:26 +04:00
int j ;
if ( options . vnn = = CTDB_CURRENT_NODE ) {
options . vnn = ctdb_ctrl_getvnn ( ctdb , TIMELIMIT ( ) , options . vnn ) ;
}
if ( ctdb_commands [ i ] . auto_all & &
options . vnn = = CTDB_BROADCAST_ALL ) {
uint32_t * nodes ;
uint32_t num_nodes ;
ret = 0 ;
nodes = ctdb_get_connected_nodes ( ctdb , TIMELIMIT ( ) , ctdb , & num_nodes ) ;
CTDB_NO_MEMORY ( ctdb , nodes ) ;
for ( j = 0 ; j < num_nodes ; j + + ) {
options . vnn = nodes [ j ] ;
ret | = ctdb_commands [ i ] . fn ( ctdb , extra_argc - 1 , extra_argv + 1 ) ;
}
talloc_free ( nodes ) ;
} else {
ret = ctdb_commands [ i ] . fn ( ctdb , extra_argc - 1 , extra_argv + 1 ) ;
}
2007-05-02 07:34:55 +04:00
break ;
}
}
2007-05-29 06:16:59 +04:00
if ( i = = ARRAY_SIZE ( ctdb_commands ) ) {
2007-04-26 16:27:49 +04:00
printf ( " Unknown control '%s' \n " , control ) ;
exit ( 1 ) ;
}
return ret ;
}