perl-5.34.1をソースからインストール。make test実施時にcachepropagate-unix.tからエラーが発生した。調査した結果、対応が難しかったので大人の解決をした話。その際の調査方法と調査ログの記事です。
経緯
訳あって古いサーバーをメンテナンス。目的はTLS1.2、1.3の対応。対応にはopensslのアップデートが必要でした。
インストールされていたperl-5.10.0だとopenssl1.1.1nのテスト実施やautoconf2.7のインストールに失敗するので、perl-5.34.1へバージョンアップを検討、検証環境にてソースからのインストールの検証を実施。
古いサーバーで、Linuxのバージョンも古いのでyumも何も使えない。そこでperlをソースからインストール。configure , make とエラーなく終了し、make testを実行、しかし1件エラー発生。
このままmake installコマンドを実行すると、とんでもないことになるかもしれないので調査開始。
結論
カーネルバージョン
[root@mackii ~]# uname -r
2.6.30.10-105.2.23.fc11.i686.PAE
カーネルバージョンが2.6.30だとperl5.34.1のmake testでエラーが発生する!
Failed 1 test out of 2449, 99.96% okay.
../dist/IO/t/cachepropagate-unix.t
エラー内容と実施手順
エラー内容
Failed 1 test out of 2449, 99.96% okay.
../dist/IO/t/cachepropagate-unix.t
### Since not all tests were successful, you may want to run some of
### them individually and examine any diagnostic messages they produce.
### See the INSTALL document's section on "make test".
### You have a good chance to get more information by running
### ./perl harness
### in the 't' directory since most (>=80%) of the tests succeeded.
### You may have to set your dynamic library search path,
### LD_LIBRARY_PATH, to point to the build directory:
### setenv LD_LIBRARY_PATH `pwd`:$LD_LIBRARY_PATH; cd t; ./perl harness
### LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH; cd t; ./perl harness
### export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH; cd t; ./perl harness
### for csh-style shells, like tcsh; or for traditional/modern
### Bourne-style shells, like bash, ksh, and zsh, respectively.
Elapsed: 2911 sec
u=75.59 s=18.57 cu=2416.92 cs=195.72 scripts=2449 tests=1180573
make: *** [test] エラー 1
実施手順
ソースをダウンロードしてきて解凍、以下の通り実行。
$ ./Configure -des -Duseshrplib -Dusethreads
$ make
$ make test
エラーが発生。エラーのメッセージをよく見ると、ソースディレクトリで、以下を実施しろとのこと。
export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH; cd t; ./perl harness
エラーモジュール名も出てるし、実行したらよい情報取れるかもねと言うので、エラーの詳細をくれるのか期待して実行。実施してみたら再度全テストが実施された・・・(サーバー古いので時間かかる。。。)
個別テストの実施について
詳しくはINSTALLドキュメントのmake testを読めと書いてあるので、そっちを読めばよかった。Harnessっていうのは単にテストの結果をサマリーして出すモジュールだったのか。と後で知る。
INSTALLドキュメントによると、個別のテスト実施は下記の通り実施しろ、とのこと。
[root@mackii perl-5.34.1]# ./perl -I. -MTestInit dist/IO/t/cachepropagate-unix.t
1..15
ok 1 - stream socket created
not ok 2 - protocol defined
# Failed test 'protocol defined'
# at dist/IO/t/cachepropagate-unix.t line 54.
ok 3 - domain defined
ok 4 - type defined
ok 5 - spawned a child
ok 6 - domain match
ok 7 # skip no Socket::SO_PROTOCOL
ok 8 - type match
ok 9 - datagram socket created
not ok 10 - protocol defined
# Failed test 'protocol defined'
# at dist/IO/t/cachepropagate-unix.t line 109.
ok 11 - domain defined
ok 12 - type defined
ok 13 - domain match
ok 14 # skip no Socket::SO_PROTOCOL
ok 15 - type match
# Looks like you failed 2 tests of 15.
原因
時間はかかったがエラーの詳細を見れた、と思ったらエラーが発生した行数だけ。
../dist/IO/t/cachepropagate-unix.t ................................... 1/15
# Failed test 'protocol defined'
# at t/cachepropagate-unix.t line 54.
../dist/IO/t/cachepropagate-unix.t ................................... 6/15
# Failed test 'protocol defined'
# at t/cachepropagate-unix.t line 109.
# Looks like you failed 2 tests of 15.
../dist/IO/t/cachepropagate-unix.t ................................... Dubious, test returned 2 (wstat 512, 0x200)
Failed 2/15 subtests
仕方ないのでcachepropagate-unix.tの中身を見てみる。
42 my $p = $listener->protocol();
43 {
44 # the value of protocol isn't well defined for AF_UNIX, when we
45 # create the socket we supply 0, which leaves it up to the implementation
46 # to select a protocol, so we (now) don't save a 0 protocol during socket
47 # creation. This test then breaks if the implementation doesn't support
48 # SO_SOCKET (at least on AF_UNIX).
49 # This specifically includes NetBSD, Darwin and cygwin.
50 # This is a TODO instead of a skip so if these ever implement SO_PROTOCOL
51 # we'll be notified about the passing TODO so the test can be updated.
52 local $TODO = "$^O doesn't support SO_PROTOCOL on AF_UNIX"
53 if $^O =~ /^(netbsd|darwin|cygwin|hpux|solaris|dragonfly|os390|gnu)$/;
54 ok(defined($p), 'protocol defined');
55 }
SO_PROTOCOLがサポートされてないと失敗します、とのこと。
SO_PROTOCOLって何かって調べたところ、Linuxのヘッダファイルに定義が含まれているらしく。
SO_PROTOCOL (Linux 2.6.32 以降)
SCOKET
ソケットのプロトコルを整数で取得する。 IPPROTO_SCTP のような値が返される。 詳細は socket(2) を参照。このソケットオプションは読み込み専用である。
2.6.32以降ってなっているので、うちのサーバー(2.6.30)では対応していませんね。原因がが判明しました。
そして打ちひしがれました。
解決策
カーネルをアップデートするの時間がかかるし、リスクが大きい。kernel panic!となるとサーバールーム現地での対応が必要になってくる。
このテストが通らないことによる影響範囲も不明で調べる方法も難易度が高い。そもそも10年くらい前にインストールした(そして放置されていた)LinuxのTLS1.2、1.3対応っていうわりと無理なアップデートをしている。
perlで稼働しているサービスは無いので(メインはapache,postfix,dovecot)多分影響ないんじゃないかってことで、エラーを無視して続行(make install)することになりました。
その後、とりあえず目的だったopenssl1.1.1n、autoconf2.7のインストールも完了しましたが、なんだろう、不安だ。
(補足)
その後本番環境でも同様に実施しましたが、全サービス問題なく動作しています。