Capistranoで(一括)apt-getする

久しぶりにCapistranoをさわり始めた。前から考えていたシステム管理的な用途に使ってみようという、半分はネタというか興味で、もう半分は実用を考えている話。Puppetも検討中というか、試しながら運用しているのだけど、パッケージ更新なんかは手で動かしたいなというのがあって。もちろんpuppetrun運用ならおおむね「手で」動かす感じにはなるのだけろうけど、まだ、その辺りの感覚がつかめていない。というようなこともあり、手を出しやすそうなCapistranoで(も)試してみている。

で、だいたいこんな感じで動くようになった:

$ cap apt:list HOSTS=host1
You are running Ruby 1.8.6, which has a bug in its threading implementation.
You are liable to encounter deadlocks running Capistrano, unless you install
the fastthread library, which is available as a gem:
   gem install fastthread
  * executing `apt:list'
  * executing "apt-get -qq -s -o Debug::NoLocking=true upgrade  | grep '^Inst ' || true"
    servers: ["host1"]
  * establishing connection to `host1'
    connected: `host1'
    [host1] executing command
    command finished
[ host1 ] libpcre3 libsnmp-base libsnmp9 snmpd
$ cap apt:upgrade HOSTS=host1 PACKAGES=snmpd,libsnmp9
[...]
  * executing `apt:upgrade'
  * executing "apt-get -qq -s -o Debug::NoLocking=true upgrade  | grep '^Inst ' || true"
    servers: ["host1"]
  * establishing connection to `host1'
    connected: `host1'
    [host1] executing command
    command finished
  * executing "/usr/bin/apt-get -q -y -s -o Debug::NoLocking=true install libsnmp9 snmpd"
    servers: ["host1"]
    [host1] executing command
 ** [out :: host1] Reading package lists...
 ** [out :: host1] 
 ** [out :: host1] Building dependency tree...
 ** [out :: host1] 
 ** [out :: host1] The following extra packages will be installed:
 ** [out :: host1] libsnmp-base
 ** [out :: host1] The following packages will be upgraded:
 ** [out :: host1] libsnmp-base libsnmp9 snmpd
 ** [out :: host1] 3 upgraded, 0 newly installed, 0 to remove and 23 not upgraded.
 ** [out :: host1] Inst libsnmp-base [5.2.3-7] (5.2.3-7etch2 Debian-Security:4.0/stable, Debian:4.0r3/stable)
 ** [out :: host1] Inst libsnmp9 [5.2.3-7] (5.2.3-7etch2 Debian-Security:4.0/stable, Debian:4.0r3/stable)
 ** [out :: host1] Inst snmpd [5.2.3-7] (5.2.3-7etch2 Debian-Security:4.0/stable, Debian:4.0r3/stable)
 ** [out :: host1] Conf libsnmp-base (5.2.3-7etch2 Debian-Security:4.0/stable, Debian:4.0r3/stable)
 ** [out :: host1] Conf libsnmp9 (5.2.3-7etch2 Debian-Security:4.0/stable, Debian:4.0r3/stable)
 ** [out :: host1] Conf snmpd (5.2.3-7etch2 Debian-Security:4.0/stable, Debian:4.0r3/stable)
    command finished
$ cap apt:upgrade HOSTS=host1 PACKAGES=snmpd,libsnmp9 APT_DRY_RUN=false
[...]
  * executing `apt:upgrade'
[...]
  * executing "sudo -p 'sudo password: ' /usr/bin/apt-get -q -y install libsnmp9 snmpd"
    servers: ["host1"]
    [host1] executing command
Password: 
 ** [out :: host1] 
 ** [out :: host1] Reading package lists...
 ** [out :: host1] 
 ** [out :: host1] Building dependency tree...
 ** [out :: host1] 
 ** [out :: host1] The following extra packages will be installed:
 ** [out :: host1] libsnmp-base
 ** [out :: host1] The following packages will be upgraded:
 ** [out :: host1] libsnmp-base libsnmp9 snmpd
 ** [out :: host1] 3 upgraded, 0 newly installed, 0 to remove and 23 not upgraded.
 ** [out :: host1] Need to get 0B/3885kB of archives.
 ** [out :: host1] After unpacking 147kB disk space will be freed.
 ** [out :: host1] Preconfiguring packages ...
 ** [out :: host1] (Reading database ...
 ** [out :: host1] 28284 files and directories currently installed.)
 ** [out :: host1] Preparing to replace libsnmp-base 5.2.3-7 (using .../libsnmp-base_5.2.3-7etch2_all.deb) ...
 ** [out :: host1] Unpacking replacement libsnmp-base ...
 ** [out :: host1] Preparing to replace libsnmp9 5.2.3-7 (using .../libsnmp9_5.2.3-7etch2_i386.deb) ...
 ** [out :: host1] Unpacking replacement libsnmp9 ...
 ** [out :: host1] Preparing to replace snmpd 5.2.3-7 (using .../snmpd_5.2.3-7etch2_i386.deb) ...
 ** [out :: host1] Stopping network management services:
 ** [out :: host1] snmpd
 ** [out :: host1] snmptrapd
 ** [out :: host1] .
 ** [out :: host1] Unpacking replacement snmpd ...
 ** [out :: host1] Setting up libsnmp-base (5.2.3-7etch2) ...
 ** [out :: host1] 
 ** [out :: host1] Setting up libsnmp9 (5.2.3-7etch2) ...
 ** [out :: host1] 
 ** [out :: host1] Setting up snmpd (5.2.3-7etch2) ...
 ** [out :: host1] Starting network management services:
 ** [out :: host1] snmpd
 ** [out :: host1] .
 ** [out :: host1] 
    command finished
$ cap apt:list HOSTS=host1
[...]
  * executing `apt:list'
  * executing "apt-get -qq -s -o Debug::NoLocking=true upgrade  | grep '^Inst ' || true"
    servers: ["host1"]
  * establishing connection to `host1'
    connected: `host1'
    [host1] executing command
    command finished
[ host1 ] libpcre3 linux-image-686 nagios-plugins-basic

ここではHOSTSで一ホストだけ指定しているけれど、指定しなければCapfileで定義されている全ホストで実行される(はず)。全ホストで更新しなければならないパッケージのリストをとったりとか、一度に更新をかけたりとか(ただし更新については設定によらず並列実行を行わないようにしている)。

問題はapt-listchangesやapt-listbugsが動くような場合。sudoのパスワード入力の関係でset :defaultrunoptions, :pty => trueが必になるのだけど、こうするとapt-listchangesなどが対話的な入力を求めてくるようになる。回避するとなると、おそらく以下のずれかが必要となる。

  • sudoパスワードをCapfileに書いておき、set :default_run_options, :pty => falseにする
  • sudoに対してCapistranoが行っているのと同じように、apt-listchangesなどに対しても問い合わせプロンプトを検出して対話的入力をエミュレートする
  • その他……?

一つめはナシではないけど制限がきつくなるのでやめて、今のところは二つめを実装して様子を見ている。apt-getのコマンドラインでDPkg::Pre-Install-Pkgsリストから指定した項目削除する指定ができると良いのだけど、ざっと見た感じではそういう機能はなさそう(lib-apt-pkgレベルではインタフェースが用意されている)。もっとも、この手のツールを適用するホストにいちいちapt-listchangesだのをインストールしているということはないといえばないのだけど(debconfはうまくコケてくれているみたい)。