arc の日記

はてなダイアリーから引っ越してきました。さらに新しい記事は https://junkato.jp/ja/blog/ で書いています。

QNAP TS-239 ProにSubversion+Tracを入れた記録

QNAP(キューナップ) ターボNAS 黒 TS-239Pro昨日付けでQNAP製のNASをセットアップしたときの記録を書きました。それだけでも結構手間だったんですが、実はその後、バージョン管理システムSubversionと連携できるWebインタフェースTracを入れるのに大変苦労したので、別に記録として残しておきます。
見ての通りかなりアドホックで汚いやり方なので、スマートな解決法をご存知の方いらっしゃいましたらご教示ください…。

2010/04/14追記; ファームウェアを更新したらApacheが上書きされ、mod_wsgiのインストール時に置換したビルドパス(/root/daily_build/云々)が新しくなっていたので、該当箇所の記述(sedコマンドの引数)をより一般的なものに修正しました。QNAPの中の人はユーザの手でプリインストールされたApacheに新しくモジュールを追加させる気がないようだ…。

Subversionのインストール

root権限を持つadminユーザで ipkg install svn すればSubversionがインストールされます。
ただし、Tracと連携させる前提でSubversionをインストールする場合、TracのエンジンであるPythonSubversionにアクセスできるようにSWIGという仕組みを有効にしておく必要があります。ipkgコマンドを使ってインストールした素のSubversionではSWIGが有効になっていないため、このままでは後々エラーが出ます。
では、どうすればいいのでしょうか。
結論から言えば、Subversion用のPython SWIG bindingパッケージ svn-py というものが用意されており、ipkg install svn-py すればSWIGを有効にしてSubversionをビルドしたのと同じ状態になります。(はじめ、Subversionをソースからビルドし直さないといけないものと思い込んで四苦八苦しました。)
このとき、依存関係でPython 2.5がインストールされます。
PythonについてはQPKGでインストールすることもできますが、svn-pyと連携が取れないうえ、後で試してみたら mod_wsgi の ./configure で以下のようなエラーを吐いてしまうので使えなさそうです。機能の絞られたビルドなのかな?

mod_wsgi.c:135:20: error: Python.h: No such file or directory
mod_wsgi.c:138:2: error: #error Sorry, Python developer package does not appear to be installed.
mod_wsgi.c:142:2: error: #error Sorry, mod_wsgi requires at least Python 2.3.0 for Python 2.X.
mod_wsgi.c:150:2: error: #error Sorry, mod_wsgi requires that Python supporting thread.

Tracのインストール

これは本当に簡単で、 ipkg install py25-trac すればいいだけです。
ちなみにPython 2.6用に py26-trac パッケージもありますが、先ほど svn-py のため強制的にPython 2.5をインストールさせられたのでこちらは使えません。

mod_wsgiのインストール

QNAPのNASについてくるApacheは、標準状態でPythonCGIとして動かせないので、mod_pythonやmod_wsgiをインストールする必要があります。ApacheとPythonを繋げる方法には色々ありますが、mod_wsgiが一番速そうなのでこれを使うことにしました。
コンパイル済みの mod_wsgi 自体は ipkg install mod-wsgi で入手できますが、これは apache パッケージに依存しています。QNAPのNASに最初から入っているApacheを使い続けることを考えると、 mod-wsgi パッケージではなく、ソースからコンパイルしたほうがよさそうです。
まずGoogle Codeのプロジェクトサイトから最新のtar.gzをwgetしてtar -zxvfで展開します。
その後、ディレクトリに入ってapxsとpython2.6のパスを指定して ./configure しようとするとエラーが出ます。

[admin@kitten mod_wsgi-3.2]# ./configure --with-apxs=/usr/local/apache/bin/apxs --with-python=/opt/bin/python2.5

apxsの先頭で指定しているPerlのパス /usr/bin/perl が存在しないようです。 ipkg install perl して /opt/bin/perl に置換します。このとき、同じ画面内に $installbuilddir へ存在しないディレクトリ /root/daily_build/NasX86/Model/TS-259/../../NasMgmt/HTTP/apache_install_tmp/build を代入している行が見えたので /usr/local/apache/build に置き換えておきました。
改めて ./configure するとやはりエラーが出ます。apxsが内部で呼び出している /usr/local/apache/build/config_vars.mk というファイル内でやはりおかしなApacheのパスを指定しているようです。置換します。

[admin@kitten mod_wsgi-3.2]# cd /usr/local/apache/build
[admin@kitten build]# cat config_vars.mk | /bin/sed -e 's@/root/daily_build/.*/apache_install_tmp@/usr/local/apache@g' > config_vars.new
[admin@kitten build]# mv config_vars.mk config_vars.backup
[admin@kitten build]# mv config_vars.new config_vars.mk

[admin@kitten build]# cd /share/MD0_DATA/home/httpdusr/mod_wsgi-3.2
[admin@kitten mod_wsgi-3.2]# ./configure --with-apxs=/usr/local/apache/bin/apxs --with-python=/opt/bin/python2.5
(失敗)

同じようなエラーが出ます。どうやらQNAPのNASにインストールされているApacheは中の人の環境でビルドされたものをコピーしてきたもののようで、ことごとくパスの指定がおかしいです。
原因らしき /usr/local/apache/bin/apr-1-config のパス指定を置換します。

[admin@kitten mod_wsgi-3.2]# cd /usr/local/apache/bin
[admin@kitten bin]# cat apr-1-config | /bin/sed -e 's@/root/daily_build/.*/apache_install_tmp@/usr/local/apache@g' > apr-1-config.new
[admin@kitten bin]# mv apr-1-config apr-1-config.backup
[admin@kitten bin]# mv apr-1-config.new apr-1-config
[admin@kitten bin]# chmod 755 apr-1-config

[admin@kitten bin]# cd /share/MD0_DATA/home/httpdusr/mod_wsgi-3.2
[admin@kitten mod_wsgi-3.2]# ./configure --with-apxs=/usr/local/apache/bin/apxs --with-python=/opt/bin/python2.5
checking Apache version... 2.2.14
configure: creating ./config.status
config.status: creating Makefile
[admin@kitten mod_wsgi-3.2]# make
(失敗)

./configureはうまくいきましたが、makeできません。
今度は /usr/local/apache/build/libtool がおかしいようです。置換します。また、途中 /bin/bash を見に行っていますが、これはQNAPのNASでは /bin/sh として存在しているようなのでシンボリックリンクを張ります。

[admin@kitten mod_wsgi-3.2]# cd /usr/local/apache/build
[admin@kitten build]# cat libtool | /bin/sed -e 's@/opt/cross-project/x86/sys-root/bin@/bin@g' > libtool.new
[admin@kitten build]# ln -s /bin/sh /bin/bash
[admin@kitten build]# mv libtool libtool.backup
[admin@kitten build]# mv libtool.new libtool
[admin@kitten build]# chmod 755 libtool

[admin@kitten build]# cd /share/MD0_DATA/home/httpdusr/mod_wsgi-3.2
[admin@kitten mod_wsgi-3.2]# make
/usr/local/apache/bin/apxs -c -I/opt/include/python2.5 -DNDEBUG   mod_wsgi.c -L/opt/lib -L/opt/lib/python2.5/config  -lpython2.5 -lpthread -ldl  -lpthread -lutil -lm
/usr/local/apache/build/libtool --silent --mode=compile gcc -prefer-pic   -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE -g -O2 -pthread -I/usr/local/apache/include  -I/usr/local/apache/include   -I/root/daily_build/NasX86/Model/TS-259/../../NasMgmt/HTTP/apache_install_tmp/include  -I/opt/include/python2.5 -DNDEBUG  -c -o mod_wsgi.lo mod_wsgi.c && touch mod_wsgi.slo
/usr/local/apache/build/libtool --silent --mode=link gcc -o mod_wsgi.la  -rpath /usr/local/apache/modules -module -avoid-version    mod_wsgi.lo -L/opt/lib -L/opt/lib/python2.5/config -lpython2.5 -lpthread -ldl -lpthread -lutil -lm
copying selected object files to avoid basename conflicts...

うまくいきました。インクルードパスが若干おかしいですが、何とかなっていてほしい。

[admin@kitten mod_wsgi-3.2]# make install
/usr/local/apache/bin/apxs -i -S LIBEXECDIR=/usr/local/apache/modules -n 'mod_wsgi' mod_wsgi.la
/usr/local/apache/build/instdso.sh SH_LIBTOOL='/usr/local/apache/build/libtool' mod_wsgi.la /usr/local/apache/modules
/usr/local/apache/build/libtool --mode=install cp mod_wsgi.la /usr/local/apache/modules/
cp .libs/mod_wsgi.so /usr/local/apache/modules/mod_wsgi.so
cp .libs/mod_wsgi.lai /usr/local/apache/modules/mod_wsgi.la
cp .libs/mod_wsgi.a /usr/local/apache/modules/mod_wsgi.a
chmod 644 /usr/local/apache/modules/mod_wsgi.a
ranlib /usr/local/apache/modules/mod_wsgi.a
PATH="$PATH:/sbin" ldconfig -n /usr/local/apache/modules
----------------------------------------------------------------------
Libraries have been installed in:
   /usr/local/apache/modules

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
     during execution
   - add LIBDIR to the `LD_RUN_PATH' environment variable
     during linking
   - use the `-Wl,--rpath -Wl,LIBDIR' linker flag
   - have your system administrator add LIBDIR to `/etc/ld.so.conf'

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
chmod 755 /usr/local/apache/modules/mod_wsgi.so

いよいよ /usr/local/apache/modules/mod_wsgi.so が作成されました。
/usr/local/apache/conf/apache.conf に LoadModule wsgi_module modules/mod_wsgi.so という行を足してサーバを停止します。

[admin@kitten mod_wsgi-3.2]# cd /usr/local/apache/bin
[admin@kitten bin]# ./apachectl stop
apache: Syntax error on line 46 of /etc/config/apache/apache.conf: Cannot load /usr/local/apache/modules/mod_wsgi.so into server: libpython2.5.so.1.0: cannot open shared object file: No such file or directory

mod_wsgi.so が libpython2.5.so.1.0 が見つからなくて落ちている旨のエラーが表示されます。
/opt/lib にあるので、これが /usr/lib からも見えるようシンボリックリンクを張ります。

[admin@kitten bin]# ln -s /opt/lib/libpython2.6.so.1.0 /usr/lib/libpython2.6.so
[admin@kitten bin]# ./apachectl restart

いけました。

プロジェクト リポジトリの初期化

[httpdusr@kitten httpdusr]$ mkdir svn
[httpdusr@kitten httpdusr]$ cd svn
[httpdusr@kitten svn]$ svnadmin create test
[httpdusr@kitten svn]$ cd ../

[httpdusr@kitten httpdusr]$ mkdir trac
[httpdusr@kitten httpdusr]$ cd trac
[httpdusr@kitten trac]$ trac-admin test initenv
Traceback (most recent call last):
  File "/opt/bin/trac-admin", line 5, in <module>
    from pkg_resources import load_entry_point
ImportError: No module named pkg_resources

Subversionリポジトリは作れましたが、Tracのほうでpkg_resources が見つからないと怒られます。
調べてみるとsetuptoolsをインストールしたらいいらしいことが分かりました。

[admin@kitten httpdusr]# wget http://pypi.python.org/packages/2.5/s/setuptools/setuptools-0.6c11-py2.5.egg#md5=64c94f3bf7a72a13ec83e0b24f2749b2
--2010-04-04 02:25:22--  http://pypi.python.org/packages/2.5/s/setuptools/setuptools-0.6c11-py2.5.egg
Resolving pypi.python.org... 82.94.164.163
Connecting to pypi.python.org|82.94.164.163|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 333390 (326K) [application/octet-stream]
Saving to: `setuptools-0.6c11-py2.5.egg'

100%[===================================================================================>] 333,390      147K/s   in 2.2s

2010-04-04 02:25:25 (147 KB/s) - `setuptools-0.6c11-py2.5.egg' saved [333390/333390]

[admin@kitten httpdusr]# sh ./setuptools-0.6c11-py2.5.egg
Processing setuptools-0.6c11-py2.5.egg
Copying setuptools-0.6c11-py2.5.egg to /share/MD0_DATA/.qpkg/Optware/local/lib/python2.5/site-packages
Adding setuptools 0.6c11 to easy-install.pth file
Installing easy_install script to /opt/local/bin
Installing easy_install-2.5 script to /opt/local/bin

Installed /share/MD0_DATA/.qpkg/Optware/local/lib/python2.5/site-packages/setuptools-0.6c11-py2.5.egg
Processing dependencies for setuptools==0.6c11
Finished processing dependencies for setuptools==0.6c11

このときは setuptools のスクリプトを公式サイトからダウンロードしてきましたが ipkg install py-setuptools でも入るようです。まぁ、同じこと。
では、再チャレンジします。

[httpdusr@kitten trac]$ trac-admin test initenv
Creating a new Trac environment at /share/MD0_DATA/home/httpdusr/trac/test

Trac will first ask a few questions about your environment
in order to initialize and prepare the project database.

 Please enter the name of your project.
 This name will be used in page titles and descriptions.

Project Name [My Project]> Test Project

 Please specify the connection string for the database to use.
 By default, a local SQLite database is created in the environment
 directory. It is also possible to use an already existing
 PostgreSQL database (check the Trac documentation for the exact
 connection string syntax).

Database connection string [sqlite:db/trac.db]>

 Please specify the type of version control system,
 By default, it will be svn.

 If you don't want to use Trac with version control integration,
 choose the default here and don't specify a repository directory.
 in the next question.

Repository type [svn]>

 Please specify the absolute path to the version control
 repository, or leave it blank to use Trac without a repository.
 You can also set the repository location later.

Path to repository [/path/to/repos]> /share/MD0_DATA/home/httpdusr/svn/test

Creating and Initializing Project
 Installing default wiki pages
 ()
 Indexing repository

---------------------------------------------------------------------
Project environment for 'Test Project' created.

You may now configure the environment by editing the file:

  /share/MD0_DATA/home/httpdusr/trac/test/conf/trac.ini

If you'd like to take this new project environment for a test drive,
try running the Trac standalone web server `tracd`:

  tracd --port 8000 /share/MD0_DATA/home/httpdusr/trac/test

Then point your browser to http://localhost:8000/test.
There you can also browse the documentation for your installed
version of Trac, including information on further setup (such as
deploying Trac to a real web server).

The latest documentation can also always be found on the project
website:

  http://trac.edgewall.org/

Congratulations!

きました。指示に従ってtracdを試してみます。

[httpdusr@kitten trac]$ tracd --port 8000 /share/MD0_DATA/home/httpdusr/trac/test
Server starting in PID 13675.
Serving on 0.0.0.0:8000 view at http://127.0.0.1:8000/
127.0.0.1 - - [04/Apr/2010 02:29:43] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [04/Apr/2010 02:29:43] "GET /favicon.ico HTTP/1.1" 404 -
127.0.0.1 - - [04/Apr/2010 02:29:46] "GET /test HTTP/1.1" 200 -
127.0.0.1 - - [04/Apr/2010 02:29:47] "GET /test/chrome/common/topbar_gradient2.png HTTP/1.1" 200 -
127.0.0.1 - - [04/Apr/2010 02:29:47] "GET /test/chrome/site/your_project_logo.png HTTP/1.1" 404 -
127.0.0.1 - - [04/Apr/2010 02:29:51] "GET /test/browser HTTP/1.1" 200 -
127.0.0.1 - - [04/Apr/2010 02:29:51] "GET /test/chrome/common/css/browser.css HTTP/1.1" 200 -
127.0.0.1 - - [04/Apr/2010 02:29:51] "GET /test/chrome/common/js/expand_dir.js HTTP/1.1" 200 -
127.0.0.1 - - [04/Apr/2010 02:29:51] "GET /test/chrome/common/js/keyboard_nav.js HTTP/1.1" 200 -
127.0.0.1 - - [04/Apr/2010 02:29:51] "GET /test/chrome/site/your_project_logo.png HTTP/1.1" 404 -
127.0.0.1 - - [04/Apr/2010 02:29:51] "GET /test/chrome/common/asc.png HTTP/1.1" 200 -
127.0.0.1 - - [04/Apr/2010 02:29:55] "GET /test/wiki HTTP/1.1" 200 -
127.0.0.1 - - [04/Apr/2010 02:29:55] "GET /test/chrome/site/your_project_logo.png HTTP/1.1" 404 -

ブラウザからアクセスしたら確かにアクセスできました。プロジェクトのロゴがないのでそこだけ404エラー。間違いなくちゃんと動いています。

Apacheの設定

以下のページに従って設定を終えました。

Google Code Archive - Long-term storage for Google Code Project Hosting.

サーバを再起動したところ、Tracのサイトが表示されました。しかし、次のエラーメッセージを吐いています。

Warning: Can't synchronize with the repository (Couldn't open Subversion repository /share/MD0_DATA/home/httpdusr/svn/test: SubversionException: ('SQLite compiled for 3.6.22, but running with 3.3.7', 200030)). Look in the Trac log for more information.

調べたところ、これはPHP用のSQLite(3.3.7)とSubversion用のSQLite(3.6.22)が衝突して起きるエラーのようです。
PHPを再コンパイルしたら直るといった情報が見つかりましたが、phpinfo();で現行PHPのビルドオプションを確認すると例によってApacheの変なパスを見ていたりして、再コンパイルは難航が予想されます。
そこでもう少し調べを進めていると、ApacheのLoadFileディレクティブで必要なライブラリを読むという解決策が見つかりました。
あまり期待せず、 libphp5 を読む前に libsqlite を読むように /usr/local/apache/conf/apache.conf を修正します。

LoadFile /opt/lib/libsqlite3.so.0
LoadModule php5_module modules/libphp5.so

果たして、サーバを再起動するとTracがうまく動くではありませんか。PHP版のSQLiteはどうなったんだ、等と少し不安も残りますが、とりあえずPHPSQLiteを使う予定もないのでよしとしましょう。

2011/12/20 追記; 本件に関して別の解決策を見つけました。Fixing an SQLite version mismatch between Subversion and PHP5によれば、Subversionリポジトリを古いフォーマットで作っておけばこの問題自体が生じないそうです。

途中、 /usr/lib にシンボリックリンクを作成したりしましたが、これは恐らくNASを再起動したときに消えます。したがって、別途対策を講じる必要があります。まぁ、それはおいおい。