2011-12-21

Redmineバージョンアップ記録

Redmine Advent Calendar jp 2011 の21日目の記事になります。

前回のPOSTで、「(バージョンアップ)移行の顛末は、何かで発表したいなあと思います」と書いておきましたが、今回話題が思いつかなかったことと、本当は勉強会でお話しできるといいのですが、参加自体が難しいので、アドベントカレンダーに便乗して書かせていただきます。

長めになってしまい申し訳ないのですが、こんな流れになっています。

  1. 移行前後の実行環境
  2. 移行の準備 / 動作確認
  3. nginx + unicornについて
  4. ログのローテーション
  5. 移行後のフォロー
  6. まとめ

1. 移行前後の実行環境

移行前は、Redmine 0.9.xを利用していました。

1系が出てからだいぶ経つので、バージョンアップはしたいなあ~と思っていたものの、本体ソースにカスタマイズ分が入っていたり、ユーザが増加していたため、なかなか移行に切り出せませんでした。(管理は別の方の担当だったので)

大きな問題はなかったので、そのまま利用していたのですが、PDF出力の利用が増えるに伴い、ある特定のチケットのPDFを出力しようとするとCPUが回りっぱなしで、あげくにタイムアウトしてしまうという状況が発生するようになりました。

さすがにこれでは困る、ということで、リソースの見直しも含めてバージョンアップの検討に入りました。

2. 移行の準備 / 動作確認

今回はRailsの実行環境も大幅に違います。本番サーバには不足しているライブラリがたくさんありましたが、インターネットからのダウンロードは使えない状況。OSも32bitだったので、別サーバで環境を用意し、DNS切り替えで新環境への移行という方法を取りました。

まずはRedmine0.9に対してカスタマイズした部分の洗い出し、新バージョンでのプラグインの互換性のチェックを行いました。
Redmine本体のバージョンが上がったため機能が向上し、プラグインでカバーする必要が無くなったものもあるので、利用しなくて良さそうなプラグインは削除。管理に役立ちそうなプラグインは追加で導入しました。

また、カスタマイズしていた部分は、出来るだけ自作プラグインや自作テーマという形で置き換えるようにしました。このあたりは、r-labsの記載や既存のソースを参考にさせていただきました。

その上で、どうしても本体をカスタマイズしないといけない部分は、Redmine本家に取り込んでもらえるようにお願いをしたりしました。

問題なくバージョンアップが出来るか、もちろん、テスト環境で本番のデータをコピーして検証をし、ユーザさんにもお願いして不具合の洗い出しを行っています。不具合や要望はRedmineのフォーラムに届け出てもらうようにしました。

最低限の本体へのカスタマイズ(1行だけ)で、あとはプラグインでの対応が可能との目処がついたので、いよいよ本番切り替えの準備。

データの同期とDNSキャッシュのクリアの時間を鑑み、ユーザさんには一定時間Redmineが使えませんよ、とのお知らせをしています。

その上で、移行日までは、正常にマイグレーションや起動ができるか、本番サーバと同じネットワーク上で切り替え予定のサーバを待機させて、定期的にファイル・DBの同期とRedmineのMigration、メッセージの書き換えを行い、読み取り専用で稼働させて、直近のデータを搭載しても問題ないかのチェックを行いました。

redmine

2011-12-15

SSHでスレーブを起動する時の注意

Jenkinsで、master / slave構成にし、SSHでログインしてスレーブのアカウントでジョブを実行しようとしても、なんだか環境変数がうまく引き継がれないとき…。

非対話モードでのログインになるので、~/.bash_profile (/etc/bash_profile)  じゃなくて、~/.bashrc  (/etc/bashrc) の方を見に行きます。

通常ログインして操作できてるのに、Jenkinsからだとうまくいかない、環境変数が引き継がれないなあ、なんて時は、ご注意を。

#私はJenkinsのスレーブのログで気が付きました。( /etc/bashrc を参照していたので)

2011-12-09

Translation Assistance Pluginの効果がイケてるらしい

先月、Translation Assistance Pluginについて書いたのですが、川口さんがその件についてコメントを下さいました。ありがとうございます!

川口さんの教えて下さった記事を見てみました..。

『このプラグインを導入して3か月が立ち、フィードバックを取り込む機会が来ました。結果はとっても目を見張るものがありました』、とのことです。

凄いですねー!

以下、ざっくりですが内容を書いてみました。(そもそも川口さんが書かれたものなので、わたしが勝手な解釈も含みつつ取り上げるのも、おこがましいのですが..)

* * *

それまでは、26か国語に対応をしつつも、それなりに充実度はバラつきがありました。(フランス、日本、ドイツに関してはかなり充実していますが)

プラグイン導入後は、17か国語が新たに加わり、40か国語に関してアップデートを行い、トータル43か国語へ対応することになりました。

新たに加わった言語はアラビア語(ただし、まだJenkinsは右から左への表記には対応していません)、エスペラント語、ヘブライ語、中国語(繁体字&簡体字どちらも)、韓国語などです。

この作業を通して、ヘブライ語やインドネシア語、イディッシュ語、ヘブライ語についてはJenkinsの表示がきちんとされなくなってしまうという課題を見つけました。

これらの変更は1.443以降に適用されます。また、今後、もっと頻度を上げて早めに取り込めるようにしていく予定です。

ローカライズにご協力下さったみなさん。本当にありがとう!そして、まだまだよろしくおねがいします!

ローカライズを通しての(Jenkinsへの)貢献は、非常に簡単です!
ローカライズ作業について、さらにもっとご興味があれば、こちらのWikiページを見て、プロジェクトのコミッタの皆さんにリクエストをしてみて下さい。

コードを書かなくても、みなさんはローカライズを通して、OSSの活動に貢献することができます。

* * *

そういえば、Hudson勉強会の時に、プラグインのローカライズについて先駆けてLTされていた、@itouakihiro (akihirox) さんのお話しも思い出しました。

コードを書いたり、ローカライズのお手伝いをしたり、Donationでの貢献など、いろいろな形で参加できるんですね。

機械的に翻訳するのではなく、動作がちゃんとわかったうえでの翻訳はとても有難いです。意味がよく分からず、「これどういうことなんだろう」と思いながら試すのも、また楽しいものではありますが:)

    2011-12-08

    外部ジョブの監視も使ってみよう!

    Jenkins Advent Calender 2011 8日目担当の、@akiko_pusuです。よろしくお願いします!

    私の場合は、Jenkinsを正統派CIツールとして使っているのではなくて、雑多なCronジョブや定型化できる作業(バックアップやリストア、リカバリなど)の管理 / 実行 / 記録のために使っています。

    作成するジョブはフリースタイルのプロジェクトで、かつ、Shell ScriptやDOSコマンドを使って処置するものがほとんど。

    ただし、「外部ジョブの監視」というタイプでのCronジョブのチェックも行っています。今回はこのタイプについてのお話しを書いてみようと思います。

    内容は、下記の通りです。
    1. 機能の説明
    2. どうやってPOSTしているの?
    3. javaを使わずにShell + curlでPOSTしてみる
    * * *


    1.機能の説明


    地味な機能?だとは思いますが、『Cronジョブのメールが届き過ぎて、全然チェックしないままになっている。そういうことが積み重なって、実際のところエラーがあったのに見落としてしまった…』というようなパターンには、有効だと思います。

    作り方は簡単で、「外部ジョブの監視」を選んで、タイトルと説明、記録をどれだけ残すかを設定するだけです。

    external-job

    JenkinsのWikiを参考にかいつまんで言うと、Jenkinsのマスタノードをトリガにせず、マスタ / スレーブの設定も行わずに、任意のホスト上でジョブを実行し、JenkinsのプロジェクトのURLに結果をPOSTし、記録のみを行う、ということになります。

    jenkins

    Jenkinsはジョブの結果を受け取る場所だけを用意し、XMLの形式でPOSTが届いたら、せっせとその記録を蓄積するだけです。

    ステータスコードによるジョブの失敗/成功の判定と、実行記録を蓄積するのみなので、結果を受けてJenkinsマスタノードが次のステップを呼び出したり、プラグインによる色々な操作につなげる…といったことは出来ません。

    ですが、少なくとも、自分のメールボックスをCronの通知でいっぱいにさせることもなくなるし、自分以外の管理者との情報共有も可能になります。通知のMAILTOの設定もaliasを使ったりすると面倒なのですが、それもしなくて良くなります。

    また、RSS、最新の成功/失敗ジョブの記録は、フリースタイルやMavenプロジェクトタイプと同じように固定URLで取得できるので、このURLを定期的にチェックして、次のアクションを起こせるように、Jenkins自身で別のジョブを作ればいいのかもしれませんね。

    2.どうやってPOSTしているの?


    JenkinsのWikiを参考にすると、こんなかんじです。


    1. jenkinsのjenkins-core.jar を使って、実行したいスクリプト (Shellや*.bat) を引数に指定してあげて、javaからラップして実行する。
    2. スクリプトの結果(出力とステータスコード)をjavaのプログラムが受け取り、XMLのフォーマットに変換する
    3. XMLをJenkinsの指定のジョブにPOSTする。
    4. Jenkins側がXMLを受け取って、ビルドの記録として蓄積。結果は<result/>を参照して判断。(ただし、結果をhexBinaryで変換する必要がある

    要は、所定のフォーマットのXMLで結果をPOSTすればいい、ということになります。

    シェルの結果からXMLに変換しJenkinsにPOSTする部分をjenkins-core.jarが担っているのですが、このケースだとjavaを使う必要がありますし、jenkins-core.jarも実行環境に配置しておかないといけません。

    サーバ、マシンの環境によってはjavaを入れていない、使えないケースもあるかと思いますが、とにかくXMLをPOSTすればいいので、javaとjenkins-core.jarを必ずしも使う必要は無かったりします。

    3. javaを使わずにShell + curlでPOSTしてみる



    JenkinsのPOST用のXMLはそんなに複雑なフォーマットではありません。
    XML生成専用のライブラリを使ってGenerate…なんてことはせずに、単純に文字列を連結するだけでも大丈夫。

    また、httpでのPOSTも、Unixの環境ならwgetやcurlが利用できます。

    下記に、Jenkins側にローカルホスト内のジョブやスクリプトの実行結果を通知するための、ラッパースクリプトを作って置いてみました。(と言っても、hudsonのラッパーを作成して下さっていたBlogエントリがあったので、そちらを利用したものですが…)

    ソース: https://github.com/akiko-pusu/misc/blob/master/misc/jenkins_wrapper.sh
    参考にしたサイト: http://blog.markfeeney.com/2010/01/hudson-external-jobs-wrapper-script.html 

    実行例は下記の通りです。
    jenkins_wrapper <jenkins_url> <job名> <script>

    % jenkins_wrapper http://jenkins.myco.com:8080 \ testjob /path/to/script.sh
    
    
    ※ tempファイルを作成するため、実行ユーザに /tmp の書き込み権限があるかをチェックして下さい。また、既存のシェルスクリプトを指定してうまく動かない場合は、フルパスで指定してみて下さい。もし、すでに、こんなCronがあったとしたら、ラッパースクリプトを使って置き換えるだけでOKです。

    #00 02 * * * /pasth_to/myscript.sh
    00 02 * * * jenkins_wrapper.sh jenkinsのURL job名 /pasth_to/myscript.sh


    TODO:

    Jenkinsのバージョンが上がって、XMLにもう少し説明を追加できるようになっているので、このラッパースクリプトもちょっと修正が必要です。また、認証付きのジョブになっている場合は、username & passwordも付加しないといけないので、こちらも対応できるようにしたいなと思っています :)

    また、ぜひ、Windows環境下に適応したラッパー書いてくださる方を募集します!(PowerShell大歓迎!そこまでの技量がなくて申し訳ないです...)

    * * *

    おわりに


    マスタ/スレーブの形が利用できない環境では、最初はわたしも jenkins-core.jar を使ってjavaでラップしていたのですが、Shellのみに置き換えたところ、cronの調整も楽になりました。(Blogを書いてくださった Markさんのおかげです!)

    Hudson時代も含め、Jenkinsさんにはとてもお世話になっていて、川口さんのおっしゃっている、『人間の貴重な時間』を、有効に使えるようになりました。

    #子どもたち、家族との時間も、急な対応に邪魔されずにすむようになりました。

    before

    みなさんも、ビルドだけでなく、どんどん定型ジョブや定型化できそうな作業を、Jenkinsに置き換えてみて下さい。また、記録もJenkinsさんにお任せしてみて下さい。
    なんでもないと思っていたcronの結果からも、記録し続けることで何かもっと改善できるヒントが見つかるかもしれません。

    @kiy0takaさんのX’masプラグインにめげずに、みなさんが良い年末年始を過ごせますように…。

    * * *

    次は@leather_soleさんになります。どうぞよろしくお願いいたします!

    2011-12-06

    チケットが消えちゃう??

    Redmine Advent Calendar jp 2011 の6日目を担当させていただきます、宜しくおねがいします!

    それまで使っていたRedmine0.9.xから、なんとか1.2.1までバージョンを上げて半月ほど。
    Apache + Passengerという環境から、nginx + unicornに実行環境を変えたため、リソース面でのtry & errorはあったものの、なんとか大きな不具合もなく動いてくれているようです。(移行の顛末は、何かで発表したいなあと思います

    今回は、そんなバージョンアップ作業中に遭遇した出来事について書かせていただきます。

    * * *

    ユーザさんにお願いして、切替え予定機上で、1.2.1での動作確認や機能の違いをチェックしてもらっていた時のこと。

    「たかのさん、チケットが消えちゃうんです!」※akiko_pusuのことです。

    バージョンアップの予定は明後日に迫っています。

    プラグインやカスタマイズした部分の動作確認が済んで、データのインポートとMigrationの工程もJenkinsを使って準備OKになっていた時期です。しかも、退社直前だったので、『あー、お迎えに送れちゃう!!』と思いながら、届け出てくれたユーザさんと一緒に現象を確認すると…。

    チケットが削除されちゃう、という不具合ではないのですが、「IE8でチケット一覧からチケットのリンクを選択したら、チケットが表示されなくなってしまう」という症状。

    私はIE9を利用していたんですが、言われたとおりにしてみると、確かに再現します。

    1. どんな状況で起こるの?

    • IE (8 and 9) を利用している。
    • チケット一覧やロードマップなど、リンク付きのチケット一覧+コンテキストメニュー(右クリック)が利用できる箇所。
    • CSSの .hascontextmenu { cursor: context-menu; } が指定されている範囲にあるセル (<td></tyd>)

    2. 再現方法は?

    • チケット一覧 or ロードマップ一覧を表示。
    • チケットの列のうちのどれか一項目を、Drag&Dropで選択する。(文字列のコピーを行う時のように、Drag&Dropで選択します)
    • 選択した後、いったんマウスのボタンを離して選択解除する。
    • 選択した部分の文字列が消えてしまう。
    • HTML的なソースは変わらないが、画面からは見えなくなってしまう & 文字があった場所はブランクになって選択できない。

    チケット一覧では<td></td>に挟まれたセル単位で消えてしまいますが、ロードマップの場合はチケットの行そのものを「選択 –> 選択解除」すると、1行分丸ごと見えなくなってしまいます。
    下記は、ロードマップでの例です。(Redmine本家です)

    context

    CSSの、.hascontextmenu { cursor: context-menu; } のスタイルが適用されている箇所では、右側に小さいコンテキストメニューを示すアイコンがくっついたカーソルが表示されます。
    次に、Copy&Pasteの要領で、コンテキストメニューが有効な範囲にある項目を選択します。

    context-2

    選択して、すぐに解除すると、選択した範囲の文字が消えてしまいます!

    context-3

    ロードマップの場合は、列ごと消せました。
    地道に遊んでみると、全部消せちゃったりします…。

    context-4

    Redmineはずーっと使っているし、IE中心の生活だったのですが、これには全く気が付いていませんでした。発見した方、凄い~と思ってしまいました!(もしかして、もうみなさんご存じだったかな…)

    「インストールしたプラグインや、表示のテーマ、あるいはカスタマイズした部分のせい?」と思い、素のRedmineや、Redmine.org(本家)、お世話になっている r-labs さまのところでも試してみたのですが、やっぱり再現。

    実際にチケットが削除されるわけではなく、表示されなくなってしまうというもののため、不具合というよりは、IEの問題だろうということで、ひとまず発見した方、関係者の間で閉じておきました(^^;

    私はCSSには詳しくないので、理由が判る方がいらしたら、ぜひフィードバックをお願いいたします!

    さすがにこんな内容ではTipsにならずに申し訳ないので、Redmineのパスワードのリセット方法を紹介します。

    * * *

    Adminのパスワードが分からなくてログインできない!

    adminアカウントでログインしたいんだけど、パスワード何だったかなあ…。
    移行の際にこんなトラブル?にも遭いました。

    で、困っていたら、redmine.jpにリセット方法が書いてありました

    こちらは、script/consoleを利用する方法です。データベースを直接Updateしなくても大丈夫。
    (この時点で、自分だけが知っているTips、にはならないかもしれませんが…)

    # ruby script/console production
    Loading production environment (Rails 2.3.11)
    >> admin = User.find_by_login(‘admin’)
    => #<User id: 1, login: "admin", hashed_password: "xxxxxxxxxxxxxxxxxxx", firstname: "Redmine", lastname: "Admin", mail: "admin@somenet.foo", admin: true, status: 1, last_login_on: "2010-02-19 13:14:19", language: "ja", auth_source_id: nil, created_on: "2008-09-29 11:51:33", updated_on: "2010-02-19 13:14:19", type: "User", identity_url: nil, mail_notification: "only_my_events", salt: "">
    >> admin.password = ‘xxxxx’
    => "admin"
    >> admin.save! #saveをお忘れなく。=> true
    >> quit

    RAILS_ENV=productionとしても同じく操作できるようです。

    実は、パスワードリセットの羽目になるまで、script/console って、使ったことがありませんでした。
    わざわざWebのUIからアクセスしなくとも & MySQLのSQL文を使わなくとも、モデルの値の操作とか出来てしまうんですね、便利!(今頃言うのは恥ずかしいけど…)

    LDAPなどの認証方式を変える場合は、こちら。(LDAP接続から内部認証方式に切り替えています)

    >> user1 = User.find_by_login(‘user1@test.xxxx’)

    >> user1.auth_source_id = nil
    => nil
    みんなのパスワードと認証方式を変えちゃう場合は、こんなかんじです。
    >> @users = User.all
    >> for user in @users
    >>   user.password = “……”
    >>   user.auth_source_id = nil
    >>   user.save!
    >> end

    ユーザさん毎にできる動作や表示される内容が違うので、検証する際にはこの方法を使ったりしています。 こんなくらいですが、なにかのお役に立てれば幸いです…。

    * * *

    次は@naitohさんです。(@naitohさんのご尽力で、PDF出力に関しては幸せになっております!)
    どうぞよろしくお願いいたします!

    2011-12-01

    RedmineのREST APIを使ってみる。

    いまごろではありますが、主に使っているRedmineのバージョンが上がったので、やっとREST APIが使える環境になりました。
    #個人的にREST APIを使ったツールを作ってみる活動はしていたのですが、メインの環境では対応していなかったのもあって、モチベーションが続いてませんでした…。

    できれば周りにも利用したり、応用したり、良いアイディアを出してもらいたいなあと思ったので、まずはどんな感じで使えるか、というサンプルを作ることにしました。

    * * *

    チケットの参照はWebから行うことの方が多いので、やっぱりチケットを作るサンプルから。

    参考にさせていただいたREST APIについての記述は、Redmine本家と、r-labsのサイトの日本語訳になります。(ありがとうございます!)

    動作確認は、daipresentsさんの記事を参考にさせていただきました。こちらもありがとうございます!

    daipresentsさんの記事では、RESTを試すクライアントとして、RESTClient を使われていました。こちらは使ったことが無かったので、ダウンロードしてみたところ、なるほど、これも便利でした。
    わたしの場合は、いつもはFiddler2 を使っているので、参考までにFiddler2でのスクリーンショットを載せておきます。

    1枚目がPOSTメソッドでリクエストを生成するところ。2枚目がレスポンスの画面です。
    うまくチケットが出来ると、Status Code 201が返ってきます。また、レスポンス本文にも、チケットのIDを含めたXMLが返ってきます。

    fiddler-request

    fiddler-result

    動作確認ができたので、じゃあ、チケットを作成するプログラムを…と思ったのですが、RubyやPerl, Pythonといったライブラリの組み込み状況は、サーバの環境によってまちまち。Perlしか入れていないところもあります。

    現在のチケット作成のAPIは、添付ファイル付きでの作成が出来ず、結局のところXMLをPOSTすることになるので、シンプル?に、curlとShellを使ったスクリプトを作ることにしました。

    チケット作成がメインで、Statusの指定やカテゴリの指定は重視していなかったので、オプション設定は行っていません。Shellを参考にカスタマイズすれば、Updateやカテゴリ設定も可能かと思います。(実はまだUpdateは試してないので、できたらまた追記します)

    使い方は、このような感じです。

    $redmine_postIssue.sh –u REDMINEのURL –k APIキー \
       –p プロジェクトID(番号じゃなく識別子)  \
      -t トラッカーID(番号) –s タイトル \
      -d チケット本文

    チケット作成時に、作成者を別途指定できたり、担当者も指定できます。ただ、やっぱり担当者とかトラッカーとかのIDをきちんと知っていないといけません。

    APIを使ってリッチなクライアントを作るって、凄いなあと思っています(^^;