俺様サーバー構築記 - Subversionサーバーの構築@デスクトップパソコン


俺様サーバー構築記 - 基本方針」以来構築を続けてきた俺様パソコン環境ですが、サーバーマシンも基本的なインストールが出来て、ぼちぼち色んなサービスなどを構築する段階になってきました。

すると各種設定がガンガン必要になり、場合によっては試行錯誤とその記録も必要になりますが、そういう場合は言うまでも無くバージョン管理が有効です。

一般的には git という話になるんだと思いますけども。私は未だ git に慣れない、というかほぼ触った事がありませんので、今回は Subversion サーバーを立てます。って言うかですね、分散以外に git の優位性がわからんのですよ。いずれ GitLab を自力で立てて git フローを勉強するつもりですので、そうしたらまた報告記事を上げます。

参考文献

なおかつ・ArchLinux インストール覚書
Subversion だけでお手軽にサーバ構築
2 Svnserve のセットアップ - Subversion - ArchWiki
許可するように設定されていても、SVNにパスワードを保存させることはできません。 - コードログ

インストール

パッケージ

何はともあれインストール。その前にスナップショットを撮りましょう。

# zfs snapshot tank/main@$(date +%Y%m%d_%H%M%S)_before_svn
# zfs list -t snapshot -S name | head -n2
NAME                                        USED  AVAIL     REFER  MOUNTPOINT
tank/main@20190629_004305_before_svn        854K      -     2.43G  -
# pacman -S --noconfirm svn 
〈省略〉
# svn --version | head -n2
svn, version 1.12.0 (r1857323)
   compiled Jun  7 2019, 01:40:12 on x86_64-pc-linux-gnu

Subversion のバージョンは 1.12.0 ですか。何が変わったんでしょうね。少なくともレッドブックは…役に立たないとは言わないけど、細かい部分でかなり変わったんじゃないかと思うんだけど。思うんだけど!info svn とか読むと、諸々の話題はレッドブックで見つかるよ〜と書いてある…

そして公式ページでも、ユーザーマニュアルはレッドブックでした。英語版だけど。という事はあんまり変わってないのかな。まあ良いか。

レッドブック以降の追加機能の調査は今後の課題としましょう。

Subversionサーバ用ユーザ

ユーザは svn とします。

# useradd -Mr -c "Subversion service" -d /srv/svn -s /sbin/nologin svn

何だかオプションがごちゃごちゃしてしまいましたが、この結果次のように登録されます。

# grep svn /etc/passwd
svn:x:977:977:Subversion service:/srv/svn:/sbin/nologin

ホームディレクトリは /srv/svn としています。ftp とか http とかもそうなんで、妥当な設定でしょう。

# grep -e ftp -e http /etc/passwd
ftp:x:14:11::/srv/ftp:/sbin/nologin
http:x:33:33::/srv/http:/sbin/nologin

svn ユーザのホームディレクトリの扱いとなった /srv/svn を作り、リポジトリはその下の /srv/svn/repo とします。

useradd コマンドの -m オプションを使用しなかったのは、余計なサブディレクトリなどを避ける為です。

# mkdir -p /srv/svn/repo

Subversionサーバの設定

svnserve の設定ファイルと、systemd用の設定ファイルを用意します。

例によって、可能な限り自動化できるコマンドを選んでいます。

# sed -i -e 's:^\(SVNSERVE_ARGS\)=.*$:\1="-r /srv/svn/repo":' /etc/conf.d/svnserve
# SYSTEMD_EDITOR="/usr/bin/cp /dev/stdin" systemctl edit svnserve <<___
> [Service]
> User=svn
> ___

systemctl edit のエディタとして /usr/bin/cp /dev/stdin を指定するのは反則級の暴挙だろうなぁとは思います。しかし反省も後悔もしていません。

なお設定結果の確認には systemctl cat コマンドを使うと楽でしょう。

# systemctl cat svnserve
# /usr/lib/systemd/system/svnserve.service
[Unit]
Description=Subversion protocol daemon
After=syslog.target network.target

[Service]
Type=forking
EnvironmentFile=/etc/conf.d/svnserve
ExecStart=/usr/bin/svnserve --daemon $SVNSERVE_ARGS

[Install]
WantedBy=multi-user.target

# /etc/systemd/system/svnserve.service.d/override.conf
[Service]
User=svn

組み込みのユーザ認証を設定します。ここに記述されるパスワードは平文で、スペースや記号も許されます。とりあえず実験用のユーザとパスワードを一つ。

# cd /srv/svn
# mkdir conf
# cat <<___ >conf/passwd
> [users]
> taro = This is 1 pen.
> ___

プライベートの場合は権限の制限は無くて、プロジェクトのディレクトリツリーは全員すべて読み書き可能にする事が多いでしょう。これを各プロジェクト間で共有のファイルとしておきます。そうでない場合はそれなりに設定してください。

# cat <<___ >conf/default-authz
> [/]
> * = rw
> ___

リポジトリを用意する為のスクリプトを作ります。滅多にしない操作を忘れないように。

# vi createprj.sh
# cat createprj.sh 
#!/bin/bash
if [[ -z "$1" ]]; then
    echo "usage: $(basename $0) <projectname>"
    exit
fi
umask 002
SVN_HOME=$(dirname $0)
cd $SVN_HOME
svnadmin create repo/$1
ret=$?
test $ret -ne 0 && exit $ret

cat <<-___ >repo/$1/conf/svnserve.conf
    [general]
    anon-access = none
    auth-access = write
    password-db = ../../../conf/passwd
    authz-db = ../../../conf/default-authz
    realm = Project $1
___
chown -R svn:svn repo/$1

echo "Edit svnserve.conf and authz in the directory $SVN_HOME/repo/$1/conf as needed."
echo "The file passwd is in the directory $SVN_HOME/conf, edit it as needed, too."
# chmod 755 createprj.sh

ここまで出来たら、ファイルとディレクトリの所有者を svn にしておきます。

# chown -R svn:svn .

Subversionクライアントの基本設定

これは、Subversion に対して昔から良く挙げられる要望への対応です。

# ls -ld /etc/subversion
ls: cannot access '/etc/subversion': No such file or directory
# mkdir /etc/subversion
# cat <<___ >/etc/subversion/config
> [miscellany]
> use-commit-times = yes
> ___

これを指定しておくと、checkout や update などの際、該当ファイルに commit 日時が設定されます!操作日時ではなく!

commit された時の該当ファイルの更新日時が再現される訳ではありませんが、それでも結構な改善でしょう。

起動

ここまで設定したら Subversion サーバを起動します。

# systemctl enable svnserve
Created symlink /etc/systemd/system/multi-user.target.wants/svnserve.service -> /usr/lib/systemd/system/svnserve.service.
# systemctl start svnserve

起動を確認。

# systemctl status svnserve
* svnserve.service - Subversion protocol daemon
   Loaded: loaded (/usr/lib/systemd/system/svnserve.service; disabled; vendor preset: disabled)
  Drop-In: /etc/systemd/system/svnserve.service.d
           `-override.conf
   Active: active (running) since Sat 2019-06-29 19:48:24 JST; 26s ago
  Process: 3158 ExecStart=/usr/bin/svnserve --daemon $SVNSERVE_ARGS (code=exited, status=0/SUCCESS)
 Main PID: 3159 (svnserve)
    Tasks: 1 (limit: 4915)
   Memory: 2.8M
   CGroup: /system.slice/svnserve.service
           `-3159 /usr/bin/svnserve --daemon -r /srv/svn/repo

Jun 29 19:48:23 anju systemd[1]: Starting Subversion protocol daemon...
Jun 29 19:48:24 anju svnserve[3158]: DIGEST-MD5 common mech free
Jun 29 19:48:24 anju systemd[1]: Started Subversion protocol daemon.
# ps aux | grep serve
svn       3159  0.0  0.0  18268   920 ?        Ss   19:48   0:00 /usr/bin/svnserve --daemon -r /srv/svn/repo
root      3270  0.0  0.0   3036  1240 pts/0    S+   19:50   0:00 grep serve

ひとまず起動できたようです。

確認

実際に操作してみます。

  1. 実験用プロジェクト test を作成
  2. ホームディレクトリで checkout
  3. 適当なテキストファイルを作成して commit
  4. テキストファイルを表示して比較
  5. 別のディレクトリに checkout して、ファイル更新日時を確認

ユーザは引き続き root のままで、Subversion のアカウントは設定しておいた最初のユーザを使用します。

サーバ側
# /srv/svn/createprj.sh test
Edit svnserve.conf and authz in the directory /srv/svn/repo/test/conf as needed.
The file passwd is in the directory /srv/svn/conf, edit it as needed, too.
# mkdir $HOME/work
# cd $HOME/work
# IFS="$IFS=" read U P <<< $(grep = /srv/svn/conf/passwd | head -n1)
# svn co --username "$U" --password "$P" svn://localhost/test/
Checked out revision 0.

素晴らしい事に、最初の svn コマンドで何も聞かれません。パスワードを保存しますか? Store password unencrypted (yes/no)? と昔は聞かれたものですが。今のバージョンでは何も聞かれません。黙って保存しない方向のようです。

# cd test
# echo "Subversion test" >document.txt
# svn add *
A         document.txt
# svn ci --password "$P" -m "first commit"
Adding         document.txt
Transmitting file data .done
Committing transaction...
Committed revision 1.
# svn cat --password "$P" svn://localhost/test/document.txt
Subversion test
# ls -l --time-style=+"%F %T %z"
total 1
-rw-r--r-- 1 root root 16 2019-07-02 22:40:55 +0900 document.txt
# svn log --password "$P" svn://localhost/test/
------------------------------------------------------------------------
r1 | taro | 2019-07-02 22:41:14 +0900 (Tue, 02 Jul 2019) | 1 line

first commit
------------------------------------------------------------------------
# mkdir $HOME/work2
# cd $HOME/work2
# svn co --password "$P" svn://localhost/test/
A    test/document.txt
Checked out revision 1.
# ls -l --time-style=+"%F %T %z"
total 1
-rw-r--r-- 1 root root 16 2019-07-02 22:41:14 +0900 document.txt

最後の、ファイル日時の確認ですが。次のようなコマンドを使用すると楽になります。

# svn log --password="$P" * --xml | xmllint --xpath "/log/logentry/date/text()" -
2019-07-02T13:41:14.299079Z
# date -u -r document.txt +"%FT%T.%6NZ"
2019-07-02T13:41:14.299079Z

最後に片付け。テスト用に作成したプロジェクトの、ワーキングディレクトリとリポジトリを削除します。

サーバ側
# cd
# rm -r work work2 /srv/svn/repo/test

これでひとまず完了です。やったね