🐚
query-digesterでパスワード無しでログインできない旨のエラーが出た
query-digesterとは
query-digesterはMySQLのスロークエリログのローテートをめちゃ良い感じにやってくれるツールです
事象
ISUCON12の練習に利用していたところ、以下のエラーが出ました。
isucon@ip-192-168-0-11:~$ sudo query-digester -duration 10
exec mysql to change long_query_time and slow_query_log_file
save slowlog to /tmp/slow_query_20231017235438.log
wait 10 seconds
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
Error: mysql exited with code: 0 at /usr/local/bin/query-digester line 95.
isucon@ip-192-168-0-11:~$
調査
95行目で出力されているようなのでコードをみてみます。2023年11月18日時点でのコードは以下でした。
(コードブロックに行数を表示することができないため、95行目にコメントで★を、後述の書き換える行にコメントで■を追加しています)
#!/usr/bin/perl
use strict;
use warnings;
use IO::Handle;
use Getopt::Long;
use File::Spec;
sub find_path {
my $pg = shift;
my $path;
for ( split /:/, $ENV{PATH} ) {
if ( -x "$_/$pg" ) {
$path = "$_/$pg";
last;
}
}
$path;
}
my $limit = 40;
my $duration = 10;
Getopt::Long::Configure ("no_ignore_case");
GetOptions(
"duration=s" => \$duration,
"clear-log" => \my $clear_log,
"stdout" => \my $stdout,
"limit=s" => \$limit,
"h|help" => \my $help,
);
my @mysqlopt = @ARGV;
$|=1;
die "duration does not seems numeric" unless $duration =~ m!^\d+$!;
$duration += 0;
my $pt_query_digest = find_path('pt-query-digest')
or die "could not find pt-query-digest";
my $mysql = find_path('mysql')
or die "could not find mysql";
my $tmpdir = "/tmp";#File::Spec->tmpdir();
my $before = <<'EOF';
SET @cur_long_query_time = @@long_query_time;
SET @cur_slow_query_log_file = @@slow_query_log_file;
SET @cur_slow_query_log = @@slow_query_log;
SET GLOBAL slow_query_log_file = "<TMP_DIR>/slow_query_<DATE>.log";
SET GLOBAL long_query_time = 0;
SET GLOBAL slow_query_log = 1;
EOF
my $after = <<'EOF';
SET GLOBAL long_query_time = @cur_long_query_time;
SET GLOBAL slow_query_log_file = @cur_slow_query_log_file;
SET GLOBAL slow_query_log = @cur_slow_query_log;
EOF
$before =~ s!<TMP_DIR>!$tmpdir!;
my @lt = localtime();
my $date = sprintf('%04d%02d%02d%02d%02d%02d',$lt[5]+1900,$lt[4],$lt[3],$lt[2],$lt[1],$lt[0]);
$before =~ s!<DATE>!$date!;
print STDERR "exec mysql to change long_query_time and slow_query_log_file\n";
print STDERR "save slowlog to $tmpdir/slow_query_$date.log\n";
#open(my $fh, ">", "$tmpdir/slow_query_$date.log");
#close($fh);
#chmod 0666, "$tmpdir/slow_query_$date.log";
my $pid = fork;
if ( defined $pid && $pid == 0 ) {
my $stop = 0;
local $SIG{INT} = sub {
$stop++;
};
local $SIG{TERM} = sub {
$stop++;
};
open(STDOUT,'>/dev/null');
open(my $pipe, '|-', $mysql, @mysqlopt, '--sigint-ignore'); // ■ここが書き換え行!!
$pipe->autoflush;
$pipe->print($before);
for my $i ( 0..$duration ) {
last if $stop;
$pipe->print("SELECT 1;\n") if $i % 7 == 0;
sleep 1;
}
$pipe->print($after);
exit;
}
print STDERR "wait $duration seconds\n";
while (wait == -1) {}
my $exit_code = $?;
if ( $exit_code != 0 ) {
die sprintf("Error: mysql exited with code: %d", $exit_code >> 8); // ★ここが95行目!!
}
print STDERR "finished capturing slowlog.\n";
print STDERR "start query-digest\n";
my $digest = *STDOUT;
if ( !$stdout ) {
open($digest, '>', "$tmpdir/slow_query_$date.digest");
}
open(my $pipe, '-|', $pt_query_digest, '--limit',$limit,"$tmpdir/slow_query_$date.log");
while(<$pipe>){
$digest->print($_);
}
print STDERR "finished pt-query-digest.\n";
print STDERR "digest saved to $tmpdir/slow_query_$date.digest\n" if !$stdout;
unlink "$tmpdir/slow_query_$date.log" if $clear_log;
対処
95行目はログ出力部分で、根本原因はMySQLでパスワード無しでログインしようとしているのがダメそうでした。ログインを実際にする箇所はコメントで■で注釈した行なので、その行を以下に書き換えました。(パスワードを直接コードに書くのはセキュリティ観点でよくないと思われるので、実行時引数でもらうなりしたほうがいいかもしれません。)
open(my $pipe, '|-', $mysql, @mysqlopt, '-u', 'root', '-proot', '--sigint-ignore');
修正後に再度実行するとエラー無く実行できました!わーい
isucon@ip-192-168-0-11:~$ sudo query-digester -duration 10
exec mysql to change long_query_time and slow_query_log_file
save slowlog to /tmp/slow_query_20231018001054.log
wait 10 seconds
mysql: [Warning] Using a password on the command line interface can be insecure.
finished capturing slowlog.
start query-digest
finished pt-query-digest.
digest saved to /tmp/slow_query_20231018001054.digest
isucon@ip-192-168-0-11:~$
Discussion