share facebook facebook twitter menu hatena pocket slack

2014.06.17 TUE

test-kichen + Chef-handler + α で cookbook テストをちょっと楽しくしたい

川原 洋平

WRITTEN BY 川原 洋平

どうも炎の料理人三ツ星シェルの かっぱこと 川原 洋平@inokara)です。

はじめに

前回test-kitchen 記事を書いててテストが終わったら通知が欲しいよなあと思ったので Chef-handlerReport 及び Exception ハンドラを利用すれば出来そうな気がしたので試してみた。

Chef-handler について

以下のスライドや記事が纏まっていて良い。

上記の記事を参考にさせて頂いて、Chef-handler はざっくりと以下のようなもの。

種類

以下の三種類。

  • Startchef-client が実行される前に実行される
  • Reportchef-client が正常に終了した際に実行される
  • Exceptionchef-client が異常終了した際に実行される

利用方法

  • solo.rbclient.rb に設定しておく
  • Cookbook** 内から LWRPchef_handler リソースを呼び出す

何が出来る?

  • 各種レポート(適用したノードのダンプ、経過時間、収束が発生したリソースのリスト、例外が発生したクラス、スタックトレース)
  • JSON ファイル、その他色々…(ここ参照)なところにレポートを出力

流れと cookbook

ひと通りウンチクを書いたので実際にやってみたい。

流れ

今回は通知に関しては AWS のメール送信サービスである SNS を、レポートの可視化については InfluxDB に放り込んで Grafana で見るというような流れを作りたい。以下のようなイメージ。

20140616_001_whole_image

また、今回は test-kitchen での cookbook 単体のテストを対象としたいので cookbook 内にハンドラ用のレシピを一つ追加する感じやってみる。

cookbook

前回に続いて以下の cookbook で試す。


中途半端な cookbook ですんません。

各種設定(1)

chef-handler-sns

chef-handler-sns はその名の通り Amazon SNS を利用して通知を行う。IAM にも対応しているらしい。

こちら を参考にして以下のようなレシピを追加する。

#
argument_array = [
  :access_key => "AKxxxxxxxxxxxxxxxxxx”,
  :secret_key => “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”,
  :topic_arn => "arn:aws:sns:us-east-1:1234567890:chef-test",
]
#
include_recipe "xml::ruby"
#
chef_gem "chef-handler-sns"
#
chef_handler "Chef::Handler::Sns" do
  source "#{Gem::Specification.find_by_name("chef-handler-sns").lib_dirs_glob}/chef/handler/sns"
  arguments argument_array
  # Exception のイベントのみを送信したい場合には true
  #supports :exception => true
  action :enable
end

適当なファイル名(reporting.rb とか)で recipe/ 以下に放り込んでおく。尚、AWS のアクセスキーやシークレットアクセスキー、SNSTopic ARN を事前に用意しておく必要がある。

Berkshelf のお出まし

レシピを見ると include_recipe をしている関係で複数の cookbook を利用することになるので Berkshelf を使うことになるので、以下のように依存する cookbookBerksfile に記述する。

cd ${chef-repo}/site-cookbooks/influxdb-chef
vim Berksfile

依存する cookbookxmlchef_handler になるので以下のように記述する。また、それらを利用することになる自身の cookbook も記載する。

source "https://api.berkshelf.com"

cookbook "xml"
cookbook "chef_handler"
cookbook "influxdb-chef”, path: "."

一旦、試す

ここまでで test-kitchen を実行すると漏れ無く SNS 経由でメール通知が届くことになる。

kitchen converge

を実行すると…以下のように test-kitchen が終了する。

20140616_002_finish_test-kitchen

また間を置かずに SNS サブスクリプションのエンドポイントに指定しているメールアドレス宛てにも以下のようにメールが届く。

20140616_003_received_mail

おお、便利かも。イタズラして Exception させてみたいので以下のようにレシピを修正して kitchen converge する。

diff --git a/recipes/default.rb b/recipes/default.rb
index b34c6ab..09eeb1b 100644
--- a/recipes/default.rb
+++ b/recipes/default.rb
@@ -9,7 +9,6 @@ end

execute "install_influxdb" do
   command "rpm -Uvh /tmp/#{REMOTE_FILE}"
-  not_if { ::File.exists?("/usr/bin/influxdb") }
 end

%w(httpd vim redhat-lsb-core).each do |sv|

以下のように収束に失敗する。すると以下のようにハンドラも実行される。

20140616_004_exec_handler

そして SNS 経由で以下のようなメールも届く。

20140616_005_received_mail

おお。

これで test-kitchen 実行した後画面に張りつかなくても別の事が出来たりして捗るかもしれない。

各種設定(2)

chef-handler-influxdb

次にやりたいのが test-kitchen の結果をメトリクスとして保存して可視化したい…という今流行りの発想。メトリクスの保存先としては InfluxDB を利用する。InfluxDB についてはこちらあたりを見て頂くと雰囲気は掴めるかも。

尚、 InfluxDB のインストールについては割愛。既にセットアップ済みの環境を利用するが事前にデータベースは作っておきたいの以下のようにして InfluxDBHTTP API を利用してデータベースを作っておく。

curl -X POST 'http://${influxdb_host}:8086/db?u=${user}&p=${pass}' -d '{"name": “chef”}’

レスポンスボディが表示されないので、ちゃんと出来たかが解らないので以下のように確認する。

curl 'http://${influxdb_host}:8086/db?u=${user}&p=${pass}'

以下のように出力されればおけけ。

[{“name”:”chef”}]%

次に先ほど chef-handler-sns の設定をしたレシピに以下を追加する。

handler_gem=['influxdb', 'chef-handler-influxdb']
handler_gem.each do |g|
  chef_gem g do
    action :install
  end
end

chef_handler 'ChefInfluxDB' do
  source ::File.join(Gem::Specification.find_by_name('chef-handler-influxdb').lib_dirs_glob,
                     'chef-handler-influxdb.rb')
  arguments [
    :host => ‘xxx.xxx.xxx.xxx’,
    :port => ‘8086’,
    :user => ‘user’,
    :pass => ‘pass’,
    :database => 'chef',
    :series => 'report',
  ]
  action :enable
end

kitchen converge を実行すると…以下のように出力される。

20140616_006_exec_handler

さらに InfluxDBWeb コンソール(http://${influxdb_host}:8083/)からアクセスして…

20140616_007_click_chef

Databases から chefExplore Data » を選択して…

20140616_008_explore_data_on_influxdb

Read Pointsselect * from report を実行した結果が以下の通り。

20140616_009_report_on_influxdb

おお、elapsed_timeINFO: Chef Run complete in 3.656150432 seconds の部分だったり、アップデートがかかったリソースは 1 つだったりが時系列で確認が出来るのはいいねえ。

まあ、せっかくなので

Grafana でも見てみましょう。

20140616_010_graph

適当にリソースを更新したりしながら kitchen converge を繰り返したのが上の図。

項目についてちょっとうんちく。

  • elapsed_timechef-client が実行開始( start_time )してから終了するまで(end_time)までの差分
  • resources_updatedchef-client が更新したリソースの数

詳細についてはこちら

最終的には…

以下のようなレポート用のレシピが出来た。


# for handler

handler_gem=['influxdb', 'chef-handler-sns', 'chef-handler-influxdb']
handler_gem.each do |g|
  chef_gem g do
    action :install
  end
end

# for SNS

argument_array = [
  :access_key => “xxxxxxxxxxxxxxxxxxxxxxxxxx”,
  :secret_key => “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”,
  :topic_arn => "arn:aws:sns:us-east-1:1234567890:chef-test",
]

# for SNS

include_recipe "xml::ruby"

# for SNS

chef_handler "Chef::Handler::Sns" do
  source "#{Gem::Specification.find_by_name("chef-handler-sns").lib_dirs_glob}/chef/handler/sns"
  arguments argument_array
  #supports :exception => true
  action :enable
end

# for influxdb

chef_handler 'ChefInfluxDB' do
  source ::File.join(Gem::Specification.find_by_name('chef-handler-influxdb').lib_dirs_glob,
                     'chef-handler-influxdb.rb')
  arguments [
    :host => ‘xxx.xxx.xxx.xxx’,
    :port => '8086',
    :user => ‘user’,
    :pass => ‘pass’,
    :database => 'chef',
    :series => 'report',
    #:data => node[:cookbook][:attribute].to_hash,
  ]
  action :enable
end

お疲れ様でしたー。

まとめ

やったこと

  • Chef のイベントハンドラ 2 種類を試した
  • 通知は chef-handler-sns レポートは chef-handler-influxdb を利用した

これで…

test-kitchen による cookbook のテストもちょっと楽しくなるかもしれないなー

元記事は、こちら