3 apt-listbugs の生い立ちと実装

樽石      
___________________________________________________________________________________________________________________________

この文書は 2005 3 月に北京で開催された Asia Debian Mini-Conf in Beijin で発表した資料の日本語 訳 で す 。

3.1 はじめに

Debian 24 時間 365 日、 多くの開発者によって日夜開発されている自由なオペレーティングシステムで す 。 わ た し た ち は こ の よ う な 最 新 の ス ナ ップ シ ョット を Debian のアップグレードフレームワークを使う こ と で 簡 単 に 共 有 す る こ と が で き 、 実 際 に 、 こ の フ レ ー ム ワ ー ク を 利 用 し て 多 く の 人 が 最 新 の Debianス ナ ップ シ ョット を 利 用 し て い ま す 。

一方で、 この最新スナップショットはときどき壊れることがあります。 apt-listbugs は、 このような壊れた ス ナ ップ シ ョット か ら あ な た の コ ン ピ ュー タ を 守 る た め の 仕 組 み で す 。

この短い文書では、 apt-listbugs がどのようにコンピュータを守るのか、 apt-listbugs の生い立ち、 実装に つ い て 簡 単 に 説 明 し ま す 。 ま た apt-listbugs の抱えている現在の問題点について紹介しま す 。

3.2 仕組み

Debian には Debian バグ追跡システム (BTS) として知られる、 Debian に関する全ての問題が利用可能 な 中 央 管 理 型 バ グ 追 跡 シ ス テ ム が あ り ま す 。 Debian のパッケージインストールフレームワークである APT apt-get aptitude 等を利用してインストールやアップグレードを行う直前に BTS から こ れ ら の 問 題 を 取 得 す る た め に apt-listbugs を呼び出します。 apt-listbugs はどのパッケ ー ジ が イ ン ス ト ー ル さ れ る の か 、 ま た ア ップ グ レ ー ド さ れ る の か を 自 動 認 識 し 、 問 題 とな るバグを見付けた場合はその事をユーザに通知し、 インストールを継続するか警告を出しま す 。

このアプローチは、 主にふたつの問題、 ひとつはユーザの視点、 もうひとつは開発者の視点を解決し ま す 。

3.2.1 ユーザの視点

ユーザの視点は apt-listbugs のメインの目的です。 APT フレームワークは任意のパッケージを簡単 にアップグレードすることができます。 複雑な作業を一切行わずに単に ’apt-get upgrade’ と実行するだけです。 これはすばらしい機能ですが、 一方でこのアプローチは壊れたパッ ケージさえも簡単にインストールさせてしまいます。 多くの人が apt-get upgrade を利用し ているため、 結果として世界中の Debian マシンが一瞬のうちに壊れてしまうことになり ます。

実際は、 壊れたパッケージの情報は BTS に既に存在している可能性が非常に高いのですがこの情報が BTS にあるかどうかを毎回チェックしないといけないとしたら apt-get upgrade による簡単なアップグ レード作業は面倒な作業に一変してしまいます。 これが apt-listbugs が必要な理由です。 apt-listbugs はそのような情報が BTS にあるかどうかをあなたの代わりに毎回自動で行い ます。

3.2.2 開発者の視点

ふたつ目の目的は Debian 開発者のためのものです。 基本的には、 BTS Debian パッケージに関するあ らゆる情報知るために利用できるすばらしいものです。 もし自分のパッケージにバグがあった場合、 他の ユーザが問題を BTS に報告してくれます。 開発者はいつでも、 どこでも、 この情報にアクセスすること ができます。

しかし、 仮に自分の環境ではたまたま発生しなかった致命的な問題が最新のパッケージに含まれてし まったとします。 こうなると、 多くのユーザは問題の深刻さを考慮して急いでバグ報告をしようとします。 それゆえ、 たったひとつのバグに対して非常にたくさんのバグ報告を受け取ることになってしまい、 開発 者はバグ報告の分類という本質的でない作業に時間をとられ、 本当に直したい致命的な問題の解 決に長い時間を要してしまうことになります。 もし、 ユーザがバグをレポートする前に似 たようなレポートを閲覧することができれば、 重複したレポートを送ることはなくなるで しょう。

3.3 ヒストリ

apt-listbugs はもともとユーザの視点をなんとかしたいという個人的な目的で数年前に開発されました。 ちょうどその時は、 大学院を修了するために修士論文を書かなければいけない時期でした。 ところ が、 何を思ったか〆切の一週間前に apt-get upgrade をしてしまったのです。 結果、 NFS が動かなくなり、 この問題を修正しなければいけなくなりました。 このバグレポートをき ちんとチェックしていれば、 このような問題にはあわなかったのですが、 バグレポートを 毎回チェックするわけにはいきませんでした。 なぜならいつインストールされるかわから ない致命的な問題のために毎回バグレポートをチェックするのは非常に大変な作業だから です。

3.3.1 CGI 問題

apt-listbugs の最初のバージョンは Debian にすぐにアップロードすることはできませんでした。 その理 由は apt-listbugs BTS CGI 出力を利用していたからです。 CGI スクリプトはスクリプト言語で書 かれていたため、 もしこのパッケージをアップロードすると、 BTS サーバが非常に高負荷に な って し ま う こ と は 容 易 に 想 像 で き ま す 。 そ こ で 、 こ の apt-listbugs を利用したら同時にア クセスできるユーザ数は何人程度なのか知るために CGI のパフォーマンスを測定するこ とにしました。 結果は、 1 パッケージのレポートを取得するのにかかる時間は約 1 秒でし た。 BTS サーバは 2 台の CPU を備えていましたので、 結局 1 秒に 2 つのバグレポート しか取得できません。 そのため、 もし 10 個のパッケージをアップグレードしようとした ら、 レポートの取得に 5 秒かかってしまいます。 これは非常に大きな問題です。 特に、 BTS サーバは Debian のマスタサーバでしたから、 もし Debian ユーザ全員がそのサーバから バグレポートを取得したら、 これはほとんど DoS アタックのような状態に陥ってしまい ます。

3.3.2 強制キャッシュ

最初に考えた解決法は CGI 出力のキャッシュを行うプロクシサーバを利用することでした。 プロキシサー バが http No-Cache 属性を無視すれば、 静的なデータを利用することができます。 もちろん TTL 問題はありますが、 DoS になってしまうよりは良いでしょう。

このサーバを用意したことで、 とりあえず Debian apt-listbugs をアップロードすることができまし たが、 はじめは experimental にアップロードして様子を見ていました。

3.3.3 index.db パーサ

はじめのバージョンの apt-listbugs はパーサに潜在的な問題を抱えていました。 それはパーサが CGI 力を利用していたことです。 CGI のフォーマットはドキュメント化されていません。 また、 CGI スクリプ ト自体遅いという問題もあります。 そのため、 別の新しいパーサが必要でした。 これは index.db パーサ と呼ばれるパーサです。 index.db パーサは BTS の内部データベースである index.db ファ イルを直接パースするパーサです。 index.db ファイル自体もドキュメント化はされていな いのですが、 このファイルは静的に生成されるものですので、 CGI よりはずっと良い解 です。

実際には、 このパーサは index.db ファイルを critical grave といった重要度毎に分割した index.db ファイルを利用します。

PIC

apt-listbugs には LDAP プロトコルを利用した実験的な LDAP パーサも存在しますが、 このパーサは CGI パーサの代わりにするには意味がないものでした。 その理由は当時の BTS LDAP サーバは内 部的に tcl スクリプトを毎回よんでいるものだったからです。 速度に変化はありませんで し た 。

Andreas Barth 氏は BTS 用のネイティブな LDAP インタフェースを作成しました。 その ため、 現在ではこのインタフェースを利用してバグを取得することが可能になっています。 詳細は http://people.debian.org/~aba/bts2/ldap/ を参照してください。 ただ、 こ のインタフェースを利用するインタフェースはまだ実装されていません。

3.3.4 SpamAssasin apt-listbugs

Index.db パーサを利用することで、 apt-listbugs は動的なデータをサーバから取得することはなく なりました。 そこで、 この時点で一時的な解決であった強制キャッシュサーバを停止しま した。

しかし、 これは別の問題を生み出したのです。 ちょうどその頃、 BTS に対して非常に多くの SPAM メールが送られるようになっており、 spamassasin BTS サーバの CPU を非常に多く使うようになっ ていたのです。 そして CPU 大量消費の原因が apt-listbugs にあるという勘違いされてしまったのです (Bug#207415)

よく考えてみると、 1 日で 46,000 個の静的データが負荷をこれほどあげるはずはありません。 秒に換算 すればわずか 0.5 個のだからです。 通常の Web サイトはもっと多くの要求を処理できています。 データ サイズに関してはどうでしょうか。 ひとつのデータは約 100 バイトですから、 これも 50B/s 程度です。 いずれにしてもこの問題の対策として apt-listbugs はサーバへの直接アクセスを禁止されてしまいま した。

とはいえ、 この問題が apt-listbugs によるものであったとしてもなかったとしても apt-listbugs がマス タサーバに直接アクセスするのはあまり良い考えではありません。 そこでこの問題をきっかけに osdn.debian.or.jp にミラーサーバを構築しました。

現在、 1 日に 4500 システムが apt-listbugs を使用しています。 以下のグラフはどれくらいの Debian システムが apt-listbugs を利用しているかを表しています。 X 軸は osdn.debian.or.jp にミラーサイトを 構築した日からの日数、 Y 軸は 1 日に osdn.debian.or.jp にアクセスする IP アドレスの数 です。

PIC

3.4 実装

apt-listbugs はオブジェクト指向スクリプト言語のひとつである Ruby で記述されています。 主に以下の クラスから構成されています。

* Acquire  
 * HTTP  
 * File  
* Parser  
 * CGI  
 * Index  
 * DSA  
 * ReleaseCritical  
* Bug  
* Factory  
 * PackageFactory  
 * StatusFactory  
 * BugsFactory  
* Viewer  
 * SimpleViewer  
 * RSSViewer

3.4.1 Acquire

Acquire はデータを取得するクラスです。 このクラスはサブクラスに対するキャッシュ機構を実装してい ます。 実際の取得メソッド実装されておらず、 サブクラスで実装します。 例えば、 HTTP サブクラ スはデータを http から取得し、 File サブクラスはデータをファイルシステムから取得し ます。

3.4.2 Parser

Parser クラスは Acquire クラスで取得されたデータをパースし、 バグ情報を保持する Bugs クラスを 生成します。 例えば以下の ruby コードは CGI 出力から apt-listbugs のバグ情を取得し ます。

acq = Debian::BTS::Acquire::HTTP.new  
cgi_parser = Debian::BTS::Parser::CGI.new(acq)  
bugs = cgi_parser.parse("apt-listbugs")  
bugs.each do |bug|  
  p bug  
end

- CGI

CGI パーサは bugs.debian.org から取得した CGI 出力をパースします。

- Index

Index パーサは BTS システムの生データである index.db ファイルをパースします。 apt-listbugs のデ フォルトパーサです。

- DSA

DSA パーサは Debian セキュリティアドバイザリのページをパースします。

- ReleaseCritical

ReleaseCritical Release-Critical ページをパースします。

3.4.3 Bug

Bug クラスは ID、 題名、 重要度、 タグ等のバグ情報を保持します。

これらのクラスは汎用的に作成されています。 そのため、 apt-listbugs 以外のプログラムからでもこれ らのクラスを利用することが可能です。

3.4.4 Factory

Factory クラスは「仕様書」 からインスタンスを生成します。 実際の作成はサブクラスによ り行われます。 このクラスは進捗表示等の Factory に汎用的なメソッドのみを実装してい ます。

- PackageFactory

PackageFactory .deb ファイルの一覧からパッケージ情報を生成します。

# creating new packages database  
new_pkgs = Factory::PackageFactory.create(pkgnames) do |msg, val|  
  config.frontend.progress(msg, val) if config.quiet == false  
end  
Factory::PackageFactory.delete_ignore_pkgs(new_pkgs)

この処理が行われている間は、 apt-listbugs から以下のメッセージが出力されます。

パッ ケージフィ ールドを読み込んでいます...

- StatusFactory

StatusFactory は指定したパッケージ名に対するの現在のシステムの情報を取得します。 この処理中は 以下のメッセージが出力されます。

パッ ケージ状態を読み込んでいます...

- BugsFactory

BugsFactory Bug クラスで表現されるバグ情報を生成します。 基本的に、 この Factory はパーサク ラスの単なるラッパーですが、 パーサクラスは一度にひとつのパッケージのみを処理するのに対し、 BugsFactory は複数のパッケージを処理できます。

バグレポートを取得しています...

3.4.5 Viewer

Viewer クラスはバグを表示するビューアを提供します。

- SimpleViewer

SimpleViewer は以下のような処理を行う組み込みの対話的ビューアです。

critical bugs of cron (3.0pl1-86 -> 3.0pl1-87) <done>  
 #282722 - Network install of Debian Woody Alpha -  cron corrupt on debian servers ?  
grave bugs of strace (4.5.8-1.2 -> 4.5.9-1) <done>  
 #294172 - strace - builds no s390 binary  
grave bugs of gaim (1:1.1.2-3 -> 1:1.1.3-1) <done>  
 #295904 - gaim: 1.1.3-1:  dies with SIGABRT on startup  
grave bugs of reportbug (3.7.1 -> 3.8) <done>  
 #295853 - reportbug includes sensitive information in report  
grave bugs of cdbs (0.4.26-4 -> 0.4.27-1) <open>  
 #295884 - cdbs: Changes control file to add new build dependency.  
grave bugs of libdb4.3 (4.3.27-1 -> 4.3.27-2) <open>  
 #294163 - libdb4.3: build failed on hppa  
Summary:  
 strace(1 bug), gaim(1 bug), cron(1 bug), cdbs(1 bug), libdb4.3(1 bug), reportbug(1 bug)  
Are you sure you want to install/upgrade the above packages? [Y/n/?/...]

- RSSViewer

RSSViewer はバグ情報を RSS (Really Simple Syndication) 形式で出力します。

PIC

3.5 問題

現 在 、 apt-listbugs が抱える一番の問題点は、 apt-get upgrade を行うたびに apt-listbugs が大量のバグを 表示してしまうことです。 しかもほとんど役に立たない多くのレポートを読まなければいけません。 それ はそれほど重要でもない問題を重要だとタグ付けされた報告が非常に多いことが原因です。 apt-listbugs changelog ファイル中の ”closes: Bug#XXXX” という形式の文字列を処理するこ とで不要なレポートを表示しないようにしていますが、 上記のようなレポートはパッケー ジ保守担当者によって手動でクローズされてしまうため、 表示から取り除くことはできま せん。

バグには open, done 等の状態があるのですが、 これを使うことはできません。 それはバグの状態とい うのは終局的なシステムだからです。 バグ報告は通常そのバグを修正した新しいパッケージが Debian アップロードされるとすぐにクローズされます。 この段階では、 バグ状態は変更されますが、 そのバグを 修正したパッケージはまだ利用できません。 ミラーサイト使っている場合、 この遅延時間もっと長くなる でしょう。

最初のバージョンの apt-listbugs はレポート文書中に存在する “Version” タグを利用してお り、 これによりいくつかのバグをフィルタすることができていました。 この情報を利用す ると

といったフィルタリングが可能でした。 しかし、 現在は apt-listbugs CGI にアクセスできないため、 この情報を利用することができません。 おそらく Since Fixed-In といったような汎用的なタグ情報が 必要であると考えています。

3.6 Tips

apt-listbugs はいろいろな利用方法があるためここでいくつか紹介します。

3.6.1 RSS によるセキュリティ問題
 
dpkg --get-selections | grep -v deinstall | awk -F’ ’ ’{print $1;}’ | \  
   xargs -n $num /usr/sbin/apt-listbugs -y -q -T security --title \  
   "Security Issues on ‘hostname --fqdn‘" rss

このスクリプトは /usr/share/doc/apt-listbugs/security にあります。

3.6.2 作業中のパッケージで解決していないバグを見る
 
grep -e ^Package:  < debian/control  | cut -d’ ’ -f2- | \  
  xargs /usr/sbin/apt-listbugs -S outstanding,open \  
    critical,grave,serious,important,normal,wishlist,minor list

このスクリプトは /usr/share/doc/apt-listbugs/deblistbugs にあります。

3.7 まとめ

apt-listbugs はまだいろいろ問題を抱えていますが、 基本的な概念は非常におもしろいものです。 現在の 興味は apt-listbugs webrick 等を使って組み込み http サーバを導入することです。 このフロントエン ドを利用すると apt-listbugs の管理が非常に便利になります。 また、 bts2ldap を利用した LDAP バック エンドも必要であると考えています。

3.8 参考

東京エリア Debian 勉強会 2005 _________________________________________________________

PIC