mysql-master-haでのREPLICATION SLAVE priv.チェックの修正

mysql-master-haでのREPLICATION SLAVE priv.チェックの修正

 mysql-master-haをちょっと触っていたところ、MHAの管理ユーザーがmysql.userテーブルをSELECTしていたのがちょっと気持ち悪かったので修正してみました:

--- lib/MHA/Server.pm.old	2012-01-09 00:06:53.000000000 +0900
+++ lib/MHA/Server.pm	2012-05-17 18:34:30.000000000 +0900
@@ -377,7 +377,7 @@
   $log = $self->{logger} unless ($log);
   if ( !$self->{no_master} && $self->{log_bin} && !$self->{not_slave} ) {
     my $dbhelper = $self->{dbhelper};
-    unless ( $dbhelper->has_repl_priv( $self->{repl_user} ) ) {
+    unless ( $dbhelper->has_repl_priv( $self->{repl_user}, $self->{repl_password}, $self->{hostname}, $self->{port} ) ) {
       $log->error(
         sprintf(
 "%s: User %s does not exist or does not have REPLICATION SLAVE privilege! Other slaves can not start replication from this host.",


--- lib/MHA/DBHelper.pm.old	2012-01-09 00:06:43.000000000 +0900
+++ lib/MHA/DBHelper.pm	2012-05-17 18:33:15.000000000 +0900
@@ -103,6 +103,7 @@
 use constant Unlock_Tables_SQL               => "UNLOCK TABLES";
 use constant Repl_User_SQL =>
   "SELECT Repl_slave_priv AS Value FROM mysql.user WHERE user = ?";
+use constant Show_Grants_SQL => "SHOW GRANTS";
 
 sub new {
   my $class = shift;
@@ -218,17 +219,26 @@
 sub has_repl_priv {
   my $self = shift;
   my $user = shift;
-  my $sth  = $self->{dbh}->prepare(Repl_User_SQL);
-  my $ret  = $sth->execute($user);
-  if ( !defined($ret) ) {
+  my $password = shift;
+  my $host = shift;
+  my $port = shift;
+
+  my $res = eval {
+    my $dbh = connect_util( $host, $port, $user, $password );
+    my $sth = $dbh->prepare(Show_Grants_SQL);
+    $sth->execute() or die;
+    my $values = $sth->fetchrow_arrayref;
+    foreach my $value (@$values) {
+      return 1 if $value =~ /\WREPLICATION SLAVE\W/;
+    }
+    return 0;
+  };
+  if ($@) {
     croak
 "Got MySQL error when checking replication privilege. $DBI::err: $DBI::errstr query:"
-      . Repl_User_SQL . "\n";
+      . Show_Grants_SQL . "\n";
   }
-  my $href  = $sth->fetchrow_hashref;
-  my $value = $href->{Value};
-  return 1 if ( defined($value) && $value eq "Y" );
-  return 0;
+  return $res;
 }
 
 sub is_binlog_enabled($) {

 repl_userで接続してSHOW GRANTSすれば権限を確認できるはず、ということで上記のような修正になっています。

 この修正をした場合はconfigにrepl_passwordが必須になると思います*1

mha管理ユーザーで必要な権限

 GRANT RELOAD, PROCESS, SUPER, REPLICATION CLIENT ON *.* TO 'mha';

――でいいのかな?

*1:repl_userにパスワードを設定している場合は。……あれ、通常でも必須なんだっけ?