タスクのプログラミング - Ruby
目次
RubyやJavaプログラムは、コントロールプランのどのノードでも実行できます。そのプログラムは、ノード上で右クリックしてEdit Script オプションを選ぶことで編集します。Ruby処理を選ぶには、ノード上で右クリックしてRubyオプションを選択します。
厳密にいうと純粋なRubyでなく、Jruby-RubyのJavaインプリメンテーションが実行されますが、これらのプログラムをRubyとして扱います。ほとんどの場合、Jruby とRubyのコードは同じです。Rubyは多くのシステムアドミニストレーションとインテグレーション作業のスクリプトに使用されているため、Rubyのプレース実行によりコントロールプランは広い範囲の機能を実施できます。Rubyプログラムは一般的にJavaプログラムよりプログラムングが簡単です。コントロールプランは、単一モードでJavaのプレースタスクとRubyのプレースタスクの混在を認めます。インピーダンスとエンベロープ(後述します)を介したデータ交換は、JavaとRubyプレース間で機能します。
標準Rubyスクリプト
ほとんどのRubyスクリプトはエディターのウィンドウに直接書き込むことができ、そのプレースにトークンが到着したときに実行されます。STDOUTへの書き込みは、コンソールへのプリント出力となります。たとえば、下記のコマンドはそのプレースのためのコンソールとセンターコンソールに"Hello World" とプリントします。puts "Hello World!"
Jruby gemsの使用
いくつかのJrubyエクステンションがControl Plan Editor インストールの一部としてインストールされます。これらのエクステンションはControl Plan Editor をインストールしたディレクトリ下のjrubylib ディレクトリの中にインストールされます。Rubyスクリプトがこれらのエクステンションにアクセスするために、それらはライブラリのパスで参照される必要があります。たとえば、JSONエクステンションを使うには、下記のコードがRubyコードの冒頭部分にある必要があります。$: << '.\jrubylib\json_pure-1.1.9\lib' $: << '.\jrubylib\json_pure-1.1.9\bin' require 'json' . # put JSON results into result hash for easier data manipulation result = JSON.parse(json_string)
$: の表現は、必要とするものが含まれるライブラリファイルがある場所の $LOAD_PATH を意味します。json ファイルはControl Plan Editor といっしょにインストールされるので、それらはインストールディレクトリに関係して参照されます。
カスタムスクリプトを開発する一つの方法は、JrubyスクリプトをControl Plan Editorの外で開発し、それらをツールの中に取り込むことです。 Jruby サイトからパッケージをダウンロードして、Control Plan Editorと関わりなしにJrubyをインストールすることができます。Rubyto同様、下記のコマンドでJrubyエクステンションやGEMSをインストールできます:
jruby -S gem install <gem_name>これであなたのシステム上でコマンドラインからネイティブでJrubyを実行しあなたのJrubyスクリプトをテストすることができます。あなたのプログラムが機能すれば、それらをControl Plan Editor のプレースの中にコピーできます。Control Plan EditorのロードパスがすべてのカスタムGEMSをアクセスできるようセットされていることを確認してください。
下記の例を見てください。あなたがXMLパーシングを使用したいと考え、Jrubyをあなたのシステム上にネイティブでインストールし、xml-simple gem をインストールしたと考えてください。Jrubyをインストールしたディレクトリが、C:\JRuby\jruby-1.3.1 であれば、あなたのgemは、C:\JRuby\jruby-1.3.1\lib\ruby\gems\1.8\gems\xml-simple-1.0.12の中にインストールされているはずです。Control Plan Editorのもとでスクリプトを実行するなら、あなたのプログラムの先頭に下記を書き入れる必要があります。
$: << 'C:\JRuby\jruby-1.3.1\lib\ruby\gems\1.8\gems\xml-simple-1.0.12\lib' require 'xml-simple'あなたのネイティブプログラムの実行が成功したが、Control Plan Editor スクリプトに追加する必要があるロードパスが何か分からない場合、ロードパスを一覧表示させるために、あなたのネイティブプログラム('require'の後ろに)に下記のコード断片を追加してください。
$:.each { |path| puts path }このコード断片はあなたのロードパス配列内の各パスをプリントするでしょう。そうしたら必ず、それらのパスをControl Plan Editor スクリプト内の $: に追加してください。
プレースのパラメータ
Rubyコードサンプルを含む、タスク処理のパラメータについての説明は、データ構造 のセクションを参照して下さい。インピーダンス
Rubyコードサンプルを含む、インピーダンスの説明、入力仕様と出力仕様の説明については、データ構造 のセクションを参照して下さい。トークンのエンベロープデータ
Rubyコードサンプルを含む、トークンのエンベロープデータについては、データ構造 のセクションを参照して下さい。制約
Rubyコードサンプルを含む、条件的制約の説明について、データ構造 のセクションを参照して下さい。Rubyからの外部プログラムの呼び出し
外部プログラムを標準のRubyプログラムと同様にControl Plan Editorから呼び出すことができます。一般的な方法はシステムコマンドを表すのにバックティックス(backticks)を使うことです。プレースタスクから呼び出したいPerlプログラムがあると想定します。そしてWindowsシステム上でControl Plan Editorを実行し、下記PerlプログラムがC:\Program Files\Tap In Systems\WorkflowActionEditor ディレクトリのhello.plに入っているとします。print "Hello World!\n";プレースのスクリプトには、下記のRubyスクリプトを入れたとします。
lines = `C:\\Perl588\\bin\\perl "C:\\Program Files\\Tap In Systems\\WorkflowActionEditor\\hello.pl"` lines.each { |line| puts line }このプレースが実行されたとき、下記がコンソール上に表示されます。
Hello World!Perl スクリプトは単に"Hello World!"をSTDOUTに出力します。本Rubyプログラムでは、Perlスクリプトを明確に呼び出して実行します。Windowsディレクトリのバックスラッシュ(\)をダブルバックスラッシュ(\\)でエスケープする必要があることに注意してください。Perlスクリプトの出力はRubyの行配列の中に取り込まれます。そしてRubyスクリプトで行配列中の各行をプリントすることでプリントします。このテクニックはどのようなPerlスクリプトを呼び出すのにも使用でき、その出力を取り込んでRubyのプレースタスクがその結果を翻訳します。Perlで記述された多数のシステム管理や監視コマンドがあるため、それらのプログラムを呼び出してそれらの結果をモデル中で処理することができます。この方法は、他の言語でも同様に使えます。
RubyからのJavaメソッド呼び出し
Javaからはわずかな関数しか使用できません (現在は!)。- ユーザインタフェースのダイアログボックスの作成
- イベント読み出しと生成のためのTap In監視システムとの相互動作
ほとんどの部分をRubyでコーディングしたいが、これらの関数を呼び出したい場合、それを行う一、二の方法があります。自分のプレース内のJava関数を分離し、パラメータやインピーダンス、データエンベロープを使って、パラメータをプレースに渡します。他の方法は、RubyスクリプトでJava関数を呼び出す方法です。 Control Plan EditorのJrubyインプリメンテーションはすべてのJavaメソッドをJrubyスクリプトに公開します。下記の Tap In管理システムにログインするJavaコードを見てください。
host = "xxxxx.tapinsystems.net"; port = 9009; username = "userid"; password = "pass"; ssl = false; spider = new com.tapin.petri.net.Spider(myself.getContextName(),host,port,username,password,ssl); count = 0; while(spider.loggedIn == false && count++ < 5) { Thread.sleep(5000); System.out.println("Loggin in? Try "+ count ); } // Now I'm logged in. I can query for events or send an event.注: Spiderオブジェクトへのリファレンスで xxxxx,tapinsystems.net にある Tap In 管理サーバにログインできるようになります。
Rubyで同様なタスクを実行してみましょう。
host = "xxxx.tapinsystems.net"; port = 9009; username = "userid"; password = "pass"; ssl = false; spider = com.tapin.petri.net.Spider.new($myself.getContextName(),host,port,username,password,ssl); count = 0; while(not spider.loggedIn and (count < 5)) do puts "Logging in #{spider.loggedIn}, count #{count}" sleep 5; count = count + 1; end if count >= 5 then puts "ERROR! Could not log into QuickView" return endSpider オブジェクトは、Java中とちょうど同様にRubyのコード内で"com.tapin.petri.net.Spider"として参照されます。その"new"メソッドはJavaメソッドですが、Rubyのシンタックスを使って呼び出されます。このテクニックは、RubyからのほとんどのJava関数呼び出しに使うことができます。
タイマー
Rubyの時間待ち機能は、"sleep"コマンドで実現します。上述の例では、"sleep 5" でRubyスクリプトが5秒待ちます。データベースアクセス
RubyタスクプロセスはJavaの ExternalDatabaseオブジェクト参照を使用して、データベース問い合わせを実行できます。 データベースオブジェクトは一つのプレースで作成し、そのオブジェクトを他のプレースで使用するためにデータエンベロープに入れて渡すことに注意してください。下記のサンプルは、どのようにコントロールプラン中でMySQLに接続するかを示します。下記のモデルを作成することを想定します。MySQL_Connectプレース内に下記のコードを持ちます:
db = com.tapin.petri.net.ExternalDatabase.new("com.mysql.jdbc.Driver", "jdbc:mysql://127.0.0.1:3306", "aptest","testlog","root",""); $myself.add("db",db);このコードは、Javaオブジェクト参照メソッドを使う、"aptest" という名称のMySQL データベースにコネクトします。そして、"db"の名前を使ってデータエンベロープにコネクションオブジェクトを追加します。 その後、Sample_Query プレース内で下記のRubyコードがあります。
db = $myself.get("db"); res = db.query("select * from testlog"); i = 0; while res.next do puts "#{res.getInt('id')} #{res.getString('msg')}" i = i + 1 end puts "Number of records = #{i}"コネクションオブジェクトを取得し、そしてtestlog テーブル上で select を実行します。Java のコネクションオブジェクトを使用しているので、select の結果を読むには Java のメソッドを使用必要があることに注意してください。Sample_Query コンソール上のサンプルの出力は下記のようになります。
1 This is message 1 2 This is message 2 3 This is message 3 Number of records = 3それ以外の方法として、Jrubyのmysql gemをロードし、Rubyのメソッドを使ってMySQLデータベースにコネクトと問う合わせをする方法があります。しかし、JavaのExternalDatabaseクラスがControl Plan Editor にバンドルされているため、セットアップはこのサンプルの方が容易です。
Tap In管理サーバからの監視イベント取得
本稿では、システム管理のための自動化モデルの構築に焦点を当てているため、サーバ状態、クラウドインスタンス、パフォーマンス統計、ネットワークコンポーネントのステータスとアプリケーションイベントといった、管理対象ITインフラストラクチャの現在状態に基づいたトリガーモデルが必要です。下記のコードは、Tap In 管理サーバに接続して、すべてのCPU使用率統計を取得するためにアクティブなアラームを問い合わせる方法を示します。このサンプルでは、CPU使用率がある閾値を越えたすべてのインスタンスIDを取得します。
# Ruby Tap In management server log in and get alarms host = "xxxxx.tapinsystems.net"; port = 9009; username = "userid"; password = "pass"; ssl = false; spider = com.tapin.petri.net.Spider.new($myself.getContextName(),host,port,username,password,ssl); count = 0; while(not spider.loggedIn and (count < 5)) do #puts "Logging in #{spider.loggedIn}, count #{count}" sleep 5; count = count + 1; end if count >= 5 then puts "ERROR! Could not log into Tap In management server." return end puts "Logged into server #{spider.loggedIn} in #{count} tries" # Assumes cpu minimum threshold was passed via data envelope cpu_min = $myself.get("cpu_min").to_f puts "Get instances where CPU% greater than #{cpu_min}" # Getting CPU utilization stats for Amazon EC2 CloudWatch statistics sql = "select * from quickview where (CLASS='Amazon') and (RULE='CPUUtilization')" puts "Querying #{sql}" db = spider.getDatabase(); rs = db.query(sql); value = 0 count = 0 n1Array = Array.new # This array will contain the instance IDs that exceed CPU threshold n1Hash = Hash.new # This has while have the instance ID and CPU if rs then while rs.next() out = Array.new out.push(rs.getString('class')) out.push(rs.getString('rule')) out.push(rs.getString('n1')) out.push(rs.getString('message')) puts out.join(";") message = rs.getString('message') # Parse the Average CPU utilization from the message text if message =~ /Avg=(.*?)\s/ then value = $1.to_f if value > cpu_min then n1Array << rs.getString('n1') # Add to array n1Hash[rs.getString('n1')] = value.to_s # Add to Hash count = count + 1 end end end else puts "No response from QuickView SQL #{sql}" end $outArray = n1Array.uniq # Put in output spec variable for use in the next place $outHash = n1Hash if $outArray.size.eql?(0) then puts "Finished. No matching instances found." $output = 0 else puts "Finished. #{$outArray.size} matching instances found." endこのリストを表示するために、このコードを使うモデルについては、Amazon のサンプルファイルを参照してください。サンプルでは、オペレータが配列中のインスタンスを選択、リブートできるようにします。
Tap In管理サーバへのイベント送出
他の重要な機能に、コントロールプランの結果に基づいてオペレータに通知ができるものがあります。Tap In 管理サーバにイベントを送ることでオペレータはそれらの結果を見ることができます。また、イベントはデータベースにロギングされるので、コントロールプラン実施の監査ログになります。host = "xxxx.tapinsystems.net"; port = 9009; username = "userid"; password = "pass"; ssl = false; spider = com.tapin.petri.net.Spider.new($myself.getContextName(),host,port,username,password,ssl); count = 0; while(not spider.loggedIn and (count < 5)) do puts "Logging in #{spider.loggedIn}, count #{count}" sleep 5; count = count + 1; end if count >= 5 then puts "ERROR! Could not log into Tap In management server." return end puts "Logged into spider #{spider.loggedIn} in count #{count}" sev = 1; prio = 50; count = 1; cls = "ActionPlan"; group = "groupie"; rule = "norules"; msg = "Hello world!"; asto = ""; rtto = ""; t1 = "host"; n1 ="localhost"; t2 = ""; n2 = ""; t3 = ""; n3 = ""; first = Time.now.to_i * 1000; last = first; stat = 0; ga = ""; gv = 0; timeout = 0; escalates = 0; json = ""; spider.addUpdateableAlarm(sev, prio, count, cls, group, rule, msg, asto, rtto,t1, t2, t3, n1, n2, n3, first, last, stat, ga, gv, timeout, escalates, json); puts "Sent event."このコードの最初の部分は、前の例のように、Tap In 管理サーバにログインします。 残りのコードで、送出するイベントをフォーマットします。イベントのフォーマットはフレキシブルであり、モデルのプレースを表す状態を提供する必要があります。イベントがどのように処理され、イベントのフィールドが使用されるかについての説明は、Wikiの イベント管理アーキテクチャ セクションを参照してください。
Email送信
プレースタスクからeメールを送るのに役立ちます。この機能は、パッケージに組み込まれ、コマンドラインからの呼び差しで起動できます。下記のコードはメール送信の例です。このサンプルは、SMTPサーバとしてgmailを使用します。パラメータはあなた自身のサーバと置き換えてください。# # Call script that sends an email # # Script call format # mail host - smpt.gmail.com # port - 465 # protocol - smtps # from - notifications@tapinsystems.com # password - # subject # message # '/usr/local/tapin/scripts/email/start-email-write.sh useid@company.com Subject "This is an AP test"' script = '.\scripts\email\start-email-write.bat' # Enter user email parameters mailhost = "smtp.gmail.com" port = "465" protocol = "smtps" from = "notifications@tapinsystems.com" to = "user@gmail.com" password = "xxxxxxx" subject = "Testing" message = "Hello World!" cmd = "#{script} #{mailhost} #{port} #{protocol} #{from} #{password} #{to} \"#{subject}\" \"#{message}\"" puts cmd lines = `"#{cmd}"` lines.each { |line| puts line }
Twitterメッセージの送出
eメール送出に代わるのが、ステータス更新をTwitter(ツイッター)送ることです。 これにより、複数の人々が、あなたのコントロールプランがモデリングしたアプリケーションのステータス更新を認知できるようにするでしょう。 Twitterはeメール以上の量のメッセージを処理できるかも知れません。eメールの送信と同様に、この関数はパッケージに組み込まれており、コマンドラインからの呼び出しで起動できます。下記のコードが、Twitterメッセージの送出例です。
# # Must be initiated on Tap In monitoring server. # Call script that sends a tweet # # Script call format # `/usr/local/tapin/scripts/twitter/start-twit-write.sh twitterId 123456 "This is an AP test"` $script = '.\scripts\twitter\start-twit-write.bat' $id = "userId" $password = "pass" $message = "Hello World!" $cmd = "#{$script} #{$id} #{$password} \"#{$message}\"" puts $cmd lines = `"#{$cmd}"` lines.each { |line| puts line }
REST 呼び出しの実施
REST 呼び出しは、急速に標準方法になりつつある、さまざまな管理システムやクラウドベンダーサービスからデータを取得したり、コマンドを発行したりするための方式です。 Rubyにより、これらのコマンドを実行するために必要なHTTPコマンドを発行することができます。多くのこれらインタフェースがそれ自身のRuby gemパッケージの中にあるので、それらもControl Plan Editorに容易に統合することができます。これらREST呼び出しの使用方法の多くの例については、クラウドAPIパッケージを参照してください。