PT-2302 - pt-k8s-debug-collector cannot pass properly to pt-mysql-summary PXC root password with special characters

- Merge branch '3.x' into PT-2302_pt-k8s-debug-collector_cannot_pass_properly_to_pt-mysql-summary_PXC_root_password_with_special_characters
- Implement fix for MongoDB
This commit is contained in:
Sveta Smirnova
2024-04-19 14:50:38 +03:00
32 changed files with 311 additions and 46 deletions

View File

@@ -61,6 +61,7 @@ extend-ignore-re = [
"RegexXtrabackupISTReceived" = "RegexXtrabackupISTReceived"
"START_ND_SUMMARY" = "START_ND_SUMMARY"
"START_ND_TOOLTIPS" = "START_ND_TOOLTIPS"
"thr" = "thr" # common abbreviation
"TOI" = "TOI"
"UNIONed" = "UNIONed"
"UNIONs" = "UNIONs"

View File

@@ -3781,7 +3781,8 @@ sub recurse_to_slaves {
my $slave_dsn = $dsn;
if ($slave_user) {
$slave_dsn->{u} = $slave_user;
PTDEBUG && _d("Using slave user $slave_user on ".$slave_dsn->{h}.":".$slave_dsn->{P});
PTDEBUG && _d("Using slave user $slave_user on "
. $slave_dsn->{h} . ":" . ( $slave_dsn->{P} ? $slave_dsn->{P} : ""));
}
if ($slave_password) {
$slave_dsn->{p} = $slave_password;

View File

@@ -5533,7 +5533,7 @@ is undefined which means an infinite number of iterations. The tool always
exits for L<"--run-time">, regardless of the value specified for this option.
For example, the tool will exit after 1 minute with
C<--run-time 1m --iterations 4 --interval 30> because 4 iterations at 30
second intervals would take 2 minutes, longer than the 1 mintue run-time.
second intervals would take 2 minutes, longer than the 1 minute run-time.
=item --log

View File

@@ -4530,7 +4530,7 @@ is undefined which means an infinite number of iterations. The tool always
exits for L<"--run-time">, regardless of the value specified for this option.
For example, the tool will exit after 1 minute with
C<--run-time 1m --iterations 4 --interval 30> because 4 iterations at 30
second intervals would take 2 minutes, longer than the 1 mintue run-time.
second intervals would take 2 minutes, longer than the 1 minute run-time.
=item --log

View File

@@ -242,7 +242,8 @@ sub recurse_to_slaves {
my $slave_dsn = $dsn;
if ($slave_user) {
$slave_dsn->{u} = $slave_user;
PTDEBUG && _d("Using slave user $slave_user on ".$slave_dsn->{h}.":".$slave_dsn->{P});
PTDEBUG && _d("Using slave user $slave_user on "
. $slave_dsn->{h} . ":" . ( $slave_dsn->{P} ? $slave_dsn->{P} : ""));
}
if ($slave_password) {
$slave_dsn->{p} = $slave_password;

View File

@@ -408,7 +408,7 @@ _parse_command_line() {
fi
if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then
val="$(echo $opt | awk -F= '{print $2}')"
val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')"
opt="$(echo $opt | awk -F= '{print $1}')"
fi
@@ -453,7 +453,7 @@ _parse_command_line() {
val=$(size_to_bytes $val)
fi
eval "OPT_$opt"="'$val'"
eval "OPT_$opt"='$val'
opt=""
val=""

View File

@@ -4058,7 +4058,8 @@ sub recurse_to_slaves {
my $slave_dsn = $dsn;
if ($slave_user) {
$slave_dsn->{u} = $slave_user;
PTDEBUG && _d("Using slave user $slave_user on ".$slave_dsn->{h}.":".$slave_dsn->{P});
PTDEBUG && _d("Using slave user $slave_user on "
. $slave_dsn->{h} . ":" . ( $slave_dsn->{P} ? $slave_dsn->{P} : ""));
}
if ($slave_password) {
$slave_dsn->{p} = $slave_password;

View File

@@ -449,7 +449,7 @@ _parse_command_line() {
fi
if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then
val="$(echo $opt | awk -F= '{print $2}')"
val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')"
opt="$(echo $opt | awk -F= '{print $1}')"
fi
@@ -494,7 +494,7 @@ _parse_command_line() {
val=$(size_to_bytes $val)
fi
eval "OPT_$opt"="'$val'"
eval "OPT_$opt"='$val'
opt=""
val=""

View File

@@ -410,7 +410,7 @@ _parse_command_line() {
fi
if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then
val="$(echo $opt | awk -F= '{print $2}')"
val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')"
opt="$(echo $opt | awk -F= '{print $1}')"
fi
@@ -455,7 +455,7 @@ _parse_command_line() {
val=$(size_to_bytes $val)
fi
eval "OPT_$opt"="'$val'"
eval "OPT_$opt"='$val'
opt=""
val=""

View File

@@ -4346,7 +4346,8 @@ sub recurse_to_slaves {
my $slave_dsn = $dsn;
if ($slave_user) {
$slave_dsn->{u} = $slave_user;
PTDEBUG && _d("Using slave user $slave_user on ".$slave_dsn->{h}.":".$slave_dsn->{P});
PTDEBUG && _d("Using slave user $slave_user on "
. $slave_dsn->{h} . ":" . ( $slave_dsn->{P} ? $slave_dsn->{P} : ""));
}
if ($slave_password) {
$slave_dsn->{p} = $slave_password;

View File

@@ -451,7 +451,7 @@ _parse_command_line() {
fi
if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then
val="$(echo $opt | awk -F= '{print $2}')"
val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')"
opt="$(echo $opt | awk -F= '{print $1}')"
fi
@@ -496,7 +496,7 @@ _parse_command_line() {
val=$(size_to_bytes $val)
fi
eval "OPT_$opt"="'$val'"
eval "OPT_$opt"='$val'
opt=""
val=""

View File

@@ -10652,7 +10652,8 @@ sub recurse_to_slaves {
my $slave_dsn = $dsn;
if ($slave_user) {
$slave_dsn->{u} = $slave_user;
PTDEBUG && _d("Using slave user $slave_user on ".$slave_dsn->{h}.":".$slave_dsn->{P});
PTDEBUG && _d("Using slave user $slave_user on "
. $slave_dsn->{h} . ":" . ( $slave_dsn->{P} ? $slave_dsn->{P} : ""));
}
if ($slave_password) {
$slave_dsn->{p} = $slave_password;

View File

@@ -449,7 +449,7 @@ _parse_command_line() {
fi
if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then
val="$(echo $opt | awk -F= '{print $2}')"
val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')"
opt="$(echo $opt | awk -F= '{print $1}')"
fi
@@ -494,7 +494,7 @@ _parse_command_line() {
val=$(size_to_bytes $val)
fi
eval "OPT_$opt"="'$val'"
eval "OPT_$opt"='$val'
opt=""
val=""

View File

@@ -2383,7 +2383,8 @@ sub recurse_to_slaves {
my $slave_dsn = $dsn;
if ($slave_user) {
$slave_dsn->{u} = $slave_user;
PTDEBUG && _d("Using slave user $slave_user on ".$slave_dsn->{h}.":".$slave_dsn->{P});
PTDEBUG && _d("Using slave user $slave_user on "
. $slave_dsn->{h} . ":" . ( $slave_dsn->{P} ? $slave_dsn->{P} : ""));
}
if ($slave_password) {
$slave_dsn->{p} = $slave_password;

View File

@@ -2794,7 +2794,8 @@ sub recurse_to_slaves {
my $slave_dsn = $dsn;
if ($slave_user) {
$slave_dsn->{u} = $slave_user;
PTDEBUG && _d("Using slave user $slave_user on ".$slave_dsn->{h}.":".$slave_dsn->{P});
PTDEBUG && _d("Using slave user $slave_user on "
. $slave_dsn->{h} . ":" . ( $slave_dsn->{P} ? $slave_dsn->{P} : ""));
}
if ($slave_password) {
$slave_dsn->{p} = $slave_password;

View File

@@ -462,7 +462,7 @@ _parse_command_line() {
fi
if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then
val="$(echo $opt | awk -F= '{print $2}')"
val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')"
opt="$(echo $opt | awk -F= '{print $1}')"
fi
@@ -507,7 +507,7 @@ _parse_command_line() {
val=$(size_to_bytes $val)
fi
eval "OPT_$opt"="'$val'"
eval "OPT_$opt"='$val'
opt=""
val=""

View File

@@ -417,7 +417,7 @@ _parse_command_line() {
fi
if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then
val="$(echo $opt | awk -F= '{print $2}')"
val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')"
opt="$(echo $opt | awk -F= '{print $1}')"
fi
@@ -462,7 +462,7 @@ _parse_command_line() {
val=$(size_to_bytes $val)
fi
eval "OPT_$opt"="'$val'"
eval "OPT_$opt"='$val'
opt=""
val=""

View File

@@ -5298,7 +5298,8 @@ sub recurse_to_slaves {
my $slave_dsn = $dsn;
if ($slave_user) {
$slave_dsn->{u} = $slave_user;
PTDEBUG && _d("Using slave user $slave_user on ".$slave_dsn->{h}.":".$slave_dsn->{P});
PTDEBUG && _d("Using slave user $slave_user on "
. $slave_dsn->{h} . ":" . ( $slave_dsn->{P} ? $slave_dsn->{P} : ""));
}
if ($slave_password) {
$slave_dsn->{p} = $slave_password;

View File

@@ -6812,7 +6812,8 @@ sub recurse_to_slaves {
my $slave_dsn = $dsn;
if ($slave_user) {
$slave_dsn->{u} = $slave_user;
PTDEBUG && _d("Using slave user $slave_user on ".$slave_dsn->{h}.":".$slave_dsn->{P});
PTDEBUG && _d("Using slave user $slave_user on "
. $slave_dsn->{h} . ":" . ( $slave_dsn->{P} ? $slave_dsn->{P} : ""));
}
if ($slave_password) {
$slave_dsn->{p} = $slave_password;
@@ -10230,7 +10231,17 @@ sub main {
unshift @dsns, $master; # dsn[0]=master, dsn[1]=slave
$dsns[0]->{dbh} = get_cxn($dsns[0], %modules);
if ( $o->get('check-master') ) {
$ms->is_master_of($dsns[0]->{dbh}, $dsns[1]->{dbh});
my $is_master_of = eval {
$ms->is_master_of($dsns[0]->{dbh}, $dsns[1]->{dbh});
};
# We should not die if replica connected via tunnel or port redirection
if ( $EVAL_ERROR ) {
$EVAL_ERROR =~ m/The slave is connected to (\d+) but the master's port is \d+/;
if ( !$1 || $1 != $dsns[0]->{P} ) {
die $EVAL_ERROR;
}
}
}
}

2
go.mod
View File

@@ -26,7 +26,7 @@ require (
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0
github.com/xlab/treeprint v1.2.0
go.mongodb.org/mongo-driver v1.14.0
go.mongodb.org/mongo-driver v1.15.0
golang.org/x/crypto v0.22.0
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22

4
go.sum
View File

@@ -118,8 +118,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc=
go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=

View File

@@ -181,7 +181,8 @@ sub recurse_to_slaves {
my $slave_dsn = $dsn;
if ($slave_user) {
$slave_dsn->{u} = $slave_user;
PTDEBUG && _d("Using slave user $slave_user on ".$slave_dsn->{h}.":".$slave_dsn->{P});
PTDEBUG && _d("Using slave user $slave_user on "
. $slave_dsn->{h} . ":" . ( $slave_dsn->{P} ? $slave_dsn->{P} : ""));
}
if ($slave_password) {
$slave_dsn->{p} = $slave_password;

View File

@@ -495,7 +495,7 @@ sub table_is_allowed {
# then we'll get d1 tables when the user only wants d2 tables. So when
# a table passes allow filters, reaching this point, meaning it is allowed,
# we make this final to check to see if it's allowed in any database (*)
# or allowed in the specific database that the user qualifed the table with.
# or allowed in the specific database that the user qualified the table with.
# The first two checks are to prevent auto-vivifying the filters which will
# cause bad results (see a similar comment in _make_filters()).
if ( $filter->{'tables'}

View File

@@ -475,7 +475,7 @@ _parse_command_line() {
# Split opt=val pair.
if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then
val="$(echo $opt | awk -F= '{print $2}')"
val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')"
opt="$(echo $opt | awk -F= '{print $1}')"
fi
@@ -533,7 +533,7 @@ _parse_command_line() {
fi
# Re-eval the option to update its global variable value.
eval "OPT_$opt"="'$val'"
eval "OPT_$opt"='$val'
opt=""
val=""

View File

@@ -186,7 +186,7 @@ services:
image: ${TEST_MONGODB_IMAGE:-mongo:4.2}
ports:
- "${TEST_MONGODB_STANDALONE_PORT:-27017}:27017"
command: mongod --replSet rs1 --shardsvr --port 27017 --oplogSize 16
command: mongod --port 27017 --oplogSize 16
postgres9:
image: ${POSTGRE_IMAGE:-postgres:9.6}
container_name: go_postgres9_1

View File

@@ -73,15 +73,15 @@ func checkUpdates(url string, timeout time.Duration, toolName, version string) (
if err != nil {
return "", err
}
advices := []Advice{}
err = json.Unmarshal(body, &advices)
var advice []Advice
err = json.Unmarshal(body, &advice)
if err != nil {
return "", err
}
for _, advice := range advices {
if advice.ToolName == PERCONA_TOOLKIT {
return advice.Advice, nil
for _, a := range advice {
if a.ToolName == PERCONA_TOOLKIT {
return a.Advice, nil
}
}

View File

@@ -16,7 +16,7 @@ func TestCheckUpdates(t *testing.T) {
body, _ := ioutil.ReadAll(r.Body)
m := strings.Split(string(body), ";")
advices := []Advice{
advice := []Advice{
{
Hash: m[0],
ToolName: m[1],
@@ -24,7 +24,7 @@ func TestCheckUpdates(t *testing.T) {
},
}
buf, _ := json.Marshal(advices)
buf, _ := json.Marshal(advice)
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, string(buf))
}))

View File

@@ -451,7 +451,7 @@ func (d *Dumper) getPodSummary(resource, podName, crName string, namespace strin
}
ports = port + ":27017"
summCmdName = "pt-mongodb-summary"
summCmdArgs = []string{"--username='" + user + "'", "--password=" + pass, "--authenticationDatabase=admin", "127.0.0.1:" + port}
summCmdArgs = []string{"--username=" + user, "--password=" + string(pass), "--authenticationDatabase=admin", "127.0.0.1:" + port}
}
cmdPortFwd := exec.Command(d.cmd, "port-forward", "pod/"+podName, ports, "-n", namespace, "--kubeconfig", d.kubeconfig)

View File

@@ -374,14 +374,14 @@ func getHostInfo(ctx context.Context, client *mongo.Client) (*hostInfo, error) {
}
cmdOpts := proto.CommandLineOptions{}
query := primitive.D{{Key: "getCmdLineOpts", Value: 1}, {Key: "recordStats", Value: 1}}
query := primitive.D{{Key: "getCmdLineOpts", Value: 1}}
err := client.Database("admin").RunCommand(ctx, query).Decode(&cmdOpts)
if err != nil {
return nil, errors.Wrap(err, "cannot get command line options")
}
ss := proto.ServerStatus{}
query = primitive.D{{Key: "serverStatus", Value: 1}, {Key: "recordStats", Value: 1}}
query = primitive.D{{Key: "serverStatus", Value: 1}}
if err := client.Database("admin").RunCommand(ctx, query).Decode(&ss); err != nil {
return nil, errors.Wrap(err, "GetHostInfo.serverStatus")
}
@@ -528,7 +528,6 @@ func getSecuritySettings(ctx context.Context, client *mongo.Client, ver string)
cmdOpts := proto.CommandLineOptions{}
err = client.Database("admin").RunCommand(ctx, primitive.D{
{Key: "getCmdLineOpts", Value: 1},
{Key: "recordStats", Value: 1},
}).Decode(&cmdOpts)
if err != nil {
return nil, errors.Wrap(err, "cannot get command line options")
@@ -633,7 +632,6 @@ func getOpCountersStats(ctx context.Context, client *mongo.Client, count int,
err := client.Database("admin").RunCommand(ctx, primitive.D{
{Key: "serverStatus", Value: 1},
{Key: "recordStats", Value: 1},
}).Decode(&ss)
if err != nil {
return nil, err

View File

@@ -0,0 +1,77 @@
#!/usr/bin/env perl
BEGIN {
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
};
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use PerconaTest;
use Sandbox;
use DSNParser;
require VersionParser;
use Test::More;
local $ENV{PTDEBUG} = "";
my $dp = new DSNParser(opts=>$dsn_opts);
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
my $dbh = $sb->get_dbh_for('master');
my $cnf = '/tmp/12345/my.sandbox.cnf';
my $output;
if ( !$dbh ) {
plan skip_all => 'Cannot connect to sandbox master';
}
else {
plan tests => 5;
}
$sb->do_as_root("master", q/create user pt2302 identified by "root_'f<=*password"/);
$sb->do_as_root("master", q/grant all on *.* to pt2302/);
my $cmd = "$trunk/bin/pt-mysql-summary --sleep 1 -- --defaults-file=$cnf --user=pt2302 --password=\"root_'f<=*password\"";
$output = `$cmd 2>&1`;
unlike(
$output,
qr/eval: Syntax error: Unterminated quoted string/s,
"pt-mysql-summary does not stop with password containing an apostrophe"
);
unlike(
$output,
qr/Access denied for user/s,
"pt-mysql-summary works fine with password containing an apostrophe"
);
$sb->do_as_root("master", q/drop user pt2302/);
$sb->do_as_root("master", q/create user pt2302 identified by 'root_"f<=*password'/);
$sb->do_as_root("master", q/grant all on *.* to pt2302/);
$cmd = "$trunk/bin/pt-mysql-summary --sleep 1 -- --defaults-file=$cnf --user=pt2302 --password='root_\"f<=*password'";
$output = `$cmd 2>&1`;
unlike(
$output,
qr/eval: Syntax error: Unterminated quoted string/s,
"pt-mysql-summary does not stop with password containing a quote"
);
unlike(
$output,
qr/Access denied for user/s,
"pt-mysql-summary works fine with password containing a quote"
);
# #############################################################################
# Done.
# #############################################################################
$sb->do_as_root("master", q/drop user pt2302/);
$sb->wipe_clean($dbh);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
exit;

View File

@@ -0,0 +1,63 @@
#!/usr/bin/env perl
BEGIN {
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
};
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More;
use PerconaTest;
use Sandbox;
require "$trunk/bin/pt-online-schema-change";
my $dp = new DSNParser(opts=>$dsn_opts);
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
my $master_dbh = $sb->get_dbh_for('master');
my $slave1_dbh = $sb->get_dbh_for('slave1');
my $slave2_dbh = $sb->get_dbh_for('slave2');
if ( !$master_dbh ) {
plan skip_all => 'Cannot connect to sandbox master';
}
elsif ( !$slave1_dbh ) {
plan skip_all => 'Cannot connect to sandbox slave1';
}
elsif ( !$slave1_dbh ) {
plan skip_all => 'Cannot connect to sandbox slave2';
}
else {
plan tests => 2;
}
$sb->load_file('master', "t/pt-online-schema-change/samples/basic_no_fks.sql");
$sb->wait_for_slaves();
# Save original PTDEBUG env because we modify it below.
my $dbg = $ENV{PTDEBUG};
$ENV{PTDEBUG} = 1;
my $output = `$trunk/bin/pt-online-schema-change h=localhost,S=/tmp/12345/mysql_sandbox12345.sock,D=pt_osc,t=t --user=msandbox --password=msandbox --slave-user=msandbox --slave-password=msandbox --alter "FORCE" --recursion-method=processlist --no-check-replication-filters --no-check-alter --no-check-plan --chunk-index=PRIMARY --no-version-check --execute 2>&1`;
unlike(
$output,
qr/Use of uninitialized value in concatenation (.) or string/,
'No error with PTDEBUG output'
) or diag($output);
# Restore PTDEBUG env.
delete $ENV{PTDEBUG};
$ENV{PTDEBUG} = $dbg || 0;
# #############################################################################
# Done.
# #############################################################################
$sb->wipe_clean($master_dbh);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
exit;

106
t/pt-table-sync/pt-1194.t Normal file
View File

@@ -0,0 +1,106 @@
#!/usr/bin/env perl
BEGIN {
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
};
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More;
use PerconaTest;
use Sandbox;
require "$trunk/bin/pt-table-sync";
my $dp = new DSNParser(opts=>$dsn_opts);
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
my $master_dbh = $sb->get_dbh_for('master');
my $slave1_dbh = $sb->get_dbh_for('slave1');
my $slave2_dbh = $sb->get_dbh_for('slave2');
my $have_ncat = `which ncat 2>/dev/null`;
if ( !$master_dbh ) {
plan skip_all => 'Cannot connect to sandbox master';
}
elsif ( !$slave1_dbh ) {
plan skip_all => 'Cannot connect to sandbox slave1';
}
elsif ( !$slave1_dbh ) {
plan skip_all => 'Cannot connect to sandbox slave2';
}
elsif (!$have_ncat) {
plan skip_all => 'ncat, required for this test, is not installed or not in PATH';
}
else {
plan tests => 3;
}
$sb->load_file('master', "t/pt-table-sync/samples/pt-1205.sql");
$sb->wait_for_slaves();
# Setting up tunnels
my $pid1 = fork();
if ( !$pid1 ) {
setpgrp;
system('ncat -k -l localhost 3333 --sh-exec "ncat 127.0.0.1 12345"');
exit;
}
my $pid2 = fork();
if ( !$pid2 ) {
setpgrp;
system('ncat -k -l localhost 3334 --sh-exec "ncat 127.0.0.1 12346"');
exit;
}
my $o = new OptionParser();
my $q = new Quoter();
my $ms = new MasterSlave(
OptionParser=>$o,
DSNParser=>$dp,
Quoter=>$q,
);
my $ss = $ms->get_slave_status($slave1_dbh);
$slave1_dbh->do('STOP SLAVE');
$slave1_dbh->do("CHANGE MASTER TO MASTER_PORT=3333, MASTER_LOG_POS=$ss->{exec_master_log_pos}");
$slave1_dbh->do('START SLAVE');
my $output = `$trunk/bin/pt-table-sync h=127.0.0.1,P=3334,u=msandbox,p=msandbox --database=test --table=t1 --sync-to-master --execute --verbose 2>&1`;
unlike(
$output,
qr/The slave is connected to \d+ but the master's port is/,
'No error for redirected replica'
) or diag($output);
kill -1, getpgrp($pid1);
kill -1, getpgrp($pid2);
$slave1_dbh->do('STOP SLAVE');
$ss = $ms->get_slave_status($slave1_dbh);
$slave1_dbh->do("CHANGE MASTER TO MASTER_PORT=12347, MASTER_LOG_POS=$ss->{exec_master_log_pos}");
$slave1_dbh->do('START SLAVE SQL_THREAD');
$output = `$trunk/bin/pt-table-sync h=127.0.0.1,P=12346,u=msandbox,p=msandbox --database=test --table=t1 --sync-to-master --execute --verbose 2>&1`;
like(
$output,
qr/The server specified as a master has no connected slaves/,
'Error printed for the wrong master'
) or diag($output);
$slave1_dbh->do('STOP SLAVE');
$slave1_dbh->do("CHANGE MASTER TO MASTER_PORT=12345, MASTER_LOG_POS=$ss->{exec_master_log_pos}");
$slave1_dbh->do('START SLAVE');
# #############################################################################
# Done.
# #############################################################################
$sb->wipe_clean($master_dbh);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
exit;