IronRubyでWindowsのサービスをコントロールする
2010/7/3追記。このコードではうまく動作しません。「webrickでリダイレクトするときの注意」を参照してweb.rbを修正してください。
Windowsのサービスをコントロールするコマンドでsc.exeってあるじゃないですか?コレを使えばリモートでサーバーのサービスをコントールできるなと思っていたんだけど同一ドメインじゃないとうまく動かないそうな。
ならば、.NetのSystem.ServiceProcessを使ってコントロールしようと思ったのがコトの始まりです。
どうせならWeb経由で動くようにしたいと思いWebrickでコントロールできるようにしてみました。
環境はIronRuby0.9.2+WindowsXP+.Net Framework2.0です。
System.ServiceProcess.rb
require 'C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.ServiceProcess.dll'
System.ServiceProcessはデフォルトではrequireできないのでdllを定義しておきます。
.Net標準のライブラリを使うのにフルパスを記述するのはなんかかっこ悪いなぁ。たぶんこの書き方は間違っている。通常はどのように定義するのでしょうか?
ご自分の環境とパスが異なる場合は変更しておいて下さい。
list.rhtml
<html> <head> <title>Window Services</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <% @services.each do |service| %> <%= service.display_name %> <b> <% if service.status == ServiceControllerStatus.Running %> 実行中 <% elsif service.status == ServiceControllerStatus.Stopped %> 停止中 <% end %> </b>| <% if service.status == ServiceControllerStatus.Running %> 開始| <a href ="stop/<%= service.service_name %>">終了</a> <% elsif service.status == ServiceControllerStatus.Stopped %> <a href ="start/<%= service.service_name %>">開始</a> |終了 <% end %>|<br> <% end %> </body> </html>
テンプレートファイルです。UTF-8で保存しておきましょう。
web.rb
require 'webrick' require 'erb' require 'System.ServiceProcess' require 'uri' include System::ServiceProcess include WEBrick server = HTTPServer.new({ :Port => 8080, :BindAddress => '127.0.0.1', :MimeTypes => HTTPUtils::DefaultMimeTypes.merge({"rhtml"=>"text/html"}), :DocumentRoot => Dir.pwd}) class ListServlet < HTTPServlet::AbstractServlet def do_GET(req, res) @services = ServiceController.GetServices.sort_by{|x| x.display_name} open('list.rhtml') do |f| e = ERB.new(f.read) res.body = e.result(binding) end res['Content-Type'] = "text/html" end end server.mount("/list", ListServlet) server.mount_proc("/start") { |req, res| service = ServiceController.new(File.basename(URI.parse(req.path).path)) service.start service.WaitForStatus(ServiceControllerStatus.Running) res.set_redirect(HTTPStatus::MovedPermanently, 'http://localhost:8080/list') } server.mount_proc("/stop") { |req, res| service = ServiceController.new(File.basename(URI.parse(req.path).path)) service.stop service.WaitForStatus(ServiceControllerStatus.Stopped) res.set_redirect(HTTPStatus::MovedPermanently, 'http://localhost:8080/list') } trap('INT') { server.shutdown } server.start
URLはサーブレットを使って分かりやすくしました。
実行
C:\000\WindowsServiceController>ir web.rb [2009-11-16 18:55:52] INFO WEBrick 1.3.1 [2009-11-16 18:55:52] INFO ruby 1.8.6 (2009-03-31) [i386-mswin32] [2009-11-16 18:55:52] INFO WEBrick::HTTPServer#start: pid=4312 port=8080
3つのファイルを1箇所にまとめて実行です。Vistaや7の人はコマンドプロンプトを管理者権限で実行してくださいね。
http://localhost:8080/list
にブラウザでアクセスすると。。。
だめじゃん。
サービスの表示用名称に日本語が含まれているためerbのresultメソッドで文字コードに互換性がないよと怒られてます。
けっこうハマったんだけど、-KuオプションでUTF-8を指定することで解決。
実行
C:\000\WindowsServiceController>ir -Ku web.rb [2009-11-16 19:05:30] INFO WEBrick 1.3.1 [2009-11-16 19:05:30] INFO ruby 1.8.6 (2009-03-31) [i386-mswin32] [2009-11-16 19:05:30] INFO WEBrick::HTTPServer#start: pid=4812 port=8080
http://localhost:8080/list
にブラウザでアクセスするとこんどはよさそうです。
webブラウザでサービスの開始or終了ができるようになりました。
.Netとはいえ手作業でWindowsフォームを作るのは大変なので、簡単なインターフェースならばhtmlを書いてwebrickに乗せるというアプローチもアリだなと思いました。