2007-08-31

FlexのHTTPServiceでPOSTされた日付型をパースする

mx.rpc.http.(mxml.)HTTPServiceを使ってサーバにリクエストを投げるとき、contentTypeが "application/x-www-form-urlencoded"(デフォルト)だと、sendメソッドの引数に与えられたオブジェクトのプロパティ群がリクエストパラメータ(サーブレットのrequest.getParameterで取得できるデータ)として使われる。

このとき、Date型のオブジェクトが含まれていると "Fri Aug 31 18:10:14 GMT+0900 2007" のような形式で送信されるのだが、一般的な Javaフレームワークはこの形式の文字列を自動的に日付型へ変換できない。少なくともStruts2ではそうだった。
(なおcontentType="application/xml"でリクエストを送信する場合、日付型のオブジェクトはISO8601なる形式でエンコードされる)

仕方ないのでサーバ側では文字列として一度受け取って、パースしてやる必要がある。
SimpleDateFormatクラスでは、この形式に対するフォーマット文字列は "EEE MMM dd HH:mm:ss z yyyy" となる(ロケールはUS)。
が、手元の Java 1.5 ではタイムゾーンのあたりでパースに失敗するようで使えなかった。

しかたないので ICU4jの SimpleDateFormatクラスを使ってみたところパース出来たので以下はサンプル。

import com.ibm.icu.text.SimpleDateFormat;

Date parsedDate =
new SimpleDateFormat(
"EEE MMM dd HH:mm:ss z yyyy", Locale.US).parse(dateString);

ところで、これに関する調べ物をしている間に Java標準のSimpleDateFormatクラスは MTセーフでないぞコノヤロウっていう話を目にしたんだけど、同一インスタンスに対するメソッド呼び出しがMTセーフでないという「だけ」なら都度newするかスレッド毎にインスタンスを持てばいいわけなのでそれほど問題ではないような気がする。
「だけ」でない場合は、これはなかなか厄介な問題のような気がする。

2007-08-29

Java1.4のログAPIで簡単にログファイル出力

Webアプリケーションなんかの場合はコンテナの管理下にあったりするログファシリティだが、実行可能jarにしてあってcronで起動するようなバッチジョブをjavaで書いたときなんかはやはり自分で設定してやらないと話にならないので、Java 1.4の標準ログAPIを使ってログを残すための一番簡単な方法をメモする。

カスタムの logging.properties ファイルは下記の通り。

handlers = java.util.logging.FileHandler # ログの出力先はファイル
java.util.logging.FileHandler.limit = 1048576 # ひとつのログファイルは最大1MBくらい
# ホームディレクトリの logs/MyBatchJob.log.番号 にログを出力
java.util.logging.FileHandler.pattern = %h/logs/MyBatchJob.log
# ログローテーションは最近の10個まで
java.util.logging.FileHandler.count = 10
# ログの出力形式は普通で
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
# ログはファイルに追記する(これをtrueにしないと毎回上書きされてしまう)
java.util.logging.FileHandler.append = true
# デフォルトのログ出力レベルはWARNING以上
.level= WARNING
# "mt.batch.job.Component" ロガーの出力レベルはINFO以上
my.batch.job.Component.level=INFO


バッチジョブのクラスでは下記のように Loggerを使う。

package my.batch.job;

public class Component {
static Logger logger = Logger.getLogger("my.batch.job.Component");
static void main(String[] args) {
try {
process();
logger.finest("Batch process done.");
}
catch (Exception ex) {
logger.log(Level.SEVERE, "Exception occured", ex);
}
}
}


あとはシステムプロパティ java.util.logging.config.file に設定ファイル名を指定してプログラムを実行してやると、指定された場所の指定されたファイルに指定されたレベル以上のログが出力される。

$ java -Djava.util.logging.config.file=logging.properties -jar MyBatchJob.jar

2007-08-26

Apache 2.2には mod_proxy_fcgiが登場予定?

Apache 2.2のモジュールとして密かに FastCGIのProxyが開発されているのを発見。
AJP(Apache JServ Protocol)が Apache2.2から標準対応になったように、FastCGI Protocolもその流れに加えられるものと見られる。

svn co http://svn.apache.org/repos/asf/httpd/httpd/branches/fcgi-proxy-dev
で、ブランチをチェックアウトできる。

cd fcgi-proxy-dev/modules/proxy
apxs2 -c mod_proxy_fcgi.c

で、.lib/mod_proxy_fcgi.so が出来るので、これをApacheのモジュールディレクトリに放り込み、httpd.confには
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
のように書いてやる。

後はバーチャルホスト設定の中で
ProxyPass /myfcgiapp fcgi://myfgihost:port
みたいにしてやれば URIに FastCGIのサービスをマッピング出来る。portは省略すると8000番。
現状、UNIX Domain Socketでの接続には対応していない模様。

AJPの場合もそうだが、RewriteRule [P]を使って Proxyの設定をすることもできる。

RewriteEngine on
RewriteRule ^myfcgiapp/(.*) fcgi://myfcgihost/$1 [P]

ProxyPassはバーチャルホスト設定内にしか書けないが RewriteRuleなら .htaccessにも書けるため手軽に URIのマッピングが出来る。

ruby-fcgiで TCPポート8000番を待ち受けるFastCGIサービスを記述した例は下記。
#!/usr/bin/ruby

FCGI_PURE_RUBY=true

require 'fcgi'
require 'socket'

s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
s.bind(Socket.sockaddr_in(8000, "0.0.0.0"))
s.listen(5)

FCGI::Server.new(s).each_request { |request|
request.out.puts "Content-type: text/plain\r\n\r\n"
request.out.puts "Hello ruby-fcgi!\r\n"
}
多くの人は FastCGIサービスを Webサーバからforkてもらう形で利用しているだろうからこの方式は見慣れないとおもう(というかこれだと既にCGIの体裁をしていない)。このやり方の利点は、サービスがWebサーバと必ずしも同一のホストで動作する必要がないため、Apache 2.2のロードバランサ機能と組み合わせてアプリケーションの負荷分散が可能なことなどである。

なお FCGI_PURE_RUBYをtrueにしないと ruby-fcgiは libfcgiを使用するモードで動作する。このモードでは stdin/stdoutを使った入出力しかできないので mod_proxy_fcgiモジュールからの利用はできない。

追記:下記のコードは正しく動作しない。
FCGI::Server.new(s).each_request { |request|
Thread.start { # スレッドでリクエストを処理
request.out.puts "Content-type: text/plain\r\n\r\n"
request.out.puts "Hello ruby-fcgi!\r\n"
request.finish
}
}
fcgi.rbはeach_requestに与えたコードブロックが制御を戻すとすぐにリクエストの終了処理を行いソケットを closeしてしまうため。作者の方はマルチスレッドへの対応を課題として認識してはいるようだ。

論理ボリュームのスナップショットが作成できない

最近どうもバックアップがうまくいってないなと思ってたら、2007-8-16頃に更新された udevやらdevice-mapperあたりの ebuild を入れたタイミングあたりで論理ボリュームのスナップショットが作成できたりできなかったりするようになってしまったようだ。

lvcreateでスナップショットを作ろうとすると
LV vg/snap in use: not deactivating
Couldn't deactivate new snapshot.
みたいなことを言われる。

「カーネル 2.6.18 でこの問題への対処が行われた」という情報をみつけたものの、今のカーネルは 2.6.20だからとっくに直ってるはず。
とりあえずワークアラウンドとして、スナップショットの作成前に udevcontrol stop_exec_queue を、作成後に udevcontrol start_exec_queue を実行してやれば良いらしいのでそのようにしてみたら問題を回避できた。

カーネルとデバイスマッパーとudevのどれかとどれかの組み合わせで発生したエンバグかな。

ちなみに udevcontrol start_exec_queueを忘れると
Error: Device 0 (vif) could not be connected. Hotplug scripts not working.
とか言われて XenのdomainUが起動できなくなるので注意。

2007-08-24

Xen3.1で 5つ以上のvifを使う

Xenと Tagged VLANを組み合わせて使っていると、いつのまにか vifがたくさん必要になってしまうが、デフォルトではどうやら4つまでのvifしか作成できないようだ。これを増やすにはdom0カーネルのパラメータに netloop.nloopbacksパラメータを与えてやる。

module /boot/vmlinuz root=/dev/sda1 netloop.nloopbacks=16

2007-08-17

手っ取り早く Windowsをシャットダウンする

リモートデスクトップで WindowsXP Proにつないでいると、スタートメニューにシャットダウンが現れない(ログオフと切断のみ)。
こんな時に手早くシャットダウンするには、コマンドプロンプトを開いて

shutdown -t 0 -s

と入力すると問答無用でシャットダウンされる。-sのかわりに -rだと再起動になるとおもう。

2007-08-16

Apache 2.2で peruser MPMを使うとログファイルに記録されるIPアドレスが0.0.0.0になってしまう

直そうと頑張っているところらしい。現状でのワークアラウンドとしては、httpd.confの Listen設定行で IPアドレスを省略せず書けば良い。

2007-08-15

パスワードなしのアカウントで Windows XP Professionalにリモートデスクトップ接続する

注:あたりまえですが、セキュリティ上の観点から推奨できる運用方法ではありません。

管理ツール→ローカルセキュリティポリシーを開く
セキュリティの設定→ローカルポリシー→セキュリティオプションまで降りていく
「アカウント:ローカルアカウントの空のパスワードの使用をコンソールログオンのみに制限する」を無効にする

これでパスワードなしのユーザーもリモートデスクトップ接続できる。再起動は不要だった。

2007-08-13

Dependency info is missing!

Gentooの環境がなにかの拍子にぶっ壊れると表題のようなメッセージが出てまともに initスクリプトが走らなくなる。
どうにかしてレスキュー環境で起動し、chrootを駆使して baselayoutを emergeしなおせば直る。

ディスクイメージとパーティション

Xenの HVM Domain(完全仮想化)を使うと、まるで実機のごとくゲストOSをインストールして動かせるわけだけれども、完全仮想ドメインに与えてやる仮想ディスクは「パーティション」ではなく「ディスク」として扱われるので、ホストOS側から見るとそのディスクイメージにはパーティションテーブルといった情報が書き込まれた謎のバイナリデータであり、ファイルシステムとしてマウントすることができない。
この問題はHVM Domainを使う場合以外にも、iSCSIで他のホストにディスクをエクスポートする場合も同様である(iSCSIで提供できるのはパーティションではなくディスク)。

これだとホストOSからファイルレベルでバックアップを取るようなことができなくて困るのでどうしたものかと思っていたが、Xenのメーリングリストを見ていたら multipath-toolsなるツール群に含まれる kpartxなるコマンドでディスクイメージの中にあるパーティションに対してデバイスマッパー経由でアクセスできるようになることがわかった。

# emerge multipath-tools (AMD64の場合maskされてるので /etc/portage/package.keywordsで適当にunmaskする)

例えば /dev/raid5/winxp なるボリュームが実は Windows XPを入れたHVM Domain用のディスクイメージだとする。ホストOSからは、そのままだと(カーネルのNTFSサポートが有効でも)このディスクをマウントすることができない。マウントしたいファイルシステムが格納されているのは、このディスクイメージの中に含まれている「パーティション」だから。

そこで

# kpartx -a /dev/raid5/winxp

としてやると、ディスクに含まれるパーティションを示す /dev/mapper/winxp1 なるデバイスが出現するので、これを mount -t ntfs /dev/mapper/winxp1 /mnt のようにしてマウントしてやることが出来るのである(パーティションが複数あるディスクイメージの場合は winxp1 winxp2 のように複数のデバイスがマッピングされる)。

マウントして、アレやソレして、アンマウントして、そいつらに対する用が済んだら、

# kpartx -d /dev/raid5/winxp

で/dev/mapperからそれらのパーティションは居なくなる。

kpartxがGUIDパーティションに対応しているかどうかは未検証(GUIDパーティションを切ったディスクイメージに対して試しにやってみたらとりあえずエラーにはならなかったが、なにぶん中身が HFS+だったのでそれ以上検証せず)

それにしても Linuxのデバイスマッパーって色々できるね・・・

2007-08-12

Gentooで Tagged VLAN(802.1Q)を使う

最近はギガビット対応の VLANスイッチも手の届く値段で買えるようになってきたので、ディスクとRAMてんこもりのホストで仮想マシンを山ほど運用している向きにはそろそろタグベース VLANの導入が行われる時期ではなかろうか。

ポートベースVLANは単にポートをグループ化してひとつのスイッチをあたかも複数であるかのように分割するだけのものだが、タグベースVLAN(802.1Q)はイーサネットのフレームにタグを付加して区別することによってネットワークを分割する。

それが具体的にどう役に立つかなど、詳しい話をしだすと長くなるので本題に入る。

Linuxで802.1Qを使うには vconfig なるユーティリティが必要なので入れる。

# emerge vconfig

/etc/conf.d/net にて、vlans_(VLAN分割したいインターフェイス名)行を作成し、使用するVLAN番号をスペース区切りで羅列する

vlans_eth0="10 20 30"

VLANインターフェイス名は物理インターフェイス名の後にドットで区切ってVLAN番号をつけたものになる。
但し /etc/conf.d/netファイルでは設定項目名にドットが使えないのでアンダーバーで代用する。
config行の内容は普通のインターフェイスと同じ書式で書けば良い。

config_eth0_10=("apipa")
config_eth0_20=("dhcp")
config_eth0_30=("192.168.0.10/24")

この設定で eth0.10 eth0.20 eth0.30がそれぞれイーサネットデバイスとして使えるようになる。
(IP Aliasingの場合 eth0:1 などコロンで区切るのだが VLANの場合はピリオドであることに注意)

initスクリプトでインターフェイスを起動する際は、物理インターフェイスだけを対象にすること。
/etc/init.d/net.eth0 start
で、eth0に設定された全てのVLANが起動するため各VLANインターフェイスごとにinitスクリプトのシンボリックリンクを作成する必要はない。

VLAN分割後のインターフェイスを Xen用にブリッジしてやれば(環境によると思うが大抵Xenのスクリプトを修正する必要あり)、domain U側からは普通のイーサネットデバイスとして使える。但し物理イーサネットデバイスが 802.1Qに対応していない場合、タグの分だけフレームサイズが大きくなる関係でフレームサイズを調整しないと通信が不安定になるかもしれない。イーサネットデバイスのドライバソースに 802.1Qや VLANといった文字列があるかどうか見てみるといいだろう。

追記:VIAの Velocityチップでは VLANを設定しても通信出来なかった。理由は不明。

最近やってる仕事はこういうの