どうも、cloudpack の ハンドラ・カワハラ(@inokara)です。
はじめに
以下の記事を参考にさせて頂いて chef-client の実行結果を Slack に飛ばしてみたのでメモです。
さらにググってみるとハンドラとして chef-handler-jenkins が既に存在していましたが、勉強を兼ねて自作してついでに gem 化して公開したのでメモです。
参考
- Chefのハンドラを使ってSensuやSlackと組み合わせる方法
- jenkinsci/chef-handler-jenkins
- tinyspeck/chef-handler-slack
- using ruby, how to create hexBinary data required by hudson’s postBuildResult?
- masquaremo / str_num_sample.rb
- Rubyでミリ秒表記のUNIXTIMEを日付表記に変換する
- 君がOpsでもRubyで書いたライブラリはGemで配ろう
- Rubygemsでライブラリを公開したので、手順をまとめてみた
- Monitoring external jobs
- 「Jenkins と cron」という資料を作ってプチ勉強会で発表しようと思ってます
- Ruby/文字列を配列に変換する方法(逆も)
chef-handler-slack
chef-handler-slack
読んで時の如くでございます。
通知の飛ばし方
使い方はとっても簡単です、上記のブログ記事に書かれている手順に従って cookbook に組み込んで収束させれば通知が飛ぶようになります。(但し、デフォルトでは収束に失敗しない(Excepstion とならない)限りは通知が飛びませんでした)
収束に失敗すると以下のように通知が飛びます。
成功した通知も飛ばしたい
ちなみに成功した場合にも通知を飛ばしたい場合には…ソースコードにちょっと手心を加えます。
if not run_status.success? msg = "Chef run failed on *#{source}*" if !run_status.exception.nil? msg += "n```" msg += run_status.formatted_exception.encode('UTF-8', {:invalid => :replace, :undef => :replace, :replace => '?'}) msg += '```' end send(msg) else # 以下に出力させたい内容を追記します msg = "Chef run finished *#{source}*" send(msg) end
出力させたい内容は run_status
の以下のメソッドで指定可能です。
名称 | 説明 |
---|---|
node | Node Object(ohai の収集した Attribute 等を含む) |
success? | 実行時に例外を含んでいなければ真を返す |
failled? | 実行時に例外を含んでいれば真を返す |
start_time | Node Object を作成した後、Chef::RunContext を作成する前の時刻 |
end_time | Chef-client 終了時の時刻 |
elapsed_time | start_time と end_time の差 |
all_resources | run_list によって読み込んだ Recipe に定義されているリソースの一覧 |
updated_resources | all_resources のうちで Chef::Runnner によって変更されたリソースの一覧 |
exception | 発生した例外のクラス |
formatted_exception | 発生した例外クラスとメッセージの文字列 |
backtrace | 例外発生時のバックトレース |
run_context | Chef::RunContext オブジェクトの全ての内容 |
上記は「Chef 活用ガイド」から引用させて頂きました。有難うございます。m(__)m
楽しいチャットオプス
まだまだ試用段階なので通知をトリガーに次の処理をどうこうするとかは考えていませんが、通知をチャット飛ばすことで得られるメリットとしては…
- 他のメンバーとの情報共有がメールと比べるとカジュアルに出来る
- カジュアルな情報共有なので自分だけのオプス、秘伝のタレ、秘伝のレシピにならずにすみそう
この二つかなと考えています。
Chef 等の構成自動管理ツール(この言い方が正しいかわかりませんが)が浸透してきても、結局それを使う(使いこなす)人が限られてしまっては上記のように秘伝のタレが秘伝のレシピになってしまいそうな状況を見ることがあります。そんな状況を少しでも打開する一つの方法としてチャットをベースとした情報共有とそれらの連携は必要なのではないかなと思っています。
俺の Chef ハンドラ
chef-handler-jenkins_notifier
勉強を兼ねて作りました。
次期バージョンの予定としては…
- https 対応
-
認証対応(しました)
を予定しております。
使い方等
README.md を御覧ください。尚、事前に Jenkins 環境を構築して通知を飛ばす為のジョブを作成しておきましょう。
デモ
早速ですがデモです。
まずは以下のように Excepstion させますね。
さすれば Jenkins 先生には以下のように通知されます。
ついでに run_status.success?
が true
の場合には…
ポーカーフェイスな先生も心なしかご満悦です。
苦労したところ(よくわからんかったところ)
ハンドラの動作や含まれる情報についてはこちらを参考させて頂き、Chef::Runstatus オブジェクトから幾つかのメソッドを取ることで通知の内容はコントロール出来ることは解りましたが、Jenkins に通知を飛ばす際に通知内容を 16 進数のバイナリにエンコードする必要があり、その方法を探すのが苦労しましたが…世界は広し、同じことをやろうとされている方が僕らの stack overflow にいらっしゃいましたので参考にさせて頂きました。
ざっくり言うと以下のような流れでバイナリエンコードします。
- メッセージ(今回は
run_status
から取得したい各種メソッド)を配列にぶっ込む - ぶっこんだ配列を
join
して文字列に変換(セパレータはn
) - 変換した文字列を
unpack
メソッドを使って処理
実際に以下のように処理しています。
log = [] log << "n" log << "Chef run Success on #{run_status.node.name}" (中略) log << "elapsed_time: " + run_status.elapsed_time.to_s + "s" log << "n" log = log.join("n") submit_jenkins run_status,log,result end end (中略) def submit_jenkins(run_status, log, result) binlog = log.unpack("H*").first
最後に
暫くは Chef の Handler を作りつつ、改めて Chef の勉強をしなおしていきたいと考えています…。
元記事はこちらです。
「chef-handler-slack を使ってみたのと Jenkins に通知を飛ばすハンドラを作って gem で公開してみた」