Author Archives: milkcocoa

Rails 3 + Haml で production 環境下でもインデントする

Haml をしようするときれいにインデントがされるから好きなんですが、Rails の production 環境下ではインデントがされません。

Haml2.2からはRailsのproductionでインデントが無いと少数派に呼びかけている – komagata [p0t]

速度が問題になるまではインデントしたいので、上記 komagata さんが書かれているように設定したものの、 Rails 3 では上手く動きませんでした。

config.after_initialize でくくらないといけないみたいです。

Hoge::Application.configure do
  config.after_initialize do
    Haml::Template::options[:ugly] = false
  end
end

これを config/initializers/haml.rb に置きました。 1
config/application.rb や config/environments/production.rb の中でもいいですね(たぶん)。

  1. Hoge は適当なアプリケーション名に置き換えること。 []

Ruby 1.9.2 で aws-s3 を使用できなかった問題の解決策

Ruby 1.9.2 が使いたいなぁと思って、いろいろとやっています。
Amazon S3 を使用したいと思って、手持ちの Mac に定番の aws-s3 をインストールして irb で試してみようとするとエラーが出て使用できませんでした。

marcel’s aws-s3 at master – GitHub

ところが Linux ではちゃんと動きます。
特にバイナリをビルドしている様子もないので、こちらの環境が悪いと判断しました。

環境

  • Ruby 1.9.2 on RVM

エラー内容

irb > require 'aws/s3'
SyntaxError: /Users/piyo/.rvm/gems/ruby-1.9.2-p0/gems/aws-s3-0.6.2/lib/aws/s3/extensions.rb:84: invalid multibyte escape: /[
\x80-\xFF]/
        from :29:in `require'
        from :29:in `require'
        from /Users/piyo/.rvm/gems/ruby-1.9.2-p0/gems/aws-s3-0.6.2/lib/aws/s3.rb:11:in `'
        from :33:in `require'
        from :33:in `rescue in require'
        from :29:in `require'
        from (irb):1 
        from /Users/piyo/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `
'

解決策

.zshrc に RUBYOPT=-Ku が設定されていたので、その設定を外しました。

Lokka を nginx + Unicorn で動かす

Lokka は komagata さんが開発されている、Ruby で書かれた CMS です(旧名 Pyhä)。

以前書いたエントリのように、Lokka も nginx と Unicorn で動かしたいと思います。
cocoa*life – Redmine を nginx + Unicorn で動かしてみる

Lokka は Sinatra ベースなので Sinatra で動かすようにすればいいだけのようです。

Unicorn の設定

Lokka のディレクトリに unicorn.rb というファイルを作成しました。
unicorn.rb は前回の使用したものをほぼそのまま使用しました。

# ワーカーの数
worker_processes 2

# ソケット
listen '/tmp/unicorn-lokka.sock'

# ログ
stderr_path 'tmp/log/unicorn.log'
stdout_path 'tmp/log/unicorn.log'

# ダウンタイムなくす
preload_app true

before_fork do |server, worker|
  old_pid = "#{ server.config[:pid] }.oldbin"
  unless old_pid == server.pid
    begin
      # SIGTTOU だと worker_processes が多いときおかしい気がする
      Process.kill :QUIT, File.read(old_pid).to_i
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end

Unicorn を起動する

unicorn -c unicorn.rb -D

nginx の設定

nginx の設定は以下のようにしました。

upstream unicorn-lokka {
         server unix:/tmp/unicorn-lokka.sock;
}

server {
        listen  80;
        server_name     lokka.local;
        location / {
                if (-f $request_filename) { break; }
                proxy_set_header X-Real-IP  $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_pass http://unicorn-lokka;
        }
}

nginx を再起動する。

/usr/local/nginx/sbin/nginx -s stop
/usr/local/nginx/sbin/nginx

参考文献

Redmine を tag ごとに更新する

バグトラッキングシステムの Redmine を運用しています。

Redmine のレポジトリは以下の github で公開されています。
edavis10’s redmine at master – GitHub

ある程度の間隔で更新していきたいところですが、これは trunk なので、これを追っていくのははばかられます。
更新する場合には tag ごとに更新したい。
いまいちどうやってやればいいのかわからなかったので、わかる範囲でやってみました。

タグの一覧は次のコマンドで見ることができます。

git tag

まず公開レポジトリからタグを取得します。

git pull --tags

タグに対するリビジョンを取得します。

git rev-parse 1.0.2
b5cfe790446f9a6bdd968aa65289873f7668f7da

このリビジョンを checkout します。

git checkout b5cfe790446f9a6bdd968aa65289873f7668f7da

2010/11/10 追記
git rev-parse の部分は必要はなく

git checkout 1.0.2

で問題ありません。

参考文献

Lokka で Google Analytics のトラッキングコードを簡単に挿入するための Helper Plugin を書いてみた

Lokka は komagata さんが開発されている、Ruby で書かれた CMS です(旧名 Pyhä)。
打倒 WordPress を目指しているそうです。

komagata’s lokka at master – GitHub

今後使用しようと思っていて、 Plugin も書けるということで、ちょっと試してみました。
簡単に Google Analytics のトラッキングコードが挿入できる Plugin です。

$LOKKA_ROOT/plugin フォルダに hello というサンプルがあるので、それを見ながら書いてみます。
komagata さんのエントリによれば、 Sinatra Extensions のサブセットだということ。

Pyhaの大体の仕組み – komagata [p0t]
Sinatra: Writing Extensions

$LOKKA_ROOT/plugin/ に google_analytics/lib/google_analytics.rb というファイルを作りました。
そして以下を記述。

module Lokka
  module Helpers
    def analytics(uid)
      haml(<<-script, {})
%script{ :type => "text/javascript" }
  :cdata
    var _gaq = _gaq || [];
    _gaq.push(['_setAccount', '#{uid}']);
    _gaq.push(['_trackPageview']);

    (function() {
      var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
      script
    end
  end
end

モジュール名をどうしたらいいのかわからなかったので、 $LOKKA_ROOT/lib/lokka/helpers.rb を参考に Lokka::Helpers に入れてしまいました。

Rails の感覚だと後は、サーバを再起動すれば動きそうですが、このままでは動きません。
おかしいなぁと思って、プロジェクトを grep してみると、 init.rb にこんな行が。

$:.unshift File.expand_path(File.join(File.dirname(__FILE__), 'plugin', 'hello', 'lib'))

これは同じように入れないといけないんだろうかと、こう書いてみる。

$:.unshift File.expand_path(File.join(File.dirname(__FILE__), 'plugin', 'google_analytics', 'lib'))

そしてもう一カ所、 $LOKKA_ROOT/lib/lokka.rb を見てみると

require 'lokka/hello'

なんて行があるので、同様に

require 'lokka/google_analytics'

と書いたところ、無事に動きました。

Redmine を nginx + Unicorn で動かしてみる

今後のために、一度 Webサーバである nginx と Railsサーバ?の Unicorn を使って Redmine を動作させてみることにしました。
すでに Redmine は Apache + Passenger で動いています。

環境

  • Ubuntu Server x86_64 10.04

Rack のアンインストール

このエントリを書いている時点では Redmine は Rails 2.3.5 で作成されていて、 Rails 2.3.5 は Rack 1.0.1 を使用します。
もし Rack の1.2.1とかがインストールされている場合にはアンインストールしましょう。
でないと、こんなエラーが出て起動しません。
これにだいぶんはまりました。

I, [2010-10-05T14:04:25.155622 #26791]  INFO -- : unlinking existing socket=/tmp/unicorn.sock
I, [2010-10-05T14:04:25.155914 #26791]  INFO -- : listening on addr=/tmp/unicorn.sock fd=3
I, [2010-10-05T14:04:25.156344 #26791]  INFO -- : Refreshing Gem list
Missing the Rails 2.3.5 gem. Please `gem install -v=2.3.5 rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.

Unicorn 0.96 doesn’t play nice with Rails 2.3.5

インストール

$ sudo apt-get install nginx
$ sudo gem install unicorn

Unicorn の設定

設定のほとんどは nginx + Unicorn を試してみた – milk1000cc からのコピペです。

ここで設定するソケットを後で使用します。

$ vi $RAILS_ROOT/config/unicorn.rb
# ワーカーの数
worker_processes 2

# ソケット
listen '/tmp/unicorn.sock'

# ログ
stderr_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT'])
stdout_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT'])

# ダウンタイムなくす
preload_app true

before_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!

  old_pid = "#{ server.config[:pid] }.oldbin"
  unless old_pid == server.pid
    begin
      # SIGTTOU だと worker_processes が多いときおかしい気がする
      Process.kill :QUIT, File.read(old_pid).to_i
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end

after_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

設定ができたら Unicorn を起動します。

$ unicorn_rails -c config/unicorn.rb -E production -D

nginx の設定

http にきたものはすべて https に転送するようにしているので、設定は以下のようになります。

upstream unicorn の部分で設定するものは、先ほどの unicorn.rb で設定したソケットです。
最下行から2行目の proxy_pass で設定する部分は、最上位の upstream hoge の hoge になります。

$ vi /etc/nginx/sites-available/redmine
upstream unicorn {
         server unix:/tmp/unicorn.sock;
}

server {
        listen          80;
        server_name     example.com; 
        rewrite ^/(.*) https://example.com/$1 permanent;
}

server {
        listen  443;    
        server_name     example.com;

        root            /var/www/redmine/public;
        error_log       /var/www/redmine/log/error.log;

        ssl  on;
        ssl_certificate  /etc/nginx/ssl/apache.pem;
        ssl_certificate_key  /etc/nginx/ssl/apache.pem;
        
        ssl_session_timeout  5m;
        ssl_protocols  SSLv2 SSLv3 TLSv1;
        ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
        ssl_prefer_server_ciphers   on;

        location / {
                if (-f $request_filename) { break; }
                proxy_set_header X-Real-IP  $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_pass http://unicorn;
        }
}

サーバのスタート

$ sudo ln -s /etc/nginx/sites-available/redmine /etc/nginx/sites-enabled/redmine
$ sudo /etc/init.d/nginx start

参考文献

devise で Basic 認証をする

devise は高機能な Rack ベースの認証システムだそうです。
plataformatec’s devise at master – GitHub

よくあるログイン画面を表示して認証する方式もありますし(これはなんというのだろう?)、いろいろな認証方式を使用することができるようです。

今回、お試しサイトを作る必要があって Basic 認証を使用することにしました。
その方法をググってもいまいちわからなかったので、ここに記載しておくことにします。
しかしながらこれで使い方があっているのかどうか、いまいち自身がないので間違っている場合には、ご指摘をお願いします。

devise では通常以下のようなコードで認証を必須にできます。

class ArticlesController < ApplicationController
  before_filter :authenticate_user!
end

以下のページによると HTTP を使用した認証にはこんな風に書いてあります。
How to: use http authentication – devise – GitHub

def http_authenticate
  authenticate_or_request_with_http_digest do |user_name, password|
    user_name == "foo" && password == "bar"
  end
  warden.custom_failure! if performed?
end

今回はパスワードは固定ではないので、えいやとこれだけにしてみました。

class ArticlesController < ApplicationController
  before_filter :authenticate_user!

  def http_authenticate
  end
end

思った通りに Basic 認証で認証することができるようになりました。

Capistrano with Bundler and RVM

最近、新しい Rails サーバを立ち上げる必要が出てきて、一から Capistrano によって deploy をする必要に迫られました。

Capistrano についてはいろいろなところで良質な記事があるので、それ自体を使うのは難しくはないと思うのですが、 RVM や Bundler を使用した環境で使用する場合に結構はまってしまったので、記録しておこうと思います。

サーバ側で RVM を使用する場合

RVM: Ruby Version Manager – RVM with Crapistrano を参照し、Ruby 1.9.2 を使うのであれば、以下の3行を deploy.rb に書き加えます。

$:.unshift(File.expand_path('./lib', ENV['rvm_path']))
require "rvm/capistrano"
set :rvm_ruby_string, '1.9.2'
set :rvm_type, :user

deploy 時に Bundler で Gem を更新する場合

deploy 時に bundle install で Gem をインストールしてほしいと思います。

大前提として、 Bundler を最新版にしておくことが重要です。
自分の場合、古いバージョンが入っていて上手く動きませんでした。

config/deploy.rb に

require "bundler/capistrano"

と書いておけば、 deploy 時に標準では shared/bundle フォルダに bundle install をしてくれます。

FreeBSD 8.1にavahiをインストールした

FreeBSDでBonjour (Zero Configuration Networking)を使用したかったのですが、インストールしようとするといろいろと無駄なものが入るので、なるべく削った状態でインストールしたいというのが積年の思いでした。

avahi 0.6.25まではどうしてもコンパイルがうまくいかなかったのですが、0.6.27になって(もしかしたら0.6.26でもいいのかも?)無事インストールができました。

$ wget http://avahi.org/download/avahi-0.6.27.tar.gz
$ tar zxf avahi-0.6.27.tar.gz
$ cd avahi-0.6.27
$ ./configure --disable-glib --disable-gobject --disable-qt3 --disable-qt4 --disable-gtk --disable-dbus --disable-python --disable-mono --disable-autoipd --disable-gdbm --disable-gtk3 --disable-monodoc
$ gmake
$ sudo gmake install

gmakeを使わないと

sed -e 's,@sbindir\@,/usr/local/sbin,g'  > avahi-daemon.sh

というところで止まってしまいます。

あと行うべきことは2点。

  • /etc/rc.conf に avahi_daemon_enable=”YES” を記述する。
  • user/group に avahi を追加する。そうしないと
    Failed to find user 'avahi'.

    と怒られて起動ができません。

参考文献

NetBSD on KuroBox : Instal the avahi

ZFS(raidz2 + spare)での修復の実際

家で使用している、ファイルサーバはFreeBSD 8.0とZFSを使用して構築したものです。
先日、接続すると上手く反応してくれなくなっていたので、調べてみたら一つのディスクがエラーを出している様子。

環境は以下のようになります。
da0: Seagate ST3500410AS
da1 – da7: HGST HDP725050GLA360
新しいHDD: HGST HDS721010CLA332

ログは確かこんな感じ(消してしまったので適当に細工)。

# zpool status
  pool: pool state: DEGRADED
status: One or more devices has experienced an unrecoverable error.  An
        attempt was made to correct the error.  Applications are unaffected.
action: Determine if the device needs to be replaced, and clear the errors
        using 'zpool clear' or replace the device with 'zpool replace'.
   see: http://www.sun.com/msg/ZFS-8000-9P
 scrub:  none requested
config:

        NAME        STATE     READ WRITE CKSUM 
        pool        DEGRADED     0     0     0 
          raidz2    DEGRADED     0     0     0 
            da1     ONLINE       0     0     0  81.1M resilvered
            da2     ONLINE       0     0     0  81.1M resilvered
            da3     DEGRADED   209  449K     0 
            da4     ONLINE       0     0     0  81.1M resilvered
            da5     ONLINE       0     0     0  81.1M resilvered
            da6     ONLINE       0     0     0  81.1M resilvered
            da7     ONLINE       0     0     0  81.1M resilvered
        spares
          da0       AVAIL

da3の調子が悪いみたいです。
こんなときにと用意していた、ホットスペアは勝手に使用してくれない様なので、手動でreplaceします。

# zpool replace da3 da0
# zpool status
  pool: pool state: DEGRADED
status: One or more devices has experienced an unrecoverable error.  An
        attempt was made to correct the error.  Applications are unaffected.
action: Determine if the device needs to be replaced, and clear the errors
        using 'zpool clear' or replace the device with 'zpool replace'.
   see: http://www.sun.com/msg/ZFS-8000-9P
 scrub: resilver completed after 2h14m with 0 errors on Thu Jul  1 03:24:59 2010
config:

        NAME        STATE     READ WRITE CKSUM 
        pool        DEGRADED     0     0     0 
          raidz2    DEGRADED     0     0     0 
            da1     ONLINE       0     0     0  81.1M resilvered
            da2     ONLINE       0     0     0  81.1M resilvered
            spare   DEGRADED     0     0     0 
              da3   OFFLINE    209  449K     0 
              da0   ONLINE       0     0     0  152G resilvered
            da4     ONLINE       0     0     0  81.1M resilvered
            da5     ONLINE       0     0     0  81.1M resilvered
            da6     ONLINE       0     0     0  81.1M resilvered
            da7     ONLINE       0     0     0  81.1M resilvered
        spares
          da0       INUSE     currently in use

このままだとずっとdegradedという嫌な表示が出たままなのでda3を切り離します。

# zpool detach pool da3

いったんマシンの電源を落とし、新しいHDDを入れて起動すると

# zpool status
NAME        STATE     READ WRITE CKSUM
pool        UNAVAIL      0     0     0  insufficient replicas
  raidz2    UNAVAIL      0     0     0  insufficient replicas
    da1     ONLINE       0     0     0
    da2     ONLINE       0     0     0
    da0     ONLINE       0     0     0
    da4     FAULTED      0     0     0  corrupted data
    da5     FAULTED      0     0     0  corrupted data
    da6     FAULTED      0     0     0  corrupted data
    da7     UNAVAIL      0     0     0  corrupted data

となってしまい、使用できない状態。
どうなっているのかを調べてみると、da3 => da7になり、da4以降が一つずつ前にずれている状態。
先でda3はdetachされているので、da4だったda3が見えていないと。

HDDのScan Orderは変えられないし、どうしたものかと悩んで調べていたら、ただ単純にexportしてimportすれば良いだけということがわかりました。

# zpool export pool
# zpool import pool
# zpool status
  pool: pool
 state: ONLINE
 scrub: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        pool        ONLINE       0     0     0
          raidz2    ONLINE       0     0     0
            da1     ONLINE       0     0     0
            da2     ONLINE       0     0     0
            da0     ONLINE       0     0     0
            da3     ONLINE       0     0     0
            da4     ONLINE       0     0     0
            da5     ONLINE       0     0     0
            da6     ONLINE       0     0     0

めでたく戻ってる!
最後は、spareはspareに戻しました。

# zpool replace pool da0 da7
# zpool status
  pool: pool
 state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
        continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
 scrub: resilver in progress for 0h47m, 40.25% done, 1h10m to go
config:

        NAME           STATE     READ WRITE CKSUM
        pool           ONLINE       0     0     0
          raidz2       ONLINE       0     0     0
            da1        ONLINE       0     0     0  31.1M resilvered
            da2        ONLINE       0     0     0  31.1M resilvered
            replacing  ONLINE       0     0     0
              da0      ONLINE       0     0     0
              da7      ONLINE       0     0     0  61.4G resilvered
            da3        ONLINE       0     0     0  31.0M resilvered
            da4        ONLINE       0     0     0  31.0M resilvered
            da5        ONLINE       0     0     0  31.0M resilvered
            da6        ONLINE       0     0     0  31.0M resilvered
# zpool add pool spare da0
# zpool status
  pool: pool
 state: ONLINE
 scrub: resilver completed after 2h21m with 0 errors on Sat Jul  3 07:07:19 2010
config:

        NAME        STATE     READ WRITE CKSUM
        pool        ONLINE       0     0     0
          raidz2    ONLINE       0     0     0
            da1     ONLINE       0     0     0  79.7M resilvered
            da2     ONLINE       0     0     0  79.6M resilvered
            da7     ONLINE       0     0     0  152G resilvered
            da3     ONLINE       0     0     0  79.6M resilvered
            da4     ONLINE       0     0     0  79.6M resilvered
            da5     ONLINE       0     0     0  79.6M resilvered
            da6     ONLINE       0     0     0  79.6M resilvered
        spares
          da0       AVAIL   

errors: No known data errors

らくちんらくちんです。

参考文献