2015年5月28日木曜日

1つのbasedirに複数のMroongaさんをぶら下げる

複数バージョンのGroonga / Mroongaで挙動の違いを調べる時に、いちいち/usr/local/mysqlを複数作るのが面倒なので手順をメモ。

コマンドの羅列はここ。 https://gist.github.com/yoku0825/a85643cd9b5a4dcd8e1c

mysqldにINSTALL PLUGINする場合、SONAMEで指定されたファイルをplugin_dirから読み出すので、plugin_dir(暗黙のデフォルトはbasedir/lib/plugin)  だけを打ち分けてやればOKなはず。


$ wget http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.24-linux-glibc2.5-x86_64.tar.gz
$ tar xzf mysql-5.6.24-linux-glibc2.5-x86_64.tar.gz
$ sudo ln -s $PWD/mysql-5.6.24-linux-glibc2.5-x86_64 /usr/local/mysql
$ wget http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.24.tar.gz
$ tar xzf mysql-5.6.24.tar.gz

$ sudo useradd mysql

ここまではフツウ。


$ sudo mkdir /usr/local/mysql/{stable_lib,nightly_lib}

plugin_dir用のディレクトリを2つ作ってやる。


$ wget http://packages.groonga.org/source/groonga/groonga-5.0.3.tar.gz
$ tar xzf groonga-5.0.3.tar.gz
$ cd groonga-5.0.3
$ ./configure --prefix=/usr/local/groonga_stable
$ make
$ sudo make install
$ cd ../

$ wget http://packages.groonga.org/nightly/groonga-5.0.3.2015.05.28.tar.gz
$ tar xzf groonga-5.0.3.2015.05.28.tar.gz
$ cd groonga-5.0.3.2015.05.28
$ ./configure --prefix=/usr/local/groonga_nightly
$ make
$ sudo make install
$ cd ../

2つのGroongaを違うディレクトリーにインストールして、


$ wget http://packages.groonga.org/source/groonga-normalizer-mysql/groonga-normalizer-mysql-1.0.9.tar.gz
$ tar xzf groonga-normalizer-mysql-1.0.9.tar.gz
$ cd groonga-normalizer-mysql-1.0.9
$ ./configure --prefix=/usr/local/groonga_stable PKG_CONFIG_PATH=/usr/local/groonga_stable/lib/pkgconfig
$ make
$ sudo make install
$ make clean

$ ./configure --prefix=/usr/local/groonga_nightly PKG_CONFIG_PATH=/usr/local/groonga_nightly/lib/pkgconfig
$ make
$ sudo make install
$ cd ../

$ wget http://packages.groonga.org/source/mroonga/mroonga-5.02.tar.gz
$ tar xzf mroonga-5.02.tar.gz
$ cd mroonga-5.02
$ ./configure --prefix=/usr/local/groonga_stable --with-mysql-source=../mysql-5.6.24 --with-mysql-config=/usr/local/mysql/bin/mysql_config PKG_CONFIG_PATH=/usr/local/groonga_stable/lib/pkgconfig
$ sed -ib 's|/usr/local/mysql/lib/plugin|/usr/local/mysql/stable_lib|' Makefile
$ make
$ sudo make install
$ make clean

$ ./configure --prefix=/usr/local/groonga_nightly --with-mysql-source=../mysql-5.6.24 --with-mysql-config=/usr/local/mysql/bin/mysql_config PKG_CONFIG_PATH=/usr/local/groonga_nightly/lib/pkgconfig
$ sed -ib 's|/usr/local/mysql/lib/plugin|/usr/local/mysql/nightly_lib|' Makefile
$ make
$ sudo make install
$ cd ..

groonga-normalizer-mysqlとMroongaを、PKG_CONFIG_PATHの値を書き換えつつmakeしてインストールする。
Mroongaのconfigureスクリプトの中でha_mroonga.soをインストールする先がmysql_config --pluginから取られているので、これをMakefileの中でいじってからmakeしてやると、それぞれのplugin_dirにインストールされます。手でコピーしてもいいです。


$ cd /usr/local/mysql
$ scripts/mysql_install_db --user=mysql --datadir=./stable_data
$ bin/mysqld_safe --no-defaults --user=mysql --datadir=./stable_data --socket=/tmp/stable.sock --port=13306 --plugin-dir=/usr/local/mysql/stable_lib &

$ scripts/mysql_install_db --user=mysql --datadir=./nightly_data
$ bin/mysqld_safe --no-defaults --user=mysql --datadir=./nightly_data --socket=/tmp/nightly.sock --port=23306 --plugin-dir=/usr/local/mysql/nightly_lib &

$ alias stable="/usr/local/mysql/bin/mysql -uroot -S /tmp/stable.sock -P 13306"
$ alias nightly="/usr/local/mysql/bin/mysql -uroot -S /tmp/nightly.sock -P 23306"

$ stable < /usr/local/groonga_stable/share/mroonga/install.sql
$ stable -e "create database d1"
$ stable stable < data.sql

$ nightly < /usr/local/groonga_stable/share/mroonga/install.sql
$ nightly -e "create database d1"
$ nightly nightly < data.sql

$ stable -e "select @@plugin_dir"
+------------------------------+
| @@plugin_dir                 |
+------------------------------+
| /usr/local/mysql/stable_lib/ |
+------------------------------+

$ nightly -e "select @@plugin_dir"
+-------------------------------+
| @@plugin_dir                  |
+-------------------------------+
| /usr/local/mysql/nightly_lib/ |
+-------------------------------+

$ ldd /usr/local/mysql/*_lib/ha_mroonga.so
/usr/local/mysql/nightly_lib/ha_mroonga.so:
        linux-vdso.so.1 =>  (0x00007fffeaf76000)
        libgroonga.so.0 => /usr/local/groonga_nightly/lib/libgroonga.so.0 (0x00007f00adc09000)
        libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f00ad8f7000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f00ad673000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f00ad2df000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f00ad0c8000)
        libz.so.1 => /lib64/libz.so.1 (0x00007f00aceb2000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f00accae000)
        librt.so.1 => /lib64/librt.so.1 (0x00007f00acaa5000)
        /lib64/ld-linux-x86-64.so.2 (0x0000003517400000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f00ac888000)
/usr/local/mysql/stable_lib/ha_mroonga.so:
        linux-vdso.so.1 =>  (0x00007fff6c7ff000)
        libgroonga.so.0 => /usr/local/groonga_stable/lib/libgroonga.so.0 (0x00007f13f4307000)
        libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f13f3ff5000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f13f3d71000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f13f39dd000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f13f37c6000)
        libz.so.1 => /lib64/libz.so.1 (0x00007f13f35b0000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f13f33ac000)
        librt.so.1 => /lib64/librt.so.1 (0x00007f13f31a3000)
        /lib64/ld-linux-x86-64.so.2 (0x0000003517400000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f13f2f86000)

あとはdatadirをそれぞれ用意してやって、データを流し込めばおしまいと。
mysqld_multiを使って起動するならこんな感じのmy.cnfにしておく。


$ sudo vim /etc/my.cnf
[mysqld_multi]
no-log

[mysqld1]
basedir   = /usr/local/mysql
mysqld    = /usr/local/mysql/bin/mysqld_safe
datadir   = /usr/local/mysql/stable_data
socket    = /tmp/stable.sock
port      = 13006
plugin-dir= /usr/local/mysql/stable_lib

[mysqld2]
basedir   = /usr/local/mysql
mysqld    = /usr/local/mysql/bin/mysqld_safe
datadir   = /usr/local/mysql/nightly_data
socket    = /tmp/nightly.sock
port      = 23006
plugin-dir= /usr/local/mysql/nightly_lib

$ mysqld_multi start 1,2
mysqld_multi log file version 2.16; run: Thu May 28 15:39:09 2015

Starting MySQL servers
150528 15:39:09 mysqld_safe Adding '/usr/lib64/libjemalloc.so.1' to LD_PRELOAD for mysqld
150528 15:39:09 mysqld_safe Adding '/usr/lib64/libjemalloc.so.1' to LD_PRELOAD for mysqld
150528 15:39:09 mysqld_safe Logging to '/usr/local/mysql/stable_data/error.log'.
150528 15:39:09 mysqld_safe Logging to '/usr/local/mysql/nightly_data/error.log'.
150528 15:39:09 mysqld_safe Starting mysqld daemon with databases from /usr/local/mysql/stable_data
150528 15:39:09 mysqld_safe Starting mysqld daemon with databases from /usr/local/mysql/nightly_data

これであとはやりたい放題。

2015年5月18日月曜日

MySQL 5.6以降でクライアントに "Warning: Using a password on the command line interface can be insecure." と言われるのを防ぐいくつかの方法

MySQL 5.6以降では、同梱のクライアント(mysqlコマンドラインクライアント, mysqladmin, mysqldumpあたりがよくありそう)に-pオプションで直接パスワードを渡すと、


$ mysql56 -utest -ptest -e "SELECT current_user()"
Warning: Using a password on the command line interface can be insecure.
+----------------+
| current_user() |
+----------------+
| test@localhost |
+----------------+

こんなのが出るようになりました。
読んで字のごとく、パスワードをコマンドラインインターフェイス(つまり-pオプション)で渡すのはセキュアじゃねーぞ、というワーニングです。
これ、標準エラー出力に吐くんですよね。

標準エラー出力に吐くということは、


$ crontab -l
1 3 * * * /usr/mysql/5.6.24/bin/mysqladmin -uflush -pxxxx flush-tables

週末に仕込んだこんなcronのエントリーがぼんぼんぼんぼんメールを投げてくるわけです。午前3時に。インセキュアだぞって。 '`,、'`,、( ´∀`)'`,、'`,、


さてこのメッセージ、mysys_ssl/my_getopt.cc にハードコードされています。エラーログドリブン ソースコードリーディング ですね。


653 /**
654  * This function should be called to print a warning message
655  * if password string is specified on the command line.
656  */
657
658 void print_cmdline_password_warning()
659 {
660   static my_bool password_warning_announced= FALSE;
661
662   if (!password_warning_announced)
663   {
664     fprintf(stderr, "Warning: Using a password on the command line "
665             "interface can be insecure.\n");
666     (void) fflush(stderr);
667     password_warning_announced= TRUE;
668   }
669 }

mysql-server/my_getopt.cc at cac6fc837a5f72203058e4acc6b8b4dba8a98294 · mysql/mysql-server


( ´-`).oO(password_warning_announcedってここ以外で使ってないので、if文なしでいきなりfprintfでいいんじゃないかって気がするんだけども。


これを出力させないように、いくつかの方法を考えてみました。セキュアかどうかは別問題です。出力させないことが大事です。


1) コマンドラインオプションから渡さずに、my.cnf系(~/.my.cnfとか、~/.mylogin.cnfも含む)で渡す。

5.6からは mysql_config_editor がありますね。かつてのわたしのお気に入りでした。日々の覚書: MySQL5.6 .mylogin.cnfで遊んでみる


$ mysql_config_editor set --login-path=mysql --user=test --password
Enter password:

$ mysql56 -e "SELECT current_user()"
+----------------+
| current_user() |
+----------------+
| test@localhost |
+----------------+

使 っ て ま せ ん '`,、'`,、( ´∀`)'`,、'`,、


MySQL 5.6にできたサーバーと、まだ5.6未満で稼動しているサーバーでスクリプト作り分けるのが めんどくさい 管理が煩雑になってしまうのが嫌。if文書きたくない。~/.my.cnfなら5.6未満でも使えますが、シェルスクリプトが ~/.my.cnf に依存するようになるので管理対象が増えて嫌。

あと.mylogin.cnf別にセキュアじゃなかったし => セキュアそうでセキュアじゃない少しセキュアな気分になれるmysql_config_editor , ~/.my.cnfだって平文で書くからセキュアじゃないし。


2) MYSQL_PWD環境変数を使ってパスワードを渡す。

これ知らない人多そう。MYSQL_PWD環境変数が設定されていて かつ -pオプションが指定されていない場合、MYSQL_PWD環境変数の中身がパスワードとして扱われます。つまりがパスワード未設定時のデフォルト値をオーバーライドしてくれる。

というわけでこれを使うと


$ MYSQL_PWD="test" mysql56 -utest -e "SELECT current_user()"
+----------------+
| current_user() |
+----------------+
| test@localhost |
+----------------+

全然セキュアになってませんが、インセキュアだと怒られることはなくなります。管理対象が増えるわけでなくてもとのcronエントリーを


$ crontab -l
1 3 * * * MYSQL_PWD=xxxx /usr/mysql/5.6.24/bin/mysqladmin -uflush flush-tables

とだけ書き換えればいいですね。らくちん。


3) mysqlコマンドラインクライアントだけダウングレードする。

yumでrpmを突っ込んでいる環境だとつらい気がしますが、バイナリーやソースコードから突っ込んでいるならこれも手です。
5.5 => 5.6のmysqlコマンドラインクライアントの新機能ってhistignoreや.mylogin.cnf対応くらいじゃないかと思うので(5.6 => 5.7はCtrl + C対応とsyslogがある)、別に最新じゃなくてもいいやって割り切りは十分アリじゃないかと思います。


4) ほげる。

オチは想像がついていると思いますが、print_cmdline_password_warningをほげります。もうバッサリreturn (void) 0; だけでいいんじゃないかな。

$ diff -c mysys_ssl/my_getopt.cc{.orig,}
*** mysys_ssl/my_getopt.cc.orig 2015-03-26 01:34:52.000000000 +0900
--- mysys_ssl/my_getopt.cc      2015-05-18 12:35:56.314531829 +0900
***************
*** 657,671 ****

  void print_cmdline_password_warning()
  {
!   static my_bool password_warning_announced= FALSE;
!
!   if (!password_warning_announced)
!   {
!     fprintf(stderr, "Warning: Using a password on the command line "
!             "interface can be insecure.\n");
!     (void) fflush(stderr);
!     password_warning_announced= TRUE;
!   }
  }


--- 657,663 ----

  void print_cmdline_password_warning()
  {
!   return (void) 0;
  }


$ client/mysql -utest -ptest -S /usr/mysql/5.6.24/data/mysql.sock -e "SELECT current_user()"
+----------------+
| current_user() |
+----------------+
| test@localhost |
+----------------+

ちょっと別件でmysqlコマンドラインクライアントをほげってrpmにすることが決まってるので、まさかの4) を採用するかも知れません。

2015年5月11日月曜日

MySQL 5.7.5からはmysql.sock.lockというのを作るようになった

A server could have its socket file taken over by a second server listening on different TCP/IP port but the same socket file. The socket file also would be unlinked by normal shutdown of the second server. To avoid this, the server now uses a lock file with the same name as the socket file and a .lock suffix. (For example, /tmp/mysql.sock has a lock file of /tmp/mysql.sock.lock.) The lock file contains the process ID of the server process that created the socket file. (Bug #17286856)
MySQL :: MySQL 5.7 Release Notes :: Changes in MySQL 5.7.5 (2014-09-25, Milestone 15)

やっぱり誰しも、--socketの設定間違えてUNIXソケットつぶしたことありますよねわかりますん! orz



$ bin/mysqld --no-defaults --initialize --datadir=/tmp/mysql1
2015-05-10T17:04:32.148319Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2015-05-10T17:04:32.526383Z 0 [Warning] InnoDB: New log files created, LSN=45790
2015-05-10T17:04:32.562985Z 0 [Warning] InnoDB: Creating foreign key constraint system tables.
2015-05-10T17:04:32.622323Z 0 [Warning] Failed to setup SSL
2015-05-10T17:04:32.622341Z 0 [Warning] SSL error: SSL context is not usable without certificate and private key
2015-05-10T17:04:32.622849Z 1 [Warning] A temporary password is generated for root@localhost: gOxQq0_u2l)B

$ bin/mysqld --no-defaults --socket=/tmp/mysql.sock --port=3306 --datadir=/tmp/mysql1
2015-05-10T17:04:54.881779Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2015-05-10T17:04:54.881843Z 0 [Warning] Insecure configuration for --secure-file-priv: Current value does not restrict location of generated files. Consider setting it to a valid, non-empty path.
2015-05-10T17:04:54.881879Z 0 [Note] bin/mysqld (mysqld 5.7.7-rc) starting as process 22478 ...
..
Version: '5.7.7-rc'  socket: '/tmp/mysql.sock'  port: 3306  Source distribution

$ ll /tmp/mysql.sock*
srwxrwxrwx 1 yoku0825 yoku0825 0 May 11 02:04 /tmp/mysql.sock
-rw------- 1 yoku0825 yoku0825 6 May 11 02:04 /tmp/mysql.sock.lock

$ cat /tmp/mysql.sock.lock
22478

こうして起動したmysqldと
(ちなみに--no-defaultsで--log-timestamps=SYSTEMが打ち消されているので、ログの時間(UTF)とファイルシステムの時間(JST)が盛大にズレて見えている)
See also, 日々の覚書: MySQL 5.7で絶対に必要になると思うlog_timestampsの設定


$ bin/mysqld --no-defaults --initialize --datadir=/tmp/mysql2
2015-05-10T17:06:46.667942Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2015-05-10T17:06:47.268897Z 0 [Warning] InnoDB: New log files created, LSN=45790
2015-05-10T17:06:47.307634Z 0 [Warning] InnoDB: Creating foreign key constraint system tables.
2015-05-10T17:06:47.367505Z 0 [Warning] Failed to setup SSL
2015-05-10T17:06:47.367526Z 0 [Warning] SSL error: SSL context is not usable without certificate and private key
2015-05-10T17:06:47.368373Z 1 [Warning] A temporary password is generated for root@localhost: au*pq3)kf6oR

$ bin/mysqld --no-defaults --socket=/tmp/mysql.sock --port=13306 --datadir=/tmp/mysql2
2015-05-10T17:07:18.521509Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2015-05-10T17:07:18.521566Z 0 [Warning] Insecure configuration for --secure-file-priv: Current value does not restrict location of generated files. Consider setting it to a valid, non-empty path.
2015-05-10T17:07:18.521601Z 0 [Note] bin/mysqld (mysqld 5.7.7-rc) starting as process 22603 ...
..
2015-05-10T17:07:18.648282Z 0 [ERROR] Another process with pid 22478 is using unix socket file.
2015-05-10T17:07:18.648287Z 0 [ERROR] Unable to setup unix socket lock file.
2015-05-10T17:07:18.648301Z 0 [ERROR] Aborting

$ ll /tmp/mysql.sock*
srwxrwxrwx 1 yoku0825 yoku0825 0 May 11 02:04 /tmp/mysql.sock
-rw------- 1 yoku0825 yoku0825 6 May 11 02:04 /tmp/mysql.sock.lock

$ cat /tmp/mysql.sock.lock
22478

datadir, portをずらしてsocketだけ一致させたmysqldを起動しようとすると、後から起動しようとした方はスタートアップ処理でmysql.sock.lockの存在を検知してAbortしてくれる。
なんか導入直後の5.7.5で試した時に転けるはいいけどmysql.sockはやっぱり消しちゃうみたいなダメな動作だった気がしていたんだけど、少なくとも5.7.7では正しく動作している。