(2年前に書いたのが下書きに残っていたので放流します。なお、記事は完結していません(なお残念ながら、詳細は失念。))
perl で書かれたOTRSというチケット管理システムをソースレベルで追跡する必要が生じたので、その作業を行った時のメモです。ただし記事の内容は、mod_perl2 で動く一般的な Web アプリのデバッグに役立つのではないかと思っています。OTRS は Vagrant 仮想環境上の CentOS7 において、RPM からインストールして正常に動いているものとします。
SSHの設定
デバッグ時は VSCode の Remote-SSH 経由でターゲットの Linux にログインしますが、この時デフォルトの vagrant ユーザとして接続すると、後述の plenv が有効にならないので、SSH 接続自体も otrs ユーザでできるように SSH 周りの設定を変更します。まずはターゲット(サーバ)側です。SSH のキーペアは vagrant ユーザのものを流用することにします。
$ whoami
vagrant
$ sudo install -d -o otrs -g apache -m 0700 /opt/otrs/.ssh
$ sudo install -o otrs -g apache -m 0600 ~/.ssh/authorized_keys /opt/otrs/.ssh
クライアント(Windows)側の ~/.ssh/config(抜粋):
Host otrs6r
Hostname 192.168.56.28
User otrs
IdentityFile "C:\Users\hotta\vm\otrs\.vagrant\machines\otrs6r\virtualbox\private_key"
また、otrs ユーザは sudo できるようにしておきます。
$ echo 'otrs ALL=(ALL) NOPASSWD: ALL' | sudo tee /etc/sudoers.d/otrs
perl 5.18.0 環境の作成
CentOS7 標準の perl は v5.16.3 ですが、後述する VSCode の Language Server and Debugger for Perl は perl の v5.18.0 以上を要求します。このため、まずは plenv を使って perl 5.18.0 環境を作成します。
plenv 環境の作成方法は本家サイトにある通りです。なお mod_perl2 のビルドに必要なので、perl のインストール時に -Duseithreads 等のコンパイルオプションを付けてインストールしています。
さらにモジュールを追加インストールするための cpanm と、VSCode で要求される Perl::LanguageServer も、合わせて導入しておきます。
$ whoami
otrs
$ git clone https://github.com/tokuhirom/plenv.git ~/.plenv
$ echo 'export PATH="$HOME/.plenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(plenv init -)"' >> ~/.bash_profile
$ git clone https://github.com/tokuhirom/Perl-Build.git ~/.plenv/plugins/perl-build/
$ exec $SHELL -l
$ plenv install 5.18.0 -Duseithreads -D ccflags=-fPIC
$ plenv install-cpanm
$ plenv exec cpanm Perl::LanguageServer
$ plenv rehash
$ plenv local 5.18.0
$ perl --version | head -2
This is perl 5, version 18, subversion 0 (v5.18.0) built for x86_64-linux-thread-multi
OTRS 固有情報
OTRS が依存する perl モジュールも合わせて cpanm でインストールする必要があります。現時点で不足しているモジュールを表示してみます。
$ ./bin/otrs.CheckModules.pl | grep -E '(FAILED|required)'
o Apache::DBI......................FAILED! Not all prerequisites for this module correctly installed.
o Archive::Zip.....................Not installed! To install, you can use: 'yum install "perl(Archive::Zip)"'. (required - Required for compressed file generation.)
.....
これらをまとめてインストールします。他にも実行時に not installed が出たパッケージも合わせて入れています。Carton だと一発でいけるかもしれないんですが、いろいろと理解が追いつかなかったので断念。
$ plenv exec cpanm Apache::DBI
$ plenv exec cpanm Archive::Zip
$ plenv exec cpanm Date::Format
$ plenv exec cpanm DateTime
$ plenv exec cpanm DBI
$ plenv exec cpanm Moo
$ plenv exec cpanm Net::DNS
$ plenv exec cpanm Template
$ plenv exec cpanm XML::LibXML
$ plenv exec cpanm YAML::XS
$ plenv exec cpanm LWP::Protocol::https
次に mod_perl2 をインストール。その後動作確認をしてみたら内部で Not Found エラーが出ていた DBD::mysql もインストール。
$ plenv exec cpanm HTML::HeadParser
$ plenv exec cpanm --sudo mod_perl2
$ plenv exec cpanm DBD::mysql --configure-args="--libs='-L/usr/lib64 -lssl -lcrypto -L/usr/local/lib -lmariadbclient'"
mod_perl2 のインストールスクリプトは、RPM 版の mod_perl の置き場所を上書きするようです。このためにインストール時に –sudo を付けています。
$ grep mod_perl.so .cpanm/build.log | grep ^cp
cp mod_perl.so /usr/lib64/httpd/modules
$ ls -l /usr/lib64/httpd/modules/mod_perl.so
-rwxr-xr-x. 1 root root 2015608 3月 30 17:19 /usr/lib64/httpd/modules/mod_perl.so
Apache が /usr/bin/perl を使う問題
OTRS では RPM パッケージで以下の設定が追加されます。
vagrant@otrs6r:$ grep -r Perlrequire /etc/httpd/
/etc/httpd/
conf.d/zzz_otrs.conf: Perlrequire /opt/otrs/scripts/apache2-perl-startup.pl
Apache2 のドキュメントによると、Perlrequire は mod_perl2 のディレクティブで、perl のコードで言うところの
require "/opt/otrs/scripts/apache2-perl-startup.pl";
と同等の機能とのことです。apache2-perl-startup.pl のシバン(ファイル1行目の起動コマンドインタプリタ指定)には
!/usr/bin/env perl
と書かれているので、plenv で入れた perl を使ってくれるかと思いきや、そうもいかないようです(RPM から入れた v5.16.3 を指している)。
$ sudo /usr/bin/env perl -v | head -2
This is perl 5, version 16, subversion 3 (v5.16.3) built for x86_64-linux-thread-multi
root や sudo 経由の otrs ユーザでは、plenv local / global で指定した perl 5.18.0 になっていません。これは、plenv は plenv を入れたユーザの .bash_profile の PATH を書き換えることで plenv の方を呼び出しているため、他のユーザでは有効にならないためです。
ここはシンボリックリンクによる力技で解決しました。
$ sudo mv /usr/bin/perl /usr/bin/perl_
$ sudo ln -f /opt/otrs/.plenv/versions/5.18.0/bin/perl /usr/bin/perl
vagrant@otrs6r:~$ sudo perl -v | head -2
This is perl 5, version 18, subversion 0 (v5.18.0) built for x86_64-linux-thread-multi
これでようやく 5.18.0 の方を見てくれるようになりました。
OTRSがplenvを見てくれない問題
その後、ブラウザからアプリのログイン画面にアクセスすると Internal Server Error になりました。あるはずのモジュールが見つからないエラーです。これについては OTRS 側の index.pl の先頭に検索パスを追加することで回避しました。
$ vi bin/cgi-bin/index.pl
$ sed -n '22,27p' bin/cgi-bin/index.pl
# use ../../ as lib location
use FindBin qw($Bin);
use lib "$Bin/../../.plenv/versions/5.18.0/lib/perl5/site_perl/5.18.0/"; # <= 追加
use lib "$Bin/../..";
use lib "$Bin/../../Kernel/cpan-lib";
use lib "$Bin/../../Custom";
ここまでの時点でいったんブラウザからアプリのURLを開き、Internal Server Error が出ない程度には動くことを確認しておきます。
フォルダを開く
次に VSCode から「フォルダを開く」で /opt/otrs を開きますが、最初ファイルが多すぎて追跡できないという警告が出たので、Visual Studio Code is unable to watch for file changes in this large workspace” (error ENOSPC)に従って、以下の通りカーネルパラメータ fs.inotify.max_user_watches のチューニングを行いました。
$ sudo vi /etc/sysctl.conf
fs.inotify.max_user_watches=524288 # この行を追加
$ sudo sysctl -p
$ cat /proc/sys/fs/inotify/max_user_watches
524288
この設定を行うと 540MiB ほど余計にメモリを喰うらしいので、VMのメモリがしょぼい場合は適宜減らした方がよいかもしれません。
さらに、追跡する必要のないディレクトリは VSCode の追跡対象から除外しておきます。Settings File Location を参照して settings.json を設置します。
$ mkdir -p .config/Code/User/
$ vi .config/Code/User/settings.json
$ cat .config/Code/User/settings.json
"files.watcherExclude": {
"**/.config/**": true,
"**/.cpan/**": true,
"**/.cpanm/**": true,
"**/.dircolors-solarized/**": true,
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/.pki/**": true,
"**/.plenv/**": true,
"**/.ssh/**": true,
"**/.vscode-server/**": true,
"**/node_modules/*/**": true
}
VSCodeの設定
VSCode では、拡張機能から Language Server and Debugger for Perl を導入します。
「実行」>「構成の追加」をすると、以下の launch.json が生成されました。
{
// IntelliSense を使用して利用可能な属性を学べます。
// 既存の属性の説明をホバーして表示します。
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "perl",
"request": "launch",
"name": "Perl-Debug",
"program": "${workspaceFolder}/${relativeFile}",
"stopOnEntry": true,
"reloadModules": true
}
]
}
その後もリソース不足で vscode-server がなかなか落ち着いてくれないので、以下のように VM のリソースを増やしました。
config.vm.define "otrs6r" do |otrs6r|
otrs6r.vm.box = "otrs20210330"
otrs6r.vm.network "private_network", ip: "192.168.56.28"
otrs6r.vm.network :forwarded_port, guest: 22, host: 12328
otrs6r.vm.hostname = "otrs6r"
otrs6r.vm.provider "virtualbox" do |vb|
vb.memory = "6000"
vb.cpus = "4"
end
end
ここまで調整して、ようやく vscode-server の初期化が正常終了しました。VSCode からの接続からファイルのパースが終わるまで数分かかりました。
(中略)
VSCodeにおけるコンパイルエラー
ブラウザからの実行時に最初に起動される bin/cgi-bin/index.pl を VSCode のエディタで開いてみると、自動的にコンパイルが行われますが、ここでエラーになります。
調べてみると、どうも VSCode の perl デバッグ機能は、コンパイル後のソースを .vscode 配下に置いているようで、そこにないファイルは「見つかりません」となるのかもしれません。
$ ls .vscode/perl-lang/opt/otrs/
Kernel bin scripts var
もともと OTRS の RPM パッケージに入っている cpan モジュールは Kernel/cpan-lib あたりに入っていますが、これらは全部 plenv 配下の cpanm で入れ直さなければならないのかもしれません。ということで、エラーになるたびにモジュールを追加していきます。
$ plenv exec cpanm IO::Interactive
$ plenv exec cpanm Math::Random::Secure
$ plenv exec cpanm Crypt::PasswdMD5
「問題」ペインがおとなしくなったら、デバッグアイコンをクリックして「▶ Perl-Debug」をクリックしてデバッグを開始しますが、ここで次の難関が。
該当の箇所(30行目)は以下です。こんなのでエラーになる perl って深いなぁ。
cpan.orgのバグトラッカーの書き込みに従って、index.pl の先頭付近にダミーの関数を追加することで回避。
sub DB::DB {}
次は以下のようなエラーです。