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"
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"
2013-05-22 08:23:17 +04:00
# include "../include/ctdb_version.h"
2010-05-20 09:48:30 +04:00
# include "../include/ctdb_client.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"
2014-03-03 06:04:25 +04:00
# include "lib/util/dlinklist.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 ;
2011-12-06 12:50:40 +04:00
uint32_t * nodes ;
2007-06-03 13:50:51 +04:00
int machinereadable ;
2010-08-20 05:28:24 +04:00
int verbose ;
2008-01-10 00:04:54 +03:00
int maxruntime ;
2011-11-28 20:11:16 +04:00
int printemptyrecords ;
2011-11-28 20:19:03 +04:00
int printdatasize ;
2011-11-28 20:36:03 +04:00
int printlmaster ;
2011-11-29 03:56:23 +04:00
int printhash ;
2011-11-29 13:24:52 +04:00
int printrecordflags ;
2007-05-29 06:16:59 +04:00
} options ;
2013-09-18 10:35:18 +04:00
# define LONGTIMEOUT options.timelimit*10
2007-05-29 06:16:59 +04:00
# define TIMELIMIT() timeval_current_ofs(options.timelimit, 0)
2013-09-18 10:35:18 +04:00
# define LONGTIMELIMIT() timeval_current_ofs(LONGTIMEOUT, 0)
2007-04-26 16:27:49 +04:00
2008-04-03 10:07:00 +04:00
static int control_version ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2012-10-30 04:49:28 +04:00
printf ( " CTDB version: %s \n " , CTDB_VERSION_STRING ) ;
2008-04-03 10:07:00 +04:00
return 0 ;
}
2011-12-06 12:50:40 +04:00
# define CTDB_NOMEM_ABORT(p) do { if (!(p)) { \
DEBUG ( DEBUG_ALERT , ( " ctdb fatal error: %s \n " , \
" Out of memory in " __location__ ) ) ; \
abort ( ) ; \
} } while ( 0 )
2008-09-22 19:38:28 +04:00
2013-08-14 23:02:37 +04:00
static uint32_t getpnn ( struct ctdb_context * ctdb )
{
if ( ( options . pnn = = CTDB_BROADCAST_ALL ) | |
( options . pnn = = CTDB_MULTICAST ) ) {
DEBUG ( DEBUG_ERR ,
( " Cannot get PNN for node %u \n " , options . pnn ) ) ;
exit ( 1 ) ;
}
if ( options . pnn = = CTDB_CURRENT_NODE ) {
return ctdb_get_pnn ( ctdb ) ;
} else {
return options . pnn ;
}
}
2013-08-19 08:40:52 +04:00
static void assert_single_node_only ( void )
{
if ( ( options . pnn = = CTDB_BROADCAST_ALL ) | |
( options . pnn = = CTDB_MULTICAST ) ) {
DEBUG ( DEBUG_ERR ,
( " This control can not be applied to multiple PNNs \n " ) ) ;
exit ( 1 ) ;
}
}
2011-12-06 12:50:40 +04:00
/* Pretty print the flags to a static buffer in human-readable format.
* This never returns NULL !
*/
static const char * pretty_print_flags ( uint32_t flags )
{
int j ;
static const struct {
uint32_t flag ;
const char * name ;
} flag_names [ ] = {
{ NODE_FLAGS_DISCONNECTED , " DISCONNECTED " } ,
{ NODE_FLAGS_PERMANENTLY_DISABLED , " DISABLED " } ,
{ NODE_FLAGS_BANNED , " BANNED " } ,
{ NODE_FLAGS_UNHEALTHY , " UNHEALTHY " } ,
{ NODE_FLAGS_DELETED , " DELETED " } ,
{ NODE_FLAGS_STOPPED , " STOPPED " } ,
{ NODE_FLAGS_INACTIVE , " INACTIVE " } ,
} ;
static char flags_str [ 512 ] ; /* Big enough to contain all flag names */
flags_str [ 0 ] = ' \0 ' ;
for ( j = 0 ; j < ARRAY_SIZE ( flag_names ) ; j + + ) {
if ( flags & flag_names [ j ] . flag ) {
if ( flags_str [ 0 ] = = ' \0 ' ) {
( void ) strcpy ( flags_str , flag_names [ j ] . name ) ;
} else {
2013-11-11 05:40:44 +04:00
( void ) strncat ( flags_str , " | " , sizeof ( flags_str ) - 1 ) ;
( void ) strncat ( flags_str , flag_names [ j ] . name ,
sizeof ( flags_str ) - 1 ) ;
2011-12-06 12:50:40 +04:00
}
}
}
if ( flags_str [ 0 ] = = ' \0 ' ) {
( void ) strcpy ( flags_str , " OK " ) ;
}
return flags_str ;
}
2012-02-07 03:21:12 +04:00
static int h2i ( char h )
{
if ( h > = ' a ' & & h < = ' f ' ) return h - ' a ' + 10 ;
if ( h > = ' A ' & & h < = ' F ' ) return h - ' f ' + 10 ;
return h - ' 0 ' ;
}
static TDB_DATA hextodata ( TALLOC_CTX * mem_ctx , const char * str )
{
int i , len ;
TDB_DATA key = { NULL , 0 } ;
len = strlen ( str ) ;
if ( len & 0x01 ) {
DEBUG ( DEBUG_ERR , ( " Key specified with odd number of hexadecimal digits \n " ) ) ;
return key ;
}
key . dsize = len > > 1 ;
key . dptr = talloc_size ( mem_ctx , key . dsize ) ;
for ( i = 0 ; i < len / 2 ; i + + ) {
key . dptr [ i ] = h2i ( str [ i * 2 ] ) < < 4 | h2i ( str [ i * 2 + 1 ] ) ;
}
return key ;
}
2011-12-06 12:50:40 +04:00
/* Parse a nodestring. Parameter dd_ok controls what happens to nodes
* that are disconnected or deleted . If dd_ok is true those nodes are
* included in the output list of nodes . If dd_ok is false , those
* nodes are filtered from the " all " case and cause an error if
* explicitly specified .
*/
static bool parse_nodestring ( struct ctdb_context * ctdb ,
2013-08-27 08:46:08 +04:00
TALLOC_CTX * mem_ctx ,
2011-12-06 12:50:40 +04:00
const char * nodestring ,
2011-12-06 12:50:40 +04:00
uint32_t current_pnn ,
2011-12-06 12:50:40 +04:00
bool dd_ok ,
uint32_t * * nodes ,
uint32_t * pnn_mode )
{
2013-08-27 08:46:08 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
2011-12-06 12:50:40 +04:00
int n ;
uint32_t i ;
struct ctdb_node_map * nodemap ;
2013-08-29 11:22:38 +04:00
int ret ;
2011-12-06 12:50:40 +04:00
* nodes = NULL ;
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE , tmp_ctx , & nodemap ) ;
if ( ret ! = 0 ) {
2011-12-06 12:50:40 +04:00
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from local node \n " ) ) ;
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2011-12-06 12:50:40 +04:00
exit ( 10 ) ;
}
if ( nodestring ! = NULL ) {
2013-08-27 08:46:08 +04:00
* nodes = talloc_array ( mem_ctx , uint32_t , 0 ) ;
2013-08-29 11:22:38 +04:00
if ( * nodes = = NULL ) {
goto failed ;
}
2011-12-06 12:50:40 +04:00
n = 0 ;
if ( strcmp ( nodestring , " all " ) = = 0 ) {
* pnn_mode = CTDB_BROADCAST_ALL ;
/* all */
for ( i = 0 ; i < nodemap - > num ; i + + ) {
2013-08-29 11:22:38 +04:00
if ( ( nodemap - > nodes [ i ] . flags &
2011-12-06 12:50:40 +04:00
( NODE_FLAGS_DISCONNECTED |
NODE_FLAGS_DELETED ) ) & & ! dd_ok ) {
continue ;
}
2013-08-27 08:46:08 +04:00
* nodes = talloc_realloc ( mem_ctx , * nodes ,
2011-12-06 12:50:40 +04:00
uint32_t , n + 1 ) ;
2013-08-29 11:22:38 +04:00
if ( * nodes = = NULL ) {
goto failed ;
}
2011-12-06 12:50:40 +04:00
( * nodes ) [ n ] = i ;
n + + ;
}
} else {
/* x{,y...} */
char * ns , * tok ;
2013-08-29 11:22:38 +04:00
ns = talloc_strdup ( tmp_ctx , nodestring ) ;
2011-12-06 12:50:40 +04:00
tok = strtok ( ns , " , " ) ;
while ( tok ! = NULL ) {
uint32_t pnn ;
2013-11-22 06:57:31 +04:00
char * endptr ;
i = ( uint32_t ) strtoul ( tok , & endptr , 0 ) ;
if ( i = = 0 & & tok = = endptr ) {
DEBUG ( DEBUG_ERR ,
( " Invalid node %s \n " , tok ) ) ;
talloc_free ( tmp_ctx ) ;
exit ( ERR_NONODE ) ;
}
2011-12-06 12:50:40 +04:00
if ( i > = nodemap - > num ) {
DEBUG ( DEBUG_ERR , ( " Node %u does not exist \n " , i ) ) ;
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2011-12-06 12:50:40 +04:00
exit ( ERR_NONODE ) ;
}
if ( ( nodemap - > nodes [ i ] . flags &
( NODE_FLAGS_DISCONNECTED |
NODE_FLAGS_DELETED ) ) & & ! dd_ok ) {
DEBUG ( DEBUG_ERR , ( " Node %u has status %s \n " , i , pretty_print_flags ( nodemap - > nodes [ i ] . flags ) ) ) ;
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2011-12-06 12:50:40 +04:00
exit ( ERR_DISNODE ) ;
}
2013-08-29 11:22:38 +04:00
if ( ( pnn = ctdb_ctrl_getpnn ( ctdb , TIMELIMIT ( ) , i ) ) < 0 ) {
2011-12-06 12:50:40 +04:00
DEBUG ( DEBUG_ERR , ( " Can not access node %u. Node is not operational. \n " , i ) ) ;
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2011-12-06 12:50:40 +04:00
exit ( 10 ) ;
}
2013-08-27 08:46:08 +04:00
* nodes = talloc_realloc ( mem_ctx , * nodes ,
2011-12-06 12:50:40 +04:00
uint32_t , n + 1 ) ;
2013-08-29 11:22:38 +04:00
if ( * nodes = = NULL ) {
goto failed ;
}
2011-12-06 12:50:40 +04:00
( * nodes ) [ n ] = i ;
n + + ;
tok = strtok ( NULL , " , " ) ;
}
talloc_free ( ns ) ;
if ( n = = 1 ) {
* pnn_mode = ( * nodes ) [ 0 ] ;
} else {
* pnn_mode = CTDB_MULTICAST ;
}
}
} else {
/* default - no nodes specified */
2013-08-27 08:46:08 +04:00
* nodes = talloc_array ( mem_ctx , uint32_t , 1 ) ;
2013-08-29 11:22:38 +04:00
if ( * nodes = = NULL ) {
goto failed ;
}
2011-12-06 12:50:40 +04:00
* pnn_mode = CTDB_CURRENT_NODE ;
2011-12-06 12:50:40 +04:00
2013-08-29 11:22:38 +04:00
if ( ( ( * nodes ) [ 0 ] = ctdb_ctrl_getpnn ( ctdb , TIMELIMIT ( ) , current_pnn ) ) < 0 ) {
goto failed ;
2011-12-06 12:50:40 +04:00
}
}
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
return true ;
2011-12-06 12:50:40 +04:00
2013-08-29 11:22:38 +04:00
failed :
talloc_free ( tmp_ctx ) ;
return false ;
2011-12-06 12:50:40 +04:00
}
2008-09-22 19:38:28 +04:00
/*
check if a database exists
*/
2013-11-13 08:25:46 +04:00
static bool db_exists ( struct ctdb_context * ctdb , const char * dbarg ,
uint32_t * dbid , const char * * dbname , uint8_t * flags )
2008-09-22 19:38:28 +04:00
{
int i , ret ;
struct ctdb_dbid_map * dbmap = NULL ;
2012-12-19 07:43:26 +04:00
bool dbid_given = false , found = false ;
uint32_t id ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
2013-11-13 08:25:46 +04:00
const char * name ;
2008-09-22 19:38:28 +04:00
2012-12-19 07:43:26 +04:00
ret = ctdb_ctrl_getdbmap ( ctdb , TIMELIMIT ( ) , options . pnn , tmp_ctx , & dbmap ) ;
2008-09-22 19:38:28 +04:00
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get dbids from node %u \n " , options . pnn ) ) ;
2012-12-19 07:43:26 +04:00
goto fail ;
2008-09-22 19:38:28 +04:00
}
2012-12-19 07:43:26 +04:00
if ( strncmp ( dbarg , " 0x " , 2 ) = = 0 ) {
id = strtoul ( dbarg , NULL , 0 ) ;
dbid_given = true ;
}
2008-09-22 19:38:28 +04:00
2012-12-19 07:43:26 +04:00
for ( i = 0 ; i < dbmap - > num ; i + + ) {
if ( dbid_given ) {
if ( id = = dbmap - > dbs [ i ] . dbid ) {
found = true ;
break ;
}
} else {
ret = ctdb_ctrl_getdbname ( ctdb , TIMELIMIT ( ) , options . pnn , dbmap - > dbs [ i ] . dbid , tmp_ctx , & name ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get dbname from dbid %u \n " , dbmap - > dbs [ i ] . dbid ) ) ;
goto fail ;
}
if ( strcmp ( name , dbarg ) = = 0 ) {
id = dbmap - > dbs [ i ] . dbid ;
found = true ;
break ;
2010-09-14 16:45:16 +04:00
}
2008-09-22 19:38:28 +04:00
}
}
2013-11-13 08:25:46 +04:00
if ( found & & dbid_given & & dbname ! = NULL ) {
ret = ctdb_ctrl_getdbname ( ctdb , TIMELIMIT ( ) , options . pnn , dbmap - > dbs [ i ] . dbid , tmp_ctx , & name ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get dbname from dbid %u \n " , dbmap - > dbs [ i ] . dbid ) ) ;
found = false ;
goto fail ;
}
}
2012-12-19 07:43:26 +04:00
if ( found ) {
if ( dbid ) * dbid = id ;
2013-11-13 08:25:46 +04:00
if ( dbname ) * dbname = talloc_strdup ( ctdb , name ) ;
2012-12-19 07:43:26 +04:00
if ( flags ) * flags = dbmap - > dbs [ i ] . flags ;
} else {
DEBUG ( DEBUG_ERR , ( " No database matching '%s' found \n " , dbarg ) ) ;
}
fail :
talloc_free ( tmp_ctx ) ;
return found ;
2008-09-22 19:38:28 +04:00
}
2007-04-27 17:14:36 +04:00
/*
see if a process exists
*/
2007-04-26 16:27:49 +04:00
static int control_process_exists ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2007-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
*/
2010-09-30 09:07:30 +04:00
static void show_statistics ( struct ctdb_statistics * s , int show_header )
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 ;
2010-06-02 07:13:09 +04:00
int tmp , days , hours , minutes , seconds ;
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 ) ,
2010-05-11 03:28:59 +04:00
STATISTICS_FIELD ( num_recoveries ) ,
2007-05-29 06:16:59 +04:00
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 ) ,
2012-05-09 06:58:19 +04:00
STATISTICS_FIELD ( locks . num_calls ) ,
STATISTICS_FIELD ( locks . num_current ) ,
STATISTICS_FIELD ( locks . num_pending ) ,
STATISTICS_FIELD ( locks . num_failed ) ,
2007-05-29 06:16:59 +04:00
STATISTICS_FIELD ( total_calls ) ,
STATISTICS_FIELD ( pending_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 ) ,
2012-02-08 06:42:30 +04:00
STATISTICS_FIELD ( total_ro_delegations ) ,
STATISTICS_FIELD ( total_ro_revokes ) ,
2007-05-05 02:11:54 +04:00
} ;
2012-03-07 10:02:41 +04:00
2010-06-02 07:13:09 +04:00
tmp = s - > statistics_current_time . tv_sec - s - > statistics_start_time . tv_sec ;
seconds = tmp % 60 ;
tmp / = 60 ;
minutes = tmp % 60 ;
tmp / = 60 ;
hours = tmp % 24 ;
tmp / = 24 ;
days = tmp ;
2010-09-30 08:59:59 +04:00
if ( options . machinereadable ) {
2010-09-30 09:07:30 +04:00
if ( show_header ) {
printf ( " CTDB version: " ) ;
printf ( " Current time of statistics: " ) ;
printf ( " Statistics collected since: " ) ;
for ( i = 0 ; i < ARRAY_SIZE ( fields ) ; i + + ) {
printf ( " %s: " , fields [ i ] . name ) ;
}
2010-10-11 08:11:18 +04:00
printf ( " num_reclock_ctdbd_latency: " ) ;
printf ( " min_reclock_ctdbd_latency: " ) ;
printf ( " avg_reclock_ctdbd_latency: " ) ;
printf ( " max_reclock_ctdbd_latency: " ) ;
printf ( " num_reclock_recd_latency: " ) ;
printf ( " min_reclock_recd_latency: " ) ;
printf ( " avg_reclock_recd_latency: " ) ;
printf ( " max_reclock_recd_latency: " ) ;
printf ( " num_call_latency: " ) ;
printf ( " min_call_latency: " ) ;
printf ( " avg_call_latency: " ) ;
2010-09-30 09:07:30 +04:00
printf ( " max_call_latency: " ) ;
2010-10-11 08:11:18 +04:00
printf ( " num_lockwait_latency: " ) ;
printf ( " min_lockwait_latency: " ) ;
printf ( " avg_lockwait_latency: " ) ;
2010-09-30 09:07:30 +04:00
printf ( " max_lockwait_latency: " ) ;
2010-10-11 08:11:18 +04:00
printf ( " num_childwrite_latency: " ) ;
printf ( " min_childwrite_latency: " ) ;
printf ( " avg_childwrite_latency: " ) ;
2010-09-30 09:07:30 +04:00
printf ( " max_childwrite_latency: " ) ;
printf ( " \n " ) ;
2010-09-30 08:59:59 +04:00
}
printf ( " %d: " , CTDB_VERSION ) ;
printf ( " %d: " , ( int ) s - > statistics_current_time . tv_sec ) ;
printf ( " %d: " , ( int ) s - > statistics_start_time . tv_sec ) ;
for ( i = 0 ; i < ARRAY_SIZE ( fields ) ; i + + ) {
printf ( " %d: " , * ( uint32_t * ) ( fields [ i ] . offset + ( uint8_t * ) s ) ) ;
}
2010-10-11 08:11:18 +04:00
printf ( " %d: " , s - > reclock . ctdbd . num ) ;
printf ( " %.6f: " , s - > reclock . ctdbd . min ) ;
printf ( " %.6f: " , s - > reclock . ctdbd . num ? s - > reclock . ctdbd . total / s - > reclock . ctdbd . num : 0.0 ) ;
printf ( " %.6f: " , s - > reclock . ctdbd . max ) ;
printf ( " %d: " , s - > reclock . recd . num ) ;
printf ( " %.6f: " , s - > reclock . recd . min ) ;
printf ( " %.6f: " , s - > reclock . recd . num ? s - > reclock . recd . total / s - > reclock . recd . num : 0.0 ) ;
printf ( " %.6f: " , s - > reclock . recd . max ) ;
printf ( " %d: " , s - > call_latency . num ) ;
printf ( " %.6f: " , s - > call_latency . min ) ;
printf ( " %.6f: " , s - > call_latency . num ? s - > call_latency . total / s - > call_latency . num : 0.0 ) ;
printf ( " %.6f: " , s - > call_latency . max ) ;
printf ( " %d: " , s - > childwrite_latency . num ) ;
printf ( " %.6f: " , s - > childwrite_latency . min ) ;
printf ( " %.6f: " , s - > childwrite_latency . num ? s - > childwrite_latency . total / s - > childwrite_latency . num : 0.0 ) ;
printf ( " %.6f: " , s - > childwrite_latency . max ) ;
2010-09-30 08:59:59 +04:00
printf ( " \n " ) ;
} else {
printf ( " CTDB version %u \n " , CTDB_VERSION ) ;
printf ( " Current time of statistics : %s " , ctime ( & s - > statistics_current_time . tv_sec ) ) ;
printf ( " Statistics collected since : (%03d %02d:%02d:%02d) %s " , days , hours , minutes , seconds , ctime ( & s - > statistics_start_time . tv_sec ) ) ;
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 ;
2007-05-05 02:11:54 +04:00
}
2010-09-30 08:59:59 +04:00
printf ( " %*s%-22s%*s%10u \n " ,
preflen ? 4 : 0 , " " ,
fields [ i ] . name + preflen ,
preflen ? 0 : 4 , " " ,
* ( uint32_t * ) ( fields [ i ] . offset + ( uint8_t * ) s ) ) ;
2007-05-05 02:11:54 +04:00
}
2012-03-20 04:43:09 +04:00
printf ( " hop_count_buckets: " ) ;
2012-03-20 05:08:12 +04:00
for ( i = 0 ; i < MAX_COUNT_BUCKETS ; i + + ) {
2012-03-07 10:02:41 +04:00
printf ( " %d " , s - > hop_count_bucket [ i ] ) ;
}
printf ( " \n " ) ;
2012-05-09 06:58:19 +04:00
printf ( " lock_buckets: " ) ;
for ( i = 0 ; i < MAX_COUNT_BUCKETS ; i + + ) {
printf ( " %d " , s - > locks . buckets [ i ] ) ;
}
printf ( " \n " ) ;
printf ( " %-30s %.6f/%.6f/%.6f sec out of %d \n " , " locks_latency MIN/AVG/MAX " , s - > locks . latency . min , s - > locks . latency . num ? s - > locks . latency . total / s - > locks . latency . num : 0.0 , s - > locks . latency . max , s - > locks . latency . num ) ;
printf ( " %-30s %.6f/%.6f/%.6f sec out of %d \n " , " reclock_ctdbd MIN/AVG/MAX " , s - > reclock . ctdbd . min , s - > reclock . ctdbd . num ? s - > reclock . ctdbd . total / s - > reclock . ctdbd . num : 0.0 , s - > reclock . ctdbd . max , s - > reclock . ctdbd . num ) ;
2010-10-11 08:11:18 +04:00
printf ( " %-30s %.6f/%.6f/%.6f sec out of %d \n " , " reclock_recd MIN/AVG/MAX " , s - > reclock . recd . min , s - > reclock . recd . num ? s - > reclock . recd . total / s - > reclock . recd . num : 0.0 , s - > reclock . recd . max , s - > reclock . recd . num ) ;
2009-05-14 04:33:25 +04:00
2010-10-11 08:11:18 +04:00
printf ( " %-30s %.6f/%.6f/%.6f sec out of %d \n " , " call_latency MIN/AVG/MAX " , s - > call_latency . min , s - > call_latency . num ? s - > call_latency . total / s - > call_latency . num : 0.0 , s - > call_latency . max , s - > call_latency . num ) ;
printf ( " %-30s %.6f/%.6f/%.6f sec out of %d \n " , " childwrite_latency MIN/AVG/MAX " , s - > childwrite_latency . min , s - > childwrite_latency . num ? s - > childwrite_latency . total / s - > childwrite_latency . num : 0.0 , s - > childwrite_latency . max , s - > childwrite_latency . num ) ;
2010-09-30 08:59:59 +04:00
}
2010-06-02 07:13:09 +04:00
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 ) ;
2010-10-11 08:11:18 +04:00
statistics . call_latency . max =
MAX ( statistics . call_latency . max , s1 . call_latency . max ) ;
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 ) ;
2010-09-30 09:07:30 +04:00
show_statistics ( & statistics , 1 ) ;
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 ;
}
2010-09-30 09:07:30 +04:00
show_statistics ( & statistics , 1 ) ;
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
2010-09-29 06:13:05 +04:00
/*
display remote ctdb rolling statistics
*/
static int control_stats ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
struct ctdb_statistics_wire * stats ;
int i , num_records = - 1 ;
2013-08-19 08:40:52 +04:00
assert_single_node_only ( ) ;
2010-09-29 06:13:05 +04:00
if ( argc = = 1 ) {
num_records = atoi ( argv [ 0 ] ) - 1 ;
}
ret = ctdb_ctrl_getstathistory ( ctdb , TIMELIMIT ( ) , options . pnn , ctdb , & stats ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get rolling statistics from node %u \n " , options . pnn ) ) ;
return ret ;
}
for ( i = 0 ; i < stats - > num ; i + + ) {
if ( stats - > stats [ i ] . statistics_start_time . tv_sec = = 0 ) {
continue ;
}
2010-09-30 09:07:30 +04:00
show_statistics ( & stats - > stats [ i ] , i = = 0 ) ;
2010-09-29 06:13:05 +04:00
if ( i = = num_records ) {
break ;
}
}
return 0 ;
}
2012-02-08 08:29:27 +04:00
/*
display remote ctdb db statistics
*/
static int control_dbstatistics ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
2012-05-09 06:58:19 +04:00
struct ctdb_db_statistics * dbstat ;
2012-12-19 07:43:26 +04:00
int i ;
uint32_t db_id ;
2013-07-15 10:35:30 +04:00
int num_hot_keys ;
2013-08-29 11:22:38 +04:00
int ret ;
2012-02-08 08:29:27 +04:00
if ( argc < 1 ) {
usage ( ) ;
}
2013-11-13 08:25:46 +04:00
if ( ! db_exists ( ctdb , argv [ 0 ] , & db_id , NULL , NULL ) ) {
2012-02-08 08:29:27 +04:00
return - 1 ;
}
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_dbstatistics ( ctdb , options . pnn , db_id , tmp_ctx , & dbstat ) ;
if ( ret ! = 0 ) {
2012-02-08 08:29:27 +04:00
DEBUG ( DEBUG_ERR , ( " Failed to read db statistics from node \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2013-06-25 09:36:13 +04:00
printf ( " DB Statistics: %s \n " , argv [ 0 ] ) ;
2012-05-09 06:58:19 +04:00
printf ( " %*s%-22s%*s%10u \n " , 0 , " " , " ro_delegations " , 4 , " " ,
dbstat - > db_ro_delegations ) ;
printf ( " %*s%-22s%*s%10u \n " , 0 , " " , " ro_revokes " , 4 , " " ,
dbstat - > db_ro_delegations ) ;
printf ( " %s \n " , " locks " ) ;
printf ( " %*s%-22s%*s%10u \n " , 4 , " " , " total " , 0 , " " ,
dbstat - > locks . num_calls ) ;
printf ( " %*s%-22s%*s%10u \n " , 4 , " " , " failed " , 0 , " " ,
dbstat - > locks . num_failed ) ;
printf ( " %*s%-22s%*s%10u \n " , 4 , " " , " current " , 0 , " " ,
dbstat - > locks . num_current ) ;
printf ( " %*s%-22s%*s%10u \n " , 4 , " " , " pending " , 0 , " " ,
dbstat - > locks . num_pending ) ;
2013-06-25 09:36:13 +04:00
printf ( " %s " , " hop_count_buckets: " ) ;
for ( i = 0 ; i < MAX_COUNT_BUCKETS ; i + + ) {
printf ( " %d " , dbstat - > hop_count_bucket [ i ] ) ;
}
printf ( " \n " ) ;
printf ( " %s " , " lock_buckets: " ) ;
for ( i = 0 ; i < MAX_COUNT_BUCKETS ; i + + ) {
printf ( " %d " , dbstat - > locks . buckets [ i ] ) ;
}
printf ( " \n " ) ;
2012-05-09 06:58:19 +04:00
printf ( " %-30s %.6f/%.6f/%.6f sec out of %d \n " ,
2013-06-25 09:36:13 +04:00
" locks_latency MIN/AVG/MAX " ,
2012-05-09 06:58:19 +04:00
dbstat - > locks . latency . min ,
( dbstat - > locks . latency . num ?
dbstat - > locks . latency . total / dbstat - > locks . latency . num :
0.0 ) ,
dbstat - > locks . latency . max ,
dbstat - > locks . latency . num ) ;
2013-07-15 10:35:30 +04:00
num_hot_keys = 0 ;
for ( i = 0 ; i < dbstat - > num_hot_keys ; i + + ) {
if ( dbstat - > hot_keys [ i ] . count > 0 ) {
num_hot_keys + + ;
}
}
dbstat - > num_hot_keys = num_hot_keys ;
2013-06-25 09:36:13 +04:00
printf ( " Num Hot Keys: %d \n " , dbstat - > num_hot_keys ) ;
2012-05-09 06:58:19 +04:00
for ( i = 0 ; i < dbstat - > num_hot_keys ; i + + ) {
2012-06-13 10:17:18 +04:00
int j ;
2013-06-25 09:36:13 +04:00
printf ( " Count:%d Key: " , dbstat - > hot_keys [ i ] . count ) ;
2012-05-09 06:58:19 +04:00
for ( j = 0 ; j < dbstat - > hot_keys [ i ] . key . dsize ; j + + ) {
printf ( " %02x " , dbstat - > hot_keys [ i ] . key . dptr [ j ] & 0xff ) ;
2012-06-13 10:17:18 +04:00
}
printf ( " \n " ) ;
}
2012-02-08 08:29:27 +04:00
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2012-02-08 08:29:27 +04:00
return 0 ;
}
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 ) {
2009-10-29 02:58:14 +03:00
printf ( " :Current Node Time:Ctdb Start Time:Last Recovery/Failover Time:Last Recovery/IPFailover Duration: \n " ) ;
2008-07-02 07:55:59 +04:00
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 ;
}
2009-10-29 02:58:14 +03:00
printf ( " Current time of node : %s " , ctime ( & uptime - > current_time . tv_sec ) ) ;
2008-01-17 03:33:23 +03:00
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 ;
2009-10-29 02:58:14 +03:00
printf ( " Ctdbd start time : (%03d %02d:%02d:%02d) %s " , days , hours , minutes , seconds , ctime ( & uptime - > ctdbd_start_time . tv_sec ) ) ;
2008-01-17 03:33:23 +03:00
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 ;
2009-10-29 02:58:14 +03:00
printf ( " Time of last recovery/failover: (%03d %02d:%02d:%02d) %s " , days , hours , minutes , seconds , ctime ( & uptime - > last_recovery_finished . tv_sec ) ) ;
2008-07-02 07:55:59 +04:00
2009-10-29 02:58:14 +03:00
printf ( " Duration of last recovery/failover: %lf seconds \n " ,
2008-07-02 07:55:59 +04:00
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 )
{
2010-06-02 04:37:00 +04:00
uint32_t mypnn ;
2008-07-10 05:12:58 +04:00
2013-08-14 23:02:37 +04:00
mypnn = getpnn ( ctdb ) ;
2008-07-10 05:12:58 +04:00
printf ( " PNN:%d \n " , mypnn ) ;
return 0 ;
}
2009-03-25 06:46:05 +03:00
struct pnn_node {
2014-03-03 06:04:25 +04:00
struct pnn_node * next , * prev ;
2014-03-03 06:20:06 +04:00
ctdb_sock_addr addr ;
2009-03-25 06:46:05 +03:00
int pnn ;
} ;
2014-03-03 05:57:30 +04:00
static struct pnn_node * read_pnn_node_file ( TALLOC_CTX * mem_ctx ,
const char * file )
2009-03-25 06:46:05 +03:00
{
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 ;
2014-03-03 05:57:30 +04:00
lines = file_lines_load ( file , & nlines , mem_ctx ) ;
2009-03-25 06:46:05 +03:00
if ( lines = = NULL ) {
2009-06-04 07:21:25 +04:00
return NULL ;
2009-03-25 06:46:05 +03:00
}
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 + + ;
2014-03-03 06:20:06 +04:00
if ( ! parse_ip ( node , NULL , 0 , & pnn_node - > addr ) ) {
DEBUG ( DEBUG_ERR ,
( " Invalid IP address '%s' in file %s \n " ,
node , file ) ) ;
/* Caller will free mem_ctx */
return NULL ;
}
2009-06-04 07:21:25 +04:00
2014-03-03 06:04:25 +04:00
DLIST_ADD_END ( pnn_nodes , pnn_node , NULL ) ;
2009-06-04 07:21:25 +04:00
}
return pnn_nodes ;
}
2014-03-03 05:57:30 +04:00
static struct pnn_node * read_nodes_file ( TALLOC_CTX * mem_ctx )
{
const char * nodes_list ;
/* read the nodes file */
nodes_list = getenv ( " CTDB_NODES " ) ;
if ( nodes_list = = NULL ) {
nodes_list = talloc_asprintf ( mem_ctx , " %s/nodes " ,
getenv ( " CTDB_BASE " ) ) ;
if ( nodes_list = = NULL ) {
DEBUG ( DEBUG_ALERT , ( __location__ " Out of memory \n " ) ) ;
exit ( 1 ) ;
}
}
return read_pnn_node_file ( mem_ctx , nodes_list ) ;
}
2009-06-04 07:21:25 +04:00
/*
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 ;
2013-08-19 08:40:52 +04:00
assert_single_node_only ( ) ;
2009-06-04 07:21:25 +04:00
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 ) {
2014-03-03 06:20:06 +04:00
if ( ctdb_sys_have_ip ( & pnn_node - > addr ) ) {
2009-03-25 06:46:05 +03:00
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 ;
}
2011-12-06 12:50:40 +04:00
/* Helpers for ctdb status
*/
2013-08-29 11:22:38 +04:00
static bool is_partially_online ( struct ctdb_context * ctdb , struct ctdb_node_and_flags * node )
2011-12-06 12:50:40 +04:00
{
2013-08-29 11:22:38 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( NULL ) ;
2011-12-06 12:50:40 +04:00
int j ;
bool ret = false ;
if ( node - > flags = = 0 ) {
2013-08-29 11:22:38 +04:00
struct ctdb_control_get_ifaces * ifaces ;
2011-12-06 12:50:40 +04:00
2013-08-29 11:22:38 +04:00
if ( ctdb_ctrl_get_ifaces ( ctdb , TIMELIMIT ( ) , node - > pnn ,
tmp_ctx , & ifaces ) = = 0 ) {
2011-12-06 12:50:40 +04:00
for ( j = 0 ; j < ifaces - > num ; j + + ) {
if ( ifaces - > ifaces [ j ] . link_state ! = 0 ) {
continue ;
}
ret = true ;
break ;
}
}
}
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2011-12-06 12:50:40 +04:00
return ret ;
}
2012-07-17 15:09:46 +04:00
static void control_status_header_machine ( void )
{
printf ( " :Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped "
" :Inactive:PartiallyOnline:ThisNode: \n " ) ;
}
2013-08-29 11:22:38 +04:00
static int control_status_1_machine ( struct ctdb_context * ctdb , int mypnn ,
struct ctdb_node_and_flags * node )
2011-12-06 13:10:34 +04:00
{
printf ( " :%d:%s:%d:%d:%d:%d:%d:%d:%d:%c: \n " , node - > pnn ,
ctdb_addr_to_str ( & node - > addr ) ,
! ! ( node - > flags & NODE_FLAGS_DISCONNECTED ) ,
! ! ( node - > flags & NODE_FLAGS_BANNED ) ,
! ! ( node - > flags & NODE_FLAGS_PERMANENTLY_DISABLED ) ,
! ! ( node - > flags & NODE_FLAGS_UNHEALTHY ) ,
! ! ( node - > flags & NODE_FLAGS_STOPPED ) ,
! ! ( node - > flags & NODE_FLAGS_INACTIVE ) ,
2013-08-29 11:22:38 +04:00
is_partially_online ( ctdb , node ) ? 1 : 0 ,
2011-12-06 13:10:34 +04:00
( node - > pnn = = mypnn ) ? ' Y ' : ' N ' ) ;
return node - > flags ;
}
2013-08-29 11:22:38 +04:00
static int control_status_1_human ( struct ctdb_context * ctdb , int mypnn ,
struct ctdb_node_and_flags * node )
2011-12-06 13:10:34 +04:00
{
printf ( " pnn:%d %-16s %s%s \n " , node - > pnn ,
ctdb_addr_to_str ( & node - > addr ) ,
2013-08-29 11:22:38 +04:00
is_partially_online ( ctdb , node ) ? " PARTIALLYONLINE " : pretty_print_flags ( node - > flags ) ,
2011-12-06 13:10:34 +04:00
node - > pnn = = mypnn ? " (THIS NODE) " : " " ) ;
return node - > flags ;
}
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
{
2013-08-29 11:22:38 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
2011-12-12 10:19:00 +04:00
int i ;
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 ;
2011-12-12 10:19:00 +04:00
uint32_t recmode , recmaster , mypnn ;
2012-11-19 21:45:37 +04:00
int num_deleted_nodes = 0 ;
2013-08-29 11:22:38 +04:00
int ret ;
2007-05-29 06:16:59 +04:00
2013-08-14 23:02:37 +04:00
mypnn = getpnn ( ctdb ) ;
2007-05-29 06:16:59 +04:00
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , options . pnn , tmp_ctx , & nodemap ) ;
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from node %u \n " , options . pnn ) ) ;
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2011-12-12 10:19:00 +04:00
return - 1 ;
2007-04-27 14:56:10 +04:00
}
2011-08-24 13:34:56 +04:00
if ( options . machinereadable ) {
2012-07-17 15:09:46 +04:00
control_status_header_machine ( ) ;
2011-08-24 13:34:56 +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 ;
}
2013-08-29 11:22:38 +04:00
( void ) control_status_1_machine ( ctdb , mypnn ,
2011-12-06 13:10:34 +04:00
& nodemap - > nodes [ i ] ) ;
2007-06-03 13:50:51 +04:00
}
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2007-06-03 13:50:51 +04:00
return 0 ;
}
2012-11-19 21:45:37 +04:00
for ( i = 0 ; i < nodemap - > num ; i + + ) {
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_DELETED ) {
num_deleted_nodes + + ;
}
}
if ( num_deleted_nodes = = 0 ) {
printf ( " Number of nodes:%d \n " , nodemap - > num ) ;
} else {
printf ( " Number of nodes:%d (including %d deleted nodes) \n " ,
nodemap - > num , num_deleted_nodes ) ;
}
2007-05-29 06:16:59 +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 ;
}
2013-08-29 11:22:38 +04:00
( void ) control_status_1_human ( ctdb , mypnn , & nodemap - > nodes [ i ] ) ;
2007-05-29 06:16:59 +04:00
}
2007-04-27 14:56:10 +04:00
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_getvnnmap ( ctdb , TIMELIMIT ( ) , options . pnn , tmp_ctx , & vnnmap ) ;
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get vnnmap from node %u \n " , options . pnn ) ) ;
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2011-12-12 10:19:00 +04:00
return - 1 ;
2007-04-27 14:56:10 +04:00
}
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
}
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_getrecmode ( ctdb , tmp_ctx , TIMELIMIT ( ) , options . pnn , & recmode ) ;
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get recmode from node %u \n " , options . pnn ) ) ;
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2011-08-23 10:35:08 +04:00
return - 1 ;
2007-05-05 22:31:22 +04:00
}
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
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_getrecmaster ( ctdb , tmp_ctx , TIMELIMIT ( ) , options . pnn , & recmaster ) ;
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get recmaster from node %u \n " , options . pnn ) ) ;
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2011-08-23 10:32:38 +04:00
return - 1 ;
2007-05-17 04:45:31 +04:00
}
2007-05-29 06:16:59 +04:00
printf ( " Recovery master:%d \n " , recmaster ) ;
2007-05-17 04:45:31 +04:00
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2007-05-17 04:45:31 +04:00
return 0 ;
}
2011-12-06 13:17:02 +04:00
static int control_nodestatus ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2013-08-29 11:22:38 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
2011-12-06 13:17:02 +04:00
int i , ret ;
struct ctdb_node_map * nodemap = NULL ;
uint32_t * nodes ;
uint32_t pnn_mode , mypnn ;
if ( argc > 1 ) {
usage ( ) ;
}
2013-08-27 08:46:08 +04:00
if ( ! parse_nodestring ( ctdb , tmp_ctx , argc = = 1 ? argv [ 0 ] : NULL ,
2011-12-06 12:50:40 +04:00
options . pnn , true , & nodes , & pnn_mode ) ) {
2011-12-06 13:17:02 +04:00
return - 1 ;
}
if ( options . machinereadable ) {
2012-07-17 15:09:46 +04:00
control_status_header_machine ( ) ;
2011-12-06 13:17:02 +04:00
} else if ( pnn_mode = = CTDB_BROADCAST_ALL ) {
printf ( " Number of nodes:%d \n " , ( int ) talloc_array_length ( nodes ) ) ;
}
2013-08-14 23:02:37 +04:00
mypnn = getpnn ( ctdb ) ;
2011-12-06 13:17:02 +04:00
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , options . pnn , tmp_ctx , & nodemap ) ;
if ( ret ! = 0 ) {
2011-12-06 12:50:40 +04:00
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from node %u \n " , options . pnn ) ) ;
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2011-12-06 13:17:02 +04:00
return - 1 ;
}
2011-12-06 12:50:40 +04:00
ret = 0 ;
2011-12-06 13:17:02 +04:00
for ( i = 0 ; i < talloc_array_length ( nodes ) ; i + + ) {
if ( options . machinereadable ) {
2013-08-29 11:22:38 +04:00
ret | = control_status_1_machine ( ctdb , mypnn ,
2011-12-06 13:17:02 +04:00
& nodemap - > nodes [ nodes [ i ] ] ) ;
} else {
2013-08-29 11:22:38 +04:00
ret | = control_status_1_human ( ctdb , mypnn ,
2011-12-06 13:17:02 +04:00
& nodemap - > nodes [ nodes [ i ] ] ) ;
}
}
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2011-12-06 13:17:02 +04:00
return ret ;
}
2014-03-03 05:57:30 +04:00
static struct pnn_node * read_natgw_nodes_file ( struct ctdb_context * ctdb ,
TALLOC_CTX * mem_ctx )
2014-03-03 05:45:23 +04:00
{
const char * natgw_list ;
2014-03-03 05:57:30 +04:00
struct pnn_node * natgw_nodes = NULL ;
2014-03-03 05:45:23 +04:00
natgw_list = getenv ( " CTDB_NATGW_NODES " ) ;
if ( natgw_list = = NULL ) {
natgw_list = talloc_asprintf ( mem_ctx , " %s/natgw_nodes " ,
getenv ( " CTDB_BASE " ) ) ;
if ( natgw_list = = NULL ) {
DEBUG ( DEBUG_ALERT , ( __location__ " Out of memory \n " ) ) ;
exit ( 1 ) ;
}
}
2014-03-03 05:57:30 +04:00
/* The PNNs will be junk but they're not used */
natgw_nodes = read_pnn_node_file ( mem_ctx , natgw_list ) ;
if ( natgw_nodes = = NULL ) {
DEBUG ( DEBUG_ERR ,
( " Failed to load natgw node list '%s' \n " , natgw_list ) ) ;
2014-03-03 05:45:23 +04:00
}
return natgw_nodes ;
}
2014-02-18 08:52:37 +04:00
/* talloc off the existing nodemap... */
static struct ctdb_node_map * talloc_nodemap ( struct ctdb_node_map * nodemap )
{
return talloc_zero_size ( nodemap ,
offsetof ( struct ctdb_node_map , nodes ) +
nodemap - > num * sizeof ( struct ctdb_node_and_flags ) ) ;
}
2014-03-03 04:41:32 +04:00
static struct ctdb_node_map *
2014-03-03 05:57:30 +04:00
filter_nodemap_by_addrs ( struct ctdb_context * ctdb ,
struct ctdb_node_map * nodemap ,
struct pnn_node * nodes )
2014-03-03 04:41:32 +04:00
{
int i ;
2014-03-03 05:57:30 +04:00
struct pnn_node * n ;
2014-03-03 04:41:32 +04:00
struct ctdb_node_map * ret ;
ret = talloc_nodemap ( nodemap ) ;
CTDB_NO_MEMORY_NULL ( ctdb , ret ) ;
ret - > num = 0 ;
for ( i = 0 ; i < nodemap - > num ; i + + ) {
2014-03-03 05:57:30 +04:00
for ( n = nodes ; n ! = NULL ; n = n - > next ) {
2014-03-03 06:20:06 +04:00
if ( ctdb_same_ip ( & n - > addr ,
& nodemap - > nodes [ i ] . addr ) ) {
2014-03-03 04:41:32 +04:00
break ;
}
}
if ( n = = NULL ) {
continue ;
}
ret - > nodes [ ret - > num ] = nodemap - > nodes [ i ] ;
ret - > num + + ;
}
return ret ;
}
2014-02-18 08:52:37 +04:00
static struct ctdb_node_map *
filter_nodemap_by_capabilities ( struct ctdb_context * ctdb ,
struct ctdb_node_map * nodemap ,
uint32_t required_capabilities )
{
int i ;
uint32_t capabilities ;
struct ctdb_node_map * ret ;
ret = talloc_nodemap ( nodemap ) ;
CTDB_NO_MEMORY_NULL ( ctdb , ret ) ;
ret - > num = 0 ;
for ( i = 0 ; i < nodemap - > num ; i + + ) {
int res = ctdb_ctrl_getcapabilities ( ctdb , TIMELIMIT ( ) ,
nodemap - > nodes [ i ] . pnn ,
& capabilities ) ;
if ( res ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get capabilities from node %u \n " ,
nodemap - > nodes [ i ] . pnn ) ) ;
talloc_free ( ret ) ;
return NULL ;
}
if ( ! ( capabilities & required_capabilities ) ) {
continue ;
}
ret - > nodes [ ret - > num ] = nodemap - > nodes [ i ] ;
ret - > num + + ;
}
return ret ;
}
2014-02-18 10:11:53 +04:00
static struct ctdb_node_map *
filter_nodemap_by_flags ( struct ctdb_context * ctdb ,
struct ctdb_node_map * nodemap ,
uint32_t flags_mask )
2012-07-18 10:59:19 +04:00
{
int i ;
2014-02-18 10:11:53 +04:00
struct ctdb_node_map * ret ;
2012-07-18 10:59:19 +04:00
2014-02-18 10:11:53 +04:00
ret = talloc_nodemap ( nodemap ) ;
CTDB_NO_MEMORY_NULL ( ctdb , ret ) ;
ret - > num = 0 ;
for ( i = 0 ; i < nodemap - > num ; i + + ) {
if ( nodemap - > nodes [ i ] . flags & flags_mask ) {
continue ;
2012-07-18 10:59:19 +04:00
}
2014-02-18 10:11:53 +04:00
ret - > nodes [ ret - > num ] = nodemap - > nodes [ i ] ;
ret - > num + + ;
2012-07-18 10:59:19 +04:00
}
2014-02-18 10:11:53 +04:00
return ret ;
2012-07-18 10:59:19 +04:00
}
2009-03-25 05:37:57 +03:00
/*
display the list of nodes belonging to this natgw configuration
*/
static int control_natgwlist ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2013-08-29 11:22:38 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
2009-03-25 05:37:57 +03:00
int i , ret ;
2014-03-03 05:57:30 +04:00
struct pnn_node * natgw_nodes = NULL ;
2014-03-03 04:41:32 +04:00
struct ctdb_node_map * orig_nodemap = NULL ;
struct ctdb_node_map * cnodemap , * nodemap ;
2012-07-18 10:59:19 +04:00
uint32_t mypnn , pnn ;
const char * ip ;
2009-03-25 05:37:57 +03:00
2012-07-18 10:59:19 +04:00
/* When we have some nodes that could be the NATGW, make a
* series of attempts to find the first node that doesn ' t have
* certain status flags set .
*/
uint32_t exclude_flags [ ] = {
/* Look for a nice healthy node */
NODE_FLAGS_DISCONNECTED | NODE_FLAGS_STOPPED | NODE_FLAGS_DELETED | NODE_FLAGS_BANNED | NODE_FLAGS_UNHEALTHY ,
/* If not found, an UNHEALTHY/BANNED node will do */
NODE_FLAGS_DISCONNECTED | NODE_FLAGS_STOPPED | NODE_FLAGS_DELETED ,
/* If not found, a STOPPED node will do */
NODE_FLAGS_DISCONNECTED | NODE_FLAGS_DELETED ,
0 ,
} ;
2009-03-25 05:37:57 +03:00
/* read the natgw nodes file into a linked list */
2014-03-03 05:45:23 +04:00
natgw_nodes = read_natgw_nodes_file ( ctdb , tmp_ctx ) ;
if ( natgw_nodes = = NULL ) {
ret = - 1 ;
goto done ;
2009-03-25 05:37:57 +03:00
}
2014-03-03 04:41:32 +04:00
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE ,
tmp_ctx , & orig_nodemap ) ;
2013-08-29 11:22:38 +04:00
if ( ret ! = 0 ) {
2009-03-25 05:37:57 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from local node. \n " ) ) ;
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2012-07-18 10:59:19 +04:00
return - 1 ;
2009-03-25 05:37:57 +03:00
}
2014-03-03 04:41:32 +04:00
/* Get a nodemap that includes only the nodes in the NATGW
* group */
2014-03-03 05:57:30 +04:00
nodemap = filter_nodemap_by_addrs ( ctdb , orig_nodemap , natgw_nodes ) ;
2014-03-03 04:41:32 +04:00
if ( nodemap = = NULL ) {
ret = - 1 ;
goto done ;
2012-07-17 15:15:57 +04:00
}
2014-02-18 08:52:37 +04:00
/* Get a nodemap that includes only the nodes with the NATGW
* capability */
cnodemap = filter_nodemap_by_capabilities ( ctdb , nodemap ,
CTDB_CAP_NATGW ) ;
if ( cnodemap = = NULL ) {
ret = - 1 ;
goto done ;
}
2012-07-18 10:59:19 +04:00
ret = 2 ; /* matches ENOENT */
pnn = - 1 ;
ip = " 0.0.0.0 " ;
for ( i = 0 ; exclude_flags [ i ] ! = 0 ; i + + ) {
2014-02-18 10:11:53 +04:00
struct ctdb_node_map * t =
filter_nodemap_by_flags ( ctdb , cnodemap ,
exclude_flags [ i ] ) ;
if ( t = = NULL ) {
/* No memory */
ret = - 1 ;
2012-07-18 10:59:19 +04:00
goto done ;
2009-03-25 05:37:57 +03:00
}
2014-02-18 10:11:53 +04:00
if ( t - > num > 0 ) {
ret = 0 ;
pnn = t - > nodes [ 0 ] . pnn ;
ip = ctdb_addr_to_str ( & t - > nodes [ 0 ] . addr ) ;
2012-07-18 10:59:19 +04:00
break ;
2009-11-06 00:19:32 +03:00
}
2014-02-18 10:11:53 +04:00
talloc_free ( t ) ;
2009-11-06 00:19:32 +03:00
}
2012-07-18 10:59:19 +04:00
if ( options . machinereadable ) {
printf ( " :Node:IP: \n " ) ;
printf ( " :%d:%s: \n " , pnn , ip ) ;
} else {
printf ( " %d %s \n " , pnn , ip ) ;
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 */
2013-08-14 23:02:37 +04:00
mypnn = getpnn ( ctdb ) ;
2012-07-17 15:15:57 +04:00
if ( options . machinereadable ) {
control_status_header_machine ( ) ;
} else {
printf ( " Number of nodes:%d \n " , nodemap - > num ) ;
}
2009-03-25 05:37:57 +03: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 ;
}
2012-07-17 15:15:57 +04:00
if ( options . machinereadable ) {
2013-08-29 11:22:38 +04:00
control_status_1_machine ( ctdb , mypnn , & ( nodemap - > nodes [ i ] ) ) ;
2012-07-17 15:15:57 +04:00
} else {
2013-08-29 11:22:38 +04:00
control_status_1_human ( ctdb , mypnn , & ( nodemap - > nodes [ i ] ) ) ;
2012-07-17 15:15:57 +04:00
}
2009-03-25 05:37:57 +03:00
}
2012-07-18 10:59:19 +04:00
done :
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2011-07-05 09:00:31 +04:00
return ret ;
2009-03-25 05:37:57 +03:00
}
2009-03-23 11:07:45 +03:00
/*
2009-12-07 18:20:55 +03:00
display the status of the scripts for monitoring ( or other events )
2009-03-23 11:07:45 +03:00
*/
2009-12-07 18:20:55 +03:00
static int control_one_scriptstatus ( struct ctdb_context * ctdb ,
enum ctdb_eventscript_call type )
2009-03-23 11:07:45 +03:00
{
2009-12-07 17:21:24 +03:00
struct ctdb_scripts_wire * script_status ;
2009-12-07 18:20:55 +03:00
int ret , i ;
2009-03-23 11:07:45 +03:00
2009-12-07 18:20:55 +03:00
ret = ctdb_ctrl_getscriptstatus ( ctdb , TIMELIMIT ( ) , options . pnn , ctdb , type , & script_status ) ;
2009-03-23 11:07:45 +03:00
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get script status from node %u \n " , options . pnn ) ) ;
return ret ;
}
2009-12-07 18:20:55 +03:00
if ( script_status = = NULL ) {
if ( ! options . machinereadable ) {
printf ( " %s cycle never run \n " ,
ctdb_eventscript_call_names [ type ] ) ;
}
return 0 ;
}
if ( ! options . machinereadable ) {
printf ( " %d scripts were executed last %s cycle \n " ,
script_status - > num_scripts ,
ctdb_eventscript_call_names [ type ] ) ;
2009-12-07 18:01:53 +03:00
}
2009-03-23 11:07:45 +03:00
for ( i = 0 ; i < script_status - > num_scripts ; i + + ) {
2009-12-07 15:42:19 +03:00
const char * status = NULL ;
2009-12-07 15:39:42 +03:00
switch ( script_status - > scripts [ i ] . status ) {
case - ETIME :
status = " TIMEDOUT " ;
break ;
2009-12-07 15:41:47 +03:00
case - ENOEXEC :
status = " DISABLED " ;
break ;
2009-12-07 15:39:42 +03:00
case 0 :
status = " OK " ;
break ;
default :
2009-12-07 15:42:19 +03:00
if ( script_status - > scripts [ i ] . status > 0 )
status = " ERROR " ;
2009-12-07 15:39:42 +03:00
break ;
}
2009-12-07 18:01:53 +03:00
if ( options . machinereadable ) {
2011-08-30 10:37:04 +04:00
printf ( " :%s:%s:%i:%s:%lu.%06lu:%lu.%06lu:%s: \n " ,
2009-12-07 18:20:55 +03:00
ctdb_eventscript_call_names [ type ] ,
2009-12-07 18:01:53 +03:00
script_status - > scripts [ i ] . name ,
script_status - > scripts [ i ] . status ,
status ,
( long ) script_status - > scripts [ i ] . start . tv_sec ,
( long ) script_status - > scripts [ i ] . start . tv_usec ,
( long ) script_status - > scripts [ i ] . finished . tv_sec ,
( long ) script_status - > scripts [ i ] . finished . tv_usec ,
script_status - > scripts [ i ] . output ) ;
continue ;
}
2009-12-07 15:42:19 +03:00
if ( status )
printf ( " %-20s Status:%s " ,
script_status - > scripts [ i ] . name , status ) ;
else
/* Some other error, eg from stat. */
printf ( " %-20s Status:CANNOT RUN (%s) " ,
script_status - > scripts [ i ] . name ,
strerror ( - script_status - > scripts [ i ] . status ) ) ;
if ( script_status - > scripts [ i ] . status > = 0 ) {
2009-03-23 11:07:45 +03:00
printf ( " Duration:%.3lf " ,
timeval_delta ( & script_status - > scripts [ i ] . finished ,
& script_status - > scripts [ i ] . start ) ) ;
}
2009-12-07 15:41:47 +03:00
if ( script_status - > scripts [ i ] . status ! = - ENOEXEC ) {
printf ( " %s " ,
ctime ( & script_status - > scripts [ i ] . start . tv_sec ) ) ;
2009-12-10 13:05:54 +03:00
if ( script_status - > scripts [ i ] . status ! = 0 ) {
printf ( " OUTPUT:%s \n " ,
script_status - > scripts [ i ] . output ) ;
}
} else {
printf ( " \n " ) ;
2009-03-23 11:07:45 +03:00
}
}
2009-12-07 18:20:55 +03:00
return 0 ;
}
static int control_scriptstatus ( struct ctdb_context * ctdb ,
int argc , const char * * argv )
{
int ret ;
enum ctdb_eventscript_call type , min , max ;
const char * arg ;
if ( argc > 1 ) {
DEBUG ( DEBUG_ERR , ( " Unknown arguments to scriptstatus \n " ) ) ;
return - 1 ;
}
if ( argc = = 0 )
arg = ctdb_eventscript_call_names [ CTDB_EVENT_MONITOR ] ;
else
arg = argv [ 0 ] ;
for ( type = 0 ; type < CTDB_EVENT_MAX ; type + + ) {
if ( strcmp ( arg , ctdb_eventscript_call_names [ type ] ) = = 0 ) {
min = type ;
max = type + 1 ;
break ;
}
}
if ( type = = CTDB_EVENT_MAX ) {
if ( strcmp ( arg , " all " ) = = 0 ) {
min = 0 ;
max = CTDB_EVENT_MAX ;
} else {
DEBUG ( DEBUG_ERR , ( " Unknown event type %s \n " , argv [ 0 ] ) ) ;
return - 1 ;
}
}
if ( options . machinereadable ) {
printf ( " :Type:Name:Code:Status:Start:End:Error Output...: \n " ) ;
}
for ( type = min ; type < max ; type + + ) {
ret = control_one_scriptstatus ( ctdb , type ) ;
if ( ret ! = 0 ) {
return ret ;
}
}
2009-03-23 11:07:45 +03:00
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 )
{
2008-10-22 04:04:41 +04:00
uint32_t recmaster ;
2013-08-29 11:22:38 +04:00
int ret ;
2008-09-12 06:06:53 +04:00
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_getrecmaster ( ctdb , ctdb , TIMELIMIT ( ) , options . pnn , & recmaster ) ;
if ( ret ! = 0 ) {
2008-09-12 06:06:53 +04:00
DEBUG ( DEBUG_ERR , ( " Unable to get recmaster from node %u \n " , options . pnn ) ) ;
2011-08-23 10:32:38 +04:00
return - 1 ;
2008-09-12 06:06:53 +04:00
}
printf ( " %d \n " , recmaster ) ;
return 0 ;
}
2010-08-18 05:09:32 +04:00
/*
2010-08-18 06:36:03 +04:00
add a tickle to a public address
2010-08-18 05:09:32 +04:00
*/
static int control_add_tickle ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2010-08-18 06:36:03 +04:00
struct ctdb_tcp_connection t ;
2010-08-18 05:09:32 +04:00
TDB_DATA data ;
int ret ;
2013-08-19 08:40:52 +04:00
assert_single_node_only ( ) ;
2010-08-18 05:09:32 +04:00
if ( argc < 2 ) {
usage ( ) ;
}
2010-08-18 06:36:03 +04:00
if ( parse_ip_port ( argv [ 0 ] , & t . src_addr ) = = 0 ) {
2010-08-18 05:09:32 +04:00
DEBUG ( DEBUG_ERR , ( " Wrongly formed ip address '%s' \n " , argv [ 0 ] ) ) ;
return - 1 ;
}
2010-08-18 06:36:03 +04:00
if ( parse_ip_port ( argv [ 1 ] , & t . dst_addr ) = = 0 ) {
2010-08-18 05:09:32 +04:00
DEBUG ( DEBUG_ERR , ( " Wrongly formed ip address '%s' \n " , argv [ 1 ] ) ) ;
return - 1 ;
}
data . dptr = ( uint8_t * ) & t ;
data . dsize = sizeof ( t ) ;
/* tell all nodes about this tcp connection */
2010-08-18 06:36:03 +04:00
ret = ctdb_control ( ctdb , options . pnn , 0 , CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE ,
2010-08-18 05:09:32 +04:00
0 , data , ctdb , NULL , NULL , NULL , NULL ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to add tickle \n " ) ) ;
return - 1 ;
}
return 0 ;
}
2010-08-18 06:36:03 +04:00
/*
delete a tickle from a node
*/
static int control_del_tickle ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
struct ctdb_tcp_connection t ;
TDB_DATA data ;
int ret ;
2013-08-19 08:40:52 +04:00
assert_single_node_only ( ) ;
2010-08-18 06:36:03 +04:00
if ( argc < 2 ) {
usage ( ) ;
}
if ( parse_ip_port ( argv [ 0 ] , & t . src_addr ) = = 0 ) {
DEBUG ( DEBUG_ERR , ( " Wrongly formed ip address '%s' \n " , argv [ 0 ] ) ) ;
return - 1 ;
}
if ( parse_ip_port ( argv [ 1 ] , & t . dst_addr ) = = 0 ) {
DEBUG ( DEBUG_ERR , ( " Wrongly formed ip address '%s' \n " , argv [ 1 ] ) ) ;
return - 1 ;
}
data . dptr = ( uint8_t * ) & t ;
data . dsize = sizeof ( t ) ;
/* tell all nodes about this tcp connection */
ret = ctdb_control ( ctdb , options . pnn , 0 , CTDB_CONTROL_TCP_REMOVE ,
0 , data , ctdb , NULL , NULL , NULL , NULL ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to remove tickle \n " ) ) ;
return - 1 ;
}
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 ;
2010-08-20 05:25:12 +04:00
unsigned port = 0 ;
2007-07-20 09:05:55 +04:00
2013-08-19 08:40:52 +04:00
assert_single_node_only ( ) ;
2007-07-20 09:05:55 +04:00
if ( argc < 1 ) {
usage ( ) ;
}
2010-08-20 05:25:12 +04:00
if ( argc = = 2 ) {
port = atoi ( argv [ 1 ] ) ;
}
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 ;
}
2010-08-18 08:37:16 +04:00
if ( options . machinereadable ) {
printf ( " :source ip:port:destination ip:port: \n " ) ;
for ( i = 0 ; i < list - > tickles . num ; i + + ) {
2010-08-20 05:25:12 +04:00
if ( port & & port ! = ntohs ( list - > tickles . connections [ i ] . dst_addr . ip . sin_port ) ) {
continue ;
}
2010-08-18 08:37:16 +04:00
printf ( " :%s:%u " , ctdb_addr_to_str ( & list - > tickles . connections [ i ] . src_addr ) , ntohs ( list - > tickles . connections [ i ] . src_addr . ip . sin_port ) ) ;
printf ( " :%s:%u: \n " , ctdb_addr_to_str ( & list - > tickles . connections [ i ] . dst_addr ) , ntohs ( list - > tickles . connections [ i ] . dst_addr . ip . sin_port ) ) ;
}
} else {
printf ( " Tickles for ip:%s \n " , ctdb_addr_to_str ( & list - > addr ) ) ;
printf ( " Num tickles:%u \n " , list - > tickles . num ) ;
for ( i = 0 ; i < list - > tickles . num ; i + + ) {
2010-08-20 05:25:12 +04:00
if ( port & & port ! = ntohs ( list - > tickles . connections [ i ] . dst_addr . ip . sin_port ) ) {
continue ;
}
2010-08-18 08:37:16 +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 ) ;
2010-06-02 03:45:21 +04:00
ret = ctdb_client_send_message ( ctdb , CTDB_BROADCAST_CONNECTED , CTDB_SRVID_DISABLE_IP_CHECK , data ) ;
2009-10-06 05:11:32 +04:00
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 ;
}
2013-08-27 09:14:10 +04:00
nodes = list_of_nodes ( ctdb , nodemap , tmp_ctx , NODE_FLAGS_INACTIVE , 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 ,
2010-02-09 10:34:47 +03:00
LONGTIMELIMIT ( ) ,
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 ;
}
2010-02-09 10:34:47 +03:00
ret = ctdb_ctrl_takeover_ip ( ctdb , LONGTIMELIMIT ( ) , pnn , & ip ) ;
2009-06-09 04:56:50 +04:00
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
2010-04-28 09:43:11 +04:00
/* update the recovery daemon so it now knows to expect the new
node assignment for this ip .
*/
2010-06-02 03:45:21 +04:00
ret = ctdb_client_send_message ( ctdb , CTDB_BROADCAST_CONNECTED , CTDB_SRVID_RECD_UPDATE_IP , data ) ;
2010-04-28 09:43:11 +04:00
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to send message to update the ip on the recovery master. \n " ) ) ;
return - 1 ;
}
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
2013-02-27 09:01:55 +04:00
/*
* scans all other nodes and returns a pnn for another node that can host this
* ip address or - 1
*/
static int
find_other_host_for_public_ip ( struct ctdb_context * ctdb , ctdb_sock_addr * addr )
{
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 + + ) {
if ( nodemap - > nodes [ i ] . flags & NODE_FLAGS_INACTIVE ) {
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 + + ) {
if ( ctdb_same_ip ( addr , & ips - > ips [ j ] . addr ) ) {
talloc_free ( tmp_ctx ) ;
return nodemap - > nodes [ i ] . pnn ;
}
}
talloc_free ( ips ) ;
}
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
/* If pnn is -1 then try to find a node to move IP to... */
static bool try_moveip ( struct ctdb_context * ctdb , ctdb_sock_addr * addr , uint32_t pnn )
{
bool pnn_specified = ( pnn = = - 1 ? false : true ) ;
int retries = 0 ;
while ( retries < 5 ) {
if ( ! pnn_specified ) {
pnn = find_other_host_for_public_ip ( ctdb , addr ) ;
if ( pnn = = - 1 ) {
return false ;
}
DEBUG ( DEBUG_NOTICE ,
( " Trying to move public IP to node %u \n " , pnn ) ) ;
}
if ( move_ip ( ctdb , addr , pnn ) = = 0 ) {
return true ;
}
sleep ( 3 ) ;
retries + + ;
}
return false ;
}
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 ;
2013-08-19 08:40:52 +04:00
assert_single_node_only ( ) ;
2009-10-06 04:41:18 +04:00
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 ;
}
2013-02-27 09:01:55 +04:00
if ( ! try_moveip ( ctdb , & addr , pnn ) ) {
DEBUG ( DEBUG_ERR , ( " Failed to move IP to node %d. \n " , pnn ) ) ;
2009-10-06 04:41:18 +04:00
return - 1 ;
}
return 0 ;
}
2012-02-27 23:56:04 +04:00
static int rebalance_node ( struct ctdb_context * ctdb , uint32_t pnn )
{
TDB_DATA data ;
data . dptr = ( uint8_t * ) & pnn ;
data . dsize = sizeof ( uint32_t ) ;
2013-09-06 07:19:09 +04:00
if ( ctdb_client_send_message ( ctdb , CTDB_BROADCAST_CONNECTED , CTDB_SRVID_REBALANCE_NODE , data ) ! = 0 ) {
DEBUG ( DEBUG_ERR ,
( " Failed to send message to force node %u to be a rebalancing target \n " ,
pnn ) ) ;
2012-02-27 23:56:04 +04:00
return - 1 ;
}
return 0 ;
}
/*
rebalance a node by setting it to allow failback and triggering a
takeover run
*/
static int control_rebalancenode ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2013-08-29 11:22:38 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
2013-09-06 07:20:26 +04:00
uint32_t * nodes ;
uint32_t pnn_mode ;
int i , ret ;
assert_single_node_only ( ) ;
if ( argc > 1 ) {
usage ( ) ;
}
/* Determine the nodes where IPs need to be reloaded */
2013-08-29 11:22:38 +04:00
if ( ! parse_nodestring ( ctdb , tmp_ctx , argc = = 1 ? argv [ 0 ] : NULL ,
2013-09-06 07:20:26 +04:00
options . pnn , true , & nodes , & pnn_mode ) ) {
2013-08-29 11:22:38 +04:00
ret = - 1 ;
goto done ;
2012-02-27 23:56:04 +04:00
}
2013-09-06 07:20:26 +04:00
for ( i = 0 ; i < talloc_array_length ( nodes ) ; i + + ) {
if ( ! rebalance_node ( ctdb , nodes [ i ] ) ) {
ret = - 1 ;
}
}
2012-02-27 23:56:04 +04:00
2013-08-29 11:22:38 +04:00
done :
talloc_free ( tmp_ctx ) ;
2013-09-06 07:20:26 +04:00
return ret ;
}
2012-02-27 23:56:04 +04:00
2012-04-03 07:43:21 +04:00
static int rebalance_ip ( struct ctdb_context * ctdb , ctdb_sock_addr * addr )
{
struct ctdb_public_ip ip ;
int ret ;
uint32_t * nodes ;
uint32_t disable_time ;
TDB_DATA data ;
struct ctdb_node_map * nodemap = NULL ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
disable_time = 30 ;
data . dptr = ( uint8_t * ) & disable_time ;
data . dsize = sizeof ( disable_time ) ;
ret = ctdb_client_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 ;
}
ip . pnn = - 1 ;
ip . addr = * addr ;
data . dptr = ( uint8_t * ) & ip ;
data . dsize = sizeof ( ip ) ;
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , options . pnn , 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 ;
}
nodes = list_of_active_nodes ( ctdb , nodemap , tmp_ctx , true ) ;
ret = ctdb_client_async_control ( ctdb , CTDB_CONTROL_RELEASE_IP ,
nodes , 0 ,
LONGTIMELIMIT ( ) ,
false , data ,
NULL , NULL ,
NULL ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to release IP on nodes \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
talloc_free ( tmp_ctx ) ;
return 0 ;
}
/*
release an ip form all nodes and have it re - assigned by recd
*/
static int control_rebalanceip ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
ctdb_sock_addr addr ;
2013-08-19 08:40:52 +04:00
assert_single_node_only ( ) ;
2012-04-03 07:43:21 +04:00
if ( argc < 1 ) {
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 ( rebalance_ip ( ctdb , & addr ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Error when trying to reassign ip \n " ) ) ;
return - 1 ;
}
return 0 ;
}
2011-11-02 06:33:28 +04:00
static int getips_store_callback ( void * param , void * data )
2008-04-23 15:05:36 +04:00
{
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 ;
2011-11-02 06:33:28 +04:00
return 0 ;
2008-04-23 15:05:36 +04:00
}
2011-11-02 06:33:28 +04:00
static int getips_count_callback ( void * param , void * data )
2008-04-23 15:05:36 +04:00
{
uint32_t * count = param ;
( * count ) + + ;
2011-11-02 06:33:28 +04:00
return 0 ;
2008-04-23 15:05:36 +04:00
}
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 ;
2012-02-06 14:01:47 +04:00
case AF_INET6 : {
uint32_t * s6_a32 = ( uint32_t * ) & ( ip - > ip6 . sin6_addr . s6_addr ) ;
key [ 0 ] = s6_a32 [ 3 ] ;
key [ 1 ] = s6_a32 [ 2 ] ;
key [ 2 ] = s6_a32 [ 1 ] ;
key [ 3 ] = s6_a32 [ 0 ] ;
2008-08-22 03:09:08 +04:00
break ;
2012-02-06 14:01:47 +04:00
}
2008-08-22 03:09:08 +04:00
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
2010-12-13 04:06:01 +03: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 ) ;
}
2013-08-16 12:47:51 +04:00
struct srvid_reply_handler_data {
bool done ;
bool wait_for_all ;
uint32_t * nodes ;
const char * srvid_str ;
} ;
2013-08-16 11:06:23 +04:00
static void srvid_broadcast_reply_handler ( struct ctdb_context * ctdb ,
uint64_t srvid ,
TDB_DATA data ,
void * private_data )
{
2013-08-16 12:47:51 +04:00
struct srvid_reply_handler_data * d =
( struct srvid_reply_handler_data * ) private_data ;
int i ;
int32_t ret ;
if ( data . dsize ! = sizeof ( ret ) ) {
DEBUG ( DEBUG_ERR , ( __location__ " Wrong reply size \n " ) ) ;
return ;
}
2013-08-16 11:06:23 +04:00
2013-08-16 12:47:51 +04:00
/* ret will be a PNN (i.e. >=0) on success, or negative on error */
ret = * ( int32_t * ) data . dptr ;
if ( ret < 0 ) {
DEBUG ( DEBUG_ERR ,
( " %s failed with result %d \n " , d - > srvid_str , ret ) ) ;
return ;
}
if ( ! d - > wait_for_all ) {
d - > done = true ;
return ;
}
/* Wait for all replies */
d - > done = true ;
for ( i = 0 ; i < talloc_array_length ( d - > nodes ) ; i + + ) {
if ( d - > nodes [ i ] = = ret ) {
DEBUG ( DEBUG_INFO ,
( " %s reply received from node %u \n " ,
d - > srvid_str , ret ) ) ;
d - > nodes [ i ] = - 1 ;
}
if ( d - > nodes [ i ] ! = - 1 ) {
/* Found a node that hasn't yet replied */
d - > done = false ;
}
}
2013-08-16 11:06:23 +04:00
}
2013-08-16 12:47:51 +04:00
/* Broadcast the given SRVID to all connected nodes. Wait for 1 reply
* or replies from all connected nodes . arg is the data argument to
* pass in the srvid_request structure - pass 0 if this isn ' t needed .
2010-12-13 04:06:01 +03:00
*/
2013-08-16 11:06:23 +04:00
static int srvid_broadcast ( struct ctdb_context * ctdb ,
2013-11-12 08:16:49 +04:00
uint64_t srvid , uint32_t * arg ,
2013-08-16 12:47:51 +04:00
const char * srvid_str , bool wait_for_all )
2010-12-13 04:06:01 +03:00
{
2013-08-09 09:41:37 +04:00
int ret ;
2010-12-13 04:06:01 +03:00
TDB_DATA data ;
2013-11-12 08:16:49 +04:00
uint32_t pnn ;
uint64_t reply_srvid ;
2013-08-16 11:06:23 +04:00
struct srvid_request request ;
2013-11-12 08:16:49 +04:00
struct srvid_request_data request_data ;
2013-08-16 12:47:51 +04:00
struct srvid_reply_handler_data reply_data ;
2013-08-09 09:41:37 +04:00
struct timeval tv ;
2010-12-13 04:06:01 +03:00
2013-08-16 11:06:23 +04:00
ZERO_STRUCT ( request ) ;
2013-08-09 09:41:37 +04:00
/* Time ticks to enable timeouts to be processed */
2010-12-13 04:06:01 +03:00
event_add_timed ( ctdb - > ev , ctdb ,
timeval_current_ofs ( 1 , 0 ) ,
ctdb_every_second , ctdb ) ;
2013-11-12 08:16:49 +04:00
pnn = ctdb_get_pnn ( ctdb ) ;
reply_srvid = getpid ( ) ;
if ( arg = = NULL ) {
request . pnn = pnn ;
request . srvid = reply_srvid ;
data . dptr = ( uint8_t * ) & request ;
data . dsize = sizeof ( request ) ;
} else {
request_data . pnn = pnn ;
request_data . srvid = reply_srvid ;
request_data . data = * arg ;
data . dptr = ( uint8_t * ) & request_data ;
data . dsize = sizeof ( request_data ) ;
}
2010-12-13 04:06:01 +03:00
2013-08-09 09:41:37 +04:00
/* Register message port for reply from recovery master */
2013-11-12 08:16:49 +04:00
ctdb_client_set_message_handler ( ctdb , reply_srvid ,
2013-08-16 11:06:23 +04:00
srvid_broadcast_reply_handler ,
2013-08-16 12:47:51 +04:00
& reply_data ) ;
2010-12-13 04:06:01 +03:00
2013-08-16 12:47:51 +04:00
reply_data . wait_for_all = wait_for_all ;
reply_data . nodes = NULL ;
reply_data . srvid_str = srvid_str ;
2010-12-13 04:06:01 +03:00
again :
2013-08-16 12:47:51 +04:00
reply_data . done = false ;
if ( wait_for_all ) {
struct ctdb_node_map * nodemap ;
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) ,
CTDB_CURRENT_NODE , ctdb , & nodemap ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR ,
( " Unable to get nodemap from current node, try again \n " ) ) ;
sleep ( 1 ) ;
goto again ;
}
if ( reply_data . nodes ! = NULL ) {
talloc_free ( reply_data . nodes ) ;
}
reply_data . nodes = list_of_connected_nodes ( ctdb , nodemap ,
NULL , true ) ;
talloc_free ( nodemap ) ;
}
2013-08-16 10:25:28 +04:00
2013-08-09 09:41:37 +04:00
/* Send to all connected nodes. Only recmaster replies */
ret = ctdb_client_send_message ( ctdb , CTDB_BROADCAST_CONNECTED ,
2013-08-16 11:06:23 +04:00
srvid , data ) ;
2013-08-09 09:41:37 +04:00
if ( ret ! = 0 ) {
/* This can only happen if the socket is closed and
* there ' s no way to recover from that , so don ' t try
* again .
*/
2013-08-16 11:06:23 +04:00
DEBUG ( DEBUG_ERR ,
( " Failed to send %s request to connected nodes \n " ,
srvid_str ) ) ;
2013-08-09 09:41:37 +04:00
return - 1 ;
2010-12-13 04:06:01 +03:00
}
tv = timeval_current ( ) ;
2013-08-09 09:41:37 +04:00
/* This loop terminates the reply is received */
2013-08-16 12:47:51 +04:00
while ( timeval_elapsed ( & tv ) < 5.0 & & ! reply_data . done ) {
2010-12-13 04:06:01 +03:00
event_loop_once ( ctdb - > ev ) ;
}
2013-08-16 12:47:51 +04:00
if ( ! reply_data . done ) {
2013-08-09 09:41:37 +04:00
DEBUG ( DEBUG_NOTICE ,
2013-08-16 11:06:23 +04:00
( " Still waiting for confirmation of %s \n " , srvid_str ) ) ;
2013-08-16 12:47:51 +04:00
sleep ( 1 ) ;
2013-05-23 07:04:06 +04:00
goto again ;
}
2010-12-13 04:06:01 +03:00
2013-11-12 08:16:49 +04:00
ctdb_client_remove_message_handler ( ctdb , reply_srvid , & reply_data ) ;
2013-08-16 12:47:51 +04:00
talloc_free ( reply_data . nodes ) ;
2013-08-16 11:06:23 +04:00
2010-12-13 04:06:01 +03:00
return 0 ;
}
2013-08-16 11:06:23 +04:00
static int ipreallocate ( struct ctdb_context * ctdb )
{
2013-11-12 08:16:49 +04:00
return srvid_broadcast ( ctdb , CTDB_SRVID_TAKEOVER_RUN , NULL ,
2013-08-16 12:47:51 +04:00
" IP reallocation " , false ) ;
2013-08-16 11:06:23 +04:00
}
2010-12-13 04:06:01 +03:00
2013-08-09 09:41:37 +04:00
static int control_ipreallocate ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
return ipreallocate ( ctdb ) ;
}
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 ;
2011-01-13 08:17:43 +03:00
int len , retries = 0 ;
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 ;
}
2011-02-02 07:00:53 +03:00
/* read the public ip list from the node */
ret = ctdb_ctrl_get_public_ips ( ctdb , TIMELIMIT ( ) , options . pnn , tmp_ctx , & ips ) ;
2008-04-23 15:05:36 +04:00
if ( ret ! = 0 ) {
2011-02-02 07:00:53 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get public ip list from node %u \n " , options . pnn ) ) ;
2008-04-23 15:05:36 +04:00
talloc_free ( tmp_ctx ) ;
2011-02-02 07:00:53 +03:00
return - 1 ;
2008-04-23 15:05:36 +04:00
}
2009-06-05 11:00:47 +04:00
for ( i = 0 ; i < ips - > num ; i + + ) {
if ( ctdb_same_ip ( & addr , & ips - > ips [ i ] . addr ) ) {
2011-02-02 07:00:53 +03:00
DEBUG ( DEBUG_ERR , ( " Can not add ip to node. Node already hosts this ip \n " ) ) ;
return 0 ;
2009-06-05 11:00:47 +04:00
}
}
2011-02-02 07:00:53 +03:00
/* Dont timeout. This command waits for an ip reallocation
which sometimes can take wuite a while if there has
been a recent recovery
*/
alarm ( 0 ) ;
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
2011-01-13 08:17:43 +03:00
do {
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. Wait 3 seconds and try again. \n " , options . pnn ) ) ;
sleep ( 3 ) ;
retries + + ;
}
} while ( retries < 5 & & ret ! = 0 ) ;
2008-03-27 01:23:27 +03:00
if ( ret ! = 0 ) {
2011-01-13 08:17:43 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to add public ip to node %u. Giving up. \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 ;
}
2012-02-27 23:56:04 +04:00
if ( rebalance_node ( ctdb , options . pnn ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Error when trying to rebalance node \n " ) ) ;
2010-12-13 04:06:01 +03:00
return ret ;
}
2008-04-23 15:05:36 +04:00
talloc_free ( tmp_ctx ) ;
2008-03-27 01:23:27 +03:00
return 0 ;
}
2012-06-20 07:32:02 +04:00
/*
add a public ip address to a node
*/
static int control_ipiface ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
ctdb_sock_addr addr ;
if ( argc ! = 1 ) {
usage ( ) ;
}
if ( ! parse_ip ( argv [ 0 ] , NULL , 0 , & addr ) ) {
printf ( " Badly formed ip : %s \n " , argv [ 0 ] ) ;
return - 1 ;
}
printf ( " IP on interface %s \n " , ctdb_sys_find_ifname ( & addr ) ) ;
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 ;
}
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_get_public_ips ( ctdb , TIMELIMIT ( ) , nodemap - > nodes [ i ] . pnn , tmp_ctx , & ips ) ;
if ( ret ! = 0 ) {
2008-11-28 01:52:26 +03:00
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 ;
}
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_get_public_ips ( ctdb , TIMELIMIT ( ) , nodemap - > nodes [ i ] . pnn , tmp_ctx , & ips ) ;
if ( ret ! = 0 ) {
2008-11-28 01:52:26 +03:00
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 ;
}
2013-03-12 16:53:58 +04:00
/* This is an optimisation. If this node is hosting the IP
2013-02-27 09:01:55 +04:00
* then try to move it somewhere else without invoking a full
* takeover run . We don ' t care if this doesn ' t work !
*/
2008-04-24 15:51:08 +04:00
if ( ips - > ips [ i ] . pnn = = options . pnn ) {
2013-02-27 09:01:55 +04:00
( void ) try_moveip ( ctdb , & addr , - 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 ;
}
2013-07-25 07:28:26 +04:00
static int kill_tcp_from_file ( struct ctdb_context * ctdb ,
int argc , const char * * argv )
{
struct ctdb_control_killtcp * killtcp ;
int max_entries , current , i ;
struct timeval timeout ;
char line [ 128 ] , src [ 128 ] , dst [ 128 ] ;
int linenum ;
TDB_DATA data ;
struct client_async_data * async_data ;
struct ctdb_client_control_state * state ;
if ( argc ! = 0 ) {
usage ( ) ;
}
linenum = 1 ;
killtcp = NULL ;
max_entries = 0 ;
current = 0 ;
while ( ! feof ( stdin ) ) {
if ( fgets ( line , sizeof ( line ) , stdin ) = = NULL ) {
continue ;
}
/* Silently skip empty lines */
if ( line [ 0 ] = = ' \n ' ) {
continue ;
}
if ( sscanf ( line , " %s %s \n " , src , dst ) ! = 2 ) {
DEBUG ( DEBUG_ERR , ( " Bad line [%d]: '%s' \n " ,
linenum , line ) ) ;
talloc_free ( killtcp ) ;
return - 1 ;
}
if ( current > = max_entries ) {
max_entries + = 1024 ;
killtcp = talloc_realloc ( ctdb , killtcp ,
struct ctdb_control_killtcp ,
max_entries ) ;
CTDB_NO_MEMORY ( ctdb , killtcp ) ;
}
if ( ! parse_ip_port ( src , & killtcp [ current ] . src_addr ) ) {
DEBUG ( DEBUG_ERR , ( " Bad IP:port on line [%d]: '%s' \n " ,
linenum , src ) ) ;
talloc_free ( killtcp ) ;
return - 1 ;
}
if ( ! parse_ip_port ( dst , & killtcp [ current ] . dst_addr ) ) {
DEBUG ( DEBUG_ERR , ( " Bad IP:port on line [%d]: '%s' \n " ,
linenum , dst ) ) ;
talloc_free ( killtcp ) ;
return - 1 ;
}
current + + ;
}
async_data = talloc_zero ( ctdb , struct client_async_data ) ;
if ( async_data = = NULL ) {
talloc_free ( killtcp ) ;
return - 1 ;
}
for ( i = 0 ; i < current ; i + + ) {
data . dsize = sizeof ( struct ctdb_control_killtcp ) ;
data . dptr = ( unsigned char * ) & killtcp [ i ] ;
timeout = TIMELIMIT ( ) ;
state = ctdb_control_send ( ctdb , options . pnn , 0 ,
CTDB_CONTROL_KILL_TCP , 0 , data ,
async_data , & timeout , NULL ) ;
if ( state = = NULL ) {
DEBUG ( DEBUG_ERR ,
( " Failed to call async killtcp control to node %u \n " ,
options . pnn ) ) ;
talloc_free ( killtcp ) ;
return - 1 ;
}
ctdb_client_async_add ( async_data , state ) ;
}
if ( ctdb_client_async_wait ( ctdb , async_data ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " killtcp failed \n " ) ) ;
talloc_free ( killtcp ) ;
return - 1 ;
}
talloc_free ( killtcp ) ;
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
2013-08-19 08:40:52 +04:00
assert_single_node_only ( ) ;
2013-07-25 07:28:26 +04:00
if ( argc = = 0 ) {
return kill_tcp_from_file ( ctdb , argc , argv ) ;
}
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
2013-08-19 08:40:52 +04:00
assert_single_node_only ( ) ;
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 ;
}
2010-02-22 07:34:26 +03:00
DEBUG ( DEBUG_ERR , ( " Srvid registered. Sleeping for 999 seconds \n " ) ) ;
sleep ( 999 ) ;
2007-08-24 09:53:41 +04:00
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 ;
}
2011-10-31 19:21:54 +04:00
/*
check if a server id exists
*/
static int check_srvids ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2011-11-30 03:00:27 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( NULL ) ;
2011-10-31 19:21:54 +04:00
uint64_t * ids ;
2011-11-30 03:00:27 +04:00
uint8_t * result ;
2011-10-31 19:21:54 +04:00
int i ;
2011-11-30 02:50:12 +04:00
if ( argc < 1 ) {
2011-11-30 03:00:27 +04:00
talloc_free ( tmp_ctx ) ;
2011-10-31 19:21:54 +04:00
usage ( ) ;
}
2011-11-30 03:00:27 +04:00
ids = talloc_array ( tmp_ctx , uint64_t , argc ) ;
result = talloc_array ( tmp_ctx , uint8_t , argc ) ;
2011-10-31 19:21:54 +04:00
2011-11-30 02:50:12 +04:00
for ( i = 0 ; i < argc ; i + + ) {
ids [ i ] = strtoull ( argv [ i ] , NULL , 0 ) ;
2011-10-31 19:21:54 +04:00
}
2013-08-29 11:22:38 +04:00
if ( ! ctdb_client_check_message_handlers ( ctdb , ids , argc , result ) ) {
2011-10-31 19:21:54 +04:00
DEBUG ( DEBUG_ERR , ( " Unable to check server_id from node %u \n " ,
2011-11-30 02:50:12 +04:00
options . pnn ) ) ;
2011-11-30 03:00:27 +04:00
talloc_free ( tmp_ctx ) ;
return - 1 ;
2011-10-31 19:21:54 +04:00
}
2011-11-30 03:00:27 +04:00
for ( i = 0 ; i < argc ; i + + ) {
2011-11-30 02:50:12 +04:00
printf ( " Server id %d:%llu %s \n " , options . pnn , ( long long ) ids [ i ] ,
2011-11-30 03:00:27 +04:00
result [ i ] ? " exists " : " does not exist " ) ;
2011-10-31 19:21:54 +04:00
}
2011-11-30 03:00:27 +04:00
talloc_free ( tmp_ctx ) ;
2011-10-31 19:21:54 +04:00
return 0 ;
}
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 ) {
2010-08-20 05:38:34 +04:00
printf ( " :Public IP:Node: " ) ;
if ( options . verbose ) {
printf ( " ActiveInterface:AvailableInterfaces:ConfiguredInterfaces: " ) ;
}
printf ( " \n " ) ;
2007-09-14 09:23:23 +04:00
} 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 + + ) {
2010-01-16 12:36:35 +03:00
struct ctdb_control_public_ip_info * info = NULL ;
int32_t pnn ;
char * aciface = NULL ;
char * avifaces = NULL ;
char * cifaces = NULL ;
if ( options . pnn = = CTDB_BROADCAST_ALL ) {
pnn = ips - > ips [ ips - > num - i ] . pnn ;
} else {
pnn = options . pnn ;
}
if ( pnn ! = - 1 ) {
ret = ctdb_ctrl_get_public_ip_info ( ctdb , TIMELIMIT ( ) , pnn , ctdb ,
& ips - > ips [ ips - > num - i ] . addr , & info ) ;
} else {
ret = - 1 ;
}
if ( ret = = 0 ) {
int j ;
for ( j = 0 ; j < info - > num ; j + + ) {
if ( cifaces = = NULL ) {
cifaces = talloc_strdup ( info ,
info - > ifaces [ j ] . name ) ;
} else {
cifaces = talloc_asprintf_append ( cifaces ,
" ,%s " ,
info - > ifaces [ j ] . name ) ;
}
if ( info - > active_idx = = j ) {
aciface = info - > ifaces [ j ] . name ;
}
if ( info - > ifaces [ j ] . link_state = = 0 ) {
continue ;
}
if ( avifaces = = NULL ) {
avifaces = talloc_strdup ( info , info - > ifaces [ j ] . name ) ;
} else {
avifaces = talloc_asprintf_append ( avifaces ,
" ,%s " ,
info - > ifaces [ j ] . name ) ;
}
}
}
2008-03-04 05:18:27 +03:00
if ( options . machinereadable ) {
2010-08-20 05:38:34 +04:00
printf ( " :%s:%d: " ,
ctdb_addr_to_str ( & ips - > ips [ ips - > num - i ] . addr ) ,
ips - > ips [ ips - > num - i ] . pnn ) ;
if ( options . verbose ) {
printf ( " %s:%s:%s: " ,
aciface ? aciface : " " ,
avifaces ? avifaces : " " ,
cifaces ? cifaces : " " ) ;
}
printf ( " \n " ) ;
2008-03-04 05:18:27 +03:00
} else {
2010-08-20 05:38:34 +04:00
if ( options . verbose ) {
printf ( " %s node[%d] active[%s] available[%s] configured[%s] \n " ,
ctdb_addr_to_str ( & ips - > ips [ ips - > num - i ] . addr ) ,
ips - > ips [ ips - > num - i ] . pnn ,
aciface ? aciface : " " ,
avifaces ? avifaces : " " ,
cifaces ? cifaces : " " ) ;
} else {
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
}
2010-01-16 12:36:35 +03:00
talloc_free ( info ) ;
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 ;
}
2009-12-17 13:23:59 +03:00
/*
public ip info
*/
static int control_ipinfo ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int i , ret ;
ctdb_sock_addr addr ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
struct ctdb_control_public_ip_info * info ;
if ( argc ! = 1 ) {
talloc_free ( tmp_ctx ) ;
usage ( ) ;
}
if ( parse_ip ( argv [ 0 ] , NULL , 0 , & addr ) = = 0 ) {
DEBUG ( DEBUG_ERR , ( " Wrongly formed ip address '%s' \n " , argv [ 0 ] ) ) ;
return - 1 ;
}
/* read the public ip info from this node */
ret = ctdb_ctrl_get_public_ip_info ( ctdb , TIMELIMIT ( ) , options . pnn ,
tmp_ctx , & addr , & info ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get public ip[%s]info from node %u \n " ,
argv [ 0 ] , options . pnn ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
printf ( " Public IP[%s] info on node %u \n " ,
ctdb_addr_to_str ( & info - > ip . addr ) ,
options . pnn ) ;
printf ( " IP:%s \n CurrentNode:%d \n NumInterfaces:%u \n " ,
ctdb_addr_to_str ( & info - > ip . addr ) ,
info - > ip . pnn , info - > num ) ;
for ( i = 0 ; i < info - > num ; i + + ) {
info - > ifaces [ i ] . name [ CTDB_IFACE_SIZE ] = ' \0 ' ;
printf ( " Interface[%u]: Name:%s Link:%s References:%u%s \n " ,
i + 1 , info - > ifaces [ i ] . name ,
info - > ifaces [ i ] . link_state ? " up " : " down " ,
( unsigned int ) info - > ifaces [ i ] . references ,
( i = = info - > active_idx ) ? " (active) " : " " ) ;
}
talloc_free ( tmp_ctx ) ;
return 0 ;
}
2009-12-16 18:50:23 +03:00
/*
display interfaces status
*/
static int control_ifaces ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2013-08-29 11:22:38 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
2011-12-06 06:11:13 +04:00
int i ;
2013-08-29 11:22:38 +04:00
struct ctdb_control_get_ifaces * ifaces ;
int ret ;
2009-12-16 18:50:23 +03:00
/* read the public ip list from this node */
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_get_ifaces ( ctdb , TIMELIMIT ( ) , options . pnn , tmp_ctx , & ifaces ) ;
if ( ret ! = 0 ) {
2009-12-16 18:50:23 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get interfaces from node %u \n " ,
options . pnn ) ) ;
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2011-12-06 06:11:13 +04:00
return - 1 ;
2009-12-16 18:50:23 +03:00
}
if ( options . machinereadable ) {
printf ( " :Name:LinkStatus:References: \n " ) ;
} else {
printf ( " Interfaces on node %u \n " , options . pnn ) ;
}
for ( i = 0 ; i < ifaces - > num ; i + + ) {
if ( options . machinereadable ) {
printf ( " :%s:%s:%u \n " ,
ifaces - > ifaces [ i ] . name ,
ifaces - > ifaces [ i ] . link_state ? " 1 " : " 0 " ,
( unsigned int ) ifaces - > ifaces [ i ] . references ) ;
} else {
printf ( " name:%s link:%s references:%u \n " ,
ifaces - > ifaces [ i ] . name ,
ifaces - > ifaces [ i ] . link_state ? " up " : " down " ,
( unsigned int ) ifaces - > ifaces [ i ] . references ) ;
}
}
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2009-12-16 18:50:23 +03:00
return 0 ;
}
2009-12-16 19:02:23 +03:00
/*
set link status of an interface
*/
static int control_setifacelink ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
struct ctdb_control_iface_info info ;
ZERO_STRUCT ( info ) ;
if ( argc ! = 2 ) {
usage ( ) ;
}
if ( strlen ( argv [ 0 ] ) > CTDB_IFACE_SIZE ) {
DEBUG ( DEBUG_ERR , ( " interfaces name '%s' too long \n " ,
argv [ 0 ] ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
strcpy ( info . name , argv [ 0 ] ) ;
if ( strcmp ( argv [ 1 ] , " up " ) = = 0 ) {
info . link_state = 1 ;
} else if ( strcmp ( argv [ 1 ] , " down " ) = = 0 ) {
info . link_state = 0 ;
} else {
DEBUG ( DEBUG_ERR , ( " link state invalid '%s' should be 'up' or 'down' \n " ,
argv [ 1 ] ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
/* read the public ip list from this node */
ret = ctdb_ctrl_set_iface_link ( ctdb , TIMELIMIT ( ) , options . pnn ,
tmp_ctx , & info ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to set link state for interfaces %s node %u \n " ,
argv [ 0 ] , options . pnn ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
talloc_free ( tmp_ctx ) ;
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 ;
}
2013-08-09 10:34:59 +04:00
typedef bool update_flags_handler_t ( struct ctdb_context * ctdb , void * data ) ;
static int update_flags_and_ipreallocate ( struct ctdb_context * ctdb ,
void * data ,
update_flags_handler_t handler ,
uint32_t flag ,
const char * desc ,
bool set_flag )
2007-06-07 03:16:17 +04:00
{
2013-08-09 10:34:59 +04:00
struct ctdb_node_map * nodemap = NULL ;
bool flag_is_set ;
2013-08-29 11:22:38 +04:00
int ret ;
2007-06-07 03:16:17 +04:00
2013-08-09 10:34:59 +04:00
/* Check if the node is already in the desired state */
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE , ctdb , & nodemap ) ;
if ( ret ! = 0 ) {
2010-02-04 02:03:21 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from local node \n " ) ) ;
exit ( 10 ) ;
}
2013-08-09 10:34:59 +04:00
flag_is_set = nodemap - > nodes [ options . pnn ] . flags & flag ;
if ( set_flag = = flag_is_set ) {
DEBUG ( DEBUG_NOTICE , ( " Node %d is %s %s \n " , options . pnn ,
( set_flag ? " already " : " not " ) , desc ) ) ;
2010-02-04 02:03:21 +03:00
return 0 ;
}
2009-07-01 03:33:08 +04:00
do {
2013-08-09 10:34:59 +04:00
if ( ! handler ( ctdb , data ) ) {
DEBUG ( DEBUG_WARNING ,
( " Failed to send control to set state %s on node %u, try again \n " ,
desc , options . pnn ) ) ;
2009-07-01 03:33:08 +04:00
}
sleep ( 1 ) ;
2013-08-09 10:34:59 +04:00
/* Read the nodemap and verify the change took effect.
* Even if the above control / hanlder timed out then it
* could still have worked !
*/
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , CTDB_CURRENT_NODE ,
ctdb , & nodemap ) ;
if ( ret ! = 0 ) {
2013-08-09 10:34:59 +04:00
DEBUG ( DEBUG_WARNING ,
( " Unable to get nodemap from local node, try again \n " ) ) ;
2009-07-01 03:33:08 +04:00
}
2013-08-09 10:34:59 +04:00
flag_is_set = nodemap - > nodes [ options . pnn ] . flags & flag ;
} while ( nodemap = = NULL | | ( set_flag ! = flag_is_set ) ) ;
2009-07-01 03:33:08 +04:00
2013-08-09 10:34:59 +04:00
return ipreallocate ( ctdb ) ;
2007-06-07 03:16:17 +04:00
}
2013-08-09 10:34:59 +04:00
/* Administratively disable a node */
static bool update_flags_disabled ( struct ctdb_context * ctdb , void * data )
2007-06-07 03:16:17 +04:00
{
2013-08-29 11:22:38 +04:00
int ret ;
ret = ctdb_ctrl_modflags ( ctdb , TIMELIMIT ( ) , options . pnn ,
NODE_FLAGS_PERMANENTLY_DISABLED , 0 ) ;
return ret = = 0 ;
2013-08-09 10:34:59 +04:00
}
2009-07-01 03:33:08 +04:00
2013-08-09 10:34:59 +04:00
static int control_disable ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
return update_flags_and_ipreallocate ( ctdb , NULL ,
update_flags_disabled ,
NODE_FLAGS_PERMANENTLY_DISABLED ,
" disabled " ,
true /* set_flag*/ ) ;
}
2009-07-01 03:33:08 +04:00
2013-08-09 10:34:59 +04:00
/* Administratively re-enable a node */
static bool update_flags_not_disabled ( struct ctdb_context * ctdb , void * data )
{
2013-08-29 11:22:38 +04:00
int ret ;
ret = ctdb_ctrl_modflags ( ctdb , TIMELIMIT ( ) , options . pnn ,
0 , NODE_FLAGS_PERMANENTLY_DISABLED ) ;
return ret = = 0 ;
2013-08-09 10:34:59 +04:00
}
2010-02-09 06:35:10 +03:00
2013-08-09 10:34:59 +04:00
static int control_enable ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
return update_flags_and_ipreallocate ( ctdb , NULL ,
update_flags_not_disabled ,
NODE_FLAGS_PERMANENTLY_DISABLED ,
" disabled " ,
false /* set_flag*/ ) ;
}
2007-06-07 03:16:17 +04:00
2013-08-09 10:34:59 +04:00
/* Stop a node */
static bool update_flags_stopped ( struct ctdb_context * ctdb , void * data )
{
2013-08-29 11:22:38 +04:00
int ret ;
ret = ctdb_ctrl_stop_node ( ctdb , TIMELIMIT ( ) , options . pnn ) ;
return ret = = 0 ;
2007-06-07 03:16:17 +04:00
}
2009-07-09 05:38:18 +04:00
static int control_stop ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2013-08-09 10:34:59 +04:00
return update_flags_and_ipreallocate ( ctdb , NULL ,
update_flags_stopped ,
NODE_FLAGS_STOPPED ,
" stopped " ,
true /* set_flag*/ ) ;
}
2009-07-09 05:38:18 +04:00
2013-08-09 10:34:59 +04:00
/* Continue a stopped node */
static bool update_flags_not_stopped ( struct ctdb_context * ctdb , void * data )
{
2013-08-29 11:22:38 +04:00
int ret ;
ret = ctdb_ctrl_continue_node ( ctdb , TIMELIMIT ( ) , options . pnn ) ;
return ret = = 0 ;
2009-07-09 05:38:18 +04:00
}
static int control_continue ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2013-08-09 10:34:59 +04:00
return update_flags_and_ipreallocate ( ctdb , NULL ,
update_flags_not_stopped ,
NODE_FLAGS_STOPPED ,
" stopped " ,
false /* set_flag */ ) ;
2009-07-09 05:38:18 +04:00
}
2008-12-09 04:03:42 +03:00
static uint32_t get_generation ( struct ctdb_context * ctdb )
{
2013-08-29 11:22:38 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
2008-12-09 04:03:42 +03:00
struct ctdb_vnn_map * vnnmap = NULL ;
int ret ;
2013-08-29 11:22:38 +04:00
uint32_t generation ;
2008-12-09 04:03:42 +03:00
/* 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 */
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_getrecmaster ( ctdb , tmp_ctx , TIMELIMIT ( ) , CTDB_CURRENT_NODE , & recmaster ) ;
if ( ret ! = 0 ) {
2008-12-09 04:03:42 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get recmaster from node %u \n " , options . pnn ) ) ;
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2008-12-09 04:03:42 +03:00
exit ( 10 ) ;
}
/* get recovery mode */
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_getrecmode ( ctdb , tmp_ctx , TIMELIMIT ( ) , recmaster , & recmode ) ;
if ( ret ! = 0 ) {
2008-12-09 04:03:42 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to get recmode from node %u \n " , options . pnn ) ) ;
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2008-12-09 04:03:42 +03:00
exit ( 10 ) ;
}
/* get the current generation number */
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_getvnnmap ( ctdb , TIMELIMIT ( ) , recmaster , tmp_ctx , & vnnmap ) ;
2008-12-09 04:03:42 +03:00
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get vnnmap from recmaster (%u) \n " , recmaster ) ) ;
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2008-12-09 04:03:42 +03:00
exit ( 10 ) ;
}
2013-08-29 11:22:38 +04:00
if ( ( recmode = = CTDB_RECOVERY_NORMAL ) & & ( vnnmap - > generation ! = 1 ) ) {
generation = vnnmap - > generation ;
talloc_free ( tmp_ctx ) ;
return generation ;
2008-12-09 04:03:42 +03:00
}
sleep ( 1 ) ;
}
}
2013-08-09 10:58:42 +04:00
/* Ban a node */
static bool update_state_banned ( struct ctdb_context * ctdb , void * data )
{
struct ctdb_ban_time * bantime = ( struct ctdb_ban_time * ) data ;
2013-08-29 11:22:38 +04:00
int ret ;
ret = ctdb_ctrl_set_ban ( ctdb , TIMELIMIT ( ) , options . pnn , bantime ) ;
return ret = = 0 ;
2013-08-09 10:58:42 +04:00
}
2007-06-07 10:34:33 +04:00
static int control_ban ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
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
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
2013-09-23 10:19:52 +04:00
if ( bantime . time = = 0 ) {
DEBUG ( DEBUG_ERR , ( " Invalid ban time specified - must be >0 \n " ) ) ;
return - 1 ;
}
2013-08-09 10:58:42 +04:00
return update_flags_and_ipreallocate ( ctdb , & bantime ,
update_state_banned ,
NODE_FLAGS_BANNED ,
" banned " ,
true /* set_flag*/ ) ;
2007-06-07 10:34:33 +04:00
}
2013-08-09 10:58:42 +04:00
/* Unban a node */
2007-06-07 10:34:33 +04:00
static int control_unban ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
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
bantime . pnn = options . pnn ;
bantime . time = 0 ;
2013-08-09 10:58:42 +04:00
return update_flags_and_ipreallocate ( ctdb , & bantime ,
update_state_banned ,
NODE_FLAGS_BANNED ,
" banned " ,
false /* set_flag*/ ) ;
2007-06-07 10:34:33 +04:00
}
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 {
2013-08-09 11:00:10 +04:00
printf ( " Node %u is banned, %d seconds remaining \n " ,
bantime - > pnn , bantime - > time ) ;
2009-09-03 20:20:39 +04:00
}
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 ;
2013-06-26 08:34:47 +04:00
bool force ;
/* "force" option ignores freeze failure and forces recovery */
force = ( argc = = 1 ) & & ( strcasecmp ( argv [ 0 ] , " force " ) = = 0 ) ;
2008-12-10 04:06:51 +03:00
/* 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 ) {
2013-06-26 08:34:47 +04:00
if ( ! force ) {
DEBUG ( DEBUG_ERR , ( " Unable to freeze node \n " ) ) ;
return ret ;
}
DEBUG ( DEBUG_WARNING , ( " Unable to freeze node but proceeding because \" force \" option given \n " ) ) ;
2007-05-24 02:08:45 +04:00
}
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 ;
2013-08-29 11:22:38 +04:00
int ret ;
2008-05-06 04:02:27 +04:00
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_getcapabilities ( ctdb , TIMELIMIT ( ) , options . pnn , & capabilities ) ;
if ( ret ! = 0 ) {
2008-05-06 04:02:27 +04:00
DEBUG ( DEBUG_ERR , ( " Unable to get capabilities from node %u \n " , options . pnn ) ) ;
2012-07-18 10:57:01 +04:00
return - 1 ;
2008-05-06 04:02:27 +04:00
}
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
*/
2014-02-19 11:45:18 +04:00
static uint32_t lvs_exclude_flags [ ] = {
/* Look for a nice healthy node */
NODE_FLAGS_INACTIVE | NODE_FLAGS_DISABLED ,
/* If not found, an UNHEALTHY node will do */
NODE_FLAGS_INACTIVE | NODE_FLAGS_PERMANENTLY_DISABLED ,
0 ,
} ;
2008-07-10 05:12:58 +04:00
static int control_lvs ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2013-08-29 11:22:38 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
2014-02-19 10:12:08 +04:00
struct ctdb_node_map * orig_nodemap = NULL ;
struct ctdb_node_map * nodemap ;
2008-07-10 05:12:58 +04:00
int i , ret ;
2014-02-19 10:12:08 +04:00
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , options . pnn ,
tmp_ctx , & orig_nodemap ) ;
2013-08-29 11:22:38 +04:00
if ( ret ! = 0 ) {
2008-07-10 05:12:58 +04:00
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from node %u \n " , options . pnn ) ) ;
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2012-07-18 10:57:01 +04:00
return - 1 ;
2008-07-10 05:12:58 +04:00
}
2014-02-19 10:12:08 +04:00
nodemap = filter_nodemap_by_capabilities ( ctdb , orig_nodemap ,
CTDB_CAP_LVS ) ;
if ( nodemap = = NULL ) {
/* No memory */
ret = - 1 ;
goto done ;
}
2012-07-18 10:57:01 +04:00
ret = 0 ;
2014-02-19 11:45:18 +04:00
for ( i = 0 ; lvs_exclude_flags [ i ] ! = 0 ; i + + ) {
struct ctdb_node_map * t =
filter_nodemap_by_flags ( ctdb , nodemap ,
lvs_exclude_flags [ i ] ) ;
if ( t = = NULL ) {
/* No memory */
ret = - 1 ;
goto done ;
2008-07-10 05:12:58 +04:00
}
2014-02-19 11:45:18 +04:00
if ( t - > num > 0 ) {
/* At least 1 node without excluded flags */
int j ;
for ( j = 0 ; j < t - > num ; j + + ) {
printf ( " %d:%s \n " , t - > nodes [ j ] . pnn ,
ctdb_addr_to_str ( & t - > nodes [ j ] . addr ) ) ;
2008-07-10 05:12:58 +04:00
}
2014-02-19 11:45:18 +04:00
goto done ;
2008-07-10 05:12:58 +04:00
}
2014-02-19 11:45:18 +04:00
talloc_free ( t ) ;
2008-07-10 05:12:58 +04:00
}
2012-07-18 10:57:01 +04:00
done :
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2012-07-18 10:57:01 +04:00
return ret ;
2008-07-10 05:12:58 +04:00
}
/*
display who is the lvs master
*/
static int control_lvsmaster ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2013-08-29 11:22:38 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
2014-02-19 10:12:08 +04:00
struct ctdb_node_map * orig_nodemap = NULL ;
struct ctdb_node_map * nodemap ;
2008-07-10 05:12:58 +04:00
int i , ret ;
2014-02-19 10:12:08 +04:00
ret = ctdb_ctrl_getnodemap ( ctdb , TIMELIMIT ( ) , options . pnn ,
tmp_ctx , & orig_nodemap ) ;
2013-08-29 11:22:38 +04:00
if ( ret ! = 0 ) {
2008-07-10 05:12:58 +04:00
DEBUG ( DEBUG_ERR , ( " Unable to get nodemap from node %u \n " , options . pnn ) ) ;
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2012-07-18 10:57:01 +04:00
return - 1 ;
2008-07-10 05:12:58 +04:00
}
2014-02-19 10:12:08 +04:00
nodemap = filter_nodemap_by_capabilities ( ctdb , orig_nodemap ,
CTDB_CAP_LVS ) ;
if ( nodemap = = NULL ) {
/* No memory */
ret = - 1 ;
goto done ;
2013-08-29 11:22:38 +04:00
}
2012-07-18 10:57:01 +04:00
2014-02-19 11:45:18 +04:00
for ( i = 0 ; lvs_exclude_flags [ i ] ! = 0 ; i + + ) {
struct ctdb_node_map * t =
filter_nodemap_by_flags ( ctdb , nodemap ,
lvs_exclude_flags [ i ] ) ;
if ( t = = NULL ) {
/* No memory */
ret = - 1 ;
goto done ;
2008-07-10 05:12:58 +04:00
}
2014-02-19 11:45:18 +04:00
if ( t - > num > 0 ) {
ret = 0 ;
printf ( options . machinereadable ?
" %d \n " : " Node %d is LVS master \n " ,
t - > nodes [ 0 ] . pnn ) ;
goto done ;
2009-05-11 08:44:59 +04:00
}
2014-02-19 11:45:18 +04:00
talloc_free ( t ) ;
2008-07-10 05:12:58 +04:00
}
printf ( " There is no LVS master \n " ) ;
2014-02-19 11:45:18 +04:00
ret = 255 ;
2012-07-18 10:57:01 +04:00
done :
2013-08-29 11:22:38 +04:00
talloc_free ( tmp_ctx ) ;
2012-07-18 10:57:01 +04:00
return ret ;
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 ;
2011-11-28 20:11:16 +04:00
struct ctdb_dump_db_context c ;
2012-12-19 07:43:26 +04:00
uint8_t flags ;
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 ( ) ;
}
2013-11-13 08:25:46 +04:00
if ( ! db_exists ( ctdb , argv [ 0 ] , NULL , & db_name , & flags ) ) {
2008-09-22 19:38:28 +04:00
return - 1 ;
}
2012-12-19 07:43:26 +04:00
ctdb_db = ctdb_attach ( ctdb , TIMELIMIT ( ) , db_name , flags & CTDB_DB_FLAGS_PERSISTENT , 0 ) ;
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
2011-11-28 20:36:03 +04:00
if ( options . printlmaster ) {
ret = ctdb_ctrl_getvnnmap ( ctdb , TIMELIMIT ( ) , options . pnn ,
ctdb , & ctdb - > vnn_map ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get vnnmap from node %u \n " ,
options . pnn ) ) ;
return ret ;
}
}
2011-11-28 20:11:16 +04:00
ZERO_STRUCT ( c ) ;
c . f = stdout ;
c . printemptyrecords = ( bool ) options . printemptyrecords ;
2011-11-28 20:19:03 +04:00
c . printdatasize = ( bool ) options . printdatasize ;
2011-11-28 20:36:03 +04:00
c . printlmaster = ( bool ) options . printlmaster ;
2011-11-29 03:56:23 +04:00
c . printhash = ( bool ) options . printhash ;
2011-11-29 13:24:52 +04:00
c . printrecordflags = ( bool ) options . printrecordflags ;
2011-11-28 20:11:16 +04:00
2007-05-29 06:16:59 +04:00
/* traverse and dump the cluster tdb */
2011-11-28 20:11:16 +04:00
ret = ctdb_dump_db ( ctdb_db , & c ) ;
2007-05-29 06:16:59 +04:00
if ( ret = = - 1 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( " Unable to dump database \n " ) ) ;
2009-12-07 11:57:45 +03:00
DEBUG ( DEBUG_ERR , ( " Maybe try 'ctdb getdbstatus %s' "
" and 'ctdb getvar AllowUnhealthyDBRead' \n " ,
db_name ) ) ;
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 ;
}
2011-07-20 06:30:33 +04:00
struct cattdb_data {
struct ctdb_context * ctdb ;
uint32_t count ;
} ;
static int cattdb_traverse ( struct tdb_context * tdb , TDB_DATA key , TDB_DATA data , void * private_data )
{
struct cattdb_data * d = private_data ;
2011-11-28 20:11:16 +04:00
struct ctdb_dump_db_context c ;
2011-07-20 06:30:33 +04:00
d - > count + + ;
2011-11-28 20:11:16 +04:00
ZERO_STRUCT ( c ) ;
c . f = stdout ;
c . printemptyrecords = ( bool ) options . printemptyrecords ;
2011-11-28 20:19:03 +04:00
c . printdatasize = ( bool ) options . printdatasize ;
2011-11-28 20:36:03 +04:00
c . printlmaster = false ;
2011-11-29 03:56:23 +04:00
c . printhash = ( bool ) options . printhash ;
2011-11-29 13:24:52 +04:00
c . printrecordflags = true ;
2011-11-28 20:11:16 +04:00
return ctdb_dumpdb_record ( d - > ctdb , key , data , & c ) ;
2011-07-20 06:30:33 +04:00
}
/*
cat the local tdb database using same format as catdb
*/
static int control_cattdb ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
const char * db_name ;
struct ctdb_db_context * ctdb_db ;
struct cattdb_data d ;
2012-12-19 07:43:26 +04:00
uint8_t flags ;
2011-07-20 06:30:33 +04:00
if ( argc < 1 ) {
usage ( ) ;
}
2013-11-13 08:25:46 +04:00
if ( ! db_exists ( ctdb , argv [ 0 ] , NULL , & db_name , & flags ) ) {
2011-07-20 06:30:33 +04:00
return - 1 ;
}
2012-12-19 07:43:26 +04:00
ctdb_db = ctdb_attach ( ctdb , TIMELIMIT ( ) , db_name , flags & CTDB_DB_FLAGS_PERSISTENT , 0 ) ;
2011-07-20 06:30:33 +04:00
if ( ctdb_db = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Unable to attach to database '%s' \n " , db_name ) ) ;
return - 1 ;
}
/* traverse the local tdb */
d . count = 0 ;
d . ctdb = ctdb ;
if ( tdb_traverse_read ( ctdb_db - > ltdb - > tdb , cattdb_traverse , & d ) = = - 1 ) {
printf ( " Failed to cattdb data \n " ) ;
exit ( 10 ) ;
}
talloc_free ( ctdb_db ) ;
printf ( " Dumped %d records \n " , d . count ) ;
return 0 ;
}
2010-12-06 08:07:55 +03:00
/*
display the content of a database key
*/
static int control_readkey ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
const char * db_name ;
struct ctdb_db_context * ctdb_db ;
struct ctdb_record_handle * h ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
TDB_DATA key , data ;
2012-12-19 07:43:26 +04:00
uint8_t flags ;
2010-12-06 08:07:55 +03:00
if ( argc < 2 ) {
usage ( ) ;
}
2013-11-13 08:25:46 +04:00
if ( ! db_exists ( ctdb , argv [ 0 ] , NULL , & db_name , & flags ) ) {
2010-12-06 08:07:55 +03:00
return - 1 ;
}
2012-12-19 07:43:26 +04:00
ctdb_db = ctdb_attach ( ctdb , TIMELIMIT ( ) , db_name , flags & CTDB_DB_FLAGS_PERSISTENT , 0 ) ;
2010-12-06 08:07:55 +03:00
if ( ctdb_db = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Unable to attach to database '%s' \n " , db_name ) ) ;
return - 1 ;
}
key . dptr = discard_const ( argv [ 1 ] ) ;
key . dsize = strlen ( ( char * ) key . dptr ) ;
2012-02-07 03:21:12 +04:00
2010-12-06 08:07:55 +03:00
h = ctdb_fetch_lock ( ctdb_db , tmp_ctx , key , & data ) ;
if ( h = = NULL ) {
printf ( " Failed to fetch record '%s' on node %d \n " ,
( const char * ) key . dptr , ctdb_get_pnn ( ctdb ) ) ;
talloc_free ( tmp_ctx ) ;
exit ( 10 ) ;
}
2013-08-29 10:58:47 +04:00
printf ( " Data: size:%d ptr:[%.*s] \n " , ( int ) data . dsize , ( int ) data . dsize , data . dptr ) ;
2010-12-06 08:07:55 +03:00
talloc_free ( ctdb_db ) ;
talloc_free ( tmp_ctx ) ;
return 0 ;
}
/*
display the content of a database key
*/
static int control_writekey ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
const char * db_name ;
struct ctdb_db_context * ctdb_db ;
struct ctdb_record_handle * h ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
TDB_DATA key , data ;
2012-12-19 07:43:26 +04:00
uint8_t flags ;
2010-12-06 08:07:55 +03:00
if ( argc < 3 ) {
usage ( ) ;
}
2013-11-13 08:25:46 +04:00
if ( ! db_exists ( ctdb , argv [ 0 ] , NULL , & db_name , & flags ) ) {
2010-12-06 08:07:55 +03:00
return - 1 ;
}
2012-12-19 07:43:26 +04:00
ctdb_db = ctdb_attach ( ctdb , TIMELIMIT ( ) , db_name , flags & CTDB_DB_FLAGS_PERSISTENT , 0 ) ;
2010-12-06 08:07:55 +03:00
if ( ctdb_db = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Unable to attach to database '%s' \n " , db_name ) ) ;
return - 1 ;
}
key . dptr = discard_const ( argv [ 1 ] ) ;
key . dsize = strlen ( ( char * ) key . dptr ) ;
2012-02-07 03:21:12 +04:00
2010-12-06 08:07:55 +03:00
h = ctdb_fetch_lock ( ctdb_db , tmp_ctx , key , & data ) ;
if ( h = = NULL ) {
printf ( " Failed to fetch record '%s' on node %d \n " ,
( const char * ) key . dptr , ctdb_get_pnn ( ctdb ) ) ;
talloc_free ( tmp_ctx ) ;
exit ( 10 ) ;
}
data . dptr = discard_const ( argv [ 2 ] ) ;
data . dsize = strlen ( ( char * ) data . dptr ) ;
2012-02-07 03:21:12 +04:00
2010-12-06 08:07:55 +03:00
if ( ctdb_record_store ( h , data ) ! = 0 ) {
printf ( " Failed to store record \n " ) ;
}
talloc_free ( h ) ;
talloc_free ( ctdb_db ) ;
talloc_free ( tmp_ctx ) ;
return 0 ;
}
2007-04-29 18:58:27 +04:00
2010-08-24 07:34:09 +04:00
/*
fetch a record from a persistent database
*/
static int control_pfetch ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
const char * db_name ;
struct ctdb_db_context * ctdb_db ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
struct ctdb_transaction_handle * h ;
TDB_DATA key , data ;
2010-08-25 02:07:03 +04:00
int fd , ret ;
2010-09-14 18:21:27 +04:00
bool persistent ;
2012-12-19 07:43:26 +04:00
uint8_t flags ;
2010-08-24 07:34:09 +04:00
if ( argc < 2 ) {
talloc_free ( tmp_ctx ) ;
usage ( ) ;
}
2013-11-13 08:25:46 +04:00
if ( ! db_exists ( ctdb , argv [ 0 ] , NULL , & db_name , & flags ) ) {
2010-08-24 07:34:09 +04:00
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2012-12-19 07:43:26 +04:00
persistent = flags & CTDB_DB_FLAGS_PERSISTENT ;
2010-09-14 18:21:27 +04:00
if ( ! persistent ) {
DEBUG ( DEBUG_ERR , ( " Database '%s' is not persistent \n " , db_name ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2011-08-08 18:35:56 +04:00
ctdb_db = ctdb_attach ( ctdb , TIMELIMIT ( ) , db_name , persistent , 0 ) ;
2010-08-24 07:34:09 +04:00
if ( ctdb_db = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Unable to attach to database '%s' \n " , db_name ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
h = ctdb_transaction_start ( ctdb_db , tmp_ctx ) ;
if ( h = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to start transaction on database %s \n " , db_name ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
key . dptr = discard_const ( argv [ 1 ] ) ;
key . dsize = strlen ( argv [ 1 ] ) ;
ret = ctdb_transaction_fetch ( h , tmp_ctx , key , & data ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to fetch record \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
if ( data . dsize = = 0 | | data . dptr = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Record is empty \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2010-08-25 02:07:03 +04:00
if ( argc = = 3 ) {
2010-08-25 03:54:37 +04:00
fd = open ( argv [ 2 ] , O_WRONLY | O_CREAT | O_TRUNC , 0600 ) ;
2010-08-25 02:07:03 +04:00
if ( fd = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " Failed to open output file %s \n " , argv [ 2 ] ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
write ( fd , data . dptr , data . dsize ) ;
close ( fd ) ;
} else {
write ( 1 , data . dptr , data . dsize ) ;
}
2010-08-24 07:34:09 +04:00
/* abort the transaction */
talloc_free ( h ) ;
talloc_free ( tmp_ctx ) ;
return 0 ;
}
2010-08-25 04:53:54 +04:00
/*
fetch a record from a tdb - file
*/
static int control_tfetch ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
const char * tdb_file ;
TDB_CONTEXT * tdb ;
TDB_DATA key , data ;
2012-02-07 03:21:12 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( NULL ) ;
2010-08-25 04:53:54 +04:00
int fd ;
if ( argc < 2 ) {
usage ( ) ;
}
tdb_file = argv [ 0 ] ;
tdb = tdb_open ( tdb_file , 0 , 0 , O_RDONLY , 0 ) ;
if ( tdb = = NULL ) {
2012-02-07 03:53:49 +04:00
printf ( " Failed to open TDB file %s \n " , tdb_file ) ;
2010-08-25 04:53:54 +04:00
return - 1 ;
}
2012-02-07 03:21:12 +04:00
if ( ! strncmp ( argv [ 1 ] , " 0x " , 2 ) ) {
key = hextodata ( tmp_ctx , argv [ 1 ] + 2 ) ;
if ( key . dsize = = 0 ) {
2012-02-07 03:53:49 +04:00
printf ( " Failed to convert \" %s \" into a TDB_DATA \n " , argv [ 1 ] ) ;
2012-02-07 03:21:12 +04:00
return - 1 ;
}
} else {
key . dptr = discard_const ( argv [ 1 ] ) ;
key . dsize = strlen ( argv [ 1 ] ) ;
}
2012-02-07 05:14:57 +04:00
2010-08-25 04:53:54 +04:00
data = tdb_fetch ( tdb , key ) ;
if ( data . dptr = = NULL | | data . dsize < sizeof ( struct ctdb_ltdb_header ) ) {
2012-02-07 03:53:49 +04:00
printf ( " Failed to read record %s from tdb %s \n " , argv [ 1 ] , tdb_file ) ;
2010-08-25 04:53:54 +04:00
tdb_close ( tdb ) ;
return - 1 ;
}
tdb_close ( tdb ) ;
if ( argc = = 3 ) {
fd = open ( argv [ 2 ] , O_WRONLY | O_CREAT | O_TRUNC , 0600 ) ;
if ( fd = = - 1 ) {
2012-02-07 03:21:12 +04:00
printf ( " Failed to open output file %s \n " , argv [ 2 ] ) ;
2010-08-25 04:53:54 +04:00
return - 1 ;
}
2012-02-07 03:53:49 +04:00
if ( options . verbose ) {
write ( fd , data . dptr , data . dsize ) ;
} else {
write ( fd , data . dptr + sizeof ( struct ctdb_ltdb_header ) , data . dsize - sizeof ( struct ctdb_ltdb_header ) ) ;
}
2010-08-25 04:53:54 +04:00
close ( fd ) ;
} else {
2012-02-07 03:53:49 +04:00
if ( options . verbose ) {
write ( 1 , data . dptr , data . dsize ) ;
} else {
write ( 1 , data . dptr + sizeof ( struct ctdb_ltdb_header ) , data . dsize - sizeof ( struct ctdb_ltdb_header ) ) ;
}
2010-08-25 04:53:54 +04:00
}
2012-02-07 03:21:12 +04:00
talloc_free ( tmp_ctx ) ;
2010-08-25 04:53:54 +04:00
return 0 ;
}
2012-02-07 05:14:57 +04:00
/*
store a record and header to a tdb - file
*/
static int control_tstore ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
const char * tdb_file ;
TDB_CONTEXT * tdb ;
2013-11-18 08:09:27 +04:00
TDB_DATA key , value , data ;
2012-02-07 05:14:57 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( NULL ) ;
2013-11-18 08:09:27 +04:00
struct ctdb_ltdb_header header ;
2012-02-07 05:14:57 +04:00
if ( argc < 3 ) {
usage ( ) ;
}
tdb_file = argv [ 0 ] ;
tdb = tdb_open ( tdb_file , 0 , 0 , O_RDWR , 0 ) ;
if ( tdb = = NULL ) {
printf ( " Failed to open TDB file %s \n " , tdb_file ) ;
return - 1 ;
}
if ( ! strncmp ( argv [ 1 ] , " 0x " , 2 ) ) {
key = hextodata ( tmp_ctx , argv [ 1 ] + 2 ) ;
if ( key . dsize = = 0 ) {
printf ( " Failed to convert \" %s \" into a TDB_DATA \n " , argv [ 1 ] ) ;
return - 1 ;
}
} else {
key . dptr = discard_const ( argv [ 1 ] ) ;
key . dsize = strlen ( argv [ 1 ] ) ;
}
if ( ! strncmp ( argv [ 2 ] , " 0x " , 2 ) ) {
2013-11-18 08:09:27 +04:00
value = hextodata ( tmp_ctx , argv [ 2 ] + 2 ) ;
if ( value . dsize = = 0 ) {
2012-02-07 05:14:57 +04:00
printf ( " Failed to convert \" %s \" into a TDB_DATA \n " , argv [ 2 ] ) ;
return - 1 ;
}
} else {
2013-11-18 08:09:27 +04:00
value . dptr = discard_const ( argv [ 2 ] ) ;
value . dsize = strlen ( argv [ 2 ] ) ;
2012-02-07 05:14:57 +04:00
}
2013-11-18 08:09:27 +04:00
ZERO_STRUCT ( header ) ;
if ( argc > 3 ) {
header . rsn = atoll ( argv [ 3 ] ) ;
}
if ( argc > 4 ) {
header . dmaster = atoi ( argv [ 4 ] ) ;
}
if ( argc > 5 ) {
header . flags = atoi ( argv [ 5 ] ) ;
}
data . dsize = sizeof ( struct ctdb_ltdb_header ) + value . dsize ;
data . dptr = talloc_size ( tmp_ctx , data . dsize ) ;
if ( data . dptr = = NULL ) {
printf ( " Failed to allocate header+value \n " ) ;
2012-02-07 05:14:57 +04:00
return - 1 ;
}
2013-11-18 08:09:27 +04:00
* ( struct ctdb_ltdb_header * ) data . dptr = header ;
memcpy ( data . dptr + sizeof ( struct ctdb_ltdb_header ) , value . dptr , value . dsize ) ;
2012-02-07 05:14:57 +04:00
if ( tdb_store ( tdb , key , data , TDB_REPLACE ) ! = 0 ) {
printf ( " Failed to write record %s to tdb %s \n " , argv [ 1 ] , tdb_file ) ;
tdb_close ( tdb ) ;
return - 1 ;
}
tdb_close ( tdb ) ;
talloc_free ( tmp_ctx ) ;
return 0 ;
}
2010-08-24 07:55:38 +04:00
/*
write a record to a persistent database
*/
static int control_pstore ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
const char * db_name ;
struct ctdb_db_context * ctdb_db ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
struct ctdb_transaction_handle * h ;
struct stat st ;
TDB_DATA key , data ;
int fd , ret ;
if ( argc < 3 ) {
talloc_free ( tmp_ctx ) ;
usage ( ) ;
}
fd = open ( argv [ 2 ] , O_RDONLY ) ;
if ( fd = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " Failed to open file containing record data : %s %s \n " , argv [ 2 ] , strerror ( errno ) ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
ret = fstat ( fd , & st ) ;
if ( ret = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " fstat of file %s failed: %s \n " , argv [ 2 ] , strerror ( errno ) ) ) ;
close ( fd ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
if ( ! S_ISREG ( st . st_mode ) ) {
DEBUG ( DEBUG_ERR , ( " Not a regular file %s \n " , argv [ 2 ] ) ) ;
close ( fd ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
data . dsize = st . st_size ;
if ( data . dsize = = 0 ) {
data . dptr = NULL ;
} else {
data . dptr = talloc_size ( tmp_ctx , data . dsize ) ;
if ( data . dptr = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to talloc %d of memory to store record data \n " , ( int ) data . dsize ) ) ;
close ( fd ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
ret = read ( fd , data . dptr , data . dsize ) ;
if ( ret ! = data . dsize ) {
DEBUG ( DEBUG_ERR , ( " Failed to read %d bytes of record data \n " , ( int ) data . dsize ) ) ;
close ( fd ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
}
close ( fd ) ;
db_name = argv [ 0 ] ;
2011-08-08 18:35:56 +04:00
ctdb_db = ctdb_attach ( ctdb , TIMELIMIT ( ) , db_name , true , 0 ) ;
2010-08-24 07:55:38 +04:00
if ( ctdb_db = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Unable to attach to database '%s' \n " , db_name ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
h = ctdb_transaction_start ( ctdb_db , tmp_ctx ) ;
if ( h = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to start transaction on database %s \n " , db_name ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
key . dptr = discard_const ( argv [ 1 ] ) ;
key . dsize = strlen ( argv [ 1 ] ) ;
ret = ctdb_transaction_store ( h , key , data ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to store record \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
ret = ctdb_transaction_commit ( h ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to commit transaction \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
talloc_free ( tmp_ctx ) ;
return 0 ;
}
2012-12-17 07:46:14 +04:00
/*
* delete a record from a persistent database
*/
static int control_pdelete ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
const char * db_name ;
struct ctdb_db_context * ctdb_db ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
struct ctdb_transaction_handle * h ;
TDB_DATA key ;
int ret ;
bool persistent ;
2012-12-19 07:43:26 +04:00
uint8_t flags ;
2012-12-17 07:46:14 +04:00
if ( argc < 2 ) {
talloc_free ( tmp_ctx ) ;
usage ( ) ;
}
2013-11-13 08:25:46 +04:00
if ( ! db_exists ( ctdb , argv [ 0 ] , NULL , & db_name , & flags ) ) {
2012-12-17 07:46:14 +04:00
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2012-12-19 07:43:26 +04:00
persistent = flags & CTDB_DB_FLAGS_PERSISTENT ;
2012-12-17 07:46:14 +04:00
if ( ! persistent ) {
DEBUG ( DEBUG_ERR , ( " Database '%s' is not persistent \n " , db_name ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
ctdb_db = ctdb_attach ( ctdb , TIMELIMIT ( ) , db_name , persistent , 0 ) ;
if ( ctdb_db = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Unable to attach to database '%s' \n " , db_name ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
h = ctdb_transaction_start ( ctdb_db , tmp_ctx ) ;
if ( h = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to start transaction on database %s \n " , db_name ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
key . dptr = discard_const ( argv [ 1 ] ) ;
key . dsize = strlen ( argv [ 1 ] ) ;
ret = ctdb_transaction_store ( h , key , tdb_null ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to delete record \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
ret = ctdb_transaction_commit ( h ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to commit transaction \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
talloc_free ( tmp_ctx ) ;
return 0 ;
}
2013-11-06 06:43:53 +04:00
static const char * ptrans_parse_string ( TALLOC_CTX * mem_ctx , const char * s ,
TDB_DATA * data )
{
const char * t ;
size_t n ;
const char * ret ; /* Next byte after successfully parsed value */
/* Error, unless someone says otherwise */
ret = NULL ;
/* Indicates no value to parse */
* data = tdb_null ;
/* Skip whitespace */
n = strspn ( s , " \t " ) ;
t = s + n ;
if ( t [ 0 ] = = ' " ' ) {
/* Quoted ASCII string - no wide characters! */
t + + ;
n = strcspn ( t , " \" " ) ;
if ( t [ n ] = = ' " ' ) {
if ( n > 0 ) {
data - > dsize = n ;
data - > dptr = talloc_memdup ( mem_ctx , t , n ) ;
CTDB_NOMEM_ABORT ( data - > dptr ) ;
}
ret = t + n + 1 ;
} else {
DEBUG ( DEBUG_WARNING , ( " Unmatched \" in input %s \n " , s ) ) ;
}
} else {
DEBUG ( DEBUG_WARNING , ( " Unsupported input format in %s \n " , s ) ) ;
}
return ret ;
}
static bool ptrans_get_key_value ( TALLOC_CTX * mem_ctx , FILE * file ,
TDB_DATA * key , TDB_DATA * value )
{
char line [ 1024 ] ; /* FIXME: make this more flexible? */
const char * t ;
char * ptr ;
ptr = fgets ( line , sizeof ( line ) , file ) ;
if ( ptr = = NULL ) {
return false ;
}
/* Get key */
t = ptrans_parse_string ( mem_ctx , line , key ) ;
if ( t = = NULL | | key - > dptr = = NULL ) {
/* Line Ignored but not EOF */
return true ;
}
/* Get value */
t = ptrans_parse_string ( mem_ctx , t , value ) ;
if ( t = = NULL ) {
/* Line Ignored but not EOF */
talloc_free ( key - > dptr ) ;
* key = tdb_null ;
return true ;
}
return true ;
}
/*
* Update a persistent database as per file / stdin
*/
static int control_ptrans ( struct ctdb_context * ctdb ,
int argc , const char * * argv )
{
const char * db_name ;
struct ctdb_db_context * ctdb_db ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
struct ctdb_transaction_handle * h ;
TDB_DATA key , value ;
FILE * file ;
int ret ;
2013-11-08 09:41:11 +04:00
if ( argc < 1 ) {
2013-11-06 06:43:53 +04:00
talloc_free ( tmp_ctx ) ;
usage ( ) ;
}
file = stdin ;
2013-11-08 09:41:11 +04:00
if ( argc = = 2 ) {
2013-11-06 06:43:53 +04:00
file = fopen ( argv [ 1 ] , " r " ) ;
if ( file = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Unable to open file for reading '%s' \n " , argv [ 1 ] ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
}
db_name = argv [ 0 ] ;
ctdb_db = ctdb_attach ( ctdb , TIMELIMIT ( ) , db_name , true , 0 ) ;
if ( ctdb_db = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Unable to attach to database '%s' \n " , db_name ) ) ;
goto error ;
}
h = ctdb_transaction_start ( ctdb_db , tmp_ctx ) ;
if ( h = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to start transaction on database %s \n " , db_name ) ) ;
goto error ;
}
while ( ptrans_get_key_value ( tmp_ctx , file , & key , & value ) ) {
if ( key . dsize ! = 0 ) {
ret = ctdb_transaction_store ( h , key , value ) ;
/* Minimise memory use */
talloc_free ( key . dptr ) ;
if ( value . dptr ! = NULL ) {
talloc_free ( value . dptr ) ;
}
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to store record \n " ) ) ;
ctdb_transaction_cancel ( h ) ;
goto error ;
}
}
}
ret = ctdb_transaction_commit ( h ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to commit transaction \n " ) ) ;
goto error ;
}
if ( file ! = stdin ) {
fclose ( file ) ;
}
talloc_free ( tmp_ctx ) ;
return 0 ;
error :
if ( file ! = stdin ) {
fclose ( file ) ;
}
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2011-08-17 04:16:35 +04:00
/*
check if a service is bound to a port or not
*/
static int control_chktcpport ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int s , ret ;
2013-11-11 05:40:44 +04:00
int v ;
2011-08-17 04:16:35 +04:00
int port ;
struct sockaddr_in sin ;
if ( argc ! = 1 ) {
printf ( " Use: ctdb chktcport <port> \n " ) ;
return EINVAL ;
}
port = atoi ( argv [ 0 ] ) ;
s = socket ( PF_INET , SOCK_STREAM , IPPROTO_TCP ) ;
if ( s = = - 1 ) {
printf ( " Failed to open local socket \n " ) ;
return errno ;
}
v = fcntl ( s , F_GETFL , 0 ) ;
2013-11-11 05:40:44 +04:00
if ( v = = - 1 | | fcntl ( s , F_SETFL , v | O_NONBLOCK ) ! = 0 ) {
printf ( " Unable to set socket non-blocking: %s \n " , strerror ( errno ) ) ;
}
2011-08-17 04:16:35 +04:00
bzero ( & sin , sizeof ( sin ) ) ;
sin . sin_family = PF_INET ;
sin . sin_port = htons ( port ) ;
ret = bind ( s , ( struct sockaddr * ) & sin , sizeof ( sin ) ) ;
close ( s ) ;
if ( ret = = - 1 ) {
printf ( " Failed to bind to local socket: %d %s \n " , errno , strerror ( errno ) ) ;
return errno ;
}
return 0 ;
}
2009-11-18 04:44:18 +03:00
static void log_handler ( struct ctdb_context * ctdb , uint64_t srvid ,
TDB_DATA data , void * private_data )
{
DEBUG ( DEBUG_ERR , ( " Log data received \n " ) ) ;
2009-11-18 11:10:50 +03:00
if ( data . dsize > 0 ) {
printf ( " %s " , data . dptr ) ;
2009-11-18 04:44:18 +03:00
}
2009-11-18 11:10:50 +03:00
2009-11-18 04:44:18 +03:00
exit ( 0 ) ;
}
/*
display a list of log messages from the in memory ringbuffer
*/
static int control_getlog ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2012-10-18 07:13:30 +04:00
int ret , i ;
bool main_daemon ;
2009-11-18 04:44:18 +03:00
struct ctdb_get_log_addr log_addr ;
TDB_DATA data ;
struct timeval tv ;
2012-10-18 07:13:30 +04:00
/* Process options */
main_daemon = true ;
2013-08-14 22:38:02 +04:00
log_addr . pnn = ctdb_get_pnn ( ctdb ) ;
2012-10-18 07:13:30 +04:00
log_addr . level = DEBUG_NOTICE ;
for ( i = 0 ; i < argc ; i + + ) {
if ( strcmp ( argv [ i ] , " recoverd " ) = = 0 ) {
main_daemon = false ;
} else {
if ( isalpha ( argv [ i ] [ 0 ] ) | | argv [ i ] [ 0 ] = = ' - ' ) {
log_addr . level = get_debug_by_desc ( argv [ i ] ) ;
} else {
log_addr . level = strtol ( argv [ i ] , NULL , 0 ) ;
}
}
2009-11-18 04:44:18 +03:00
}
2012-10-18 07:13:30 +04:00
/* Our message port is our PID */
log_addr . srvid = getpid ( ) ;
2009-11-18 04:44:18 +03:00
data . dptr = ( unsigned char * ) & log_addr ;
data . dsize = sizeof ( log_addr ) ;
DEBUG ( DEBUG_ERR , ( " Pulling logs from node %u \n " , options . pnn ) ) ;
2010-06-02 03:51:47 +04:00
ctdb_client_set_message_handler ( ctdb , log_addr . srvid , log_handler , NULL ) ;
2009-11-18 04:44:18 +03:00
sleep ( 1 ) ;
DEBUG ( DEBUG_ERR , ( " Listen for response on %d \n " , ( int ) log_addr . srvid ) ) ;
2012-10-18 07:13:30 +04:00
if ( main_daemon ) {
int32_t res ;
char * errmsg ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
ret = ctdb_control ( ctdb , options . pnn , 0 , CTDB_CONTROL_GET_LOG ,
0 , data , tmp_ctx , NULL , & res , NULL , & errmsg ) ;
if ( ret ! = 0 | | res ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to get logs - %s \n " , errmsg ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2009-11-18 04:44:18 +03:00
talloc_free ( tmp_ctx ) ;
2012-10-18 07:13:30 +04:00
} else {
ret = ctdb_client_send_message ( ctdb , options . pnn ,
CTDB_SRVID_GETLOG , data ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to send getlog request message to %u \n " , options . pnn ) ) ;
return - 1 ;
}
2009-11-18 04:44:18 +03:00
}
tv = timeval_current ( ) ;
/* this loop will terminate when we have received the reply */
2012-10-18 07:13:30 +04:00
while ( timeval_elapsed ( & tv ) < ( double ) options . timelimit ) {
2009-11-18 04:44:18 +03:00
event_loop_once ( ctdb - > ev ) ;
}
DEBUG ( DEBUG_INFO , ( " Timed out waiting for log data. \n " ) ) ;
return 0 ;
}
/*
clear the in memory log area
*/
static int control_clearlog ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
2012-10-18 07:13:30 +04:00
if ( argc = = 0 | | ( argc > = 1 & & strcmp ( argv [ 0 ] , " recoverd " ) ! = 0 ) ) {
/* "recoverd" not given - get logs from main daemon */
int32_t res ;
char * errmsg ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
2009-11-18 04:44:18 +03:00
2012-10-18 07:13:30 +04:00
ret = ctdb_control ( ctdb , options . pnn , 0 , CTDB_CONTROL_CLEAR_LOG ,
0 , tdb_null , tmp_ctx , NULL , & res , NULL , & errmsg ) ;
if ( ret ! = 0 | | res ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to clear logs \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2012-10-16 13:57:31 +04:00
2012-10-18 07:13:30 +04:00
talloc_free ( tmp_ctx ) ;
2012-10-16 13:57:31 +04:00
} else {
2012-10-18 07:13:30 +04:00
TDB_DATA data ; /* unused in recoverd... */
data . dsize = 0 ;
2012-10-16 13:57:31 +04:00
2012-10-18 07:13:30 +04:00
ret = ctdb_client_send_message ( ctdb , options . pnn , CTDB_SRVID_CLEARLOG , data ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to send clearlog request message to %u \n " , options . pnn ) ) ;
return - 1 ;
}
2012-10-16 13:57:31 +04:00
}
return 0 ;
}
2013-08-28 09:38:48 +04:00
/* Reload public IPs on a specified nodes */
static int control_reloadips ( struct ctdb_context * ctdb , int argc , const char * * argv )
2012-04-30 09:50:44 +04:00
{
2013-08-29 11:22:38 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
2013-08-28 09:38:48 +04:00
uint32_t * nodes ;
uint32_t pnn_mode ;
2013-11-12 08:16:49 +04:00
uint32_t timeout ;
2013-08-29 11:22:38 +04:00
int ret ;
2012-04-30 09:50:44 +04:00
2013-08-28 09:38:48 +04:00
assert_single_node_only ( ) ;
2012-04-30 09:50:44 +04:00
2013-08-28 09:38:48 +04:00
if ( argc > 1 ) {
usage ( ) ;
2012-04-30 09:50:44 +04:00
}
2013-08-28 09:38:48 +04:00
/* Determine the nodes where IPs need to be reloaded */
2013-08-29 11:22:38 +04:00
if ( ! parse_nodestring ( ctdb , tmp_ctx , argc = = 1 ? argv [ 0 ] : NULL ,
2013-08-28 09:38:48 +04:00
options . pnn , true , & nodes , & pnn_mode ) ) {
2013-08-29 11:22:38 +04:00
ret = - 1 ;
goto done ;
2012-04-30 09:50:44 +04:00
}
2013-08-28 09:38:48 +04:00
again :
/* Disable takeover runs on all connected nodes. A reply
* indicating success is needed from each node so all nodes
* will need to be active . This will retry until maxruntime
* is exceeded , hence no error handling .
*
* A check could be added to not allow reloading of IPs when
* there are disconnected nodes . However , this should
* probably be left up to the administrator .
*/
2013-11-12 08:16:49 +04:00
timeout = LONGTIMEOUT ;
srvid_broadcast ( ctdb , CTDB_SRVID_DISABLE_TAKEOVER_RUNS , & timeout ,
2013-08-28 09:38:48 +04:00
" Disable takeover runs " , true ) ;
2012-04-30 09:50:44 +04:00
2013-08-28 09:38:48 +04:00
/* Now tell all the desired nodes to reload their public IPs.
* Keep trying this until it succeeds . This assumes all
* failures are transient , which might not be true . . .
*/
if ( ctdb_client_async_control ( ctdb , CTDB_CONTROL_RELOAD_PUBLIC_IPS ,
nodes , 0 , LONGTIMELIMIT ( ) ,
false , tdb_null ,
NULL , NULL , NULL ) ! = 0 ) {
DEBUG ( DEBUG_ERR ,
( " Unable to reload IPs on some nodes, try again. \n " ) ) ;
goto again ;
2012-04-30 09:50:44 +04:00
}
2013-08-28 09:38:48 +04:00
/* It isn't strictly necessary to wait until takeover runs are
* re - enabled but doing so can ' t hurt .
*/
2013-11-12 08:16:49 +04:00
timeout = 0 ;
srvid_broadcast ( ctdb , CTDB_SRVID_DISABLE_TAKEOVER_RUNS , & timeout ,
2013-08-28 09:38:48 +04:00
" Enable takeover runs " , true ) ;
2012-04-30 09:50:44 +04:00
2013-08-28 09:38:48 +04:00
ipreallocate ( ctdb ) ;
2012-04-30 09:50:44 +04:00
2013-08-29 11:22:38 +04:00
ret = 0 ;
done :
talloc_free ( tmp_ctx ) ;
return ret ;
2012-04-30 09:50:44 +04:00
}
2009-11-18 04:44:18 +03: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 ;
}
2009-12-07 11:23:02 +03:00
if ( options . machinereadable ) {
2012-03-20 09:58:35 +04:00
printf ( " :ID:Name:Path:Persistent:Sticky:Unhealthy:ReadOnly: \n " ) ;
2009-12-07 11:23:02 +03:00
for ( i = 0 ; i < dbmap - > num ; i + + ) {
const char * path ;
const char * name ;
const char * health ;
bool persistent ;
2011-09-01 04:28:15 +04:00
bool readonly ;
2012-03-20 09:58:35 +04:00
bool sticky ;
2009-12-07 11:23:02 +03: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 ) ;
ctdb_ctrl_getdbhealth ( ctdb , TIMELIMIT ( ) , options . pnn ,
dbmap - > dbs [ i ] . dbid , ctdb , & health ) ;
2011-09-01 04:21:55 +04:00
persistent = dbmap - > dbs [ i ] . flags & CTDB_DB_FLAGS_PERSISTENT ;
2011-09-01 04:28:15 +04:00
readonly = dbmap - > dbs [ i ] . flags & CTDB_DB_FLAGS_READONLY ;
2012-03-20 09:58:35 +04:00
sticky = dbmap - > dbs [ i ] . flags & CTDB_DB_FLAGS_STICKY ;
printf ( " :0x%08X:%s:%s:%d:%d:%d:%d: \n " ,
2009-12-07 11:23:02 +03:00
dbmap - > dbs [ i ] . dbid , name , path ,
2012-03-20 09:58:35 +04:00
! ! ( persistent ) , ! ! ( sticky ) ,
! ! ( health ) , ! ! ( readonly ) ) ;
2009-12-07 11:23:02 +03:00
}
return 0 ;
}
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 ;
2009-12-02 14:54:29 +03:00
const char * health ;
2007-09-21 06:24:02 +04:00
bool persistent ;
2011-09-01 04:28:15 +04:00
bool readonly ;
2012-03-20 09:58:35 +04:00
bool sticky ;
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 ) ;
2009-12-02 14:54:29 +03:00
ctdb_ctrl_getdbhealth ( ctdb , TIMELIMIT ( ) , options . pnn , dbmap - > dbs [ i ] . dbid , ctdb , & health ) ;
2011-09-01 04:21:55 +04:00
persistent = dbmap - > dbs [ i ] . flags & CTDB_DB_FLAGS_PERSISTENT ;
2011-09-01 04:28:15 +04:00
readonly = dbmap - > dbs [ i ] . flags & CTDB_DB_FLAGS_READONLY ;
2012-03-20 09:58:35 +04:00
sticky = dbmap - > dbs [ i ] . flags & CTDB_DB_FLAGS_STICKY ;
printf ( " dbid:0x%08x name:%s path:%s%s%s%s%s \n " ,
2009-12-02 14:54:29 +03:00
dbmap - > dbs [ i ] . dbid , name , path ,
persistent ? " PERSISTENT " : " " ,
2012-03-20 09:58:35 +04:00
sticky ? " STICKY " : " " ,
2011-09-01 04:28:15 +04:00
readonly ? " READONLY " : " " ,
2009-12-02 14:54:29 +03:00
health ? " UNHEALTHY " : " " ) ;
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 ;
}
2009-12-02 14:57:29 +03:00
/*
display the status of a database on a remote ctdb
*/
static int control_getdbstatus ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
const char * db_name ;
2012-12-19 07:43:26 +04:00
uint32_t db_id ;
uint8_t flags ;
const char * path ;
const char * health ;
2009-12-02 14:57:29 +03:00
if ( argc < 1 ) {
usage ( ) ;
}
2013-11-13 08:25:46 +04:00
if ( ! db_exists ( ctdb , argv [ 0 ] , & db_id , & db_name , & flags ) ) {
2012-12-19 07:43:26 +04:00
return - 1 ;
2009-12-02 14:57:29 +03:00
}
2012-12-19 07:43:26 +04:00
ctdb_ctrl_getdbpath ( ctdb , TIMELIMIT ( ) , options . pnn , db_id , ctdb , & path ) ;
ctdb_ctrl_getdbhealth ( ctdb , TIMELIMIT ( ) , options . pnn , db_id , ctdb , & health ) ;
printf ( " dbid: 0x%08x \n name: %s \n path: %s \n PERSISTENT: %s \n STICKY: %s \n READONLY: %s \n HEALTH: %s \n " ,
db_id , db_name , path ,
( flags & CTDB_DB_FLAGS_PERSISTENT ? " yes " : " no " ) ,
( flags & CTDB_DB_FLAGS_STICKY ? " yes " : " no " ) ,
( flags & CTDB_DB_FLAGS_READONLY ? " yes " : " no " ) ,
( health ? health : " OK " ) ) ;
2009-12-02 14:57:29 +03: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 ;
2013-08-29 11:22:38 +04:00
int ret ;
2007-10-08 03:47:20 +04:00
2013-08-19 08:40:52 +04:00
assert_single_node_only ( ) ;
2013-08-14 23:02:37 +04:00
mypnn = getpnn ( ctdb ) ;
2007-10-08 03:47:20 +04:00
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_getrecmaster ( ctdb , ctdb , TIMELIMIT ( ) , options . pnn , & recmaster ) ;
if ( ret ! = 0 ) {
2007-10-08 03:47:20 +04:00
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
2013-01-11 07:07:12 +04:00
/*
get a node ' s runstate
*/
static int control_runstate ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
int ret ;
enum ctdb_runstate runstate ;
ret = ctdb_ctrl_get_runstate ( ctdb , TIMELIMIT ( ) , options . pnn , & runstate ) ;
if ( ret = = - 1 ) {
printf ( " Unable to get runstate response from node %u \n " ,
options . pnn ) ;
return - 1 ;
2013-01-11 07:09:14 +04:00
} else {
bool found = true ;
enum ctdb_runstate t ;
int i ;
for ( i = 0 ; i < argc ; i + + ) {
found = false ;
t = runstate_from_string ( argv [ i ] ) ;
if ( t = = CTDB_RUNSTATE_UNKNOWN ) {
printf ( " Invalid run state (%s) \n " , argv [ i ] ) ;
return - 1 ;
}
if ( t = = runstate ) {
found = true ;
break ;
}
}
if ( ! found ) {
printf ( " CTDB not in required run state (got %s) \n " ,
runstate_to_string ( ( enum ctdb_runstate ) runstate ) ) ;
return - 1 ;
}
2013-01-11 07:07:12 +04:00
}
printf ( " %s \n " , runstate_to_string ( runstate ) ) ;
return 0 ;
}
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 ) ;
2013-05-21 09:41:56 +04:00
if ( ret ! = 0 ) {
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 ;
}
2011-12-22 15:13:10 +04:00
printf ( " %-23s = %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
/*
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 ;
2010-09-14 16:49:42 +04:00
bool persistent = false ;
2007-05-29 06:16:59 +04:00
2007-04-30 17:54:06 +04:00
if ( argc < 1 ) {
usage ( ) ;
}
db_name = argv [ 0 ] ;
2010-09-14 16:49:42 +04:00
if ( argc > 2 ) {
usage ( ) ;
}
if ( argc = = 2 ) {
if ( strcmp ( argv [ 1 ] , " persistent " ) ! = 0 ) {
usage ( ) ;
}
persistent = true ;
}
2007-04-30 17:54:06 +04:00
2011-08-08 18:35:56 +04:00
ctdb_db = ctdb_attach ( ctdb , TIMELIMIT ( ) , db_name , persistent , 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 ( ) ;
}
2013-11-13 08:25:46 +04:00
if ( ! db_exists ( ctdb , argv [ 0 ] , & db_id , NULL , NULL ) ) {
2012-12-19 07:43:26 +04:00
return - 1 ;
}
2009-10-10 08:04:18 +04:00
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 ;
}
2012-03-20 09:58:35 +04:00
/*
set the sticky records capability for a database
*/
static int control_setdbsticky ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
uint32_t db_id ;
2012-12-19 07:43:26 +04:00
int ret ;
2012-03-20 09:58:35 +04:00
if ( argc < 1 ) {
usage ( ) ;
}
2013-11-13 08:25:46 +04:00
if ( ! db_exists ( ctdb , argv [ 0 ] , & db_id , NULL , NULL ) ) {
2012-12-19 07:43:26 +04:00
return - 1 ;
2012-03-20 09:58:35 +04:00
}
ret = ctdb_ctrl_set_db_sticky ( ctdb , options . pnn , db_id ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to set db to support sticky records \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
talloc_free ( tmp_ctx ) ;
return 0 ;
}
2011-09-01 05:08:18 +04:00
/*
set the readonly capability for a database
*/
static int control_setdbreadonly ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
2012-02-13 03:27:59 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
2011-09-01 05:08:18 +04:00
uint32_t db_id ;
2012-12-19 07:43:26 +04:00
int ret ;
2011-09-01 05:08:18 +04:00
if ( argc < 1 ) {
usage ( ) ;
}
2013-11-13 08:25:46 +04:00
if ( ! db_exists ( ctdb , argv [ 0 ] , & db_id , NULL , NULL ) ) {
2012-12-19 07:43:26 +04:00
return - 1 ;
2012-02-13 03:27:59 +04:00
}
2011-09-01 05:08:18 +04:00
ret = ctdb_ctrl_set_db_readonly ( ctdb , options . pnn , db_id ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to set db to support readonly \n " ) ) ;
2012-02-13 03:27:59 +04:00
talloc_free ( tmp_ctx ) ;
2011-09-01 05:08:18 +04:00
return - 1 ;
}
2012-02-13 03:27:59 +04:00
talloc_free ( tmp_ctx ) ;
2011-09-01 05:08:18 +04:00
return 0 ;
}
2011-11-28 09:30:46 +04:00
/*
get db seqnum
*/
static int control_getdbseqnum ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint32_t db_id ;
uint64_t seqnum ;
2013-08-29 11:22:38 +04:00
int ret ;
2011-11-28 09:30:46 +04:00
if ( argc < 1 ) {
usage ( ) ;
}
2013-11-13 08:25:46 +04:00
if ( ! db_exists ( ctdb , argv [ 0 ] , & db_id , NULL , NULL ) ) {
2012-12-19 07:43:26 +04:00
return - 1 ;
}
2011-11-28 09:30:46 +04:00
2013-08-29 11:22:38 +04:00
ret = ctdb_ctrl_getdbseqnum ( ctdb , TIMELIMIT ( ) , options . pnn , db_id , & seqnum ) ;
if ( ret ! = 0 ) {
2011-11-28 09:30:46 +04:00
DEBUG ( DEBUG_ERR , ( " Unable to get seqnum from node. " ) ) ;
return - 1 ;
}
printf ( " Sequence number:%lld \n " , ( long long ) seqnum ) ;
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 )
{
2013-11-13 08:25:46 +04:00
const char * db_name ;
2012-12-19 07:43:26 +04:00
int ret ;
2008-08-13 16:03:29 +04:00
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 ;
2009-12-07 11:22:02 +03:00
const char * reason = NULL ;
2012-12-19 07:43:26 +04:00
uint32_t db_id ;
uint8_t flags ;
2008-08-13 16:03:29 +04:00
2013-08-19 08:40:52 +04:00
assert_single_node_only ( ) ;
2008-08-13 16:03:29 +04:00
if ( argc ! = 2 ) {
DEBUG ( DEBUG_ERR , ( " Invalid arguments \n " ) ) ;
return - 1 ;
}
2013-11-13 08:25:46 +04:00
if ( ! db_exists ( ctdb , argv [ 0 ] , & db_id , & db_name , & flags ) ) {
2008-08-13 16:03:29 +04:00
return - 1 ;
}
2009-12-07 11:22:02 +03:00
ret = ctdb_ctrl_getdbhealth ( ctdb , TIMELIMIT ( ) , options . pnn ,
2012-12-19 07:43:26 +04:00
db_id , tmp_ctx , & reason ) ;
2009-12-07 11:22:02 +03:00
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to get dbhealth for database '%s' \n " ,
argv [ 0 ] ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
if ( reason ) {
uint32_t allow_unhealthy = 0 ;
ctdb_ctrl_get_tunable ( ctdb , TIMELIMIT ( ) , options . pnn ,
" AllowUnhealthyDBRead " ,
& allow_unhealthy ) ;
if ( allow_unhealthy ! = 1 ) {
DEBUG ( DEBUG_ERR , ( " database '%s' is unhealthy: %s \n " ,
argv [ 0 ] , reason ) ) ;
2011-09-02 18:23:22 +04:00
DEBUG ( DEBUG_ERR , ( " disallow backup : tunable AllowUnhealthyDBRead = %u \n " ,
2009-12-07 11:22:02 +03:00
allow_unhealthy ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
DEBUG ( DEBUG_WARNING , ( " WARNING database '%s' is unhealthy - see 'ctdb getdbstatus %s' \n " ,
argv [ 0 ] , argv [ 0 ] ) ) ;
DEBUG ( DEBUG_WARNING , ( " WARNING! allow backup of unhealthy database: "
" tunnable AllowUnhealthyDBRead = %u \n " ,
allow_unhealthy ) ) ;
}
2008-08-14 04:57:08 +04:00
2013-11-13 08:25:46 +04:00
ctdb_db = ctdb_attach ( ctdb , TIMELIMIT ( ) , db_name , flags & CTDB_DB_FLAGS_PERSISTENT , 0 ) ;
2008-08-14 04:57:08 +04:00
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 ;
}
2013-11-11 05:40:44 +04:00
ZERO_STRUCT ( dbhdr ) ;
2008-08-14 02:35:19 +04:00
dbhdr . version = DB_VERSION ;
dbhdr . timestamp = time ( NULL ) ;
2012-12-19 07:43:26 +04:00
dbhdr . persistent = flags & CTDB_DB_FLAGS_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
}
2013-11-11 05:40:44 +04:00
strncpy ( discard_const ( dbhdr . name ) , argv [ 0 ] , MAX_DB_NAME - 1 ) ;
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 ) ) ) ;
}
}
2011-07-05 00:29:00 +04:00
2011-09-12 17:04:46 +04:00
DEBUG ( DEBUG_ERR , ( " Database backed up to %s \n " , argv [ 1 ] ) ) ;
2011-07-05 00:29:00 +04:00
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 ] ;
2010-05-20 05:26:37 +04:00
char * dbname ;
2008-08-13 16:03:29 +04:00
2013-08-19 08:40:52 +04:00
assert_single_node_only ( ) ;
2010-05-20 05:26:37 +04:00
if ( argc < 1 | | argc > 2 ) {
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 ) ) ;
2013-11-11 05:40:44 +04:00
close ( fh ) ;
2008-08-14 02:35:19 +04:00
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2010-08-24 07:35:33 +04:00
dbname = discard_const ( dbhdr . name ) ;
2010-05-20 05:26:37 +04:00
if ( argc = = 2 ) {
2010-08-24 07:35:33 +04:00
dbname = discard_const ( argv [ 1 ] ) ;
2010-05-20 05:26:37 +04:00
}
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 " ,
2010-05-20 05:26:37 +04:00
dbname , tbuf ) ;
2008-08-14 02:35:19 +04:00
2008-08-13 16:03:29 +04:00
2011-08-08 18:35:56 +04:00
ctdb_db = ctdb_attach ( ctdb , TIMELIMIT ( ) , dbname , dbhdr . persistent , 0 ) ;
2008-08-13 16:03:29 +04:00
if ( ctdb_db = = NULL ) {
2010-05-20 05:26:37 +04:00
DEBUG ( DEBUG_ERR , ( " Unable to attach to database '%s' \n " , dbname ) ) ;
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 ;
}
2009-12-02 14:58:03 +03:00
data . dptr = ( void * ) & ctdb_db - > db_id ;
data . dsize = sizeof ( ctdb_db - > db_id ) ;
/* mark the database as healthy */
nodes = list_of_active_nodes ( ctdb , nodemap , tmp_ctx , true ) ;
if ( ctdb_client_async_control ( ctdb , CTDB_CONTROL_DB_SET_HEALTHY ,
nodes , 0 ,
TIMELIMIT ( ) , false , data ,
NULL , NULL ,
NULL ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to mark database as healthy. \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
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 ;
}
2009-12-04 17:24:23 +03:00
/*
* dump a database backup from a file
*/
static int control_dumpdbbackup ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
TDB_DATA outdata ;
struct db_file_header dbhdr ;
int i , fh ;
struct tm * tm ;
char tbuf [ 100 ] ;
struct ctdb_rec_data * rec = NULL ;
struct ctdb_marshall_buffer * m ;
2011-11-28 20:11:16 +04:00
struct ctdb_dump_db_context c ;
2009-12-04 17:24:23 +03:00
2013-08-19 08:40:52 +04:00
assert_single_node_only ( ) ;
2009-12-04 17:24:23 +03:00
if ( argc ! = 1 ) {
DEBUG ( DEBUG_ERR , ( " Invalid arguments \n " ) ) ;
return - 1 ;
}
fh = open ( argv [ 0 ] , O_RDONLY ) ;
if ( fh = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " Failed to open file '%s' \n " , argv [ 0 ] ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
read ( fh , & dbhdr , sizeof ( dbhdr ) ) ;
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 ) ) ;
2013-11-11 05:40:44 +04:00
close ( fh ) ;
2009-12-04 17:24:23 +03:00
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
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 ) ;
m = ( struct ctdb_marshall_buffer * ) outdata . dptr ;
tm = localtime ( & dbhdr . timestamp ) ;
strftime ( tbuf , sizeof ( tbuf ) - 1 , " %Y/%m/%d %H:%M:%S " , tm ) ;
printf ( " Backup of database name:'%s' dbid:0x%x08x from @ %s \n " ,
dbhdr . name , m - > db_id , tbuf ) ;
2011-11-28 20:11:16 +04:00
ZERO_STRUCT ( c ) ;
c . f = stdout ;
c . printemptyrecords = ( bool ) options . printemptyrecords ;
2011-11-28 20:19:03 +04:00
c . printdatasize = ( bool ) options . printdatasize ;
2011-11-28 20:36:03 +04:00
c . printlmaster = false ;
2011-11-29 03:56:23 +04:00
c . printhash = ( bool ) options . printhash ;
2011-11-29 13:24:52 +04:00
c . printrecordflags = ( bool ) options . printrecordflags ;
2011-11-28 20:11:16 +04:00
2009-12-04 17:24:23 +03:00
for ( i = 0 ; i < m - > count ; i + + ) {
uint32_t reqid = 0 ;
TDB_DATA key , data ;
/* we do not want the header splitted, so we pass NULL*/
rec = ctdb_marshall_loop_next ( m , rec , & reqid ,
NULL , & key , & data ) ;
2011-11-28 20:11:16 +04:00
ctdb_dumpdb_record ( ctdb , key , data , & c ) ;
2009-12-04 17:24:23 +03:00
}
printf ( " Dumped %d records \n " , i ) ;
talloc_free ( tmp_ctx ) ;
return 0 ;
}
2009-11-29 06:05:03 +03:00
/*
* wipe a database from a file
*/
static int control_wipedb ( struct ctdb_context * ctdb , int argc ,
const char * * argv )
{
2013-11-13 08:25:46 +04:00
const char * db_name ;
2009-11-29 06:05:03 +03:00
int ret ;
TALLOC_CTX * tmp_ctx = talloc_new ( ctdb ) ;
TDB_DATA data ;
struct ctdb_db_context * ctdb_db ;
struct ctdb_node_map * nodemap = NULL ;
struct ctdb_vnn_map * vnnmap = NULL ;
int i ;
struct ctdb_control_wipe_database w ;
uint32_t * nodes ;
uint32_t generation ;
2012-12-19 07:43:26 +04:00
uint8_t flags ;
2009-11-29 06:05:03 +03:00
2013-08-19 08:40:52 +04:00
assert_single_node_only ( ) ;
2009-11-29 06:05:03 +03:00
if ( argc ! = 1 ) {
DEBUG ( DEBUG_ERR , ( " Invalid arguments \n " ) ) ;
return - 1 ;
}
2013-11-13 08:25:46 +04:00
if ( ! db_exists ( ctdb , argv [ 0 ] , NULL , & db_name , & flags ) ) {
2009-11-29 06:05:03 +03:00
return - 1 ;
}
2013-11-13 08:25:46 +04:00
ctdb_db = ctdb_attach ( ctdb , TIMELIMIT ( ) , db_name , flags & CTDB_DB_FLAGS_PERSISTENT , 0 ) ;
2009-11-29 06:05:03 +03:00
if ( ctdb_db = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Unable to attach to database '%s' \n " ,
argv [ 0 ] ) ) ;
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 ) ;
for ( i = 1 ; i < = NUM_DB_PRIORITIES ; i + + ) {
ret = ctdb_client_async_control ( ctdb , CTDB_CONTROL_FREEZE ,
nodes , i ,
TIMELIMIT ( ) ,
false , tdb_null ,
NULL , NULL ,
NULL ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Unable to freeze nodes. \n " ) ) ;
ctdb_ctrl_setrecmode ( ctdb , TIMELIMIT ( ) , options . pnn ,
CTDB_RECOVERY_ACTIVE ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
}
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 ) ;
ret = ctdb_client_async_control ( ctdb , CTDB_CONTROL_TRANSACTION_START ,
nodes , 0 ,
TIMELIMIT ( ) , false , data ,
NULL , NULL ,
NULL ) ;
if ( ret ! = 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 ,
nodes , 0 ,
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 ) ;
2009-12-02 14:58:03 +03:00
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
data . dptr = ( void * ) & ctdb_db - > db_id ;
data . dsize = sizeof ( ctdb_db - > db_id ) ;
/* mark the database as healthy */
nodes = list_of_active_nodes ( ctdb , nodemap , tmp_ctx , true ) ;
if ( ctdb_client_async_control ( ctdb , CTDB_CONTROL_DB_SET_HEALTHY ,
nodes , 0 ,
TIMELIMIT ( ) , false , data ,
NULL , NULL ,
NULL ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to mark database as healthy. \n " ) ) ;
ctdb_ctrl_setrecmode ( ctdb , TIMELIMIT ( ) , options . pnn , CTDB_RECOVERY_ACTIVE ) ;
2009-11-29 06:05:03 +03:00
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 ,
nodes , 0 ,
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 ,
nodes , 0 ,
TIMELIMIT ( ) ,
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 ;
}
2011-07-05 00:29:00 +04:00
DEBUG ( DEBUG_ERR , ( " Database wiped. \n " ) ) ;
2009-11-29 06:05:03 +03:00
talloc_free ( tmp_ctx ) ;
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 ;
2013-08-16 14:10:10 +04:00
struct srvid_request rd ;
2008-04-01 08:34:54 +04:00
2013-08-14 22:38:02 +04:00
rd . pnn = ctdb_get_pnn ( ctdb ) ;
2008-04-01 08:34:54 +04:00
rd . srvid = getpid ( ) ;
/* register a message port for receiveing the reply so that we
can receive the reply
*/
2010-06-02 03:51:47 +04:00
ctdb_client_set_message_handler ( ctdb , rd . srvid , mem_dump_handler , NULL ) ;
2008-04-01 08:34:54 +04:00
data . dptr = ( uint8_t * ) & rd ;
data . dsize = sizeof ( rd ) ;
2010-06-02 03:45:21 +04:00
ret = ctdb_client_send_message ( ctdb , options . pnn , CTDB_SRVID_MEM_DUMP , data ) ;
2008-04-01 08:34:54 +04:00
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 ;
}
2010-02-04 01:45:32 +03:00
/*
send a message to a srvid
*/
static int control_msgsend ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
unsigned long srvid ;
int ret ;
TDB_DATA data ;
if ( argc < 2 ) {
usage ( ) ;
}
srvid = strtoul ( argv [ 0 ] , NULL , 0 ) ;
data . dptr = ( uint8_t * ) discard_const ( argv [ 1 ] ) ;
data . dsize = strlen ( argv [ 1 ] ) ;
2010-06-02 03:45:21 +04:00
ret = ctdb_client_send_message ( ctdb , CTDB_BROADCAST_CONNECTED , srvid , data ) ;
2010-02-04 01:45:32 +03:00
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to send memdump request message to %u \n " , options . pnn ) ) ;
return - 1 ;
}
return 0 ;
}
/*
handler for msglisten
*/
static void msglisten_handler ( struct ctdb_context * ctdb , uint64_t srvid ,
TDB_DATA data , void * private_data )
{
int i ;
printf ( " Message received: " ) ;
for ( i = 0 ; i < data . dsize ; i + + ) {
printf ( " %c " , data . dptr [ i ] ) ;
}
printf ( " \n " ) ;
}
/*
listen for messages on a messageport
*/
static int control_msglisten ( struct ctdb_context * ctdb , int argc , const char * * argv )
{
uint64_t srvid ;
srvid = getpid ( ) ;
/* register a message port and listen for messages
*/
2010-06-02 03:51:47 +04:00
ctdb_client_set_message_handler ( ctdb , srvid , msglisten_handler , NULL ) ;
2010-02-04 01:45:32 +03:00
printf ( " Listening for messages on srvid:%d \n " , ( int ) srvid ) ;
while ( 1 ) {
event_loop_once ( ctdb - > ev ) ;
}
return 0 ;
}
2008-02-19 06:44:48 +03:00
/*
list all nodes in the cluster
2010-09-09 01:35:10 +04:00
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 )
{
2010-09-09 01:35:10 +04:00
TALLOC_CTX * mem_ctx = talloc_new ( NULL ) ;
struct pnn_node * pnn_nodes ;
struct pnn_node * pnn_node ;
2008-02-19 06:44:48 +03:00
2013-08-19 08:40:52 +04:00
assert_single_node_only ( ) ;
2010-09-09 01:35:10 +04:00
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 ;
}
2008-02-19 06:44:48 +03:00
2010-09-09 01:35:10 +04:00
for ( pnn_node = pnn_nodes ; pnn_node ; pnn_node = pnn_node - > next ) {
2014-03-03 06:20:06 +04:00
const char * addr = ctdb_addr_to_str ( & pnn_node - > addr ) ;
2010-09-09 01:35:10 +04:00
if ( options . machinereadable ) {
2014-03-03 06:20:06 +04:00
printf ( " :%d:%s: \n " , pnn_node - > pnn , addr ) ;
2010-09-09 01:35:10 +04:00
} else {
2014-03-03 06:20:06 +04:00
printf ( " %s \n " , addr ) ;
2009-06-04 07:21:25 +04:00
}
2008-02-19 06:44:48 +03:00
}
2010-09-09 01:35:10 +04:00
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
2013-08-19 08:40:52 +04:00
assert_single_node_only ( ) ;
2013-08-14 22:38:02 +04:00
mypnn = ctdb_get_pnn ( ctdb ) ;
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 [ ] = {
2012-10-30 04:49:28 +04:00
{ " version " , control_version , true , true , " show version of ctdb " } ,
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 " } ,
2013-04-18 14:30:14 +04:00
{ " runstate " , control_runstate , true , false , " get/check runstate of a node " , " [setup|first_recovery|startup|running] " } ,
2009-03-25 06:46:05 +03:00
{ " 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 " } ,
2010-09-29 06:13:05 +04:00
{ " stats " , control_stats , false , false , " show rolling statistics " , " [number of history records] " } ,
2009-03-25 06:46:05 +03:00
{ " ip " , control_ip , false , false , " show which public ip's that ctdb manages " } ,
2009-12-17 13:23:59 +03:00
{ " ipinfo " , control_ipinfo , true , false , " show details about a public ip that ctdb manages " , " <ip> " } ,
2009-12-16 18:50:23 +03:00
{ " ifaces " , control_ifaces , true , false , " show which interfaces that ctdb manages " } ,
2009-12-16 19:02:23 +03:00
{ " setifacelink " , control_setifacelink , true , false , " set interface link status " , " <iface> <status> " } ,
2009-03-25 06:46:05 +03:00
{ " 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 " } ,
2012-12-19 07:43:26 +04:00
{ " getdbstatus " , control_getdbstatus , true , false , " show the status of a database " , " <dbname|dbid> " } ,
{ " catdb " , control_catdb , true , false , " dump a ctdb database " , " <dbname|dbid> " } ,
{ " cattdb " , control_cattdb , true , false , " dump a local tdb database " , " <dbname|dbid> " } ,
2009-03-25 06:46:05 +03:00
{ " 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 " } ,
2012-10-18 07:13:30 +04:00
{ " getlog " , control_getlog , true , false , " get the log data from the in memory ringbuffer " , " [<level>] [recoverd] " } ,
{ " clearlog " , control_clearlog , true , false , " clear the log data from the in memory ringbuffer " , " [recoverd] " } ,
2010-09-14 16:49:42 +04:00
{ " attach " , control_attach , true , false , " attach to a database " , " <dbname> [persistent] " } ,
2009-03-25 06:46:05 +03:00
{ " 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 " } ,
2013-10-25 09:25:25 +04:00
{ " ban " , control_ban , true , false , " ban a node from the cluster " , " <bantime> " } ,
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 " } ,
2013-05-23 10:06:47 +04:00
{ " sync " , control_ipreallocate , false , false , " wait until ctdbd has synced all state changes " } ,
2013-08-19 07:54:49 +04:00
{ " ipreallocate " , control_ipreallocate , false , false , " force the recovery daemon to perform a ip reallocation procedure " } ,
2009-10-12 02:22:17 +04:00
{ " 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 " } ,
2013-07-25 07:28:26 +04:00
{ " killtcp " , kill_tcp , false , false , " kill a tcp connection. " , " [<srcip:port> <dstip:port>] " } ,
2009-03-25 06:46:05 +03:00
{ " 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> " } ,
2010-08-20 05:25:12 +04:00
{ " gettickles " , control_get_tickles , false , false , " get the list of tickles registered for this ip " , " <ip> [<port>] " } ,
2010-08-18 05:09:32 +04:00
{ " addtickle " , control_add_tickle , false , false , " add a tickle for this ip " , " <ip>:<port> <ip>:<port> " } ,
2009-03-25 06:46:05 +03:00
2010-08-18 06:36:03 +04:00
{ " deltickle " , control_del_tickle , false , false , " delete a tickle from this ip " , " <ip>:<port> <ip>:<port> " } ,
2009-03-25 06:46:05 +03:00
{ " 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 " } ,
2011-11-30 02:50:12 +04:00
{ " check_srvids " , check_srvids , false , false , " check if a srvid exists " , " <id>+ " } ,
2009-03-25 06:46:05 +03:00
{ " 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> " } ,
2012-04-03 07:43:21 +04:00
{ " rebalanceip " , control_rebalanceip , false , false , " release an ip from the node and let recd rebalance it " , " <ip> " } ,
2009-03-25 06:46:05 +03:00
{ " 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> " } ,
2012-12-19 07:43:26 +04:00
{ " backupdb " , control_backupdb , false , false , " backup the database into a file. " , " <dbname|dbid> <file> " } ,
2010-05-20 05:26:37 +04:00
{ " restoredb " , control_restoredb , false , false , " restore the database from a file. " , " <file> [dbname] " } ,
2009-12-04 17:24:23 +03:00
{ " dumpdbbackup " , control_dumpdbbackup , false , true , " dump database backup from a file. " , " <file> " } ,
2012-12-19 07:43:26 +04:00
{ " wipedb " , control_wipedb , false , false , " wipe the contents of a database. " , " <dbname|dbid> " } ,
2012-07-06 14:35:23 +04:00
{ " recmaster " , control_recmaster , true , false , " show the pnn for the recovery master. " } ,
2011-11-10 08:41:03 +04:00
{ " scriptstatus " , control_scriptstatus , true , false , " show the status of the monitoring scripts (or all scripts) " , " [all] " } ,
2013-08-19 07:54:49 +04:00
{ " enablescript " , control_enablescript , true , false , " enable an eventscript " , " <script> " } ,
{ " disablescript " , control_disablescript , true , false , " disable an eventscript " , " <script> " } ,
{ " natgwlist " , control_natgwlist , true , false , " show the nodes belonging to this natgw configuration " } ,
{ " xpnn " , control_xpnn , false , true , " find the pnn of the local node without talking to the daemon (unreliable) " } ,
{ " getreclock " , control_getreclock , true , false , " Show the reclock file of a node " } ,
{ " setreclock " , control_setreclock , true , 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} " } ,
2012-12-19 07:43:26 +04:00
{ " setdbprio " , control_setdbprio , false , false , " Set DB priority " , " <dbname|dbid> <prio:1-3> " } ,
{ " getdbprio " , control_getdbprio , false , false , " Get DB priority " , " <dbname|dbid> " } ,
{ " setdbreadonly " , control_setdbreadonly , false , false , " Set DB readonly capable " , " <dbname|dbid> " } ,
{ " setdbsticky " , control_setdbsticky , false , false , " Set DB sticky-records capable " , " <dbname|dbid> " } ,
2010-02-04 01:45:32 +03:00
{ " msglisten " , control_msglisten , false , false , " Listen on a srvid port for messages " , " <msg srvid> " } ,
{ " msgsend " , control_msgsend , false , false , " Send a message to srvid " , " <srvid> <message> " } ,
2012-12-19 07:43:26 +04:00
{ " pfetch " , control_pfetch , false , false , " fetch a record from a persistent database " , " <dbname|dbid> <key> [<file>] " } ,
{ " pstore " , control_pstore , false , false , " write a record to a persistent database " , " <dbname|dbid> <key> <file containing record> " } ,
{ " pdelete " , control_pdelete , false , false , " delete a record from a persistent database " , " <dbname|dbid> <key> " } ,
2013-11-06 06:43:53 +04:00
{ " ptrans " , control_ptrans , false , false , " update a persistent database (from stdin) " , " <dbname|dbid> " } ,
2012-02-07 05:14:57 +04:00
{ " tfetch " , control_tfetch , false , true , " fetch a record from a [c]tdb-file [-v] " , " <tdb-file> <key> [<file>] " } ,
2013-11-18 08:09:27 +04:00
{ " tstore " , control_tstore , false , true , " store a record (including ltdb header) " , " <tdb-file> <key> <data> [<rsn> <dmaster> <flags>] " } ,
2014-01-31 05:46:21 +04:00
{ " readkey " , control_readkey , true , false , " read the content off a database key " , " <dbname|dbid> <key> " } ,
{ " writekey " , control_writekey , true , false , " write to a database key " , " <dbname|dbid> <key> <value> " } ,
2011-08-17 04:16:35 +04:00
{ " checktcpport " , control_chktcpport , false , true , " check if a service is bound to a specific tcp port or not " , " <port> " } ,
2013-09-23 10:20:42 +04:00
{ " rebalancenode " , control_rebalancenode , false , false , " mark nodes as forced IP rebalancing targets " , " [<pnn-list>] " } ,
2012-12-19 07:43:26 +04:00
{ " getdbseqnum " , control_getdbseqnum , false , false , " get the sequence number off a database " , " <dbname|dbid> " } ,
2013-09-23 10:20:42 +04:00
{ " nodestatus " , control_nodestatus , true , false , " show and return node status " , " [<pnn-list>] " } ,
2012-12-19 07:43:26 +04:00
{ " dbstatistics " , control_dbstatistics , false , false , " show db statistics " , " <dbname|dbid> " } ,
2013-09-23 10:20:42 +04:00
{ " reloadips " , control_reloadips , false , false , " reload the public addresses file on specified nodes " , " [<pnn-list>] " } ,
{ " ipiface " , control_ipiface , false , true , " Find which interface an ip address is hosted on " , " <ip> " } ,
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 "
2010-08-20 05:28:24 +04:00
" -v generate verbose 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 } ,
2010-08-20 05:28:24 +04:00
{ " verbose " , ' v ' , POPT_ARG_NONE , & options . verbose , 0 , " enable verbose 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 " } ,
2011-11-28 20:11:16 +04:00
{ " print-emptyrecords " , 0 , POPT_ARG_NONE , & options . printemptyrecords , 0 , " print the empty records when dumping databases (catdb, cattdb, dumpdbbackup) " , NULL } ,
2011-11-28 20:19:03 +04:00
{ " print-datasize " , 0 , POPT_ARG_NONE , & options . printdatasize , 0 , " do not print record data when dumping databases, only the data size " , NULL } ,
2011-11-28 20:36:03 +04:00
{ " print-lmaster " , 0 , POPT_ARG_NONE , & options . printlmaster , 0 , " print the record's lmaster in catdb " , NULL } ,
2011-11-29 03:56:23 +04:00
{ " print-hash " , 0 , POPT_ARG_NONE , & options . printhash , 0 , " print the record's hash when dumping databases " , NULL } ,
2011-11-29 13:24:52 +04:00
{ " print-recordflags " , 0 , POPT_ARG_NONE , & options . printrecordflags , 0 , " print the record flags in catdb and dumpdbbackup " , NULL } ,
2007-04-26 16:27:49 +04:00
POPT_TABLEEND
} ;
int opt ;
const char * * extra_argv ;
int extra_argc = 0 ;
2007-05-29 10:02:02 +04:00
int ret = - 1 , i ;
2007-04-26 16:27:49 +04:00
poptContext pc ;
struct event_context * ev ;
const char * control ;
2007-05-29 06:16:59 +04:00
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 ;
2013-08-09 05:56:29 +04:00
options . timelimit = 10 ;
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-04-26 16:27:49 +04:00
control = extra_argv [ 0 ] ;
2013-10-21 12:43:47 +04:00
/* Default value for CTDB_BASE - don't override */
setenv ( " CTDB_BASE " , ETCDIR " /ctdb " , 0 ) ;
2007-04-26 16:27:49 +04:00
ev = event_context_init ( NULL ) ;
2010-07-12 10:38:37 +04:00
if ( ! ev ) {
DEBUG ( DEBUG_ERR , ( " Failed to initialize event system \n " ) ) ;
exit ( 1 ) ;
}
2007-04-26 16:27:49 +04:00
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 ) {
2011-11-29 07:20:26 +04:00
break ;
}
}
2007-06-11 16:25:26 +04:00
2011-11-29 07:20:26 +04:00
if ( i = = ARRAY_SIZE ( ctdb_commands ) ) {
DEBUG ( DEBUG_ERR , ( " Unknown control '%s' \n " , control ) ) ;
exit ( 1 ) ;
}
2009-06-04 07:21:25 +04:00
2011-11-29 07:20:26 +04:00
if ( ctdb_commands [ i ] . without_daemon = = true ) {
2011-11-29 07:25:31 +04:00
if ( nodestring ! = NULL ) {
DEBUG ( DEBUG_ERR , ( " Can't specify node(s) with \" ctdb %s \" \n " , control ) ) ;
exit ( 1 ) ;
}
2011-11-29 07:38:39 +04:00
return ctdb_commands [ i ] . fn ( NULL , extra_argc - 1 , extra_argv + 1 ) ;
2011-11-29 07:20:26 +04:00
}
2009-06-04 07:21:25 +04:00
2011-11-29 07:20:26 +04:00
/* initialise ctdb */
ctdb = ctdb_cmdline_client ( ev , TIMELIMIT ( ) ) ;
2010-06-09 03:17:35 +04:00
2011-11-29 07:38:39 +04:00
if ( ctdb = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Failed to init ctdb \n " ) ) ;
exit ( 1 ) ;
}
2007-06-11 16:25:26 +04:00
2011-12-06 12:50:40 +04:00
/* setup the node number(s) to contact */
2013-08-27 08:46:08 +04:00
if ( ! parse_nodestring ( ctdb , ctdb , nodestring , CTDB_CURRENT_NODE , false ,
2011-12-06 12:50:40 +04:00
& options . nodes , & options . pnn ) ) {
usage ( ) ;
2011-11-29 08:18:45 +04:00
}
2011-11-29 07:38:39 +04:00
if ( options . pnn = = CTDB_CURRENT_NODE ) {
2011-12-06 12:50:40 +04:00
options . pnn = options . nodes [ 0 ] ;
2007-05-02 07:34:55 +04:00
}
2011-11-29 07:20:26 +04:00
if ( ctdb_commands [ i ] . auto_all & &
2011-12-06 12:50:40 +04:00
( ( options . pnn = = CTDB_BROADCAST_ALL ) | |
( options . pnn = = CTDB_MULTICAST ) ) ) {
2011-11-29 07:20:26 +04:00
int j ;
2011-12-06 12:50:40 +04:00
ret = 0 ;
for ( j = 0 ; j < talloc_array_length ( options . nodes ) ; j + + ) {
options . pnn = options . nodes [ j ] ;
2011-11-29 07:20:26 +04:00
ret | = ctdb_commands [ i ] . fn ( ctdb , extra_argc - 1 , extra_argv + 1 ) ;
}
} else {
ret = ctdb_commands [ i ] . fn ( ctdb , extra_argc - 1 , extra_argv + 1 ) ;
2007-04-26 16:27:49 +04:00
}
2011-12-06 12:50:40 +04:00
talloc_free ( ctdb ) ;
2012-08-20 09:02:24 +04:00
talloc_free ( ev ) ;
2011-12-15 04:26:09 +04:00
( void ) poptFreeContext ( pc ) ;
2011-12-06 12:50:40 +04:00
2007-04-26 16:27:49 +04:00
return ret ;
2012-02-07 05:14:57 +04:00
2007-04-26 16:27:49 +04:00
}