UT-VPNとhttpsを同時に使用するときの注意点
UT-VPNとApacheを同時に動かしているサーバで少しはまったので一応残しておく。
UT-VPNサーバを起動すると、デフォルトでは443、5555、992の3つのポートが開く。
その際、どれか1つのポートが使われている場合、当然ながらそのポートは使われない。
一番多いのは、既にApache等のWebサーバが動いており、https(443)を既に使っている場合だろう。
しかし、ここでApacheを停止すると、UT-VPNが443ポートの状況を常に監視しているのか、即座にUT-VPNが443ポートを占有するのである。
今回現象が起こったサーバの場合、週に1回ログをローテーションするためにApacheを再起動しているのだが、Apacheが停止して再び起動する際、既にUT-VPNが443を占有しており、起動に失敗した。
正確にはこのサーバは少しおかしくて、apachectl restartするとなぜかたまにApacheが停止したまま上がらないことがあるので、数分後に明示的にapachectl startが動くようにしてあるのだが、そのタイミングでこの現象が起こった。
(apachectl restartがちゃんと動いたときはそういったことは起こらなかった。)
対処としては、UT-VPNが余計なポートを使わないようにすること。
(そもそも5555しか使っていないので、992とかが空いてるのもセキュリティ上よろしくない。)
utvpncmdから、ListenerListでポートの使用状況を確認する。
VPN Server>ListenerList ListenerList コマンド - TCP リスナー一覧の取得 ポート番号|状態 ----------+---------- TCP 443 |エラー発生 TCP 5555 |動作中 TCP 992 |動作中 コマンドは正常に終了しました。
なるほど、空いていなかったポートは「エラー発生」となっていたのか。
ListenerDeleteコマンドで余計なリスナーを削除する。
VPN Server>ListenerDelete ListenerDelete コマンド - TCP リスナーの削除 削除する TCP/IP リスナーのポート番号: 443 コマンドは正常に終了しました。 VPN Server>ListenerDelete ListenerDelete コマンド - TCP リスナーの削除 削除する TCP/IP リスナーのポート番号: 992 コマンドは正常に終了しました。
これで余計なポートは全て閉じた。
まあ、ちゃんと運用するサーバであれば最初から使うポートだけに絞るはずなので、こんな現象に遭遇することはまず無いとは思うのだけれど。
MacPortsでインストールしたTwitter GemでMultiJson::DecodeError
MacPorts-1.9.2を使ってインストールしたrubygemsでTwitter Gemを入れたところ少しハマったので残しておく。
MacPortsはパッケージインストーラで入れただけ。
その後rubygemsをインストール。
$ sudo port install rb-rubygems
ここで
$ which gem ruby
すると両方/opt/localの下を指しているが、
$ gem --version $ ruby --version
の出力を見るとどうもMac標準の/usr/binの下が呼ばれていそうなので、シェルを一回再起動する。
次にTwitter Gemsをインストール。
$ sudo gem install twitter
動作を確認するため、サンプルを書く。
require 'rubygems' require 'twitter' p Twitter.user('junji_furuya').location
これを実行したところ、MultiJson::DecodeErrorになった。
/opt/local/lib/ruby/gems/1.8/gems/multi_json-0.0.5/lib/multi_json.rb:66:in `decode': #<RuntimeError: Did not recognize your engine specification. Please specify either a symbol or a class.> (MultiJson::DecodeError) from /opt/local/lib/ruby/gems/1.8/gems/faraday_middleware-0.3.2/lib/faraday/parse_json.rb:22:in `register_on_complete' from /opt/local/lib/ruby/gems/1.8/gems/faraday-0.5.7/lib/faraday/response.rb:47:in `call' from /opt/local/lib/ruby/gems/1.8/gems/faraday-0.5.7/lib/faraday/response.rb:47:in `finish' from /opt/local/lib/ruby/gems/1.8/gems/faraday-0.5.7/lib/faraday/response.rb:47:in `each' from /opt/local/lib/ruby/gems/1.8/gems/faraday-0.5.7/lib/faraday/response.rb:47:in `finish' from /opt/local/lib/ruby/gems/1.8/gems/faraday-0.5.7/lib/faraday/builder.rb:19:in `inner_app' from /opt/local/lib/ruby/gems/1.8/gems/faraday-0.5.7/lib/faraday/response.rb:17:in `call' from /opt/local/lib/ruby/gems/1.8/gems/faraday-0.5.7/lib/faraday/response.rb:17:in `call' from /opt/local/lib/ruby/gems/1.8/gems/faraday-0.5.7/lib/faraday/adapter/net_http.rb:57:in `call' from /opt/local/lib/ruby/gems/1.8/gems/twitter-1.1.2/lib/faraday/multipart.rb:16:in `call' from /opt/local/lib/ruby/gems/1.8/gems/faraday-0.5.7/lib/faraday/request.rb:85:in `run' from /opt/local/lib/ruby/gems/1.8/gems/faraday-0.5.7/lib/faraday/request.rb:27:in `run' from /opt/local/lib/ruby/gems/1.8/gems/faraday-0.5.7/lib/faraday/connection.rb:177:in `run_request' from /opt/local/lib/ruby/gems/1.8/gems/faraday-0.5.7/lib/faraday/connection.rb:66:in `get' from /opt/local/lib/ruby/gems/1.8/gems/twitter-1.1.2/lib/twitter/request.rb:28:in `send' from /opt/local/lib/ruby/gems/1.8/gems/twitter-1.1.2/lib/twitter/request.rb:28:in `request' from /opt/local/lib/ruby/gems/1.8/gems/twitter-1.1.2/lib/twitter/request.rb:6:in `get' from /opt/local/lib/ruby/gems/1.8/gems/twitter-1.1.2/lib/twitter/client/user.rb:23:in `user' from /opt/local/lib/ruby/gems/1.8/gems/twitter-1.1.2/lib/twitter.rb:21:in `send' from /opt/local/lib/ruby/gems/1.8/gems/twitter-1.1.2/lib/twitter.rb:21:in `method_missing' from hello_world.rb:5
どうも何か設定が足りない様子。
ググってもよく分からなかったので、/opt/local/lib/ruby/gems/1.8/gems/multi_json-0.0.5/lib/multi_json.rbの中身を読と、12〜36行目付近に次のような記述があった。
REQUIREMENT_MAP = [ ["yajl", :yajl], ["json", :json_gem], ["active_support", :active_support], ["json/pure", :json_pure] ] # The default engine based on what you currently # have loaded and installed. First checks to see # if any engines are already loaded, then checks # to see which are installed if none are loaded. def default_engine return :yajl if defined?(::Yajl) return :json_gem if defined?(::JSON) return :active_support if defined?(::ActiveSupport::JSON) REQUIREMENT_MAP.each do |(library, engine)| begin require library return engine rescue LoadError next end end end
どうもREQUIREMENT_MAPの各要素の1番目の要素の文字列を順番にrequireしている様子。
要はJSONのエンジンがインストールされていないのが原因らしい。
そこでyajlをrubygemsからインストール。
$ gems search --remote yajl benofsky-yajl-ruby (0.7.7) filipegiusti-yajl-ruby (0.6.4) sprout-yajl-library (0.0.1) yajl-ruby (0.8.1) $ sudo gems install yajl-ruby
これで、サンプルを動かすことができた。
$ ruby -Ku location.rb "東京都北区"
IDEのHDDに入ったLinuxをVMWare仮想マシンに変換してみたが…
RedHat ES 4 が入ったサーバの電源が故障してしまい、起動しなくなってしまった。
内蔵HDDのデータは無事のようなので、この際VMWareの仮想マシンに変換することにした。
作戦としては
http://d.hatena.ne.jp/mitszo/20080403/p1
を参考にさせていただき(つーかパクり)、
- HDDをddコマンドが使えるマシンに接続し、ディスクイメージを抽出
- 仮想マシンを作成
- CD Linuxから仮想マシンを起動
- CD Linux上のddコマンドを使い、仮想マシンのディスクに元環境のディスクイメージを流し込む
- 仮想マシンを普通に起動する
といった感じ。
HDDをddコマンドが使えるマシンに接続し、ディスクイメージを抽出
元のマシンから内蔵HDDを取り出した後、こういうやつを使い、Linux等、ddコマンドが利用可能なマシンのUSBポートに接続する。
最初はWindows版のddコマンドを利用しようと思ったのだが、ext3がどうしても見えなかったので諦め、Linux機(Ubuntu 10.04 LTS)を使うことにした。
接続したHDDから、ddコマンドでディスクイメージを抽出する。
HDDは/dev/sdcとして認識された。保存先はSambaで共有されたディレクトリとした。
$ sudo su -
# dd if=/dev/sdc of=/var/smb-share/ide-disk.img
CD Linuxから仮想マシンを起動
Ubuntu 10.04 LTSのisoイメージがあったため、それを使うことにする。
isoイメージを仮想マシンに接続して起動し、「インストールせずにUbuntuを試す」的な選択肢を選ぶ。
CD Linux上のddコマンドを使い、仮想マシンのディスクに元環境のディスクイメージを流し込む
起動後、先ほどディスクイメージを抽出したディレクトリをsmbfsを使ってマウントし、仮想マシンのディスクにddコマンドで流し込む。(この前にネットワークの設定は必要。)
Ubuntu上のディスクユーティリティで確認したところ、仮想マシンのディスクは/dev/sdaとして認識されているようであった。
$ sudo su - # apt-get install smbfs # mkdir /mnt/smb-share # mount -t smbfs //xxx.xxx.xxx.xxx/smb-share /mnt/smb-share Password: # dd if=/mnt/smb-share/ide-disk.img of=/dev/sda
仮想マシンを普通に起動する
デスクトップ上の電源ボタンから再起動を選ぶと、メディアを取り除いてEnterを押すようメッセージが表示されるので、isoイメージを切断し、Enterを押す。
すると、想定通りRedHat ES 4のgrubの画面が出た!
喜び勇んでEnterボタンを押すと、早々とkernel panicになった。
エラーメッセージを読んでみると、「No volume groups found」とある。
ここからが地獄の始まりであった。
initrdがVolumeGroupを認識できないのだろうということは分かるのだが、Ubuntuから起動してvgscanすると普通に見えるし、元のマシンで動いていたときも/はLVMでマウントされていたはずなので、なぜ認識できないのかが分からない。
色々ネットで調べていたところ、
http://chiji.atnifty.com/topics/?p=68
というエントリに当たり、解決した。
考えてみれば当たり前なのだけど、VMWareのディスクはSCSIエミュレーションなので、IDEで動いていた元のマシンとは別のカーネルモジュールを読み込ませてやらないと、カーネルはディスクを認識できない。
/etc/modprobe.confの記述内容の決定
上のエントリで紹介されている方法に従い作業することにする。(手順はほとんど同じなのだが、一応記録しておくことにする。)
まずは/etc/modprobe.confに正しいカーネルモジュールのエントリを記述する必要がある。
これについてはいい方法が思いつかなくて、別の仮想マシンに新規でRedHat ES 4 をインストールし、その/etc/modprobe.confの内容をひかえておくことにした。
ただし、RedHat ES 4 のメディアが既に手元に無い状況だったため、CentOS 4.8で代用することにする。
仮想ディスク上の/etc/modprobe.confを編集した後、initrdを再生成する
こちらも作業にはRedHat ES 4 のメディアのレスキューモードを使いたかったのだけど、CentOS 4.8のisoイメージで代用することにする。
CentOS 4.8のisoイメージを仮想マシンに接続して起動する。
boot: プロンプトでlinux rescueを入力してEnterを押す。
すると、必要なドライバが読み込まれ、勝手に/mnt/sysimageに仮想ディスクのパーティションがマウントされるので、
# vi /mnt/sysimage/etc/modprobe.conf
として、上でひかえたmodprobe.confの内容に書き換える。NICのドライバも当然ながら元環境とは異なっていたため、合わせて記述を変えた。
コメントアウトされているエントリは、元々記述されていた箇所。
#alias eth0 e1000 #alias snd-card-0 snd-intel8x0 #options snd-card-0 index=0 #install snd-intel8x0 /sbin/modprobe --ignore-install snd-intel8x0 && /usr/sbin/alsactl restore >/dev/null 2>&1 || : #remove snd-intel8x0 { /usr/sbin/alsactl store >/dev/null 2>&1 || : ; }; /sbin/modprobe -r --ignore-remove snd-intel8x0 #alias usb-controller ehci-hcd #alias usb-controller1 uhci-hcd alias eth0 pcnet32 alias scsi_hostadapter mptbase alias scsi_hostadapter1 mptscsi alias scsi_hostadapter2 mptspi alias scsi_hostadapter3 mptsas alias scsi_hostadapter4 mptscsih alias scsi_hostadapter5 ata_piix
そうした上で、initrdを再生成。chrootし、/usr/local/src/initrdで作業することとする。
# chroot /mnt/sysimage # cd /usr/local/src # mkdir initrd # cd initrd # mkinitrd initrd-2.6.9-5.EL.img 2.6.9-5.EL
しかし、「No module mptscsi found for kernel 2.6.9-5.EL, aborting.」となって怒られる。
この辺りは、RedHat ES 4 とCentOS 4.8の差異が影響しているかもしれない。
仕方がないので、無いと言われるモジュールはコメントアウトして再試行することにする。
最終的なmodprobe.confは下記のようになり、initrdも正常に生成することができた。
#alias eth0 e1000 #alias snd-card-0 snd-intel8x0 #options snd-card-0 index=0 #install snd-intel8x0 /sbin/modprobe --ignore-install snd-intel8x0 && /usr/sbin/alsactl restore >/dev/null 2>&1 || : #remove snd-intel8x0 { /usr/sbin/alsactl store >/dev/null 2>&1 || : ; }; /sbin/modprobe -r --ignore-remove snd-intel8x0 #alias usb-controller ehci-hcd #alias usb-controller1 uhci-hcd alias eth0 pcnet32 alias scsi_hostadapter mptbase #alias scsi_hostadapter1 mptscsi #alias scsi_hostadapter2 mptspi #alias scsi_hostadapter3 mptsas alias scsi_hostadapter4 mptscsih alias scsi_hostadapter5 ata_piix
最後に生成したinitrdを/bootにコピーして再起動する。
# cd /boot # mv initrd-2.6.9-5.EL.img initrd-2.6.9-5.EL.img.org # cp /usr/local/src/initrd/initrd-2.6.9-5.EL.img . # reboot
これで、kernel panicが起こることなく、ログインプロンプトまで流れるようになった。
正直大変だった
最初は手順通りやれば簡単だと思ったのだが、予想外に大変だった。
実際にはgrubの設定いじったり、lvm.confを変えてみたり、的外れなことをたくさんやってたし。(まあ、色々勉強にはなったが…)
よく考えると、VMWare Convertorを使えばもっと簡単にできたのではないだろうか。
最初、Windows版を入れて少し試してみたのだけれども、Windowsからext3が見えないし、物理マシンとしても認識させることができないので、今回の手順の方が簡単と思い、すぐ諦めてしまったのだ。
よく見るとLinux版のConvertorも用意されているようだし、試してみる価値はある。
今後このようなケースに遭遇することを考え、本腰を入れて検証してみようと思う。
SSHポートフォワーディングによるリモートデスクトップ接続の色々
今日、自宅のLAN内のPCにVPN経由でリモートデスクトップ接続しようとしたら、なぜか繋がらなかった。
代替案を考えたのだけれども、LinuxルータにSSH接続が可能なので、ポートフォワーディングを利用すればいいんじゃないかと考えた。
接続元PCはMacなので、ターミナルから
ssh -L 3389:(接続先マシンのプライベートIPアドレス):3389 \ (ルータのユーザID)@(ルータのグローバルIPアドレス)
としてルータとのSSH接続を確立し、ポートフォワーディングが可能なようにしておく。そしてRemote Desktop Connection for Mac 2を利用して、接続先にlocalhostを指定することで、無事接続できた。なんだこれ、超簡単だな。これだけだったらわざわざVPN使う必要もない感じだ。
そこで、ちょっと思ったのが、iPadからも同じことが可能なのではということ。iOSはマルチタスクをサポートしているので、SSHクライアントをポートフォワーディングのオプションをつけてバックグランドで起動しておき、RDPクライアントでlocalhostに接続すればよいはず。
早速試してみたが、やはり可能だった。使用したアプリは、SSH→iSSH、RDP→iTap RDP。iSSHで接続先の設定画面で、「Tunnels」というメニューがあるので、Add Tunnel...からポート設定を追加すればよい。(サポートされているのはローカル→サーバのポート転送のみのような感じ。)
余談だが、このiTap RDP、接続先の設定を保存した後、接続先にRDP接続が可能かチェックして緑→OK、赤→NGのアイコンで教えてくれる。SSHの接続を確立する前は、接続先がlocalhostなので当然赤なのだけれども、SSH接続後、緑に変わる。これはちょっと面白い。
繋がった瞬間はおおお!って感じで結構感動するのだが、画面の切り替えがパラパラというか、結構もっさりしており、iPadを使うようにはサクサク動かせない。(そこは、うちのインターネット回線が遅いせいかもしれないけど。)ただ、このアプリの操作性自体は結構頑張っていて、Windowsマシンのブラウザを二本指のスワイプでスクロールできたり、ダブルタップでのアイコンのドラッグ、同じくダブルタップでの右クリック動作など、Macのトラックパッドに近い操作感だ。
これで日常作業するのはさすがにきついが、緊急手段としては十分実用レベルだ。
SQL Server 2005のデフォルト分離レベル
規定値はREAD_COMMITTEDなんですね。これは2008でも変わらないようだ。
こんなことも知らなかった自分に((((;゜Д゜)))ですわ。
試しに2005で
-- テスト用テーブルを作成。 CREATE TABLE TEST(id int, amt int) GO -- テスト用データを挿入。 INSERT INTO TEST VALUES (1, 100); INSERT INTO TEST VALUES (2, 200); INSERT INTO TEST VALUES (3, 300); GO BEGIN TRAN UPDATE TEST SET amt = 500 WHERE id = 1
した後に、別のセッションで
SELECT * FROM TEST;
とやったら、延々と待ってた。((((;゜Д゜)))
例外処理とか間違えたら死ねるな。
ていうか、デフォルトのREAD_COMMITTEDのままでは普通運用しないのか?
S2Container-2.4.42でのS2Chronos-1.0.0の利用
S2Chronos-1.0.0を使用していた環境のS2Containerを2.4.18から2.4.42にバージョンアップしたところ、Taskが起動しなくなってしまった。
Eclipse上でデバッグしてみたところ、s2chronos-coreに含まれるTaskExecuteStrategyImpl#load()の495行目、
Object value = pd.getValue(this.task);
で例外が発生し、スケジューラスレッドが終了してしまう。
なぜかと思い調べてみると、どうやら、S2Containerに含まれるPropertyDescImpl#getValue()の動作が変更されているようだ。
2.4.18のときはsetterのみが定義されたフィールドであってもgetValue()が値を返していたが、2.4.42では例外が発生するようになっている。(同メソッドのjavadocは変更されていないので、2.4.18から2.4.42までの間に、正しい動作に修正された、ということらしい。)
事実、問題と思われるフィールドのgetterを実装したところ、正しくTaskが起動された。
ということは、Taskが使用するS2Container上のコンポーネントや、S2Chronosのドキュメントにあるexceptionフィールドに対して、getterを定義する必要がある。
このためだけにgetterを定義するのは微妙なので、なんとか回避する方法を模索してみた。
このTaskExecuteStrategyImpl#load()だが、デバッグしてみると処理のほとんどがスキップされるし、問題の例外発生部分についても、ローカル変数にPropertyDescImpl#getValue()の値を格納して終わっているので、実行されなくても問題がないように思われた。
そこで、思い切ってload()メソッドの動作をスキップしようと思い、TaskExecuteStrategyImplを継承したクラスを作成し、load()メソッドをオーバーライドして空実装とし、s2chronos-core.diconでそのクラスを使うように修正。
その結果、多少強引な手ではあるが、動作するようになった。
うーーん、ググっても全然引っかからないし、皆困ってないんだろうか?
ていうか、問題が起こった環境自体、2.3から移行した関係で設定の仕方とか2.4風でなかったりするので、その辺が原因なのかも。
なんか根本的に間違ってる予感がしてきたので、S2Containerのドキュメントを一から読みながら環境を見直してみるか。