mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-18 09:43:09 +00:00
Implement and test --recursion-method=none in MasterSlave.pm and pt-table-checksum.
This commit is contained in:
@@ -2485,6 +2485,9 @@ sub get_slaves {
|
||||
dsn_table_dsn => $dsn_table_dsn,
|
||||
);
|
||||
}
|
||||
elsif ( $method =~ m/none/i ) {
|
||||
PTDEBUG && _d('Not getting to slaves');
|
||||
}
|
||||
else {
|
||||
die "Invalid --recursion-method: $method. Valid values are: "
|
||||
. "dsn=DSN, hosts, or processlist.\n";
|
||||
@@ -2499,6 +2502,11 @@ sub recurse_to_slaves {
|
||||
my $dp = $args->{dsn_parser};
|
||||
my $dsn = $args->{dsn};
|
||||
|
||||
if ( lc($args->{method} || '') eq 'none' ) {
|
||||
PTDEBUG && _d('Not recursing to slaves');
|
||||
return;
|
||||
}
|
||||
|
||||
my $dbh;
|
||||
eval {
|
||||
$dbh = $args->{dbh} || $dp->get_dbh(
|
||||
@@ -4080,12 +4088,15 @@ sub _next_boundaries {
|
||||
return 1; # continue nibbling
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ( $self->identical_boundaries($self->{lower}, $self->{next_lower}) ) {
|
||||
PTDEBUG && _d('Infinite loop detected');
|
||||
my $tbl = $self->{tbl};
|
||||
my $index = $tbl->{tbl_struct}->{keys}->{$self->{index}};
|
||||
my $n_cols = scalar @{$index->{cols}};
|
||||
my $chunkno = $self->{nibbleno};
|
||||
|
||||
die "Possible infinite loop detected! "
|
||||
. "The lower boundary for chunk $chunkno is "
|
||||
. "<" . join(', ', @{$self->{lower}}) . "> and the lower "
|
||||
@@ -4112,6 +4123,7 @@ sub _next_boundaries {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PTDEBUG && _d($self->{ub_sth}->{Statement}, 'params:',
|
||||
join(', ', @{$self->{lower}}), $self->{limit});
|
||||
$self->{ub_sth}->execute(@{$self->{lower}}, $self->{limit});
|
||||
|
@@ -76,6 +76,10 @@ sub get_slaves {
|
||||
dsn_table_dsn => $dsn_table_dsn,
|
||||
);
|
||||
}
|
||||
elsif ( $method =~ m/none/i ) {
|
||||
# https://bugs.launchpad.net/percona-toolkit/+bug/987694
|
||||
PTDEBUG && _d('Not getting to slaves');
|
||||
}
|
||||
else {
|
||||
die "Invalid --recursion-method: $method. Valid values are: "
|
||||
. "dsn=DSN, hosts, or processlist.\n";
|
||||
@@ -110,6 +114,12 @@ sub recurse_to_slaves {
|
||||
my $dp = $args->{dsn_parser};
|
||||
my $dsn = $args->{dsn};
|
||||
|
||||
if ( lc($args->{method} || '') eq 'none' ) {
|
||||
# https://bugs.launchpad.net/percona-toolkit/+bug/987694
|
||||
PTDEBUG && _d('Not recursing to slaves');
|
||||
return;
|
||||
}
|
||||
|
||||
my $dbh;
|
||||
eval {
|
||||
$dbh = $args->{dbh} || $dp->get_dbh(
|
||||
|
@@ -9,7 +9,7 @@ BEGIN {
|
||||
use strict;
|
||||
use warnings FATAL => 'all';
|
||||
use English qw(-no_match_vars);
|
||||
use Test::More tests => 47;
|
||||
use Test::More tests => 50;
|
||||
|
||||
use MasterSlave;
|
||||
use DSNParser;
|
||||
@@ -119,6 +119,96 @@ SKIP: {
|
||||
[],
|
||||
"get_slaves() by processlist"
|
||||
);
|
||||
|
||||
# ##########################################################################
|
||||
# --recursion-method=none
|
||||
# https://bugs.launchpad.net/percona-toolkit/+bug/987694
|
||||
# ##########################################################################
|
||||
|
||||
# Create percona.checksums to make the privs happy.
|
||||
diag(`/tmp/12345/use -e "create database if not exists percona"`);
|
||||
diag(`/tmp/12345/use -e "create table if not exists percona.checksums (id int)"`);
|
||||
|
||||
# Create a read-only checksum user that can't SHOW SLAVES HOSTS or much else.
|
||||
diag(`/tmp/12345/use -u root < $trunk/t/lib/samples/ro-checksum-user.sql`);
|
||||
|
||||
my $ro_dbh = DBI->connect(
|
||||
"DBI:mysql:;host=127.0.0.1;port=12345", 'ro_checksum_user', 'msandbox',
|
||||
{ PrintError => 0, RaiseError => 1 });
|
||||
my $ro_dsn = {
|
||||
h => '127.1',
|
||||
P => '12345',
|
||||
u => 'ro_checksum_user',
|
||||
p => 'ro_checksum_user',
|
||||
};
|
||||
|
||||
@ARGV = ('--recursion-method', 'hosts');
|
||||
$o->get_opts();
|
||||
throws_ok(
|
||||
sub {
|
||||
$slaves = $ms->get_slaves(
|
||||
OptionParser => $o,
|
||||
DSNParser => $dp,
|
||||
Quoter => $q,
|
||||
dbh => $ro_dbh,
|
||||
dsn => $ro_dsn,
|
||||
make_cxn => sub {
|
||||
my $cxn = new Cxn(
|
||||
@_,
|
||||
DSNParser => $dp,
|
||||
OptionParser => $o,
|
||||
);
|
||||
$cxn->connect();
|
||||
return $cxn;
|
||||
},
|
||||
);
|
||||
},
|
||||
qr/Access denied/,
|
||||
"Can't SHOW SLAVE HOSTS without privs (bug 987694)"
|
||||
);
|
||||
|
||||
@ARGV = ('--recursion-method', 'none');
|
||||
$o->get_opts();
|
||||
$slaves = $ms->get_slaves(
|
||||
OptionParser => $o,
|
||||
DSNParser => $dp,
|
||||
Quoter => $q,
|
||||
dbh => $ro_dbh,
|
||||
dsn => $ro_dsn,
|
||||
make_cxn => sub {
|
||||
my $cxn = new Cxn(
|
||||
@_,
|
||||
DSNParser => $dp,
|
||||
OptionParser => $o,
|
||||
);
|
||||
$cxn->connect();
|
||||
return $cxn;
|
||||
},
|
||||
);
|
||||
is_deeply(
|
||||
$slaves,
|
||||
[],
|
||||
"No privs needed for --recursion-method=none (bug 987694)"
|
||||
);
|
||||
|
||||
my $recursed = 0;
|
||||
$ms->recurse_to_slaves(
|
||||
{ dsn_parser => $dp,
|
||||
dbh => $ro_dbh,
|
||||
dsn => $ro_dsn,
|
||||
recurse => 2,
|
||||
callback => sub { $recursed++ },
|
||||
method => 'none',
|
||||
});
|
||||
is(
|
||||
$recursed,
|
||||
0,
|
||||
"recurse_to_slaves() doesn't recurse if method=none"
|
||||
);
|
||||
|
||||
$ro_dbh->disconnect();
|
||||
diag(`/tmp/12345/use -u root -e "drop user 'ro_checksum_user'\@'%'"`);
|
||||
|
||||
}
|
||||
|
||||
# #############################################################################
|
||||
|
3
t/lib/samples/ro-checksum-user.sql
Normal file
3
t/lib/samples/ro-checksum-user.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
CREATE USER 'ro_checksum_user'@'%' IDENTIFIED BY 'msandbox';
|
||||
GRANT SELECT ON sakila.* TO 'ro_checksum_user'@'%';
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON percona.checksums TO 'ro_checksum_user'@'%';
|
98
t/pt-table-checksum/privs.t
Normal file
98
t/pt-table-checksum/privs.t
Normal file
@@ -0,0 +1,98 @@
|
||||
#!/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;
|
||||
|
||||
# Hostnames make testing less accurate. Tests need to see
|
||||
# that such-and-such happened on specific slave hosts, but
|
||||
# the sandbox servers are all on one host so all slaves have
|
||||
# the same hostname.
|
||||
$ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} = 1;
|
||||
|
||||
use Data::Dumper;
|
||||
use PerconaTest;
|
||||
use Sandbox;
|
||||
|
||||
# Fix @INC because pt-table-checksum uses subclass OobNibbleIterator.
|
||||
shift @INC; # our unshift (above)
|
||||
shift @INC; # PerconaTest's unshift
|
||||
require "$trunk/bin/pt-table-checksum";
|
||||
|
||||
my $dp = new DSNParser(opts=>$dsn_opts);
|
||||
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
|
||||
my $master_dbh = $sb->get_dbh_for('master');
|
||||
my $slave_dbh = $sb->get_dbh_for('slave1');
|
||||
|
||||
if ( !$master_dbh ) {
|
||||
plan skip_all => 'Cannot connect to sandbox master';
|
||||
}
|
||||
elsif ( !$slave_dbh ) {
|
||||
plan skip_all => 'Cannot connect to sandbox slave1';
|
||||
}
|
||||
elsif ( !@{$master_dbh->selectall_arrayref('show databases like "sakila"')} ) {
|
||||
plan skip_all => 'sakila database is not loaded';
|
||||
}
|
||||
else {
|
||||
plan tests => 2;
|
||||
}
|
||||
|
||||
# The sandbox servers run with lock_wait_timeout=3 and it's not dynamic
|
||||
# so we need to specify --lock-wait-timeout=3 else the tool will die.
|
||||
my $master_dsn = 'h=127.1,P=12345';
|
||||
my @args = (qw(--lock-wait-timeout 3));
|
||||
my $row;
|
||||
my $output;
|
||||
my $exit_status;
|
||||
my $sample = "t/pt-table-checksum/samples/";
|
||||
|
||||
# ############################################################################
|
||||
# --recursion-method=none to avoid SHOW SLAVE HOSTS
|
||||
# https://bugs.launchpad.net/percona-toolkit/+bug/987694
|
||||
# ############################################################################
|
||||
|
||||
# Create percona.checksums because ro_checksum_user doesn't have the privs.
|
||||
pt_table_checksum::main(@args,
|
||||
"$master_dsn,u=msandbox,p=msandbox",
|
||||
qw(-t sakila.country --quiet --quiet));
|
||||
|
||||
diag(`/tmp/12345/use -u root < $trunk/t/lib/samples/ro-checksum-user.sql`);
|
||||
PerconaTest::wait_for_table($slave_dbh, "mysql.tables_priv", "user='ro_checksum_user'");
|
||||
|
||||
$output = output(
|
||||
sub { $exit_status = pt_table_checksum::main(@args,
|
||||
"$master_dsn,u=ro_checksum_user,p=msandbox",
|
||||
# Comment out this line and the tests fail because ro_checksum_user
|
||||
# doesn't have privs to SHOW SLAVE HOSTS. This proves that
|
||||
# --recursion-method none is working.
|
||||
qw(--recursion-method none)
|
||||
) },
|
||||
stderr => 1,
|
||||
);
|
||||
|
||||
is(
|
||||
$exit_status,
|
||||
0,
|
||||
"Read-only user (bug 987694): 0 exit"
|
||||
);
|
||||
|
||||
like(
|
||||
$output,
|
||||
qr/ sakila.store$/m,
|
||||
"Read-only user (bug 987694): checksummed rows"
|
||||
);
|
||||
|
||||
diag(`/tmp/12345/use -u root -e "drop user 'ro_checksum_user'\@'%'"`);
|
||||
|
||||
# #############################################################################
|
||||
# Done.
|
||||
# #############################################################################
|
||||
$sb->wipe_clean($master_dbh);
|
||||
exit;
|
Reference in New Issue
Block a user