#!/usr/bin/perl
my
$DEBUG
=
$MySQL::Sandbox::DEBUG
;
runs_as_root();
unless
( -d
$ENV
{
'SANDBOX_HOME'
} ) {
mkdir
$ENV
{
'SANDBOX_HOME'
}
or
die
"can't create $ENV{'SANDBOX_HOME'} ($CHILD_ERROR) \n"
;
}
my
$msb
= MySQL::Sandbox->new();
my
%defaults
= (
circular_base_port
=>
$MySQL::Sandbox::default_base_port
{multiple},,
group_directory
=>
'multi_msb'
,
);
$msb
->parse_options ( MySQL::Sandbox::Scripts::parse_options_many() );
GetOptions (
map
{
$msb
->{parse_options}{
$_
}{parse}, \
$msb
->{options}{
$_
} }
grep
{
$msb
->{parse_options}{
$_
}{parse}}
keys
%{
$msb
->{parse_options}}
) or
$msb
->get_help();
$msb
->get_help()
if
$msb
->{options}{
'help'
};
unless
(
$msb
->{options}{server_version}) {
$msb
->{options}{server_version} =
shift
or
$msb
->get_help(
'server version required'
);
}
for
my
$opt
(
qw(repl_user repl_password remote_access)
) {
if
(
defined
$msb
->{options}{
$opt
}) {
$MySQL::Sandbox::default_users
{
$opt
} =
$msb
->{options}{
$opt
};
}
}
if
(
$msb
->{options}{node_options})
{
$ENV
{NODE_OPTIONS} =
$msb
->{options}{node_options};
}
if
(
$msb
->{options}{one_node_options})
{
for
my
$node_opt
(@{
$msb
->{options}{one_node_options}} )
{
if
(
$node_opt
=~ /^(\d+):\s*(\S.+)/)
{
$ENV
{
"NODE${1}_OPTIONS"
} = $2;
}
else
{
get_help(
"invalid format for --one_node_option ($node_opt)"
);
}
}
}
my
$base_version
;
my
$release_no
;
my
$dashed_version
;
my
$replication_port
= 0;
my
$temp_path
=
$msb
->{options}{server_version};
$temp_path
=~ s{.*/}{};
my
$prefix
=
''
;
if
(
$temp_path
=~ /^(\D+)\d+/ ) {
$prefix
= $1;
}
if
(
$temp_path
=~ /(\d+)\.(\d+)\.(\d+)/ ) {
$base_version
=
"$1$2$3"
;
$release_no
= $3;
$dashed_version
=
"${prefix}$1_$2_$3"
;
$base_version
=~ s/^0+//;
}
else
{
$msb
->get_help(
"No recognizable version pattern in $msb->{options}{server_version}\n"
);
}
my
$group_directory
;
if
(
$msb
->{options}{group_directory}) {
$group_directory
=
"$msb->{options}{upper_directory}/$msb->{options}{group_directory}"
;
}
else
{
$group_directory
=
"$msb->{options}{upper_directory}/$defaults{group_directory}_$dashed_version"
;
}
if
( -d
$group_directory
) {
if
( -x
"$group_directory/clear_all"
) {
system
"$group_directory/clear_all"
;
}
system
"rm -rf $group_directory/*"
;
}
else
{
print
"creating group directory $group_directory\n"
if
$msb
->{options}{verbose};
mkdir
$group_directory
or
die
"can't create $group_directory\n"
;
}
if
( -f
"$group_directory/needs_initialization"
) {
system
"rm -f $group_directory/needs_initialization"
;
}
if
(
$msb
->{options}{
'master_master'
}) {
$msb
->{options}{
'how_many_nodes'
} = 2;
$msb
->{options}{
'circular'
} = 1;
}
for
my
$dir
( 1 ..
$msb
->{options}{how_many_nodes}) {
if
( -d
"$group_directory/node$dir"
) {
system
"rm -rf $group_directory/node$dir"
and
die
"unable to clean $group_directory/node$dir\n"
;
}
}
if
(
$msb
->{options}{sandbox_base_port}) {
$replication_port
=
$msb
->{options}{sandbox_base_port};
}
else
{
$replication_port
=
$defaults
{circular_base_port} +
$base_version
+ (
$release_no
* 100);
}
if
(
$msb
->{options}{check_base_port}) {
$replication_port
= get_ranges({
min_range
=>
$replication_port
,
range_size
=>
$msb
->{options}{how_many_nodes},
max_range
=> 64000,
search_path
=>
$ENV
{SANDBOX_HOME},
}, 1);
}
my
$circular_replication_script
=
"$group_directory/set_circular_replication.sh"
;
if
(
$msb
->{options}{
'circular'
}) {
$msb
->write_to(
$circular_replication_script
,
'>'
,
qq(
#!/bin/bash
TMPL1="change master to master_host='127.0.0.1',"
TMPL2="master_user='$MySQL::Sandbox::default_users{'repl_user'}',"
TMPL3="master_password='$MySQL::Sandbox::default_users{'repl_password'}',"
TMPL4="master_port"
TMPL="\$TMPL1 \$TMPL2 \$TMPL3 \$TMPL4"
)
);
$msb
->write_to(
$circular_replication_script
,
'>>'
,
"$group_directory/use_all 'reset master' "
);
$msb
->write_to(
$circular_replication_script
,
'>>'
,
"$group_directory/use_all 'stop slave' "
);
}
for
my
$node
(1 ..
$msb
->{options}{how_many_nodes}) {
my
$additional_node_options
=
$ENV
{NODE_OPTIONS} ||
''
;
if
(
$msb
->{options}{gtid})
{
$additional_node_options
.=
' --gtid '
;
}
my
$this_node_options
=
$ENV
{
"NODE${node}_OPTIONS"
} ||
''
;
my
$node_port
=
$replication_port
+
$node
;
if
(
$msb
->{options}{
'circular'
}) {
my
$master_node_port
=
$node
== 1
?
$node_port
+
$msb
->{options}{how_many_nodes} -1
:
$node_port
-1;
$additional_node_options
.=
'-c log-slave-updates '
.
'-c replicate-same-server-id=0 '
.
'-c auto_increment_increment='
.
$msb
->{options}{
'how_many_nodes'
}
.
' '
.
'-c auto_increment_offset='
.
$node
.
' '
.
'-c report-host=SBnode'
.
$node
.
' '
.
"-c report-port=$node_port"
;
}
$additional_node_options
.=
q{ }
;
my
$node_id
= 100 +
$node
;
print
"installing node $node\n"
;
my
$install_node
=
''
;
my
$install_node_command
=
qq(
make_sandbox $msb->{options}{server_version} -- \\
--datadir_from=script \\
--upper_directory=$group_directory \\
--sandbox_directory=node$node \\
--history_dir=$group_directory \\
--no_confirm \\
--no_check_port \\
--repl_user=$msb->{options}{repl_user} \\
--repl_password=$msb->{options}{repl_password} \\
--remote_access=$msb->{options}{remote_access} \\
--prompt_prefix=node$node \\
--sandbox_port=$node_port \\
-c server-id=$node_id \\
-c relay-log-index=mysql-relay \\
-c relay-log=mysql-relay \\
-c log-bin=mysql-bin $additional_node_options $this_node_options
)
;
if
(
$msb
->{options}{interactive}
or (
$additional_node_options
=~ /\binteractive\b/)) {
system
(
$install_node_command
);
}
else
{
$install_node
=
qx($install_node_command)
;
}
print
$install_node
if
$msb
->{options}{verbose};
if
(
$CHILD_ERROR
) {
print
"error installing node $node\n"
;
print
"$install_node\n($CHILD_ERROR $OS_ERROR)\n"
;
exit
(1)
}
if
(
$msb
->{options}{
'circular'
}) {
my
$master_node
=
$node
+ 1 ;
if
(
$master_node
>
$msb
->{options}{
'how_many_nodes'
} ) {
$master_node
= 1;
}
$msb
->write_to(
$circular_replication_script
,
'>>'
,
sprintf
(
q(echo "$TMPL=%d" | %s/node%d/use -u root )
,
$node_port
,
$group_directory
,
$master_node
)
);
}
}
if
(
$msb
->{options}{
'circular'
}) {
$msb
->write_to(
$circular_replication_script
,
'>>'
,
"$group_directory/use_all 'start slave' "
);
chmod
0755,
$circular_replication_script
;
}
my
$current_dir
=
$ENV
{PWD};
chdir
$group_directory
;
for
my
$cmd
(
qw(start stop clear send_kill )
) {
my
$cmd_fname
=
$cmd
.
'_all'
;
$msb
->write_to(
$cmd_fname
,
'>'
,
'#!/bin/sh'
);
$msb
->write_to(
$cmd_fname
,
'>>'
,
qq(echo '# executing "$cmd"' on $group_directory)
);
if
(
$cmd
=~ /stop|clear|send_kill/ &&
$msb
->{options}{
'circular'
}) {
$msb
->write_to (
$cmd_fname
,
'>>'
,
qq($group_directory/use_all "stop slave")
);
}
for
my
$node
(1 ..
$msb
->{options}{how_many_nodes} ) {
$msb
->write_to (
$cmd_fname
,
'>>'
,
qq(echo 'executing "$cmd" on node $node')
);
$msb
->write_to (
$cmd_fname
,
'>>'
,
qq($group_directory/node$node/$cmd "\$@")
);
if
((
$cmd
eq
'start'
) and
$msb
->{options}{
'circular'
}) {
$msb
->write_to (
$cmd_fname
,
'>>'
,
"if [ -f $group_directory/node$node/data/master.info ] \n"
.
"then\n"
.
" echo 'stop slave' | $group_directory/n$node -u root\n"
.
"fi"
);
}
}
chmod
0755,
$cmd_fname
;
}
$msb
->write_to(
'restart_all'
,
'>'
,
'#!/bin/sh'
);
$msb
->write_to(
'restart_all'
,
'>>'
,
qq($group_directory/stop_all)
);
$msb
->write_to(
'restart_all'
,
'>>'
,
qq($group_directory/start_all "\$@")
);
chmod
0755,
'restart_all'
;
$msb
->write_to(
'use_all'
,
'>'
,
'#!/bin/sh'
);
my
$node_list
=
join
(
' '
, (1 ..
$msb
->{options}{how_many_nodes}) );
$msb
->write_to(
'use_all'
,
'>>'
,
'if [ "$1 " = " " ]'
);
$msb
->write_to(
'use_all'
,
'>>'
,
'then'
);
$msb
->write_to(
'use_all'
,
'>>'
,
' echo "syntax: $0 command"'
);
$msb
->write_to(
'use_all'
,
'>>'
,
' exit 1'
);
$msb
->write_to(
'use_all'
,
'>>'
,
'fi'
);
$msb
->write_to(
'use_all'
,
'>>'
,
''
);
$msb
->write_to(
'use_all'
,
'>>'
,
'for SNUM in '
.
$node_list
);
$msb
->write_to(
'use_all'
,
'>>'
,
'do '
);
$msb
->write_to(
'use_all'
,
'>>'
,
' echo "# server: $SNUM: " '
);
$msb
->write_to(
'use_all'
,
'>>'
,
' echo "$@" | '
.
$group_directory
.
'/node$SNUM/use $MYCLIENT_OPTIONS '
);
$msb
->write_to(
'use_all'
,
'>>'
,
'done '
);
chmod
0755,
'use_all'
;
$msb
->write_to(
'status_all'
,
'>'
,
'#!/bin/sh'
);
my
$gdir
=
$group_directory
;
$gdir
=~ s{.*/}{};
my
$group_type
=
'MULTIPLE'
;
if
(
$msb
->{options}{
'circular'
}) {
$group_type
=
'CIRC-REPL'
;
}
$msb
->write_to(
'status_all'
,
'>>'
,
"echo $group_type $gdir"
);
$msb
->write_to(
'status_all'
,
'>>'
,
'for SNUM in '
.
$node_list
);
$msb
->write_to(
'status_all'
,
'>>'
,
'do '
);
$msb
->write_to(
'status_all'
,
'>>'
,
' '
.
$group_directory
.
'/node$SNUM/status'
);
$msb
->write_to(
'status_all'
,
'>>'
,
' '
.
$group_directory
.
'/node$SNUM/use -BN -e'
.
qq( "select CONCAT('port: ', \@\@port)
AS port" ));
$msb
->write_to(
'status_all'
,
'>>'
,
'done '
);
chmod
0755,
'status_all'
;
$msb
->write_to(
'check_slaves'
,
'>'
,
'#!/bin/sh'
);
$msb
->write_to(
'check_slaves'
,
'>>'
,
'for NNUM in '
.
$node_list
);
$msb
->write_to(
'check_slaves'
,
'>>'
,
'do'
);
$msb
->write_to(
'check_slaves'
,
'>>'
,
' echo "node # $NNUM"'
);
$msb
->write_to(
'check_slaves'
,
'>>'
,
' '
.
$group_directory
.
'/node$NNUM/use -BN -e'
.
qq( "select CONCAT('port: ', \@\@port)
AS port" ));
$msb
->write_to(
'check_slaves'
,
'>>'
,
" $group_directory/node\$NNUM/use -e "
.
qq( 'show master status\\G' | grep "File\\|Position" )
);
$msb
->write_to(
'check_slaves'
,
'>>'
,
' echo "" '
);
$msb
->write_to(
'check_slaves'
,
'>>'
,
" $group_directory/node\$NNUM/use -e "
.
qq( 'show slave status\\G' | grep "\\(Running:\\|Master_Log_Pos\\|\\<Master_Log_File\\)
") );
$msb
->write_to(
'check_slaves'
,
'>>'
,
'done '
);
chmod
0755,
'check_slaves'
;
for
my
$node
(1 ..
$msb
->{options}{how_many_nodes} ) {
$msb
->write_to(
"n$node"
,
'>'
,
"#!/bin/sh"
);
$msb
->write_to(
"n$node"
,
'>'
,
qq($group_directory/node$node/use "\$@")
);
chmod
0755,
"n$node"
;
}
if
(
$msb
->{options}{
'circular'
}) {
$msb
->write_to(
"$group_directory/clear_all"
,
'>>'
,
"date > $group_directory/needs_initialization"
);
$msb
->write_to(
qq($group_directory/start_all)
,
'>>'
,
"if [ -f $group_directory/needs_initialization ] \n"
.
"then\n"
.
" $circular_replication_script\n"
.
" rm -f $group_directory/needs_initialization\n"
.
"else\n"
.
" $group_directory/use_all 'start slave' \n"
.
"fi"
);
my
$result
=
system
(
$circular_replication_script
);
if
(
$result
) {
die
(
"error starting up circular replication ($!)\n"
);
}
else
{
print
"Circular replication activated\n"
;
}
}
my
@nodes
;
for
my
$N
(1 ..
$msb
->{options}{how_many_nodes})
{
push
@nodes
,
"node$N"
;
}
for
my
$json
(
qw(connection.json default_connection.json)
)
{
my
$json_text
= MySQL::Sandbox::get_json_from_dirs(\
@nodes
,
$json
);
$msb
->write_to(
$json
,
'>'
,
$json_text
);
}
if
(
$msb
->{options}{circular})
{
$msb
->write_to(
'README'
,
'>'
, MySQL::Sandbox::Scripts::get_readme_circular());
$msb
->write_to(
'README'
,
'>>'
, MySQL::Sandbox::Scripts::get_readme_common_replication());
}
else
{
$msb
->write_to(
'README'
,
'>'
, MySQL::Sandbox::Scripts::get_readme_multiple());
}
$msb
->write_to(
'README'
,
'>>'
, MySQL::Sandbox::Scripts::get_readme_common());
chdir
$current_dir
;
print
"group directory installed in "
, use_env(
$group_directory
),
"\n"
;
sbinstr(
"group_directory installed in <"
.
use_env(
$group_directory
) .
">"
);