2007-04-26 16:27:49 +04:00
/*
ctdb control tool
Copyright ( C ) Andrew Tridgell 2007
2007-10-08 03:47:20 +04:00
Copyright ( C ) Ronnie Sahlberg 2007
2007-04-26 16:27:49 +04:00
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
2007-07-10 09:29:31 +04:00
the Free Software Foundation ; either version 3 of the License , or
2007-05-31 07:50:53 +04:00
( 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
2007-07-10 09:29:31 +04:00
along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2007-04-26 16:27:49 +04:00
*/
# include "includes.h"
# include "lib/events/events.h"
2008-01-17 03:33:23 +03:00
# include "system/time.h"
2007-04-26 16:27:49 +04:00
# include "system/filesys.h"
2007-06-07 16:26:27 +04:00
# include "system/network.h"
2008-02-05 02:36:06 +03:00
# include "system/locale.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"
2008-04-22 18:55:57 +04:00
# include "../common/rb_tree.h"
2008-08-14 04:57:08 +04:00
# include "db_wrap.h"
2007-04-26 16:27:49 +04:00
2008-12-17 06:26:01 +03:00
# define ERR_TIMEOUT 20 /* timed out trying to reach node */
# define ERR_NONODE 21 /* node does not exist */
# define ERR_DISNODE 22 /* node is disconnected */
2008-12-10 03:49:51 +03:00
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 ;
2007-09-04 04:14:41 +04:00
uint32_t pnn ;
2007-06-03 13:50:51 +04:00
int machinereadable ;
2008-01-10 00:04:54 +03:00
int maxruntime ;
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
2008-04-03 10:07:00 +04:00
# ifdef CTDB_VERS
static int control_version ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
# define STR(x) #x
# define XSTR(x) STR(x)
printf ( " CTDB version: %s \n " , XSTR ( CTDB_VERS ) ) ;
return 0 ;
}
# endif
2008-09-22 19:38:28 +04:00
2008-12-17 06:26:01 +03:00
/*
verify that a node exists and is reachable
*/
static void verify_node ( struct ctdb_context * ctdb )
{
int ret ;
struct ctdb_node_map * nodemap = NULL ;
if ( options . pnn = = CTDB_CURRENT_NODE ) {
return ;
}
if ( options . pnn = = CTDB_BROADCAST_ALL ) {
return ;
}
/* verify the node exists */
if ( ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE , ctdb , & nodemap ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from local node \n " ) ) ;
exit ( 10 ) ;
}
if ( options . pnn > = nodemap - > num ) {
DEBUG ( DEBUG_ERR , ( " Node %u does not exist \n " , options . pnn ) ) ;
exit ( ERR_NONODE ) ;
}
2009-06-01 09:43:30 +04:00
if ( nodemap - > nodes [ options . pnn ] . flags & NODE_FLAGS_DELETED ) {
DEBUG ( DEBUG_ERR , ( " Node %u is DELETED \n " , options . pnn ) ) ;
exit ( ERR_DISNODE ) ;
}
2008-12-17 06:26:01 +03:00
if ( nodemap - > nodes [ options . pnn ] . flags & NODE_FLAGS_DISCONNECTED ) {
DEBUG ( DEBUG_ERR , ( " Node %u is DISCONNECTED \n " , options . pnn ) ) ;
exit ( ERR_DISNODE ) ;
}
/* verify we can access the node */
ret = ctdb_ctrl_getpnn ( ctdb , TIMELIMIT ( ) , options . pnn ) ;
if ( ret = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " Can not ban node. Node is not operational. \n " ) ) ;
exit ( 10 ) ;
}
}
2008-09-22 19:38:28 +04:00
/*
check if a database exists
*/
static int db_exists ( struct ctdb_context * ctdb , const char * db_name )
{
int i , ret ;
struct ctdb_dbid_map * dbmap = NULL ;
ret = ctdb_ctrl_getdbmap ( ctdb , TIMELIMIT ( ) , options . pnn , ctdb , & dbmap ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get dbids from node %u \n " , options . pnn ) ) ;
return - 1 ;
}
for ( i = 0 ; i < dbmap - > num ; i + + ) {
const char * name ;
ctdb_ctrl_getdbname ( ctdb , TIMELIMIT ( ) , options . pnn , dbmap - > dbs [ i ] . dbid , ctdb , & name ) ;
if ( ! strcmp ( name , db_name ) ) {
return 0 ;
}
}
return - 1 ;
}
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-09-04 04:14:41 +04:00
uint32_t pnn , 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-09-04 04:14:41 +04:00
if ( sscanf ( argv [ 0 ] , " %u:%u " , & pnn , & pid ) ! = 2 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Badly formed pnn:pid \n " ) ) ;
2007-04-26 16:51:41 +04:00
return - 1 ;
}
2007-04-26 16:27:49 +04:00
2007-09-04 04:14:41 +04:00
ret = ctdb_ctrl_process_exists ( ctdb , pnn , pid ) ;
2007-04-26 16:27:49 +04:00
if ( ret = = 0 ) {
2007-09-04 04:14:41 +04:00
printf ( " %u:%u exists \n " , pnn , pid ) ;
2007-04-26 16:27:49 +04:00
} else {
2007-09-04 04:14:41 +04:00
printf ( " %u:%u does not exist \n " , pnn , 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 ) ,
2008-05-28 07:04:25 +04:00
STATISTICS_FIELD ( childwrite_calls ) ,
STATISTICS_FIELD ( pending_childwrite_calls ) ,
2007-05-29 06:16:59 +04:00
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 ) ) ;
}
2009-05-14 04:33:25 +04:00
printf ( " %-30s %.6f sec \n " , " max_reclock_ctdbd " , s - > reclock . ctdbd ) ;
printf ( " %-30s %.6f sec \n " , " max_reclock_recd " , s - > reclock . recd ) ;
2007-05-05 02:11:54 +04:00
printf ( " %-30s %.6f sec \n " , " max_call_latency " , s - > max_call_latency ) ;
printf ( " %-30s %.6f sec \n " , " max_lockwait_latency " , s - > max_lockwait_latency ) ;
2008-05-28 07:04:25 +04:00
printf ( " %-30s %.6f sec \n " , " max_childwrite_latency " , s - > max_childwrite_latency ) ;
2007-05-05 02:11:54 +04:00
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 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " 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-09-04 04:14:41 +04:00
if ( options . pnn = = CTDB_BROADCAST_ALL ) {
2007-05-29 06:16:59 +04:00
return control_statistics_all ( ctdb ) ;
2007-04-28 19:13:30 +04:00
}
2007-09-04 04:14:41 +04:00
ret = ctdb_ctrl_statistics ( ctdb , options . pnn , & statistics ) ;
2007-04-26 16:51:41 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get statistics from node %u \n " , options . pnn ) ) ;
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-09-04 04:14:41 +04:00
ret = ctdb_statistics_reset ( ctdb , options . pnn ) ;
2007-04-28 21:13:36 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to reset statistics on node %u \n " , options . pnn ) ) ;
2007-04-28 21:13:36 +04:00
return ret ;
}
return 0 ;
}
2007-05-02 04:20:34 +04:00
2008-01-17 03:33:23 +03:00
/*
display uptime of remote node
*/
static int control_uptime ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
struct ctdb_uptime * uptime = NULL ;
int tmp , days , hours , minutes , seconds ;
ret = ctdb_ctrl_uptime ( ctdb , ctdb , TIMELIMIT ( ) , options . pnn , & uptime ) ;
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get uptime from node %u \n " , options . pnn ) ) ;
2008-01-17 03:33:23 +03:00
return ret ;
}
2008-03-04 05:29:48 +03:00
if ( options . machinereadable ) {
2008-07-02 07:55:59 +04:00
printf ( " :Current Node Time:Ctdb Start Time:Last Recovery Time:Last Recovery Duration: \n " ) ;
printf ( " :%u:%u:%u:%lf \n " ,
2008-03-04 05:29:48 +03:00
( unsigned int ) uptime - > current_time . tv_sec ,
( unsigned int ) uptime - > ctdbd_start_time . tv_sec ,
2008-07-02 07:55:59 +04:00
( unsigned int ) uptime - > last_recovery_finished . tv_sec ,
timeval_delta ( & uptime - > last_recovery_finished ,
& uptime - > last_recovery_started )
) ;
2008-03-04 05:29:48 +03:00
return 0 ;
}
2008-01-17 03:33:23 +03:00
printf ( " Current time of node : %s " , ctime ( & uptime - > current_time . tv_sec ) ) ;
tmp = uptime - > current_time . tv_sec - uptime - > ctdbd_start_time . tv_sec ;
seconds = tmp % 60 ;
tmp / = 60 ;
minutes = tmp % 60 ;
tmp / = 60 ;
hours = tmp % 24 ;
tmp / = 24 ;
days = tmp ;
printf ( " Ctdbd start time : (%03d %02d:%02d:%02d) %s " , days , hours , minutes , seconds , ctime ( & uptime - > ctdbd_start_time . tv_sec ) ) ;
2008-07-02 07:55:59 +04:00
tmp = uptime - > current_time . tv_sec - uptime - > last_recovery_finished . tv_sec ;
2008-01-17 03:33:23 +03:00
seconds = tmp % 60 ;
tmp / = 60 ;
minutes = tmp % 60 ;
tmp / = 60 ;
hours = tmp % 24 ;
tmp / = 24 ;
days = tmp ;
2008-07-02 07:55:59 +04:00
printf ( " Time of last recovery : (%03d %02d:%02d:%02d) %s " , days , hours , minutes , seconds , ctime ( & uptime - > last_recovery_finished . tv_sec ) ) ;
printf ( " Duration of last recovery : %lf seconds \n " ,
timeval_delta ( & uptime - > last_recovery_finished ,
& uptime - > last_recovery_started ) ) ;
2008-01-17 03:33:23 +03:00
return 0 ;
}
2008-07-10 05:12:58 +04:00
/*
show the PNN of the current node
*/
static int control_pnn ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int mypnn ;
2008-12-17 06:26:01 +03:00
mypnn = ctdb_ctrl_getpnn ( ctdb , TIMELIMIT ( ) , options . pnn ) ;
2008-07-10 05:12:58 +04:00
if ( mypnn = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get pnn from local node. " ) ) ;
return - 1 ;
}
printf ( " PNN:%d \n " , mypnn ) ;
return 0 ;
}
2009-03-25 06:46:05 +03:00
struct pnn_node {
struct pnn_node * next ;
const char * addr ;
int pnn ;
} ;
2009-06-04 07:21:25 +04:00
static struct pnn_node * read_nodes_file ( TALLOC_CTX * mem_ctx )
2009-03-25 06:46:05 +03:00
{
const char * nodes_list ;
int nlines ;
char * * lines ;
2009-06-04 07:21:25 +04:00
int i , pnn ;
2009-03-25 06:46:05 +03:00
struct pnn_node * pnn_nodes = NULL ;
struct pnn_node * pnn_node ;
2009-06-04 07:21:25 +04:00
struct pnn_node * tmp_node ;
2009-03-25 06:46:05 +03:00
/* read the nodes file */
nodes_list = getenv ( " CTDB_NODES " ) ;
if ( nodes_list = = NULL ) {
nodes_list = " /etc/ctdb/nodes " ;
}
lines = file_lines_load ( nodes_list , & nlines , mem_ctx ) ;
if ( lines = = NULL ) {
2009-06-04 07:21:25 +04:00
return NULL ;
2009-03-25 06:46:05 +03:00
}
while ( nlines > 0 & & strcmp ( lines [ nlines - 1 ] , " " ) = = 0 ) {
nlines - - ;
}
for ( i = 0 , pnn = 0 ; i < nlines ; i + + ) {
char * node ;
node = lines [ i ] ;
/* strip leading spaces */
while ( ( * node = = ' ' ) | | ( * node = = ' \t ' ) ) {
node + + ;
}
if ( * node = = ' # ' ) {
2009-06-04 07:21:25 +04:00
pnn + + ;
2009-03-25 06:46:05 +03:00
continue ;
}
if ( strcmp ( node , " " ) = = 0 ) {
continue ;
}
pnn_node = talloc ( mem_ctx , struct pnn_node ) ;
pnn_node - > pnn = pnn + + ;
pnn_node - > addr = talloc_strdup ( pnn_node , node ) ;
pnn_node - > next = pnn_nodes ;
pnn_nodes = pnn_node ;
}
2009-06-04 07:21:25 +04:00
/* swap them around so we return them in incrementing order */
pnn_node = pnn_nodes ;
pnn_nodes = NULL ;
while ( pnn_node ) {
tmp_node = pnn_node ;
pnn_node = pnn_node - > next ;
tmp_node - > next = pnn_nodes ;
pnn_nodes = tmp_node ;
}
return pnn_nodes ;
}
/*
show the PNN of the current node
discover the pnn by loading the nodes file and try to bind to all
addresses one at a time until the ip address is found .
*/
static int control_xpnn ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
TALLOC_CTX * mem_ctx = talloc_new ( NULL ) ;
struct pnn_node * pnn_nodes ;
struct pnn_node * pnn_node ;
pnn_nodes = read_nodes_file ( mem_ctx ) ;
if ( pnn_nodes = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to read nodes file \n " ) ) ;
talloc_free ( mem_ctx ) ;
return - 1 ;
}
2009-03-25 06:46:05 +03:00
for ( pnn_node = pnn_nodes ; pnn_node ; pnn_node = pnn_node - > next ) {
ctdb_sock_addr addr ;
if ( parse_ip ( pnn_node - > addr , NULL , 63999 , & addr ) = = 0 ) {
2009-06-04 07:21:25 +04:00
DEBUG ( DEBUG_ERR , ( " Wrongly formed ip address '%s' in nodes file \n " , pnn_node - > addr ) ) ;
talloc_free ( mem_ctx ) ;
2009-03-25 06:46:05 +03:00
return - 1 ;
}
if ( ctdb_sys_have_ip ( & addr ) ) {
printf ( " PNN:%d \n " , pnn_node - > pnn ) ;
2009-06-04 07:21:25 +04:00
talloc_free ( mem_ctx ) ;
2009-03-25 06:46:05 +03:00
return 0 ;
}
}
printf ( " Failed to detect which PNN this node is \n " ) ;
2009-06-04 07:21:25 +04:00
talloc_free ( mem_ctx ) ;
2009-03-25 06:46:05 +03:00
return - 1 ;
}
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 ;
2007-09-04 04:14:41 +04:00
int mypnn ;
2007-05-29 06:16:59 +04:00
2007-09-04 04:38:48 +04:00
mypnn = ctdb_ctrl_getpnn ( ctdb , TIMELIMIT ( ) , options . pnn ) ;
2007-09-04 04:14:41 +04:00
if ( mypnn = = - 1 ) {
2007-08-07 07:40:13 +04:00
return - 1 ;
}
2007-05-29 06:16:59 +04:00
2007-09-04 04:14:41 +04:00
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , options . pnn , ctdb , & nodemap ) ;
2007-05-29 06:16:59 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from node %u \n " , options . pnn ) ) ;
2007-05-29 06:16:59 +04:00
return ret ;
2007-04-27 14:56:10 +04:00
}
2007-06-03 13:50:51 +04:00
if ( options . machinereadable ) {
2009-07-09 05:38:18 +04:00
printf ( " :Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped: \n " ) ;
2007-06-03 13:50:51 +04:00
for ( i = 0 ; i < nodemap - > num ; i + + ) {
2009-06-01 09:43:30 +04:00
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_DELETED ) {
continue ;
}
2009-07-09 05:38:18 +04:00
printf ( " :%d:%s:%d:%d:%d:%d:%d: \n " , nodemap - > nodes [ i ] . pnn ,
2008-08-19 08:58:29 +04:00
ctdb_addr_to_str ( & nodemap - > nodes [ i ] . addr ) ,
2007-06-07 09:18:55 +04:00
! ! ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_DISCONNECTED ) ,
2008-01-29 03:39:06 +03:00
! ! ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_BANNED ) ,
! ! ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_PERMANENTLY_DISABLED ) ,
2009-07-09 05:38:18 +04:00
! ! ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_UNHEALTHY ) ,
! ! ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_STOPPED ) ) ;
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 " } ,
2009-06-01 08:18:34 +04:00
{ NODE_FLAGS_DELETED , " DELETED " } ,
2009-07-09 05:38:18 +04:00
{ NODE_FLAGS_STOPPED , " STOPPED " } ,
2007-06-07 10:34:33 +04:00
} ;
char * flags_str = NULL ;
int j ;
2009-06-01 09:43:30 +04:00
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_DELETED ) {
continue ;
}
2007-06-07 10:34:33 +04:00
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-09-04 03:50:07 +04:00
printf ( " pnn:%d %-16s %s%s \n " , nodemap - > nodes [ i ] . pnn ,
2008-08-19 08:58:29 +04:00
ctdb_addr_to_str ( & nodemap - > nodes [ i ] . addr ) ,
2007-06-06 04:25:46 +04:00
flags_str ,
2007-09-04 04:14:41 +04:00
nodemap - > nodes [ i ] . pnn = = mypnn ? " (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-09-04 04:14:41 +04:00
ret = ctdb_ctrl_getvnnmap ( ctdb , TIMELIMIT ( ) , options . pnn , ctdb , & vnnmap ) ;
2007-04-27 14:56:10 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get vnnmap from node %u \n " , options . pnn ) ) ;
2007-04-27 14:56:10 +04:00
return ret ;
}
2007-08-22 06:38:31 +04:00
if ( vnnmap - > generation = = INVALID_GENERATION ) {
printf ( " Generation:INVALID \n " ) ;
} else {
printf ( " Generation:%d \n " , vnnmap - > generation ) ;
}
2007-04-27 14:56:10 +04:00
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-09-04 04:14:41 +04:00
ret = ctdb_ctrl_getrecmode ( ctdb , ctdb , TIMELIMIT ( ) , options . pnn , & recmode ) ;
2007-05-05 22:31:22 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get recmode from node %u \n " , options . pnn ) ) ;
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-09-04 04:14:41 +04:00
ret = ctdb_ctrl_getrecmaster ( ctdb , ctdb , TIMELIMIT ( ) , options . pnn , & recmaster ) ;
2007-05-17 04:45:31 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get recmaster from node %u \n " , options . pnn ) ) ;
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 ;
}
2009-03-23 11:07:45 +03:00
2009-03-25 05:37:57 +03:00
struct natgw_node {
struct natgw_node * next ;
const char * addr ;
} ;
/*
display the list of nodes belonging to this natgw configuration
*/
static int control_natgwlist ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int i , ret ;
const char * natgw_list ;
int nlines ;
char * * lines ;
struct natgw_node * natgw_nodes = NULL ;
struct natgw_node * natgw_node ;
struct ctdb_node_map * nodemap = NULL ;
/* read the natgw nodes file into a linked list */
natgw_list = getenv ( " NATGW_NODES " ) ;
if ( natgw_list = = NULL ) {
natgw_list = " /etc/ctdb/natgw_nodes " ;
}
lines = file_lines_load ( natgw_list , & nlines , ctdb ) ;
if ( lines = = NULL ) {
ctdb_set_error ( ctdb , " Failed to load natgw node list '%s' \n " , natgw_list ) ;
return - 1 ;
}
while ( nlines > 0 & & strcmp ( lines [ nlines - 1 ] , " " ) = = 0 ) {
nlines - - ;
}
for ( i = 0 ; i < nlines ; i + + ) {
char * node ;
node = lines [ i ] ;
/* strip leading spaces */
while ( ( * node = = ' ' ) | | ( * node = = ' \t ' ) ) {
node + + ;
}
if ( * node = = ' # ' ) {
continue ;
}
if ( strcmp ( node , " " ) = = 0 ) {
continue ;
}
natgw_node = talloc ( ctdb , struct natgw_node ) ;
natgw_node - > addr = talloc_strdup ( natgw_node , node ) ;
2009-05-20 14:08:13 +04:00
CTDB_NO_MEMORY ( ctdb , natgw_node - > addr ) ;
2009-03-25 05:37:57 +03:00
natgw_node - > next = natgw_nodes ;
natgw_nodes = natgw_node ;
}
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE , ctdb , & nodemap ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from local node. \n " ) ) ;
return ret ;
}
i = 0 ;
while ( i < nodemap - > num ) {
for ( natgw_node = natgw_nodes ; natgw_node ; natgw_node = natgw_node - > next ) {
if ( ! strcmp ( natgw_node - > addr , ctdb_addr_to_str ( & nodemap - > nodes [ i ] . addr ) ) ) {
break ;
}
}
/* this node was not in the natgw so we just remove it from
* the list
*/
if ( ( natgw_node = = NULL )
| | ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_DISCONNECTED ) ) {
int j ;
for ( j = i + 1 ; j < nodemap - > num ; j + + ) {
nodemap - > nodes [ j - 1 ] = nodemap - > nodes [ j ] ;
}
nodemap - > num - - ;
continue ;
}
i + + ;
}
2009-07-17 03:29:58 +04:00
/* print the natgw master
* we dont allow STOPPED or DELETED nodes to become the natgwmaster
*/
2009-03-25 05:37:57 +03:00
for ( i = 0 ; i < nodemap - > num ; i + + ) {
2009-07-17 03:29:58 +04:00
if ( ! ( nodemap - > nodes [ i ] . flags & ( NODE_FLAGS_DISCONNECTED | NODE_FLAGS_STOPPED | NODE_FLAGS_DELETED ) ) ) {
2009-07-17 03:45:05 +04:00
printf ( " %d %s \n " , nodemap - > nodes [ i ] . pnn , ctdb_addr_to_str ( & nodemap - > nodes [ i ] . addr ) ) ;
2009-03-25 05:37:57 +03:00
break ;
}
}
2009-07-17 03:36:22 +04:00
/* unless all nodes are STOPPED, when we pick one anyway */
if ( i = = nodemap - > num ) {
for ( i = 0 ; i < nodemap - > num ; i + + ) {
if ( ! ( nodemap - > nodes [ i ] . flags & ( NODE_FLAGS_DISCONNECTED | NODE_FLAGS_DELETED ) ) ) {
2009-07-17 03:45:05 +04:00
printf ( " %d %s \n " , nodemap - > nodes [ i ] . pnn , ctdb_addr_to_str ( & nodemap - > nodes [ i ] . addr ) ) ;
2009-07-17 03:36:22 +04:00
break ;
}
}
/* or if we still can not find any */
if ( i = = nodemap - > num ) {
2009-07-17 03:45:05 +04:00
printf ( " -1 0.0.0.0 \n " ) ;
2009-07-17 03:36:22 +04:00
}
}
2009-03-25 05:37:57 +03:00
/* print the pruned list of nodes belonging to this natgw list */
for ( i = 0 ; i < nodemap - > num ; i + + ) {
2009-06-01 09:43:30 +04:00
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_DELETED ) {
continue ;
}
2009-07-09 05:38:18 +04:00
printf ( " :%d:%s:%d:%d:%d:%d:%d \n " , nodemap - > nodes [ i ] . pnn ,
2009-03-25 05:37:57 +03:00
ctdb_addr_to_str ( & nodemap - > nodes [ i ] . addr ) ,
! ! ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_DISCONNECTED ) ,
! ! ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_BANNED ) ,
! ! ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_PERMANENTLY_DISABLED ) ,
2009-07-09 05:38:18 +04:00
! ! ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_UNHEALTHY ) ,
! ! ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_STOPPED ) ) ;
2009-03-25 05:37:57 +03:00
}
return 0 ;
}
2009-03-23 11:07:45 +03:00
/*
display the status of the monitoring scripts
*/
static int control_scriptstatus ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int i , ret ;
struct ctdb_monitoring_wire * script_status ;
ret = ctdb_ctrl_getscriptstatus ( ctdb , TIMELIMIT ( ) , options . pnn , ctdb , & script_status ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get script status from node %u \n " , options . pnn ) ) ;
return ret ;
}
printf ( " %d scripts were executed last monitoring cycle \n " , script_status - > num_scripts ) ;
for ( i = 0 ; i < script_status - > num_scripts ; i + + ) {
2009-08-13 07:04:08 +04:00
if ( script_status - > scripts [ i ] . disabled ) {
printf ( " %-20s Status:DISABLED \n " ,
script_status - > scripts [ i ] . name ) ;
continue ;
}
2009-03-23 11:07:45 +03:00
printf ( " %-20s Status:%s " ,
script_status - > scripts [ i ] . name ,
script_status - > scripts [ i ] . timedout ? " TIMEDOUT " : script_status - > scripts [ i ] . status = = 0 ? " OK " : " ERROR " ) ;
if ( script_status - > scripts [ i ] . timedout = = 0 ) {
printf ( " Duration:%.3lf " ,
timeval_delta ( & script_status - > scripts [ i ] . finished ,
& script_status - > scripts [ i ] . start ) ) ;
}
printf ( " %s " ,
ctime ( & script_status - > scripts [ i ] . start . tv_sec ) ) ;
if ( ( script_status - > scripts [ i ] . timedout ! = 0 )
| | ( script_status - > scripts [ i ] . status ! = 0 ) ) {
printf ( " OUTPUT:%s \n " ,
script_status - > scripts [ i ] . output ) ;
}
}
return 0 ;
}
2009-08-13 07:04:08 +04:00
/*
enable an eventscript
*/
static int control_enablescript ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
if ( argc < 1 ) {
usage ( ) ;
}
ret = ctdb_ctrl_enablescript ( ctdb , TIMELIMIT ( ) , options . pnn , argv [ 0 ] ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to enable script %s on node %u \n " , argv [ 0 ] , options . pnn ) ) ;
return ret ;
}
return 0 ;
}
/*
disable an eventscript
*/
static int control_disablescript ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
if ( argc < 1 ) {
usage ( ) ;
}
ret = ctdb_ctrl_disablescript ( ctdb , TIMELIMIT ( ) , options . pnn , argv [ 0 ] ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to disable script %s on node %u \n " , argv [ 0 ] , options . pnn ) ) ;
return ret ;
}
return 0 ;
}
2008-09-12 06:06:53 +04:00
/*
display the pnn of the recovery master
*/
static int control_recmaster ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
2008-10-22 04:04:41 +04:00
uint32_t recmaster ;
2008-09-12 06:06:53 +04:00
ret = ctdb_ctrl_getrecmaster ( ctdb , ctdb , TIMELIMIT ( ) , options . pnn , & recmaster ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get recmaster from node %u \n " , options . pnn ) ) ;
return ret ;
}
printf ( " %d \n " , recmaster ) ;
return 0 ;
}
2007-07-20 09:05:55 +04:00
/*
2007-09-04 04:14:41 +04:00
get a list of all tickles for this pnn
2007-07-20 09:05:55 +04:00
*/
static int control_get_tickles ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
struct ctdb_control_tcp_tickle_list * list ;
2008-08-19 08:58:29 +04:00
ctdb_sock_addr addr ;
2007-07-20 09:05:55 +04:00
int i , ret ;
if ( argc < 1 ) {
usage ( ) ;
}
2009-03-24 05:45:11 +03:00
if ( parse_ip ( argv [ 0 ] , NULL , 0 , & addr ) = = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Wrongly formed ip address '%s' \n " , argv [ 0 ] ) ) ;
2007-09-04 03:50:07 +04:00
return - 1 ;
}
2007-07-20 09:05:55 +04:00
2008-08-19 08:58:29 +04:00
ret = ctdb_ctrl_get_tcp_tickles ( ctdb , TIMELIMIT ( ) , options . pnn , ctdb , & addr , & list ) ;
2007-07-20 09:05:55 +04:00
if ( ret = = - 1 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to list tickles \n " ) ) ;
2007-07-20 09:05:55 +04:00
return - 1 ;
}
2008-08-19 08:58:29 +04:00
printf ( " Tickles for ip:%s \n " , ctdb_addr_to_str ( & list - > addr ) ) ;
2007-07-20 09:05:55 +04:00
printf ( " Num tickles:%u \n " , list - > tickles . num ) ;
for ( i = 0 ; i < list - > tickles . num ; i + + ) {
2008-08-19 08:58:29 +04:00
printf ( " SRC: %s:%u " , ctdb_addr_to_str ( & list - > tickles . connections [ i ] . src_addr ) , ntohs ( list - > tickles . connections [ i ] . src_addr . ip . sin_port ) ) ;
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 ) ) ;
2007-07-20 09:05:55 +04:00
}
talloc_free ( list ) ;
return 0 ;
}
2008-04-23 15:05:36 +04:00
2009-10-06 04:41:18 +04:00
static int move_ip ( struct ctdb_context * ctdb , ctdb_sock_addr * addr , uint32_t pnn )
2008-03-04 04:20:23 +03:00
{
struct ctdb_all_public_ips * ips ;
2009-06-09 04:56:50 +04:00
struct ctdb_public_ip ip ;
2008-03-04 04:20:23 +03:00
int i , ret ;
2009-10-06 04:41:18 +04:00
uint32_t * nodes ;
2009-10-06 05:11:32 +04:00
uint32_t disable_time ;
2009-06-09 04:56:50 +04:00
TDB_DATA data ;
struct ctdb_node_map * nodemap = NULL ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
2008-03-04 04:20:23 +03:00
2009-10-06 05:11:32 +04:00
disable_time = 30 ;
data . dptr = ( uint8_t * ) & disable_time ;
data . dsize = sizeof ( disable_time ) ;
ret = ctdb_send_message ( ctdb , CTDB_BROADCAST_CONNECTED , CTDB_SRVID_DISABLE_IP_CHECK , data ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to send message to disable ipcheck \n " ) ) ;
return - 1 ;
}
2008-03-04 04:20:23 +03:00
/* read the public ip list from the node */
ret = ctdb_ctrl_get_public_ips ( ctdb , TIMELIMIT ( ) , pnn , ctdb , & ips ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get public ip list from node %u \n " , pnn ) ) ;
2009-06-09 04:56:50 +04:00
talloc_free ( tmp_ctx ) ;
2008-03-04 04:20:23 +03:00
return - 1 ;
}
for ( i = 0 ; i < ips - > num ; i + + ) {
2009-10-06 04:41:18 +04:00
if ( ctdb_same_ip ( addr , & ips - > ips [ i ] . addr ) ) {
2008-03-04 04:20:23 +03:00
break ;
}
}
if ( i = = ips - > num ) {
DEBUG ( DEBUG_ERR , ( " Node %u can not host ip address '%s' \n " ,
2009-10-06 04:41:18 +04:00
pnn , ctdb_addr_to_str ( addr ) ) ) ;
2009-06-09 04:56:50 +04:00
talloc_free ( tmp_ctx ) ;
2008-03-04 04:20:23 +03:00
return - 1 ;
}
2009-06-09 04:56:50 +04:00
ip . pnn = pnn ;
2009-10-06 04:41:18 +04:00
ip . addr = * addr ;
2009-06-09 04:56:50 +04:00
data . dptr = ( uint8_t * ) & ip ;
data . dsize = sizeof ( ip ) ;
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , options . pnn , tmp_ctx , & nodemap ) ;
2008-04-23 15:05:36 +04:00
if ( ret ! = 0 ) {
2009-06-09 04:56:50 +04:00
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from node %u \n " , options . pnn ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-10-06 04:41:18 +04:00
nodes = list_of_active_nodes_except_pnn ( ctdb , nodemap , tmp_ctx , pnn ) ;
2009-06-09 04:56:50 +04:00
ret = ctdb_client_async_control ( ctdb , CTDB_CONTROL_RELEASE_IP ,
2009-10-12 06:06:16 +04:00
nodes , 0 ,
TIMELIMIT ( ) ,
2009-06-09 04:56:50 +04:00
false , data ,
NULL , NULL ,
NULL ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to release IP on nodes \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
ret = ctdb_ctrl_takeover_ip ( ctdb , TIMELIMIT ( ) , pnn , & ip ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to take over IP on node %d \n " , pnn ) ) ;
talloc_free ( tmp_ctx ) ;
2008-04-23 15:05:36 +04:00
return - 1 ;
}
2008-03-04 04:20:23 +03:00
2009-06-09 04:56:50 +04:00
talloc_free ( tmp_ctx ) ;
2008-04-23 15:05:36 +04:00
return 0 ;
}
2008-03-04 04:20:23 +03:00
2009-10-06 04:41:18 +04:00
/*
move / failover an ip address to a specific node
*/
static int control_moveip ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t pnn ;
ctdb_sock_addr addr ;
if ( argc < 2 ) {
usage ( ) ;
return - 1 ;
}
if ( parse_ip ( argv [ 0 ] , NULL , 0 , & addr ) = = 0 ) {
DEBUG ( DEBUG_ERR , ( " Wrongly formed ip address '%s' \n " , argv [ 0 ] ) ) ;
return - 1 ;
}
if ( sscanf ( argv [ 1 ] , " %u " , & pnn ) ! = 1 ) {
DEBUG ( DEBUG_ERR , ( " Badly formed pnn \n " ) ) ;
return - 1 ;
}
if ( move_ip ( ctdb , & addr , pnn ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to move ip to node %d \n " , pnn ) ) ;
return - 1 ;
}
return 0 ;
}
2008-04-23 15:05:36 +04:00
void getips_store_callback ( void * param , void * data )
{
2008-08-19 08:58:29 +04:00
struct ctdb_public_ip * node_ip = ( struct ctdb_public_ip * ) data ;
2008-04-23 15:05:36 +04:00
struct ctdb_all_public_ips * ips = param ;
int i ;
i = ips - > num + + ;
2008-08-19 08:58:29 +04:00
ips - > ips [ i ] . pnn = node_ip - > pnn ;
ips - > ips [ i ] . addr = node_ip - > addr ;
2008-04-23 15:05:36 +04:00
}
void getips_count_callback ( void * param , void * data )
{
uint32_t * count = param ;
( * count ) + + ;
}
2008-08-22 03:09:08 +04:00
# define IP_KEYLEN 4
static uint32_t * ip_key ( ctdb_sock_addr * ip )
{
static uint32_t key [ IP_KEYLEN ] ;
bzero ( key , sizeof ( key ) ) ;
switch ( ip - > sa . sa_family ) {
case AF_INET :
key [ 0 ] = ip - > ip . sin_addr . s_addr ;
break ;
case AF_INET6 :
key [ 0 ] = ip - > ip6 . sin6_addr . s6_addr32 [ 3 ] ;
key [ 1 ] = ip - > ip6 . sin6_addr . s6_addr32 [ 2 ] ;
key [ 2 ] = ip - > ip6 . sin6_addr . s6_addr32 [ 1 ] ;
key [ 3 ] = ip - > ip6 . sin6_addr . s6_addr32 [ 0 ] ;
break ;
default :
DEBUG ( DEBUG_ERR , ( __location__ " ERROR, unknown family passed :%u \n " , ip - > sa . sa_family ) ) ;
return key ;
}
return key ;
}
static void * add_ip_callback ( void * parm , void * data )
{
return parm ;
}
2008-04-23 15:05:36 +04:00
static int
control_get_all_public_ips ( struct ctdb_context * ctdb , TALLOC_CTX * tmp_ctx , struct ctdb_all_public_ips * * ips )
{
struct ctdb_all_public_ips * tmp_ips ;
struct ctdb_node_map * nodemap = NULL ;
2008-08-22 03:09:08 +04:00
trbt_tree_t * ip_tree ;
2008-04-23 15:05:36 +04:00
int i , j , len , ret ;
uint32_t count ;
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE , tmp_ctx , & nodemap ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from node %u \n " , options . pnn ) ) ;
return ret ;
}
2008-08-22 03:09:08 +04:00
ip_tree = trbt_create ( tmp_ctx , 0 ) ;
2008-04-23 15:05:36 +04:00
for ( i = 0 ; i < nodemap - > num ; i + + ) {
2009-06-01 09:43:30 +04:00
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_DELETED ) {
continue ;
}
2008-04-23 15:05:36 +04:00
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_DISCONNECTED ) {
continue ;
}
/* read the public ip list from this node */
ret = ctdb_ctrl_get_public_ips ( ctdb , TIMELIMIT ( ) , nodemap - > nodes [ i ] . pnn , tmp_ctx , & tmp_ips ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get public ip list from node %u \n " , nodemap - > nodes [ i ] . pnn ) ) ;
return - 1 ;
}
for ( j = 0 ; j < tmp_ips - > num ; j + + ) {
2008-08-19 08:58:29 +04:00
struct ctdb_public_ip * node_ip ;
2008-04-23 15:05:36 +04:00
2008-08-19 08:58:29 +04:00
node_ip = talloc ( tmp_ctx , struct ctdb_public_ip ) ;
node_ip - > pnn = tmp_ips - > ips [ j ] . pnn ;
node_ip - > addr = tmp_ips - > ips [ j ] . addr ;
2008-04-23 15:05:36 +04:00
2008-08-22 03:09:08 +04:00
trbt_insertarray32_callback ( ip_tree ,
IP_KEYLEN , ip_key ( & tmp_ips - > ips [ j ] . addr ) ,
add_ip_callback ,
node_ip ) ;
2008-04-23 15:05:36 +04:00
}
talloc_free ( tmp_ips ) ;
2008-03-04 04:20:23 +03:00
}
2008-04-23 15:05:36 +04:00
/* traverse */
count = 0 ;
2008-08-22 03:09:08 +04:00
trbt_traversearray32 ( ip_tree , IP_KEYLEN , getips_count_callback , & count ) ;
2008-04-23 15:05:36 +04:00
len = offsetof ( struct ctdb_all_public_ips , ips ) +
count * sizeof ( struct ctdb_public_ip ) ;
tmp_ips = talloc_zero_size ( tmp_ctx , len ) ;
2008-08-22 03:09:08 +04:00
trbt_traversearray32 ( ip_tree , IP_KEYLEN , getips_store_callback , tmp_ips ) ;
2008-04-23 15:05:36 +04:00
* ips = tmp_ips ;
2008-03-04 04:20:23 +03:00
return 0 ;
}
2008-04-23 15:05:36 +04:00
2008-04-24 15:51:08 +04:00
/*
* scans all other nodes and returns a pnn for another node that can host this
* ip address or - 1
*/
static int
2008-08-19 08:58:29 +04:00
find_other_host_for_public_ip ( struct ctdb_context * ctdb , ctdb_sock_addr * addr )
2008-04-24 15:51:08 +04:00
{
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
struct ctdb_all_public_ips * ips ;
struct ctdb_node_map * nodemap = NULL ;
int i , j , ret ;
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE , tmp_ctx , & nodemap ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from node %u \n " , options . pnn ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
for ( i = 0 ; i < nodemap - > num ; i + + ) {
2009-06-01 09:43:30 +04:00
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_INACTIVE ) {
2008-04-24 15:51:08 +04:00
continue ;
}
if ( nodemap - > nodes [ i ] . pnn = = options . pnn ) {
continue ;
}
/* read the public ip list from this node */
ret = ctdb_ctrl_get_public_ips ( ctdb , TIMELIMIT ( ) , nodemap - > nodes [ i ] . pnn , tmp_ctx , & ips ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get public ip list from node %u \n " , nodemap - > nodes [ i ] . pnn ) ) ;
return - 1 ;
}
for ( j = 0 ; j < ips - > num ; j + + ) {
2008-08-19 08:58:29 +04:00
if ( ctdb_same_ip ( addr , & ips - > ips [ j ] . addr ) ) {
2008-04-24 15:51:08 +04:00
talloc_free ( tmp_ctx ) ;
return nodemap - > nodes [ i ] . pnn ;
}
}
talloc_free ( ips ) ;
}
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2008-03-27 01:23:27 +03:00
/*
add a public ip address to a node
*/
static int control_addip ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2008-04-23 15:05:36 +04:00
int i , ret ;
2008-03-27 01:23:27 +03:00
int len ;
2009-10-06 04:41:18 +04:00
uint32_t pnn ;
2008-03-27 01:23:27 +03:00
unsigned mask ;
2008-08-19 08:58:29 +04:00
ctdb_sock_addr addr ;
2008-03-27 01:23:27 +03:00
struct ctdb_control_ip_iface * pub ;
2008-04-23 15:05:36 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
struct ctdb_all_public_ips * ips ;
2009-10-06 01:19:25 +04:00
2008-03-27 01:23:27 +03:00
if ( argc ! = 2 ) {
2008-04-23 15:05:36 +04:00
talloc_free ( tmp_ctx ) ;
2008-03-27 01:23:27 +03:00
usage ( ) ;
}
2009-01-19 17:33:24 +03:00
if ( ! parse_ip_mask ( argv [ 0 ] , argv [ 1 ] , & addr , & mask ) ) {
2008-03-27 01:23:27 +03:00
DEBUG ( DEBUG_ERR , ( " Badly formed ip/mask : %s \n " , argv [ 0 ] ) ) ;
2008-04-23 15:05:36 +04:00
talloc_free ( tmp_ctx ) ;
2008-03-27 01:23:27 +03:00
return - 1 ;
}
2008-04-23 15:05:36 +04:00
ret = control_get_all_public_ips ( ctdb , tmp_ctx , & ips ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get public ip list from cluster \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-06-05 11:00:47 +04:00
/* check if some other node is already serving this ip, if not,
* we will claim it
*/
for ( i = 0 ; i < ips - > num ; i + + ) {
if ( ctdb_same_ip ( & addr , & ips - > ips [ i ] . addr ) ) {
break ;
}
}
2008-04-03 09:35:23 +04:00
len = offsetof ( struct ctdb_control_ip_iface , iface ) + strlen ( argv [ 1 ] ) + 1 ;
2008-04-23 15:05:36 +04:00
pub = talloc_size ( tmp_ctx , len ) ;
2008-03-27 01:23:27 +03:00
CTDB_NO_MEMORY ( ctdb , pub ) ;
2008-08-19 08:58:29 +04:00
pub - > addr = addr ;
2008-03-27 01:23:27 +03:00
pub - > mask = mask ;
2008-03-31 05:49:39 +04:00
pub - > len = strlen ( argv [ 1 ] ) + 1 ;
memcpy ( & pub - > iface [ 0 ] , argv [ 1 ] , strlen ( argv [ 1 ] ) + 1 ) ;
2008-03-27 01:23:27 +03:00
ret = ctdb_ctrl_add_public_ip ( ctdb , TIMELIMIT ( ) , options . pnn , pub ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to add public ip to node %u \n " , options . pnn ) ) ;
2008-04-23 15:05:36 +04:00
talloc_free ( tmp_ctx ) ;
2008-03-27 01:23:27 +03:00
return ret ;
}
2009-10-06 01:19:25 +04:00
if ( i = = ips - > num ) {
/* no one has this ip so we claim it */
2009-10-06 04:41:18 +04:00
pnn = options . pnn ;
2009-10-06 01:19:25 +04:00
} else {
2009-10-06 04:41:18 +04:00
pnn = ips - > ips [ i ] . pnn ;
2009-10-06 01:19:25 +04:00
}
2009-06-05 11:00:47 +04:00
2009-10-06 04:41:18 +04:00
if ( move_ip ( ctdb , & addr , pnn ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to move ip to node %d \n " , pnn ) ) ;
2008-04-23 15:05:36 +04:00
return - 1 ;
}
talloc_free ( tmp_ctx ) ;
2008-03-27 01:23:27 +03:00
return 0 ;
}
2008-11-28 01:52:26 +03:00
static int control_delip ( struct ctdb_context * ctdb , int argc , const char * * argv ) ;
static int control_delip_all ( struct ctdb_context * ctdb , int argc , const char * * argv , ctdb_sock_addr * addr )
{
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
struct ctdb_node_map * nodemap = NULL ;
struct ctdb_all_public_ips * ips ;
int ret , i , j ;
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE , tmp_ctx , & nodemap ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from current node \n " ) ) ;
return ret ;
}
/* remove it from the nodes that are not hosting the ip currently */
for ( i = 0 ; i < nodemap - > num ; i + + ) {
2009-06-01 09:43:30 +04:00
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_INACTIVE ) {
2008-11-28 01:52:26 +03:00
continue ;
}
if ( ctdb_ctrl_get_public_ips ( ctdb , TIMELIMIT ( ) , nodemap - > nodes [ i ] . pnn , tmp_ctx , & ips ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get public ip list from node %d \n " , nodemap - > nodes [ i ] . pnn ) ) ;
continue ;
}
for ( j = 0 ; j < ips - > num ; j + + ) {
if ( ctdb_same_ip ( addr , & ips - > ips [ j ] . addr ) ) {
break ;
}
}
if ( j = = ips - > num ) {
continue ;
}
if ( ips - > ips [ j ] . pnn = = nodemap - > nodes [ i ] . pnn ) {
continue ;
}
options . pnn = nodemap - > nodes [ i ] . pnn ;
control_delip ( ctdb , argc , argv ) ;
}
/* remove it from every node (also the one hosting it) */
for ( i = 0 ; i < nodemap - > num ; i + + ) {
2009-06-01 09:43:30 +04:00
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_INACTIVE ) {
2008-11-28 01:52:26 +03:00
continue ;
}
if ( ctdb_ctrl_get_public_ips ( ctdb , TIMELIMIT ( ) , nodemap - > nodes [ i ] . pnn , tmp_ctx , & ips ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get public ip list from node %d \n " , nodemap - > nodes [ i ] . pnn ) ) ;
continue ;
}
for ( j = 0 ; j < ips - > num ; j + + ) {
if ( ctdb_same_ip ( addr , & ips - > ips [ j ] . addr ) ) {
break ;
}
}
if ( j = = ips - > num ) {
continue ;
}
options . pnn = nodemap - > nodes [ i ] . pnn ;
control_delip ( ctdb , argc , argv ) ;
}
talloc_free ( tmp_ctx ) ;
return 0 ;
}
2008-03-27 01:23:27 +03:00
/*
delete a public ip address from a node
*/
static int control_delip ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2008-04-24 15:51:08 +04:00
int i , ret ;
2008-08-19 08:58:29 +04:00
ctdb_sock_addr addr ;
2008-03-27 01:23:27 +03:00
struct ctdb_control_ip_iface pub ;
2008-04-24 15:51:08 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
struct ctdb_all_public_ips * ips ;
2008-03-27 01:23:27 +03:00
if ( argc ! = 1 ) {
2008-04-24 15:51:08 +04:00
talloc_free ( tmp_ctx ) ;
2008-03-27 01:23:27 +03:00
usage ( ) ;
}
2009-03-24 05:45:11 +03:00
if ( parse_ip ( argv [ 0 ] , NULL , 0 , & addr ) = = 0 ) {
2008-03-27 01:23:27 +03:00
DEBUG ( DEBUG_ERR , ( " Wrongly formed ip address '%s' \n " , argv [ 0 ] ) ) ;
return - 1 ;
}
2008-11-28 01:52:26 +03:00
if ( options . pnn = = CTDB_BROADCAST_ALL ) {
return control_delip_all ( ctdb , argc , argv , & addr ) ;
}
2008-08-19 08:58:29 +04:00
pub . addr = addr ;
2008-03-27 01:23:27 +03:00
pub . mask = 0 ;
pub . len = 0 ;
2008-04-24 15:51:08 +04:00
ret = ctdb_ctrl_get_public_ips ( ctdb , TIMELIMIT ( ) , options . pnn , tmp_ctx , & ips ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get public ip list from cluster \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
for ( i = 0 ; i < ips - > num ; i + + ) {
2008-08-19 08:58:29 +04:00
if ( ctdb_same_ip ( & addr , & ips - > ips [ i ] . addr ) ) {
2008-04-24 15:51:08 +04:00
break ;
}
}
if ( i = = ips - > num ) {
DEBUG ( DEBUG_ERR , ( " This node does not support this public address '%s' \n " ,
2008-08-19 08:58:29 +04:00
ctdb_addr_to_str ( & addr ) ) ) ;
2008-04-24 15:51:08 +04:00
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
if ( ips - > ips [ i ] . pnn = = options . pnn ) {
ret = find_other_host_for_public_ip ( ctdb , & addr ) ;
if ( ret ! = - 1 ) {
2009-10-06 04:41:18 +04:00
if ( move_ip ( ctdb , & addr , ret ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to move ip to node %d \n " , ret ) ) ;
2009-06-05 11:57:14 +04:00
return - 1 ;
2008-04-24 15:51:08 +04:00
}
}
}
2008-03-27 01:23:27 +03:00
ret = ctdb_ctrl_del_public_ip ( ctdb , TIMELIMIT ( ) , options . pnn , & pub ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to del public ip from node %u \n " , options . pnn ) ) ;
2008-04-24 15:51:08 +04:00
talloc_free ( tmp_ctx ) ;
2008-03-27 01:23:27 +03:00
return ret ;
}
2008-04-24 15:51:08 +04:00
talloc_free ( tmp_ctx ) ;
2008-03-27 01:23:27 +03: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 )
{
2007-07-12 02:30:04 +04:00
int ret ;
struct ctdb_control_killtcp killtcp ;
2007-07-04 08:14:48 +04:00
2007-07-12 02:30:04 +04:00
if ( argc < 2 ) {
2007-07-04 08:14:48 +04:00
usage ( ) ;
}
2008-08-19 08:58:29 +04:00
if ( ! parse_ip_port ( argv [ 0 ] , & killtcp . src_addr ) ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Bad IP:port '%s' \n " , argv [ 0 ] ) ) ;
2007-07-04 10:51:13 +04:00
return - 1 ;
}
2007-07-04 08:14:48 +04:00
2008-08-19 08:58:29 +04:00
if ( ! parse_ip_port ( argv [ 1 ] , & killtcp . dst_addr ) ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Bad IP:port '%s' \n " , argv [ 1 ] ) ) ;
2007-07-04 10:51:13 +04:00
return - 1 ;
}
2007-07-04 08:14:48 +04:00
2007-09-04 04:14:41 +04:00
ret = ctdb_ctrl_killtcp ( ctdb , TIMELIMIT ( ) , options . pnn , & killtcp ) ;
2007-07-12 02:30:04 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to killtcp from node %u \n " , options . pnn ) ) ;
2007-07-12 02:30:04 +04:00
return ret ;
2007-07-04 08:14:48 +04:00
}
2007-09-13 04:02:56 +04:00
return 0 ;
2007-07-04 08:14:48 +04:00
}
2007-08-24 09:53:41 +04:00
2007-10-09 05:56:09 +04:00
/*
send a gratious arp
*/
static int control_gratious_arp ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
2008-06-04 09:13:00 +04:00
ctdb_sock_addr addr ;
2007-10-09 05:56:09 +04:00
if ( argc < 2 ) {
usage ( ) ;
}
2009-03-24 05:45:11 +03:00
if ( ! parse_ip ( argv [ 0 ] , NULL , 0 , & addr ) ) {
2008-06-04 09:13:00 +04:00
DEBUG ( DEBUG_ERR , ( " Bad IP '%s' \n " , argv [ 0 ] ) ) ;
2007-10-09 05:56:09 +04:00
return - 1 ;
}
2008-06-04 09:13:00 +04:00
ret = ctdb_ctrl_gratious_arp ( ctdb , TIMELIMIT ( ) , options . pnn , & addr , argv [ 1 ] ) ;
2007-10-09 05:56:09 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to send gratious_arp from node %u \n " , options . pnn ) ) ;
2007-10-09 05:56:09 +04:00
return ret ;
}
return 0 ;
}
2007-08-24 09:53:41 +04:00
/*
register a server id
*/
static int regsrvid ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
struct ctdb_server_id server_id ;
if ( argc < 3 ) {
usage ( ) ;
}
2007-09-04 04:21:51 +04:00
server_id . pnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
2007-08-24 09:53:41 +04:00
server_id . type = strtoul ( argv [ 1 ] , NULL , 0 ) ;
server_id . server_id = strtoul ( argv [ 2 ] , NULL , 0 ) ;
ret = ctdb_ctrl_register_server_id ( ctdb , TIMELIMIT ( ) , & server_id ) ;
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to register server_id from node %u \n " , options . pnn ) ) ;
2007-08-24 09:53:41 +04:00
return ret ;
}
return - 1 ;
}
/*
unregister a server id
*/
static int unregsrvid ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
struct ctdb_server_id server_id ;
if ( argc < 3 ) {
usage ( ) ;
}
2007-09-04 04:21:51 +04:00
server_id . pnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
2007-08-24 09:53:41 +04:00
server_id . type = strtoul ( argv [ 1 ] , NULL , 0 ) ;
server_id . server_id = strtoul ( argv [ 2 ] , NULL , 0 ) ;
ret = ctdb_ctrl_unregister_server_id ( ctdb , TIMELIMIT ( ) , & server_id ) ;
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to unregister server_id from node %u \n " , options . pnn ) ) ;
2007-08-24 09:53:41 +04:00
return ret ;
}
return - 1 ;
}
/*
check if a server id exists
*/
static int chksrvid ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t status ;
int ret ;
struct ctdb_server_id server_id ;
if ( argc < 3 ) {
usage ( ) ;
}
2007-09-04 04:21:51 +04:00
server_id . pnn = strtoul ( argv [ 0 ] , NULL , 0 ) ;
2007-08-24 09:53:41 +04:00
server_id . type = strtoul ( argv [ 1 ] , NULL , 0 ) ;
server_id . server_id = strtoul ( argv [ 2 ] , NULL , 0 ) ;
2007-09-04 04:14:41 +04:00
ret = ctdb_ctrl_check_server_id ( ctdb , TIMELIMIT ( ) , options . pnn , & server_id , & status ) ;
2007-08-24 09:53:41 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to check server_id from node %u \n " , options . pnn ) ) ;
2007-08-24 09:53:41 +04:00
return ret ;
}
if ( status ) {
2007-09-04 04:21:51 +04:00
printf ( " Server id %d:%d:%d EXISTS \n " , server_id . pnn , server_id . type , server_id . server_id ) ;
2007-08-24 09:53:41 +04:00
} else {
2007-09-04 04:21:51 +04:00
printf ( " Server id %d:%d:%d does NOT exist \n " , server_id . pnn , server_id . type , server_id . server_id ) ;
2007-08-24 09:53:41 +04:00
}
return 0 ;
}
2007-08-26 04:57:02 +04:00
/*
get a list of all server ids that are registered on a node
*/
static int getsrvids ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int i , ret ;
struct ctdb_server_id_list * server_ids ;
2007-09-04 04:14:41 +04:00
ret = ctdb_ctrl_get_server_id_list ( ctdb , ctdb , TIMELIMIT ( ) , options . pnn , & server_ids ) ;
2007-08-26 04:57:02 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get server_id list from node %u \n " , options . pnn ) ) ;
2007-08-26 04:57:02 +04:00
return ret ;
}
for ( i = 0 ; i < server_ids - > num ; i + + ) {
printf ( " Server id %d:%d:%d \n " ,
2007-09-04 04:21:51 +04:00
server_ids - > server_ids [ i ] . pnn ,
2007-08-26 04:57:02 +04:00
server_ids - > server_ids [ i ] . type ,
server_ids - > server_ids [ i ] . server_id ) ;
}
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 )
{
2008-05-14 09:47:47 +04:00
int ret ;
ctdb_sock_addr src , dst ;
2007-07-05 02:56:02 +04:00
if ( argc < 2 ) {
usage ( ) ;
}
if ( ! parse_ip_port ( argv [ 0 ] , & src ) ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Bad IP:port '%s' \n " , argv [ 0 ] ) ) ;
2007-07-05 02:56:02 +04:00
return - 1 ;
}
if ( ! parse_ip_port ( argv [ 1 ] , & dst ) ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Bad IP:port '%s' \n " , argv [ 1 ] ) ) ;
2007-07-05 02:56:02 +04:00
return - 1 ;
}
2008-05-14 09:47:47 +04:00
ret = ctdb_sys_send_tcp ( & src , & dst , 0 , 0 , 0 ) ;
2007-07-05 02:56:02 +04:00
if ( ret = = 0 ) {
return 0 ;
}
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Error while sending tickle ack \n " ) ) ;
2007-07-05 02:56:02 +04:00
return - 1 ;
}
2007-09-07 10:45:19 +04:00
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 )
{
2007-09-14 09:19:44 +04:00
int i , ret ;
2007-09-07 10:45:19 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
2007-06-04 15:11:51 +04:00
struct ctdb_all_public_ips * ips ;
2008-04-22 18:55:57 +04:00
if ( options . pnn = = CTDB_BROADCAST_ALL ) {
/* read the list of public ips from all nodes */
ret = control_get_all_public_ips ( ctdb , tmp_ctx , & ips ) ;
} else {
/* read the public ip list from this node */
ret = ctdb_ctrl_get_public_ips ( ctdb , TIMELIMIT ( ) , options . pnn , tmp_ctx , & ips ) ;
}
2007-06-04 15:11:51 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get public ips from node %u \n " , options . pnn ) ) ;
2007-09-07 10:45:19 +04:00
talloc_free ( tmp_ctx ) ;
2007-06-04 15:11:51 +04:00
return ret ;
}
2007-09-14 09:23:23 +04:00
if ( options . machinereadable ) {
printf ( " :Public IP:Node: \n " ) ;
} else {
2008-04-22 18:55:57 +04:00
if ( options . pnn = = CTDB_BROADCAST_ALL ) {
printf ( " Public IPs on ALL nodes \n " ) ;
} else {
printf ( " Public IPs on node %u \n " , options . pnn ) ;
}
2007-09-07 10:45:19 +04:00
}
2007-10-17 07:42:42 +04:00
for ( i = 1 ; i < = ips - > num ; i + + ) {
2008-03-04 05:18:27 +03:00
if ( options . machinereadable ) {
2008-08-19 08:58:29 +04:00
printf ( " :%s:%d: \n " , ctdb_addr_to_str ( & ips - > ips [ ips - > num - i ] . addr ) , ips - > ips [ ips - > num - i ] . pnn ) ;
2008-03-04 05:18:27 +03:00
} else {
2008-08-19 08:58:29 +04:00
printf ( " %s %d \n " , ctdb_addr_to_str ( & ips - > ips [ ips - > num - i ] . addr ) , ips - > ips [ ips - > num - i ] . pnn ) ;
2008-03-04 05:18:27 +03:00
}
2007-06-04 15:11:51 +04:00
}
2007-09-07 10:45:19 +04:00
talloc_free ( tmp_ctx ) ;
2007-06-04 15:11:51 +04:00
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-09-04 04:14:41 +04:00
ret = ctdb_ctrl_getpid ( ctdb , TIMELIMIT ( ) , options . pnn , & pid ) ;
2007-05-25 07:05:25 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get daemon pid from node %u \n " , options . pnn ) ) ;
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 ;
}
2009-07-06 05:49:55 +04:00
/*
handler for receiving the response to ipreallocate
*/
static void ip_reallocate_handler ( struct ctdb_context * ctdb , uint64_t srvid ,
TDB_DATA data , void * private_data )
{
exit ( 0 ) ;
}
2009-08-03 06:51:55 +04:00
static void ctdb_every_second ( struct event_context * ev , struct timed_event * te , struct timeval t , void * p )
{
struct ctdb_context * ctdb = talloc_get_type ( p , struct ctdb_context ) ;
event_add_timed ( ctdb - > ev , ctdb ,
timeval_current_ofs ( 1 , 0 ) ,
ctdb_every_second , ctdb ) ;
}
2009-07-06 05:49:55 +04:00
/*
ask the recovery daemon on the recovery master to perform a ip reallocation
*/
static int control_ipreallocate ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2009-08-03 06:51:55 +04:00
int i , ret ;
2009-07-06 05:49:55 +04:00
TDB_DATA data ;
struct rd_memdump_reply rd ;
uint32_t recmaster ;
2009-08-03 06:51:55 +04:00
struct ctdb_node_map * nodemap = NULL ;
int retries = 0 ;
struct timeval tv = timeval_current ( ) ;
/* we need some events to trigger so we can timeout and restart
the loop
*/
event_add_timed ( ctdb - > ev , ctdb ,
timeval_current_ofs ( 1 , 0 ) ,
ctdb_every_second , ctdb ) ;
2009-07-06 05:49:55 +04:00
rd . pnn = ctdb_ctrl_getpnn ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE ) ;
if ( rd . pnn = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " Failed to get pnn of local node \n " ) ) ;
return - 1 ;
}
rd . srvid = getpid ( ) ;
/* register a message port for receiveing the reply so that we
can receive the reply
*/
ctdb_set_message_handler ( ctdb , rd . srvid , ip_reallocate_handler , NULL ) ;
data . dptr = ( uint8_t * ) & rd ;
data . dsize = sizeof ( rd ) ;
2009-08-03 06:51:55 +04:00
again :
if ( retries > 5 ) {
DEBUG ( DEBUG_ERR , ( " Failed waiting for cluster convergense \n " ) ) ;
exit ( 10 ) ;
}
/* check that there are valid nodes available */
if ( ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , options . pnn , ctdb , & nodemap ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from local node \n " ) ) ;
exit ( 10 ) ;
}
for ( i = 0 ; i < nodemap - > num ; i + + ) {
if ( ( nodemap - > nodes [ i ] . flags & ( NODE_FLAGS_DELETED | NODE_FLAGS_BANNED | NODE_FLAGS_STOPPED ) ) = = 0 ) {
break ;
}
}
if ( i = = nodemap - > num ) {
DEBUG ( DEBUG_ERR , ( " No recmaster available, no need to wait for cluster convergence \n " ) ) ;
return 0 ;
}
2009-07-06 05:49:55 +04:00
ret = ctdb_ctrl_getrecmaster ( ctdb , ctdb , TIMELIMIT ( ) , options . pnn , & recmaster ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get recmaster from node %u \n " , options . pnn ) ) ;
return ret ;
}
2009-08-03 06:51:55 +04:00
/* verify the node exists */
if ( ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , recmaster , ctdb , & nodemap ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from local node \n " ) ) ;
exit ( 10 ) ;
}
2009-09-03 20:20:39 +04:00
/* check tha there are nodes available that can act as a recmaster */
for ( i = 0 ; i < nodemap - > num ; i + + ) {
if ( nodemap - > nodes [ i ] . flags & ( NODE_FLAGS_DELETED | NODE_FLAGS_BANNED | NODE_FLAGS_STOPPED ) ) {
continue ;
}
}
if ( i = = nodemap - > num ) {
return 0 ;
}
2009-08-03 06:51:55 +04:00
/* verify the recovery master is not STOPPED, nor BANNED */
if ( nodemap - > nodes [ recmaster ] . flags & ( NODE_FLAGS_DELETED | NODE_FLAGS_BANNED | NODE_FLAGS_STOPPED ) ) {
DEBUG ( DEBUG_ERR , ( " No suitable recmaster found. Try again \n " ) ) ;
retries + + ;
sleep ( 1 ) ;
goto again ;
}
/* verify the recovery master is not STOPPED, nor BANNED */
if ( nodemap - > nodes [ recmaster ] . flags & ( NODE_FLAGS_DELETED | NODE_FLAGS_BANNED | NODE_FLAGS_STOPPED ) ) {
DEBUG ( DEBUG_ERR , ( " No suitable recmaster found. Try again \n " ) ) ;
retries + + ;
sleep ( 1 ) ;
goto again ;
}
2009-07-06 05:49:55 +04:00
ret = ctdb_send_message ( ctdb , recmaster , CTDB_SRVID_TAKEOVER_RUN , data ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to send ip takeover run request message to %u \n " , options . pnn ) ) ;
return - 1 ;
}
2009-08-03 06:51:55 +04:00
tv = timeval_current ( ) ;
2009-07-06 05:49:55 +04:00
/* this loop will terminate when we have received the reply */
2009-08-03 06:51:55 +04:00
while ( timeval_elapsed ( & tv ) < 3.0 ) {
2009-07-06 05:49:55 +04:00
event_loop_once ( ctdb - > ev ) ;
}
2009-08-17 04:56:12 +04:00
DEBUG ( DEBUG_INFO , ( " Timed out waiting for recmaster ipreallocate. Trying again \n " ) ) ;
2009-08-03 06:51:55 +04:00
retries + + ;
sleep ( 1 ) ;
goto again ;
2009-07-06 05:49:55 +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 ;
2009-07-01 03:33:08 +04:00
struct ctdb_node_map * nodemap = NULL ;
2007-06-07 03:16:17 +04:00
2009-07-01 03:33:08 +04:00
do {
ret = ctdb_ctrl_modflags ( ctdb , TIMELIMIT ( ) , options . pnn , NODE_FLAGS_PERMANENTLY_DISABLED , 0 ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to disable node %u \n " , options . pnn ) ) ;
return ret ;
}
sleep ( 1 ) ;
/* read the nodemap and verify the change took effect */
if ( ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE , ctdb , & nodemap ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from local node \n " ) ) ;
exit ( 10 ) ;
}
} while ( ! ( nodemap - > nodes [ options . pnn ] . flags & NODE_FLAGS_PERMANENTLY_DISABLED ) ) ;
2009-07-06 05:49:55 +04:00
ret = control_ipreallocate ( ctdb , argc , argv ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " IP Reallocate failed on node %u \n " , options . pnn ) ) ;
return ret ;
}
2007-06-07 03:16:17 +04:00
return 0 ;
}
/*
enable a disabled remote node
*/
static int control_enable ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
2009-07-01 03:33:08 +04:00
struct ctdb_node_map * nodemap = NULL ;
do {
ret = ctdb_ctrl_modflags ( ctdb , TIMELIMIT ( ) , options . pnn , 0 , NODE_FLAGS_PERMANENTLY_DISABLED ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to enable node %u \n " , options . pnn ) ) ;
return ret ;
}
sleep ( 1 ) ;
/* read the nodemap and verify the change took effect */
if ( ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE , ctdb , & nodemap ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from local node \n " ) ) ;
exit ( 10 ) ;
}
} while ( nodemap - > nodes [ options . pnn ] . flags & NODE_FLAGS_PERMANENTLY_DISABLED ) ;
2009-07-06 05:49:55 +04:00
ret = control_ipreallocate ( ctdb , argc , argv ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " IP Reallocate failed on node %u \n " , options . pnn ) ) ;
return ret ;
}
2007-06-07 03:16:17 +04:00
return 0 ;
}
2009-07-09 05:38:18 +04:00
/*
stop a remote node
*/
static int control_stop ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
struct ctdb_node_map * nodemap = NULL ;
do {
2009-07-09 06:22:46 +04:00
ret = ctdb_ctrl_stop_node ( ctdb , TIMELIMIT ( ) , options . pnn ) ;
2009-07-09 05:38:18 +04:00
if ( ret ! = 0 ) {
2009-07-29 03:58:40 +04:00
DEBUG ( DEBUG_ERR , ( " Unable to stop node %u try again \n " , options . pnn ) ) ;
2009-07-09 05:38:18 +04:00
}
2009-07-09 06:22:46 +04:00
2009-07-09 05:38:18 +04:00
sleep ( 1 ) ;
/* read the nodemap and verify the change took effect */
if ( ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE , ctdb , & nodemap ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from local node \n " ) ) ;
exit ( 10 ) ;
}
} while ( ! ( nodemap - > nodes [ options . pnn ] . flags & NODE_FLAGS_STOPPED ) ) ;
ret = control_ipreallocate ( ctdb , argc , argv ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " IP Reallocate failed on node %u \n " , options . pnn ) ) ;
return ret ;
}
return 0 ;
}
/*
restart a stopped remote node
*/
static int control_continue ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
struct ctdb_node_map * nodemap = NULL ;
do {
2009-07-09 06:22:46 +04:00
ret = ctdb_ctrl_continue_node ( ctdb , TIMELIMIT ( ) , options . pnn ) ;
2009-07-09 05:38:18 +04:00
if ( ret ! = 0 ) {
2009-07-09 06:22:46 +04:00
DEBUG ( DEBUG_ERR , ( " Unable to continue node %u \n " , options . pnn ) ) ;
2009-07-09 05:38:18 +04:00
return ret ;
}
2009-07-09 06:22:46 +04:00
2009-07-09 05:38:18 +04:00
sleep ( 1 ) ;
/* read the nodemap and verify the change took effect */
if ( ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE , ctdb , & nodemap ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from local node \n " ) ) ;
exit ( 10 ) ;
}
} while ( nodemap - > nodes [ options . pnn ] . flags & NODE_FLAGS_STOPPED ) ;
ret = control_ipreallocate ( ctdb , argc , argv ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " IP Reallocate failed on node %u \n " , options . pnn ) ) ;
return ret ;
}
return 0 ;
}
2008-12-09 04:03:42 +03:00
static uint32_t get_generation ( struct ctdb_context * ctdb )
{
struct ctdb_vnn_map * vnnmap = NULL ;
int ret ;
/* wait until the recmaster is not in recovery mode */
while ( 1 ) {
uint32_t recmode , recmaster ;
if ( vnnmap ! = NULL ) {
talloc_free ( vnnmap ) ;
vnnmap = NULL ;
}
/* get the recmaster */
ret = ctdb_ctrl_getrecmaster ( ctdb , ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE , & recmaster ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get recmaster from node %u \n " , options . pnn ) ) ;
exit ( 10 ) ;
}
/* get recovery mode */
ret = ctdb_ctrl_getrecmode ( ctdb , ctdb , TIMELIMIT ( ) , recmaster , & recmode ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get recmode from node %u \n " , options . pnn ) ) ;
exit ( 10 ) ;
}
/* get the current generation number */
ret = ctdb_ctrl_getvnnmap ( ctdb , TIMELIMIT ( ) , recmaster , ctdb , & vnnmap ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get vnnmap from recmaster (%u) \n " , recmaster ) ) ;
exit ( 10 ) ;
}
if ( ( recmode = = CTDB_RECOVERY_NORMAL )
& & ( vnnmap - > generation ! = 1 ) ) {
return vnnmap - > generation ;
}
sleep ( 1 ) ;
}
}
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 ;
2008-12-09 04:03:42 +03:00
struct ctdb_node_map * nodemap = NULL ;
2009-09-03 20:20:39 +04:00
struct ctdb_ban_time bantime ;
2007-06-07 10:34:33 +04:00
if ( argc < 1 ) {
usage ( ) ;
}
2008-12-09 04:03:42 +03:00
/* verify the node exists */
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE , ctdb , & nodemap ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from local node \n " ) ) ;
return ret ;
}
2008-10-14 18:23:57 +04:00
2008-12-09 04:03:42 +03:00
if ( nodemap - > nodes [ options . pnn ] . flags & NODE_FLAGS_BANNED ) {
DEBUG ( DEBUG_ERR , ( " Node %u is already banned. \n " , options . pnn ) ) ;
return - 1 ;
}
2009-09-03 20:20:39 +04:00
bantime . pnn = options . pnn ;
bantime . time = strtoul ( argv [ 0 ] , NULL , 0 ) ;
2007-06-07 10:34:33 +04:00
2009-09-03 20:20:39 +04:00
ret = ctdb_ctrl_set_ban ( ctdb , TIMELIMIT ( ) , options . pnn , & bantime ) ;
2007-06-07 10:34:33 +04:00
if ( ret ! = 0 ) {
2009-09-03 20:20:39 +04:00
DEBUG ( DEBUG_ERR , ( " Banning node %d for %d seconds failed. \n " , bantime . pnn , bantime . time ) ) ;
2007-06-07 10:34:33 +04:00
return - 1 ;
2009-09-03 20:20:39 +04:00
}
2008-12-09 04:03:42 +03:00
2009-09-03 20:20:39 +04:00
ret = control_ipreallocate ( ctdb , argc , argv ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " IP Reallocate failed on node %u \n " , options . pnn ) ) ;
return ret ;
2008-12-09 04:03:42 +03:00
}
2007-06-07 10:34:33 +04:00
return 0 ;
}
/*
unban a node from the cluster
*/
static int control_unban ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
2009-05-12 12:32:41 +04:00
struct ctdb_node_map * nodemap = NULL ;
2009-09-03 20:20:39 +04:00
struct ctdb_ban_time bantime ;
2008-12-09 04:03:42 +03:00
2009-09-03 20:20:39 +04:00
/* verify the node exists */
2009-05-12 12:32:41 +04:00
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE , ctdb , & nodemap ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from local node \n " ) ) ;
return ret ;
}
if ( ! ( nodemap - > nodes [ options . pnn ] . flags & NODE_FLAGS_BANNED ) ) {
2009-09-03 20:20:39 +04:00
DEBUG ( DEBUG_ERR , ( " Node %u is not banned. \n " , options . pnn ) ) ;
2009-05-12 12:32:41 +04:00
return - 1 ;
}
2009-09-03 20:20:39 +04:00
bantime . pnn = options . pnn ;
bantime . time = 0 ;
ret = ctdb_ctrl_set_ban ( ctdb , TIMELIMIT ( ) , options . pnn , & bantime ) ;
2007-06-07 10:34:33 +04:00
if ( ret ! = 0 ) {
2009-09-03 20:20:39 +04:00
DEBUG ( DEBUG_ERR , ( " Unbanning node %d failed. \n " , bantime . pnn ) ) ;
2007-06-07 10:34:33 +04:00
return - 1 ;
2009-09-03 20:20:39 +04:00
}
ret = control_ipreallocate ( ctdb , argc , argv ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " IP Reallocate failed on node %u \n " , options . pnn ) ) ;
return ret ;
2008-12-09 04:03:42 +03:00
}
2007-06-07 10:34:33 +04:00
return 0 ;
}
2009-09-03 20:20:39 +04:00
/*
show ban information for a node
*/
static int control_showban ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
struct ctdb_node_map * nodemap = NULL ;
struct ctdb_ban_time * bantime ;
/* verify the node exists */
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE , ctdb , & nodemap ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from local node \n " ) ) ;
return ret ;
}
ret = ctdb_ctrl_get_ban ( ctdb , TIMELIMIT ( ) , options . pnn , ctdb , & bantime ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Showing ban info for node %d failed. \n " , options . pnn ) ) ;
return - 1 ;
}
if ( bantime - > time = = 0 ) {
printf ( " Node %u is not banned \n " , bantime - > pnn ) ;
} else {
printf ( " Node %u is banned banned for %d seconds \n " , bantime - > pnn , bantime - > time ) ;
}
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-09-04 04:14:41 +04:00
ret = ctdb_ctrl_shutdown ( ctdb , TIMELIMIT ( ) , options . pnn ) ;
2007-05-25 07:05:25 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to shutdown node %u \n " , options . pnn ) ) ;
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 ;
2008-12-10 04:06:51 +03:00
uint32_t generation , next_generation ;
/* record the current generation number */
generation = get_generation ( ctdb ) ;
2007-05-24 02:08:45 +04:00
2009-10-12 06:06:16 +04:00
ret = ctdb_ctrl_freeze_priority ( ctdb , TIMELIMIT ( ) , options . pnn , 1 ) ;
2007-05-24 02:08:45 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to freeze node \n " ) ) ;
2007-05-24 02:08:45 +04:00
return ret ;
}
2007-04-29 16:51:56 +04:00
2007-09-04 04:14:41 +04:00
ret = ctdb_ctrl_setrecmode ( ctdb , TIMELIMIT ( ) , options . pnn , CTDB_RECOVERY_ACTIVE ) ;
2007-04-29 16:51:56 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to set recovery mode \n " ) ) ;
2007-04-29 16:51:56 +04:00
return ret ;
}
2008-12-10 04:06:51 +03:00
/* wait until we are in a new generation */
while ( 1 ) {
next_generation = get_generation ( ctdb ) ;
if ( next_generation ! = generation ) {
return 0 ;
}
sleep ( 1 ) ;
}
2007-04-29 16:51:56 +04:00
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-09-04 04:14:41 +04:00
ret = ctdb_ctrl_getmonmode ( ctdb , TIMELIMIT ( ) , options . pnn , & monmode ) ;
2007-05-21 03:24:34 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get monmode from node %u \n " , options . pnn ) ) ;
2007-05-21 03:24:34 +04:00
return ret ;
}
2008-05-16 03:21:44 +04:00
if ( ! options . machinereadable ) {
printf ( " Monitoring mode:%s (%d) \n " , monmode = = CTDB_MONITORING_ACTIVE ? " ACTIVE " : " DISABLED " , monmode ) ;
} else {
printf ( " :mode: \n " ) ;
printf ( " :%d: \n " , monmode ) ;
}
2007-05-21 03:24:34 +04:00
return 0 ;
}
2008-03-25 00:27:38 +03:00
2008-05-06 04:02:27 +04:00
/*
display capabilities of a remote node
*/
static int control_getcapabilities ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t capabilities ;
int ret ;
ret = ctdb_ctrl_getcapabilities ( ctdb , TIMELIMIT ( ) , options . pnn , & capabilities ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get capabilities from node %u \n " , options . pnn ) ) ;
return ret ;
}
if ( ! options . machinereadable ) {
printf ( " RECMASTER: %s \n " , ( capabilities & CTDB_CAP_RECMASTER ) ? " YES " : " NO " ) ;
printf ( " LMASTER: %s \n " , ( capabilities & CTDB_CAP_LMASTER ) ? " YES " : " NO " ) ;
2008-07-10 04:37:22 +04:00
printf ( " LVS: %s \n " , ( capabilities & CTDB_CAP_LVS ) ? " YES " : " NO " ) ;
2009-07-28 03:58:11 +04:00
printf ( " NATGW: %s \n " , ( capabilities & CTDB_CAP_NATGW ) ? " YES " : " NO " ) ;
2008-05-06 04:02:27 +04:00
} else {
2009-07-28 03:58:11 +04:00
printf ( " :RECMASTER:LMASTER:LVS:NATGW: \n " ) ;
printf ( " :%d:%d:%d:%d: \n " ,
2008-05-06 04:02:27 +04:00
! ! ( capabilities & CTDB_CAP_RECMASTER ) ,
2008-07-10 04:37:22 +04:00
! ! ( capabilities & CTDB_CAP_LMASTER ) ,
2009-07-28 03:58:11 +04:00
! ! ( capabilities & CTDB_CAP_LVS ) ,
! ! ( capabilities & CTDB_CAP_NATGW ) ) ;
2008-05-06 04:02:27 +04:00
}
return 0 ;
}
2008-07-10 05:12:58 +04:00
/*
display lvs configuration
*/
static int control_lvs ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t * capabilities ;
struct ctdb_node_map * nodemap = NULL ;
int i , ret ;
int healthy_count = 0 ;
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , options . pnn , ctdb , & nodemap ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from node %u \n " , options . pnn ) ) ;
return ret ;
}
capabilities = talloc_array ( ctdb , uint32_t , nodemap - > num ) ;
CTDB_NO_MEMORY ( ctdb , capabilities ) ;
/* collect capabilities for all connected nodes */
for ( i = 0 ; i < nodemap - > num ; i + + ) {
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_INACTIVE ) {
continue ;
}
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_PERMANENTLY_DISABLED ) {
continue ;
}
ret = ctdb_ctrl_getcapabilities ( ctdb , TIMELIMIT ( ) , i , & capabilities [ i ] ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get capabilities from node %u \n " , i ) ) ;
return ret ;
}
if ( ! ( capabilities [ i ] & CTDB_CAP_LVS ) ) {
continue ;
}
if ( ! ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_UNHEALTHY ) ) {
healthy_count + + ;
}
}
/* Print all LVS nodes */
for ( i = 0 ; i < nodemap - > num ; i + + ) {
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_INACTIVE ) {
continue ;
}
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_PERMANENTLY_DISABLED ) {
continue ;
}
if ( ! ( capabilities [ i ] & CTDB_CAP_LVS ) ) {
continue ;
}
if ( healthy_count ! = 0 ) {
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_UNHEALTHY ) {
continue ;
}
}
2008-08-19 08:58:29 +04:00
printf ( " %d:%s \n " , i ,
ctdb_addr_to_str ( & nodemap - > nodes [ i ] . addr ) ) ;
2008-07-10 05:12:58 +04:00
}
return 0 ;
}
/*
display who is the lvs master
*/
static int control_lvsmaster ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t * capabilities ;
struct ctdb_node_map * nodemap = NULL ;
int i , ret ;
int healthy_count = 0 ;
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , options . pnn , ctdb , & nodemap ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from node %u \n " , options . pnn ) ) ;
return ret ;
}
capabilities = talloc_array ( ctdb , uint32_t , nodemap - > num ) ;
CTDB_NO_MEMORY ( ctdb , capabilities ) ;
/* collect capabilities for all connected nodes */
for ( i = 0 ; i < nodemap - > num ; i + + ) {
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_INACTIVE ) {
continue ;
}
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_PERMANENTLY_DISABLED ) {
continue ;
}
ret = ctdb_ctrl_getcapabilities ( ctdb , TIMELIMIT ( ) , i , & capabilities [ i ] ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get capabilities from node %u \n " , i ) ) ;
return ret ;
}
if ( ! ( capabilities [ i ] & CTDB_CAP_LVS ) ) {
continue ;
}
if ( ! ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_UNHEALTHY ) ) {
healthy_count + + ;
}
}
/* find and show the lvsmaster */
for ( i = 0 ; i < nodemap - > num ; i + + ) {
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_INACTIVE ) {
continue ;
}
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_PERMANENTLY_DISABLED ) {
continue ;
}
if ( ! ( capabilities [ i ] & CTDB_CAP_LVS ) ) {
continue ;
}
if ( healthy_count ! = 0 ) {
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_UNHEALTHY ) {
continue ;
}
}
2009-05-11 08:44:59 +04:00
if ( options . machinereadable ) {
printf ( " %d \n " , i ) ;
} else {
printf ( " Node %d is LVS master \n " , i ) ;
}
2008-07-10 05:12:58 +04:00
return 0 ;
}
printf ( " There is no LVS master \n " ) ;
2009-05-11 07:56:28 +04:00
return - 1 ;
2008-07-10 05:12:58 +04:00
}
2008-03-25 00:27:38 +03:00
/*
disable monitoring on a node
*/
static int control_disable_monmode ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
ret = ctdb_ctrl_disable_monmode ( ctdb , TIMELIMIT ( ) , options . pnn ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to disable monmode on node %u \n " , options . pnn ) ) ;
return ret ;
}
printf ( " Monitoring mode:%s \n " , " DISABLED " ) ;
return 0 ;
}
/*
enable monitoring on a node
*/
static int control_enable_monmode ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
ret = ctdb_ctrl_enable_monmode ( ctdb , TIMELIMIT ( ) , options . pnn ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to enable monmode on node %u \n " , options . pnn ) ) ;
return ret ;
}
printf ( " Monitoring mode:%s \n " , " ACTIVE " ) ;
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 ] ;
2008-09-22 19:38:28 +04:00
if ( db_exists ( ctdb , db_name ) ) {
DEBUG ( DEBUG_ERR , ( " Database '%s' does not exist \n " , db_name ) ) ;
return - 1 ;
}
2008-06-04 04:46:20 +04:00
ctdb_db = ctdb_attach ( ctdb , db_name , false , 0 ) ;
2007-05-29 06:16:59 +04:00
2007-05-04 06:18:39 +04:00
if ( ctdb_db = = NULL ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " 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 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to dump database \n " ) ) ;
2007-05-29 06:16:59 +04:00
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-09-04 04:14:41 +04:00
ret = ctdb_ctrl_getdbmap ( ctdb , TIMELIMIT ( ) , options . pnn , ctdb , & dbmap ) ;
2007-04-28 14:00:50 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get dbids from node %u \n " , options . pnn ) ) ;
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-09-21 06:24:02 +04:00
bool persistent ;
2007-04-28 14:00:50 +04:00
2007-09-21 06:24:02 +04:00
ctdb_ctrl_getdbpath ( ctdb , TIMELIMIT ( ) , options . pnn , dbmap - > dbs [ i ] . dbid , ctdb , & path ) ;
ctdb_ctrl_getdbname ( ctdb , TIMELIMIT ( ) , options . pnn , dbmap - > dbs [ i ] . dbid , ctdb , & name ) ;
persistent = dbmap - > dbs [ i ] . persistent ;
printf ( " dbid:0x%08x name:%s path:%s %s \n " , dbmap - > dbs [ i ] . dbid , name ,
path , persistent ? " PERSISTENT " : " " ) ;
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-10-08 03:47:20 +04:00
/*
check if the local node is recmaster or not
it will return 1 if this node is the recmaster and 0 if it is not
or if the local ctdb daemon could not be contacted
*/
static int control_isnotrecmaster ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t mypnn , recmaster ;
int ret ;
mypnn = ctdb_ctrl_getpnn ( ctdb , TIMELIMIT ( ) , options . pnn ) ;
if ( mypnn = = - 1 ) {
printf ( " Failed to get pnn of node \n " ) ;
return 1 ;
}
ret = ctdb_ctrl_getrecmaster ( ctdb , ctdb , TIMELIMIT ( ) , options . pnn , & recmaster ) ;
if ( ret ! = 0 ) {
printf ( " Failed to get the recmaster \n " ) ;
return 1 ;
}
if ( recmaster ! = mypnn ) {
printf ( " this node is not the recmaster \n " ) ;
return 1 ;
}
printf ( " this node is the recmaster \n " ) ;
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 ( ) ;
2007-09-04 04:14:41 +04:00
ret = ctdb_ctrl_ping ( ctdb , options . pnn ) ;
2007-06-11 16:25:26 +04:00
if ( ret = = - 1 ) {
2007-09-04 04:14:41 +04:00
printf ( " Unable to get ping response from node %u \n " , options . pnn ) ;
2008-12-08 04:57:40 +03:00
return - 1 ;
2007-06-11 16:25:26 +04:00
} else {
printf ( " response from %u time=%.6f sec (%d clients) \n " ,
2007-09-04 04:14:41 +04:00
options . pnn , 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 ] ;
2007-09-04 04:14:41 +04:00
ret = ctdb_ctrl_get_tunable ( ctdb , TIMELIMIT ( ) , options . pnn , name , & value ) ;
2007-06-04 13:53:19 +04:00
if ( ret = = - 1 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get tunable variable '%s' \n " , name ) ) ;
2007-06-04 13:53:19 +04:00
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 ) ;
2007-09-04 04:14:41 +04:00
ret = ctdb_ctrl_set_tunable ( ctdb , TIMELIMIT ( ) , options . pnn , name , value ) ;
2007-06-04 13:53:19 +04:00
if ( ret = = - 1 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to set tunable variable '%s' \n " , name ) ) ;
2007-06-04 13:53:19 +04:00
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 ;
2007-09-04 04:14:41 +04:00
ret = ctdb_ctrl_list_tunables ( ctdb , TIMELIMIT ( ) , options . pnn , ctdb , & list , & count ) ;
2007-06-04 13:53:19 +04:00
if ( ret = = - 1 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to list tunable variables \n " ) ) ;
2007-06-04 13:53:19 +04:00
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 ;
2008-02-05 02:26:23 +03:00
int32_t level ;
2007-04-28 19:42:40 +04:00
2007-09-04 04:14:41 +04:00
ret = ctdb_ctrl_get_debuglevel ( ctdb , options . pnn , & level ) ;
2007-06-11 16:25:26 +04:00
if ( ret ! = 0 ) {
2008-03-04 05:23:06 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get debuglevel response from node %u \n " , options . pnn ) ) ;
return ret ;
2007-06-11 16:25:26 +04:00
} else {
2008-03-04 05:23:06 +03:00
if ( options . machinereadable ) {
printf ( " :Name:Level: \n " ) ;
printf ( " :%s:%d: \n " , get_debug_by_level ( level ) , level ) ;
} else {
2008-05-29 02:19:35 +04:00
printf ( " Node %u is at debug level %s (%d) \n " , options . pnn , get_debug_by_level ( level ) , level ) ;
2008-03-04 05:23:06 +03:00
}
2007-04-27 17:14:36 +04:00
}
return 0 ;
}
2009-06-25 06:17:19 +04:00
/*
display reclock file of a node
*/
static int control_getreclock ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
const char * reclock ;
ret = ctdb_ctrl_getreclock ( ctdb , TIMELIMIT ( ) , options . pnn , ctdb , & reclock ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get reclock file from node %u \n " , options . pnn ) ) ;
return ret ;
} else {
2009-09-28 07:39:54 +04:00
if ( options . machinereadable ) {
if ( reclock ! = NULL ) {
printf ( " %s " , reclock ) ;
}
2009-06-25 06:17:19 +04:00
} else {
2009-09-28 07:39:54 +04:00
if ( reclock = = NULL ) {
printf ( " No reclock file used. \n " ) ;
} else {
printf ( " Reclock file:%s \n " , reclock ) ;
}
2009-06-25 06:17:19 +04:00
}
}
return 0 ;
}
2007-05-29 06:16:59 +04:00
2009-06-25 08:25:18 +04:00
/*
set the reclock file of a node
*/
static int control_setreclock ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
const char * reclock ;
if ( argc = = 0 ) {
reclock = NULL ;
} else if ( argc = = 1 ) {
reclock = argv [ 0 ] ;
} else {
usage ( ) ;
}
ret = ctdb_ctrl_setreclock ( ctdb , TIMELIMIT ( ) , options . pnn , reclock ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get reclock file from node %u \n " , options . pnn ) ) ;
return ret ;
}
return 0 ;
}
2009-07-28 03:58:11 +04:00
/*
2009-07-28 07:45:13 +04:00
set the natgw state on / off
2009-07-28 03:58:11 +04:00
*/
static int control_setnatgwstate ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
uint32_t natgwstate ;
if ( argc = = 0 ) {
usage ( ) ;
}
if ( ! strcmp ( argv [ 0 ] , " on " ) ) {
natgwstate = 1 ;
} else if ( ! strcmp ( argv [ 0 ] , " off " ) ) {
natgwstate = 0 ;
} else {
usage ( ) ;
}
ret = ctdb_ctrl_setnatgwstate ( ctdb , TIMELIMIT ( ) , options . pnn , natgwstate ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to set the natgw state for node %u \n " , options . pnn ) ) ;
return ret ;
}
return 0 ;
}
2009-07-28 07:45:13 +04:00
/*
set the lmaster role on / off
*/
static int control_setlmasterrole ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
uint32_t lmasterrole ;
if ( argc = = 0 ) {
usage ( ) ;
}
if ( ! strcmp ( argv [ 0 ] , " on " ) ) {
lmasterrole = 1 ;
} else if ( ! strcmp ( argv [ 0 ] , " off " ) ) {
lmasterrole = 0 ;
} else {
usage ( ) ;
}
ret = ctdb_ctrl_setlmasterrole ( ctdb , TIMELIMIT ( ) , options . pnn , lmasterrole ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to set the lmaster role for node %u \n " , options . pnn ) ) ;
return ret ;
}
return 0 ;
}
/*
set the recmaster role on / off
*/
static int control_setrecmasterrole ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
uint32_t recmasterrole ;
if ( argc = = 0 ) {
usage ( ) ;
}
if ( ! strcmp ( argv [ 0 ] , " on " ) ) {
recmasterrole = 1 ;
} else if ( ! strcmp ( argv [ 0 ] , " off " ) ) {
recmasterrole = 0 ;
} else {
usage ( ) ;
}
ret = ctdb_ctrl_setrecmasterrole ( ctdb , TIMELIMIT ( ) , options . pnn , recmasterrole ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to set the recmaster role for node %u \n " , options . pnn ) ) ;
return ret ;
}
return 0 ;
}
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
{
2009-07-01 02:26:00 +04:00
int i , ret ;
2008-11-28 03:29:43 +03:00
int32_t level ;
2007-04-27 17:14:36 +04:00
2009-07-01 02:26:00 +04:00
if ( argc = = 0 ) {
printf ( " You must specify the debug level. Valid levels are: \n " ) ;
2009-07-01 03:17:13 +04:00
for ( i = 0 ; debug_levels [ i ] . description ! = NULL ; i + + ) {
2009-07-01 02:26:00 +04:00
printf ( " %s (%d) \n " , debug_levels [ i ] . description , debug_levels [ i ] . level ) ;
}
return 0 ;
2007-04-27 17:14:36 +04:00
}
2009-07-01 02:26:00 +04:00
if ( isalpha ( argv [ 0 ] [ 0 ] ) | | argv [ 0 ] [ 0 ] = = ' - ' ) {
2008-02-05 02:26:23 +03:00
level = get_debug_by_desc ( argv [ 0 ] ) ;
} else {
2008-11-28 03:29:43 +03:00
level = strtol ( argv [ 0 ] , NULL , 0 ) ;
2008-02-05 02:26:23 +03:00
}
2007-04-27 17:14:36 +04:00
2009-07-01 03:17:13 +04:00
for ( i = 0 ; debug_levels [ i ] . description ! = NULL ; i + + ) {
2009-07-01 02:26:00 +04:00
if ( level = = debug_levels [ i ] . level ) {
break ;
}
}
2009-07-01 03:17:13 +04:00
if ( debug_levels [ i ] . description = = NULL ) {
2009-07-01 03:21:07 +04:00
printf ( " Invalid debug level, must be one of \n " ) ;
for ( i = 0 ; debug_levels [ i ] . description ! = NULL ; i + + ) {
printf ( " %s (%d) \n " , debug_levels [ i ] . description , debug_levels [ i ] . level ) ;
}
2009-07-01 02:26:00 +04:00
return - 1 ;
}
2007-09-04 04:14:41 +04:00
ret = ctdb_ctrl_set_debuglevel ( ctdb , options . pnn , level ) ;
2007-06-11 16:25:26 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to set debug level on node %u \n " , options . pnn ) ) ;
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 ;
2009-10-12 02:22:17 +04:00
uint32_t priority ;
if ( argc = = 1 ) {
priority = strtol ( argv [ 0 ] , NULL , 0 ) ;
} else {
priority = 0 ;
}
DEBUG ( DEBUG_ERR , ( " Freeze by priority %u \n " , priority ) ) ;
2007-05-12 09:15:27 +04:00
2009-10-12 02:22:17 +04:00
ret = ctdb_ctrl_freeze_priority ( ctdb , TIMELIMIT ( ) , options . pnn , priority ) ;
2007-06-11 16:25:26 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to freeze node %u \n " , options . pnn ) ) ;
2007-06-11 16:25:26 +04:00
}
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 ;
2009-10-12 02:22:17 +04:00
uint32_t priority ;
if ( argc = = 1 ) {
priority = strtol ( argv [ 0 ] , NULL , 0 ) ;
} else {
priority = 0 ;
}
DEBUG ( DEBUG_ERR , ( " Thaw by priority %u \n " , priority ) ) ;
2007-05-12 09:15:27 +04:00
2009-10-12 02:22:17 +04:00
ret = ctdb_ctrl_thaw_priority ( ctdb , TIMELIMIT ( ) , options . pnn , priority ) ;
2007-06-11 16:25:26 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to thaw node %u \n " , options . pnn ) ) ;
2007-06-11 16:25:26 +04:00
}
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 ] ;
2008-06-04 04:46:20 +04:00
ctdb_db = ctdb_attach ( ctdb , db_name , false , 0 ) ;
2007-04-30 17:54:06 +04:00
if ( ctdb_db = = NULL ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to attach to database '%s' \n " , db_name ) ) ;
2007-04-30 17:54:06 +04:00
return - 1 ;
}
return 0 ;
}
2009-10-10 07:26:09 +04:00
/*
set db priority
*/
static int control_setdbprio ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
struct ctdb_db_priority db_prio ;
int ret ;
if ( argc < 2 ) {
usage ( ) ;
}
db_prio . db_id = strtoul ( argv [ 0 ] , NULL , 0 ) ;
db_prio . priority = strtoul ( argv [ 1 ] , NULL , 0 ) ;
ret = ctdb_ctrl_set_db_priority ( ctdb , TIMELIMIT ( ) , options . pnn , & db_prio ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to set db prio \n " ) ) ;
return - 1 ;
}
return 0 ;
}
2009-10-10 08:04:18 +04:00
/*
get db priority
*/
static int control_getdbprio ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t db_id , priority ;
int ret ;
if ( argc < 1 ) {
usage ( ) ;
}
db_id = strtoul ( argv [ 0 ] , NULL , 0 ) ;
ret = ctdb_ctrl_get_db_priority ( ctdb , TIMELIMIT ( ) , options . pnn , db_id , & priority ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get db prio \n " ) ) ;
return - 1 ;
}
DEBUG ( DEBUG_ERR , ( " Priority:%u \n " , priority ) ) ;
return 0 ;
}
2008-04-02 04:13:30 +04:00
/*
2008-08-13 16:03:29 +04:00
run an eventscript on a node
2008-04-02 04:13:30 +04:00
*/
static int control_eventscript ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
TDB_DATA data ;
int ret ;
int32_t res ;
char * errmsg ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
if ( argc ! = 1 ) {
DEBUG ( DEBUG_ERR , ( " Invalid arguments \n " ) ) ;
return - 1 ;
}
data . dptr = ( unsigned char * ) discard_const ( argv [ 0 ] ) ;
data . dsize = strlen ( ( char * ) data . dptr ) + 1 ;
DEBUG ( DEBUG_ERR , ( " Running eventscripts with arguments \" %s \" on node %u \n " , data . dptr , options . pnn ) ) ;
ret = ctdb_control ( ctdb , options . pnn , 0 , CTDB_CONTROL_RUN_EVENTSCRIPTS ,
0 , data , tmp_ctx , NULL , & res , NULL , & errmsg ) ;
if ( ret ! = 0 | | res ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to run eventscripts - %s \n " , errmsg ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
talloc_free ( tmp_ctx ) ;
return 0 ;
}
2008-08-14 02:35:19 +04:00
# define DB_VERSION 1
# define MAX_DB_NAME 64
2008-08-13 16:03:29 +04:00
struct db_file_header {
2008-08-14 02:35:19 +04:00
unsigned long version ;
time_t timestamp ;
2008-08-13 16:03:29 +04:00
unsigned long persistent ;
unsigned long size ;
2008-08-14 02:35:19 +04:00
const char name [ MAX_DB_NAME ] ;
2008-08-13 16:03:29 +04:00
} ;
2008-08-14 04:57:08 +04:00
struct backup_data {
struct ctdb_marshall_buffer * records ;
uint32_t len ;
uint32_t total ;
bool traverse_error ;
} ;
static int backup_traverse ( struct tdb_context * tdb , TDB_DATA key , TDB_DATA data , void * private )
{
struct backup_data * bd = talloc_get_type ( private , struct backup_data ) ;
struct ctdb_rec_data * rec ;
/* add the record */
rec = ctdb_marshall_record ( bd - > records , 0 , key , NULL , data ) ;
if ( rec = = NULL ) {
bd - > traverse_error = true ;
DEBUG ( DEBUG_ERR , ( " Failed to marshall record \n " ) ) ;
return - 1 ;
}
bd - > records = talloc_realloc_size ( NULL , bd - > records , rec - > length + bd - > len ) ;
if ( bd - > records = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to expand marshalling buffer \n " ) ) ;
bd - > traverse_error = true ;
return - 1 ;
}
bd - > records - > count + + ;
memcpy ( bd - > len + ( uint8_t * ) bd - > records , rec , rec - > length ) ;
bd - > len + = rec - > length ;
talloc_free ( rec ) ;
bd - > total + + ;
return 0 ;
}
2008-08-13 16:03:29 +04:00
/*
* backup a database to a file
*/
static int control_backupdb ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int i , ret ;
struct ctdb_dbid_map * dbmap = NULL ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
struct db_file_header dbhdr ;
2008-08-14 04:57:08 +04:00
struct ctdb_db_context * ctdb_db ;
struct backup_data * bd ;
2009-05-20 14:08:13 +04:00
int fh = - 1 ;
int status = - 1 ;
2008-08-13 16:03:29 +04:00
if ( argc ! = 2 ) {
DEBUG ( DEBUG_ERR , ( " Invalid arguments \n " ) ) ;
return - 1 ;
}
ret = ctdb_ctrl_getdbmap ( ctdb , TIMELIMIT ( ) , options . pnn , tmp_ctx , & dbmap ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get dbids from node %u \n " , options . pnn ) ) ;
return ret ;
}
for ( i = 0 ; i < dbmap - > num ; i + + ) {
const char * name ;
ctdb_ctrl_getdbname ( ctdb , TIMELIMIT ( ) , options . pnn , dbmap - > dbs [ i ] . dbid , tmp_ctx , & name ) ;
if ( ! strcmp ( argv [ 0 ] , name ) ) {
talloc_free ( discard_const ( name ) ) ;
break ;
}
talloc_free ( discard_const ( name ) ) ;
}
if ( i = = dbmap - > num ) {
DEBUG ( DEBUG_ERR , ( " No database with name '%s' found \n " , argv [ 0 ] ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2008-08-14 04:57:08 +04:00
ctdb_db = ctdb_attach ( ctdb , argv [ 0 ] , dbmap - > dbs [ i ] . persistent , 0 ) ;
if ( ctdb_db = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Unable to attach to database '%s' \n " , argv [ 0 ] ) ) ;
2009-05-20 14:08:13 +04:00
talloc_free ( tmp_ctx ) ;
2008-08-14 04:57:08 +04:00
return - 1 ;
}
ret = tdb_transaction_start ( ctdb_db - > ltdb - > tdb ) ;
if ( ret = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " Failed to start transaction \n " ) ) ;
2008-08-13 16:03:29 +04:00
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2008-08-14 04:57:08 +04:00
bd = talloc_zero ( tmp_ctx , struct backup_data ) ;
if ( bd = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate backup_data \n " ) ) ;
2008-08-13 16:03:29 +04:00
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2008-08-14 04:57:08 +04:00
bd - > records = talloc_zero ( bd , struct ctdb_marshall_buffer ) ;
if ( bd - > records = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate ctdb_marshall_buffer \n " ) ) ;
2008-08-13 16:03:29 +04:00
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2008-08-14 04:57:08 +04:00
bd - > len = offsetof ( struct ctdb_marshall_buffer , data ) ;
bd - > records - > db_id = ctdb_db - > db_id ;
/* traverse the database collecting all records */
if ( tdb_traverse_read ( ctdb_db - > ltdb - > tdb , backup_traverse , bd ) = = - 1 | |
bd - > traverse_error ) {
DEBUG ( DEBUG_ERR , ( " Traverse error \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
tdb_transaction_cancel ( ctdb_db - > ltdb - > tdb ) ;
2008-08-13 16:03:29 +04:00
fh = open ( argv [ 1 ] , O_RDWR | O_CREAT , 0600 ) ;
if ( fh = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " Failed to open file '%s' \n " , argv [ 1 ] ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2008-08-14 02:35:19 +04:00
dbhdr . version = DB_VERSION ;
dbhdr . timestamp = time ( NULL ) ;
2008-08-13 16:03:29 +04:00
dbhdr . persistent = dbmap - > dbs [ i ] . persistent ;
2008-08-14 04:57:08 +04:00
dbhdr . size = bd - > len ;
2008-08-14 02:36:39 +04:00
if ( strlen ( argv [ 0 ] ) > = MAX_DB_NAME ) {
2008-08-14 02:35:19 +04:00
DEBUG ( DEBUG_ERR , ( " Too long dbname \n " ) ) ;
2009-05-20 14:08:13 +04:00
goto done ;
2008-08-14 02:35:19 +04:00
}
2008-08-14 02:36:39 +04:00
strncpy ( discard_const ( dbhdr . name ) , argv [ 0 ] , MAX_DB_NAME ) ;
2009-05-20 14:08:13 +04:00
ret = write ( fh , & dbhdr , sizeof ( dbhdr ) ) ;
if ( ret = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " write failed: %s \n " , strerror ( errno ) ) ) ;
goto done ;
}
ret = write ( fh , bd - > records , bd - > len ) ;
if ( ret = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " write failed: %s \n " , strerror ( errno ) ) ) ;
goto done ;
}
2008-08-13 16:03:29 +04:00
2009-05-20 14:08:13 +04:00
status = 0 ;
done :
if ( fh ! = - 1 ) {
ret = close ( fh ) ;
if ( ret = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " close failed: %s \n " , strerror ( errno ) ) ) ;
}
}
2008-08-13 16:03:29 +04:00
talloc_free ( tmp_ctx ) ;
2009-05-20 14:08:13 +04:00
return status ;
2008-08-13 16:03:29 +04:00
}
/*
* restore a database from a file
*/
static int control_restoredb ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
TDB_DATA outdata ;
TDB_DATA data ;
struct db_file_header dbhdr ;
struct ctdb_db_context * ctdb_db ;
struct ctdb_node_map * nodemap = NULL ;
struct ctdb_vnn_map * vnnmap = NULL ;
2009-10-12 06:06:16 +04:00
int i , fh ;
2008-08-13 16:03:29 +04:00
struct ctdb_control_wipe_database w ;
uint32_t * nodes ;
uint32_t generation ;
2008-08-14 02:35:19 +04:00
struct tm * tm ;
char tbuf [ 100 ] ;
2008-08-13 16:03:29 +04:00
2008-08-14 02:35:19 +04:00
if ( argc ! = 1 ) {
2008-08-13 16:03:29 +04:00
DEBUG ( DEBUG_ERR , ( " Invalid arguments \n " ) ) ;
return - 1 ;
}
2008-08-14 02:35:19 +04:00
fh = open ( argv [ 0 ] , O_RDONLY ) ;
2008-08-13 16:03:29 +04:00
if ( fh = = - 1 ) {
2008-08-14 02:35:19 +04:00
DEBUG ( DEBUG_ERR , ( " Failed to open file '%s' \n " , argv [ 0 ] ) ) ;
2008-08-13 16:03:29 +04:00
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
read ( fh , & dbhdr , sizeof ( dbhdr ) ) ;
2008-08-14 02:35:19 +04:00
if ( dbhdr . version ! = DB_VERSION ) {
DEBUG ( DEBUG_ERR , ( " Invalid version of database dump. File is version %lu but expected version was %u \n " , dbhdr . version , DB_VERSION ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2008-08-13 16:03:29 +04:00
outdata . dsize = dbhdr . size ;
outdata . dptr = talloc_size ( tmp_ctx , outdata . dsize ) ;
if ( outdata . dptr = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to allocate data of size '%lu' \n " , dbhdr . size ) ) ;
close ( fh ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
read ( fh , outdata . dptr , outdata . dsize ) ;
close ( fh ) ;
2008-08-14 02:35:19 +04:00
tm = localtime ( & dbhdr . timestamp ) ;
strftime ( tbuf , sizeof ( tbuf ) - 1 , " %Y/%m/%d %H:%M:%S " , tm ) ;
printf ( " Restoring database '%s' from backup @ %s \n " ,
dbhdr . name , tbuf ) ;
2008-08-13 16:03:29 +04:00
2008-08-14 02:35:19 +04:00
ctdb_db = ctdb_attach ( ctdb , dbhdr . name , dbhdr . persistent , 0 ) ;
2008-08-13 16:03:29 +04:00
if ( ctdb_db = = NULL ) {
2008-08-14 02:35:19 +04:00
DEBUG ( DEBUG_ERR , ( " Unable to attach to database '%s' \n " , dbhdr . name ) ) ;
2008-08-13 16:03:29 +04:00
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , options . pnn , ctdb , & nodemap ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from node %u \n " , options . pnn ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = ctdb_ctrl_getvnnmap ( ctdb , TIMELIMIT ( ) , options . pnn , tmp_ctx , & vnnmap ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get vnnmap from node %u \n " , options . pnn ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
/* freeze all nodes */
nodes = list_of_active_nodes ( ctdb , nodemap , tmp_ctx , true ) ;
2009-10-12 06:06:16 +04:00
for ( i = 1 ; i < = NUM_DB_PRIORITIES ; i + + ) {
if ( ctdb_client_async_control ( ctdb , CTDB_CONTROL_FREEZE ,
nodes , i ,
TIMELIMIT ( ) ,
2008-08-13 16:03:29 +04:00
false , tdb_null ,
NULL , NULL ,
NULL ) ! = 0 ) {
2009-10-12 06:06:16 +04:00
DEBUG ( DEBUG_ERR , ( " Unable to freeze nodes. \n " ) ) ;
ctdb_ctrl_setrecmode ( ctdb , TIMELIMIT ( ) , options . pnn , CTDB_RECOVERY_ACTIVE ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2008-08-13 16:03:29 +04:00
}
generation = vnnmap - > generation ;
data . dptr = ( void * ) & generation ;
data . dsize = sizeof ( generation ) ;
/* start a cluster wide transaction */
nodes = list_of_active_nodes ( ctdb , nodemap , tmp_ctx , true ) ;
if ( ctdb_client_async_control ( ctdb , CTDB_CONTROL_TRANSACTION_START ,
2009-10-12 06:06:16 +04:00
nodes , 0 ,
2008-08-13 16:03:29 +04:00
TIMELIMIT ( ) , false , data ,
NULL , NULL ,
NULL ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to start cluster wide transactions. \n " ) ) ;
return - 1 ;
}
w . db_id = ctdb_db - > db_id ;
w . transaction_id = generation ;
data . dptr = ( void * ) & w ;
data . dsize = sizeof ( w ) ;
/* wipe all the remote databases. */
nodes = list_of_active_nodes ( ctdb , nodemap , tmp_ctx , true ) ;
if ( ctdb_client_async_control ( ctdb , CTDB_CONTROL_WIPE_DATABASE ,
2009-10-12 06:06:16 +04:00
nodes , 0 ,
2008-08-13 16:03:29 +04:00
TIMELIMIT ( ) , false , data ,
NULL , NULL ,
NULL ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to wipe database. \n " ) ) ;
ctdb_ctrl_setrecmode ( ctdb , TIMELIMIT ( ) , options . pnn , CTDB_RECOVERY_ACTIVE ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
/* push the database */
nodes = list_of_active_nodes ( ctdb , nodemap , tmp_ctx , true ) ;
if ( ctdb_client_async_control ( ctdb , CTDB_CONTROL_PUSH_DB ,
2009-10-12 06:06:16 +04:00
nodes , 0 ,
2008-08-13 16:03:29 +04:00
TIMELIMIT ( ) , false , outdata ,
NULL , NULL ,
NULL ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to push database. \n " ) ) ;
ctdb_ctrl_setrecmode ( ctdb , TIMELIMIT ( ) , options . pnn , CTDB_RECOVERY_ACTIVE ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
data . dptr = ( void * ) & generation ;
data . dsize = sizeof ( generation ) ;
/* commit all the changes */
if ( ctdb_client_async_control ( ctdb , CTDB_CONTROL_TRANSACTION_COMMIT ,
2009-10-12 06:06:16 +04:00
nodes , 0 ,
2008-08-13 16:03:29 +04:00
TIMELIMIT ( ) , false , data ,
NULL , NULL ,
NULL ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to commit databases. \n " ) ) ;
ctdb_ctrl_setrecmode ( ctdb , TIMELIMIT ( ) , options . pnn , CTDB_RECOVERY_ACTIVE ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
/* thaw all nodes */
nodes = list_of_active_nodes ( ctdb , nodemap , tmp_ctx , true ) ;
if ( ctdb_client_async_control ( ctdb , CTDB_CONTROL_THAW ,
2009-10-12 06:06:16 +04:00
nodes , 0 ,
TIMELIMIT ( ) ,
2008-08-13 16:03:29 +04:00
false , tdb_null ,
NULL , NULL ,
NULL ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to thaw nodes. \n " ) ) ;
ctdb_ctrl_setrecmode ( ctdb , TIMELIMIT ( ) , options . pnn , CTDB_RECOVERY_ACTIVE ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
talloc_free ( tmp_ctx ) ;
return 0 ;
}
2008-12-05 08:32:30 +03:00
/*
* set flags of a node in the nodemap
*/
static int control_setflags ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
int32_t status ;
int node ;
int flags ;
TDB_DATA data ;
struct ctdb_node_flag_change c ;
if ( argc ! = 2 ) {
usage ( ) ;
return - 1 ;
}
if ( sscanf ( argv [ 0 ] , " %d " , & node ) ! = 1 ) {
DEBUG ( DEBUG_ERR , ( " Badly formed node \n " ) ) ;
usage ( ) ;
return - 1 ;
}
if ( sscanf ( argv [ 1 ] , " 0x%x " , & flags ) ! = 1 ) {
DEBUG ( DEBUG_ERR , ( " Badly formed flags \n " ) ) ;
usage ( ) ;
return - 1 ;
}
c . pnn = node ;
c . old_flags = 0 ;
c . new_flags = flags ;
data . dsize = sizeof ( c ) ;
data . dptr = ( unsigned char * ) & c ;
ret = ctdb_control ( ctdb , options . pnn , 0 , CTDB_CONTROL_MODIFY_FLAGS , 0 ,
data , NULL , NULL , & status , NULL , NULL ) ;
if ( ret ! = 0 | | status ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to modify flags \n " ) ) ;
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 )
{
2008-01-22 06:22:41 +03:00
TDB_DATA data ;
int ret ;
int32_t res ;
char * errmsg ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
ret = ctdb_control ( ctdb , options . pnn , 0 , CTDB_CONTROL_DUMP_MEMORY ,
0 , tdb_null , tmp_ctx , & data , & res , NULL , & errmsg ) ;
if ( ret ! = 0 | | res ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Failed to dump memory - %s \n " , errmsg ) ) ;
2008-01-22 06:22:41 +03:00
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
write ( 1 , data . dptr , data . dsize ) ;
talloc_free ( tmp_ctx ) ;
return 0 ;
2007-05-29 06:16:59 +04:00
}
2008-04-01 08:34:54 +04:00
/*
handler for memory dumps
*/
static void mem_dump_handler ( struct ctdb_context * ctdb , uint64_t srvid ,
TDB_DATA data , void * private_data )
{
write ( 1 , data . dptr , data . dsize ) ;
exit ( 0 ) ;
}
/*
dump memory usage on the recovery daemon
*/
static int control_rddumpmemory ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
TDB_DATA data ;
struct rd_memdump_reply rd ;
rd . pnn = ctdb_ctrl_getpnn ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE ) ;
if ( rd . pnn = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " Failed to get pnn of local node \n " ) ) ;
return - 1 ;
}
rd . srvid = getpid ( ) ;
/* register a message port for receiveing the reply so that we
can receive the reply
*/
ctdb_set_message_handler ( ctdb , rd . srvid , mem_dump_handler , NULL ) ;
data . dptr = ( uint8_t * ) & rd ;
data . dsize = sizeof ( rd ) ;
ret = ctdb_send_message ( ctdb , options . pnn , CTDB_SRVID_MEM_DUMP , data ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to send memdump request message to %u \n " , options . pnn ) ) ;
return - 1 ;
}
/* this loop will terminate when we have received the reply */
while ( 1 ) {
event_loop_once ( ctdb - > ev ) ;
}
return 0 ;
}
2008-02-19 06:44:48 +03:00
/*
list all nodes in the cluster
2009-06-04 07:21:25 +04:00
if the daemon is running , we read the data from the daemon .
if the daemon is not running we parse the nodes file directly
2008-02-19 06:44:48 +03:00
*/
static int control_listnodes ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int i , ret ;
struct ctdb_node_map * nodemap = NULL ;
2009-06-04 07:21:25 +04:00
if ( ctdb ! = NULL ) {
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , options . pnn , ctdb , & nodemap ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from node %u \n " , options . pnn ) ) ;
return ret ;
}
2008-02-19 06:44:48 +03:00
2009-06-04 07:21:25 +04:00
for ( i = 0 ; i < nodemap - > num ; i + + ) {
2009-06-04 07:25:58 +04:00
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_DELETED ) {
continue ;
}
2009-06-04 07:21:25 +04:00
if ( options . machinereadable ) {
printf ( " :%d:%s: \n " , nodemap - > nodes [ i ] . pnn , ctdb_addr_to_str ( & nodemap - > nodes [ i ] . addr ) ) ;
} else {
printf ( " %s \n " , ctdb_addr_to_str ( & nodemap - > nodes [ i ] . addr ) ) ;
}
2009-06-01 09:43:30 +04:00
}
2009-06-04 07:21:25 +04:00
} else {
TALLOC_CTX * mem_ctx = talloc_new ( NULL ) ;
struct pnn_node * pnn_nodes ;
struct pnn_node * pnn_node ;
pnn_nodes = read_nodes_file ( mem_ctx ) ;
if ( pnn_nodes = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to read nodes file \n " ) ) ;
talloc_free ( mem_ctx ) ;
return - 1 ;
}
for ( pnn_node = pnn_nodes ; pnn_node ; pnn_node = pnn_node - > next ) {
ctdb_sock_addr addr ;
if ( parse_ip ( pnn_node - > addr , NULL , 63999 , & addr ) = = 0 ) {
DEBUG ( DEBUG_ERR , ( " Wrongly formed ip address '%s' in nodes file \n " , pnn_node - > addr ) ) ;
talloc_free ( mem_ctx ) ;
return - 1 ;
}
if ( options . machinereadable ) {
printf ( " :%d:%s: \n " , pnn_node - > pnn , pnn_node - > addr ) ;
} else {
printf ( " %s \n " , pnn_node - > addr ) ;
}
}
talloc_free ( mem_ctx ) ;
2008-02-19 06:44:48 +03:00
}
return 0 ;
}
/*
reload the nodes file on the local node
*/
static int control_reload_nodes_file ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2008-02-21 00:25:01 +03:00
int i , ret ;
int mypnn ;
struct ctdb_node_map * nodemap = NULL ;
2008-02-19 06:44:48 +03:00
2008-02-21 00:25:01 +03:00
mypnn = ctdb_ctrl_getpnn ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE ) ;
if ( mypnn = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " Failed to read pnn of local node \n " ) ) ;
return - 1 ;
}
2008-02-19 06:44:48 +03:00
2008-02-21 00:25:01 +03:00
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE , ctdb , & nodemap ) ;
2008-02-19 06:44:48 +03:00
if ( ret ! = 0 ) {
2008-02-21 00:25:01 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from local node \n " ) ) ;
return ret ;
2008-02-19 06:44:48 +03:00
}
2008-02-21 00:25:01 +03:00
/* reload the nodes file on all remote nodes */
for ( i = 0 ; i < nodemap - > num ; i + + ) {
if ( nodemap - > nodes [ i ] . pnn = = mypnn ) {
continue ;
}
DEBUG ( DEBUG_NOTICE , ( " Reloading nodes file on node %u \n " , nodemap - > nodes [ i ] . pnn ) ) ;
ret = ctdb_ctrl_reload_nodes_file ( ctdb , TIMELIMIT ( ) ,
nodemap - > nodes [ i ] . pnn ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " ERROR: Failed to reload nodes file on node %u. You MUST fix that node manually! \n " , nodemap - > nodes [ i ] . pnn ) ) ;
}
}
/* reload the nodes file on the local node */
DEBUG ( DEBUG_NOTICE , ( " Reloading nodes file on node %u \n " , mypnn ) ) ;
ret = ctdb_ctrl_reload_nodes_file ( ctdb , TIMELIMIT ( ) , mypnn ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " ERROR: Failed to reload nodes file on node %u. You MUST fix that node manually! \n " , mypnn ) ) ;
}
2008-12-02 05:26:30 +03:00
/* initiate a recovery */
control_recover ( ctdb , argc , argv ) ;
2008-02-19 06:44:48 +03:00
return 0 ;
}
2007-05-29 06:16:59 +04:00
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 ;
2009-03-25 06:46:05 +03:00
bool without_daemon ; /* can be run without daemon running ? */
2007-05-29 06:16:59 +04:00
const char * msg ;
const char * args ;
} ctdb_commands [ ] = {
2008-04-03 10:07:00 +04:00
# ifdef CTDB_VERS
2009-03-25 06:46:05 +03:00
{ " version " , control_version , true , false , " show version of ctdb " } ,
2008-04-03 10:07:00 +04:00
# endif
2009-03-25 06:46:05 +03:00
{ " status " , control_status , true , false , " show node status " } ,
{ " uptime " , control_uptime , true , false , " show node uptime " } ,
{ " ping " , control_ping , true , false , " ping all nodes " } ,
{ " getvar " , control_getvar , true , false , " get a tunable variable " , " <name> " } ,
{ " setvar " , control_setvar , true , false , " set a tunable variable " , " <name> <value> " } ,
{ " listvars " , control_listvars , true , false , " list tunable variables " } ,
{ " statistics " , control_statistics , false , false , " show statistics " } ,
{ " statisticsreset " , control_statistics_reset , true , false , " reset statistics " } ,
{ " ip " , control_ip , false , false , " show which public ip's that ctdb manages " } ,
{ " process-exists " , control_process_exists , true , false , " check if a process exists on a node " , " <pid> " } ,
{ " getdbmap " , control_getdbmap , true , false , " show the database map " } ,
{ " catdb " , control_catdb , true , false , " dump a database " , " <dbname> " } ,
{ " getmonmode " , control_getmonmode , true , false , " show monitoring mode " } ,
{ " getcapabilities " , control_getcapabilities , true , false , " show node capabilities " } ,
{ " pnn " , control_pnn , true , false , " show the pnn of the currnet node " } ,
{ " lvs " , control_lvs , true , false , " show lvs configuration " } ,
{ " lvsmaster " , control_lvsmaster , true , false , " show which node is the lvs master " } ,
2009-06-04 07:21:25 +04:00
{ " disablemonitor " , control_disable_monmode , true , false , " set monitoring mode to DISABLE " } ,
{ " enablemonitor " , control_enable_monmode , true , false , " set monitoring mode to ACTIVE " } ,
2009-03-25 06:46:05 +03:00
{ " setdebug " , control_setdebug , true , false , " set debug level " , " <EMERG|ALERT|CRIT|ERR|WARNING|NOTICE|INFO|DEBUG> " } ,
{ " getdebug " , control_getdebug , true , false , " get debug level " } ,
{ " attach " , control_attach , true , false , " attach to a database " , " <dbname> " } ,
{ " dumpmemory " , control_dumpmemory , true , false , " dump memory map to stdout " } ,
{ " rddumpmemory " , control_rddumpmemory , true , false , " dump memory map from the recovery daemon to stdout " } ,
{ " getpid " , control_getpid , true , false , " get ctdbd process ID " } ,
{ " disable " , control_disable , true , false , " disable a nodes public IP " } ,
{ " enable " , control_enable , true , false , " enable a nodes public IP " } ,
2009-07-09 05:38:18 +04:00
{ " stop " , control_stop , true , false , " stop a node " } ,
{ " continue " , control_continue , true , false , " re-start a stopped node " } ,
2009-03-25 06:46:05 +03:00
{ " ban " , control_ban , true , false , " ban a node from the cluster " , " <bantime|0> " } ,
2009-09-03 20:20:39 +04:00
{ " unban " , control_unban , true , false , " unban a node " } ,
{ " showban " , control_showban , true , false , " show ban information " } ,
2009-03-25 06:46:05 +03:00
{ " shutdown " , control_shutdown , true , false , " shutdown ctdbd " } ,
{ " recover " , control_recover , true , false , " force recovery " } ,
2009-07-02 07:00:26 +04:00
{ " ipreallocate " , control_ipreallocate , true , false , " force the recovery daemon to perform a ip reallocation procedure " } ,
2009-10-12 02:22:17 +04:00
{ " freeze " , control_freeze , true , false , " freeze databases " , " [priority:1-3] " } ,
{ " thaw " , control_thaw , true , false , " thaw databases " , " [priority:1-3] " } ,
2009-03-25 06:46:05 +03:00
{ " isnotrecmaster " , control_isnotrecmaster , false , false , " check if the local node is recmaster or not " } ,
{ " killtcp " , kill_tcp , false , false , " kill a tcp connection. " , " <srcip:port> <dstip:port> " } ,
{ " gratiousarp " , control_gratious_arp , false , false , " send a gratious arp " , " <ip> <interface> " } ,
{ " tickle " , tickle_tcp , false , false , " send a tcp tickle ack " , " <srcip:port> <dstip:port> " } ,
{ " gettickles " , control_get_tickles , false , false , " get the list of tickles registered for this ip " , " <ip> " } ,
{ " regsrvid " , regsrvid , false , false , " register a server id " , " <pnn> <type> <id> " } ,
{ " unregsrvid " , unregsrvid , false , false , " unregister a server id " , " <pnn> <type> <id> " } ,
{ " chksrvid " , chksrvid , false , false , " check if a server id exists " , " <pnn> <type> <id> " } ,
{ " getsrvids " , getsrvids , false , false , " get a list of all server ids " } ,
{ " vacuum " , ctdb_vacuum , false , false , " vacuum the databases of empty records " , " [max_records] " } ,
{ " repack " , ctdb_repack , false , false , " repack all databases " , " [max_freelist] " } ,
2009-06-04 07:21:25 +04:00
{ " listnodes " , control_listnodes , false , true , " list all nodes in the cluster " } ,
{ " reloadnodes " , control_reload_nodes_file , false , false , " reload the nodes file and restart the transport on all nodes " } ,
2009-03-25 06:46:05 +03:00
{ " moveip " , control_moveip , false , false , " move/failover an ip address to another node " , " <ip> <node> " } ,
{ " addip " , control_addip , true , false , " add a ip address to a node " , " <ip/mask> <iface> " } ,
{ " delip " , control_delip , false , false , " delete an ip address from a node " , " <ip> " } ,
{ " eventscript " , control_eventscript , true , false , " run the eventscript with the given parameters on a node " , " <arguments> " } ,
{ " backupdb " , control_backupdb , false , false , " backup the database into a file. " , " <database> <file> " } ,
2009-06-04 07:21:25 +04:00
{ " restoredb " , control_restoredb , false , false , " restore the database from a file. " , " <file> " } ,
{ " recmaster " , control_recmaster , false , false , " show the pnn for the recovery master. " } ,
{ " setflags " , control_setflags , false , false , " set flags for a node in the nodemap. " , " <node> <flags> " } ,
2009-08-13 07:04:08 +04:00
{ " scriptstatus " , control_scriptstatus , false , false , " show the status of the monitoring scripts " } ,
{ " enablescript " , control_enablescript , false , false , " enable an eventscript " , " <script> " } ,
{ " disablescript " , control_disablescript , false , false , " disable an eventscript " , " <script> " } ,
2009-06-04 07:21:25 +04:00
{ " natgwlist " , control_natgwlist , false , false , " show the nodes belonging to this natgw configuration " } ,
{ " xpnn " , control_xpnn , true , true , " find the pnn of the local node without talking to the daemon (unreliable) " } ,
2009-06-25 06:17:19 +04:00
{ " getreclock " , control_getreclock , false , false , " Show the reclock file of a node " } ,
2009-06-25 08:25:18 +04:00
{ " setreclock " , control_setreclock , false , false , " Set/clear the reclock file of a node " , " [filename] " } ,
2009-07-28 03:58:11 +04:00
{ " setnatgwstate " , control_setnatgwstate , false , false , " Set NATGW state to on/off " , " {on|off} " } ,
2009-07-28 07:45:13 +04:00
{ " setlmasterrole " , control_setlmasterrole , false , false , " Set LMASTER role to on/off " , " {on|off} " } ,
{ " setrecmasterrole " , control_setrecmasterrole , false , false , " Set RECMASTER role to on/off " , " {on|off} " } ,
2009-10-10 07:26:09 +04:00
{ " setdbprio " , control_setdbprio , false , false , " Set DB priority " , " <dbid> <prio:1-3> " } ,
2009-10-10 08:04:18 +04:00
{ " getdbprio " , control_getdbprio , false , false , " Get DB priority " , " <dbid> " } ,
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 + + ) {
2007-07-05 04:00:51 +04:00
printf ( " %-15s %-27s %s \n " ,
2007-05-29 06:16:59 +04:00
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
2008-01-10 00:04:54 +03:00
static void ctdb_alarm ( int sig )
{
printf ( " Maximum runtime exceeded - exiting \n " ) ;
2008-12-10 03:49:51 +03:00
_exit ( ERR_TIMEOUT ) ;
2008-01-10 00:04:54 +03: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 } ,
2008-01-10 00:04:54 +03:00
{ " maxruntime " , ' T ' , POPT_ARG_INT , & options . maxruntime , 0 , " die if runtime exceeds this limit (in seconds) " , " integer " } ,
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
2008-01-08 15:02:43 +03:00
setlinebuf ( stdout ) ;
2007-05-29 06:16:59 +04:00
/* set some defaults */
2008-01-10 00:04:54 +03:00
options . maxruntime = 0 ;
2007-05-29 06:16:59 +04:00
options . timelimit = 3 ;
2007-09-04 04:14:41 +04:00
options . pnn = 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 :
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Invalid option %s: %s \n " ,
2007-08-08 04:19:42 +04:00
poptBadOption ( pc , 0 ) , poptStrerror ( opt ) ) ) ;
2007-04-26 16:27:49 +04:00
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 ( ) ;
}
2008-12-10 04:01:19 +03:00
if ( options . maxruntime = = 0 ) {
const char * ctdb_timeout ;
ctdb_timeout = getenv ( " CTDB_TIMEOUT " ) ;
if ( ctdb_timeout ! = NULL ) {
options . maxruntime = strtoul ( ctdb_timeout , NULL , 0 ) ;
2009-08-17 04:54:45 +04:00
} else {
/* default timeout is 120 seconds */
options . maxruntime = 120 ;
2008-12-10 04:01:19 +03:00
}
}
2009-08-17 04:54:45 +04:00
signal ( SIGALRM , ctdb_alarm ) ;
alarm ( options . maxruntime ) ;
2008-01-10 00:04:54 +03:00
2007-05-29 06:16:59 +04:00
/* setup the node number to contact */
if ( nodestring ! = NULL ) {
if ( strcmp ( nodestring , " all " ) = = 0 ) {
2007-09-04 04:14:41 +04:00
options . pnn = CTDB_BROADCAST_ALL ;
2007-05-29 06:16:59 +04:00
} else {
2007-09-04 04:14:41 +04:00
options . pnn = strtoul ( nodestring , NULL , 0 ) ;
2007-05-29 06:16:59 +04:00
}
}
2007-04-26 16:27:49 +04:00
control = extra_argv [ 0 ] ;
ev = event_context_init ( NULL ) ;
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 ;
2009-06-04 07:21:25 +04:00
if ( ctdb_commands [ i ] . without_daemon = = true ) {
close ( 2 ) ;
}
/* initialise ctdb */
ctdb = ctdb_cmdline_client ( ev ) ;
2009-03-25 06:46:05 +03:00
if ( ctdb_commands [ i ] . without_daemon = = false ) {
if ( ctdb = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to init ctdb \n " ) ) ;
exit ( 1 ) ;
}
/* verify the node exists */
verify_node ( ctdb ) ;
if ( options . pnn = = CTDB_CURRENT_NODE ) {
int pnn ;
pnn = ctdb_ctrl_getpnn ( ctdb , TIMELIMIT ( ) , options . pnn ) ;
if ( pnn = = - 1 ) {
return - 1 ;
}
options . pnn = pnn ;
2007-08-07 07:40:13 +04:00
}
2007-06-11 16:25:26 +04:00
}
if ( ctdb_commands [ i ] . auto_all & &
2007-09-04 04:14:41 +04:00
options . pnn = = CTDB_BROADCAST_ALL ) {
2007-06-11 16:25:26 +04:00
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 + + ) {
2007-09-04 04:14:41 +04:00
options . pnn = nodes [ j ] ;
2007-06-11 16:25:26 +04:00
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 ) ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unknown control '%s' \n " , control ) ) ;
2007-04-26 16:27:49 +04:00
exit ( 1 ) ;
}
return ret ;
}