日常業務で Serverspec を利用して構成管理をチェックしていますが、改めて「Serverspec」の内部構造について調べました。
まだまだ「Serverspec」のすべてを理解できていませんが、今後も「プログラミング」や「Ruby」や「Rake」を理解するために引き続き勉強していきます。
Serverspec をインストールする
Serverspecをインストールするのは簡単です。
[test@cent07 serverspec-test]$ gem install serverspec |
Serverspec を実行する
Serverspec を実行します。
まずは Serverspec 管理用のディレクトリ(serverspec-test)を作成します。
[test@cent07 ~]$ mkdir serverspec-test [test@cent07 ~]$ cd serverspec-test/ |
Serverspec の初期化をする
次に Serverspec の初期化をします。
[test@cent07 serverspec-test]$ serverspec-init 1) UN*X Select number: 1 ← 「1」を入力します。 Select a backend type: 1) SSH Select number: 2 + spec/ |
Rakefile ファイルの中身を解析
「Ruby」と「Rake」はまだまだ初心者だと思うので1行1行解析をしていきます。
内容的には「Serverspec」の勉強ではなく「Ruby」や「Rake」の勉強です。
[test@cent07 serverspec-test]$ cat Rakefile task :spec => ‘spec:all’ namespace :spec do task :all => targets targets.each do |target| |
Rake とは?
そもそも「Rake」とは一体何なのか分からなかったので調べました。
Rake は Make に似た Ruby で書かれたビルドツールです。
どのようにビルドするのかは、「Rakefile」に記述します。
rake は「Rakefile」の内容を解析し、「Rakefile」の内容に沿ってビルドをします。
※「ビルドする」とは、ソースコードをコンパイルしてライブラリなどリンクをして、最終的にプログラムとして使えるようにすることを言います。
■Rakeを使ったプログラム
[test@cent07 test01]$ pwd task :hello do ← task でタスク名を指定して、do で閉じます。 |
■Rakeを実行
[test@cent07 test01]$ rake hello ← rake コマンドでタスク名(hello)を指定します。 |
Rakefileとは?
rake は Rakefile の内容を解析し Rakefile の内容に従ってビルドを実行します。
Rakefile に簡単な例を記述してビルドをしてみます。
まずは「Rakefile」を作成します。
[test@cent07 src]$ vi Rakefile CC = “gcc” task :default => “hello” file “hello” => “hello.o” do file “hello.o” => “hello.c” do [test@cent07 src]$ |
Rakefile を作成したら「rake」コマンドを実行します。
[test@cent07 src]$ rake |
ファイル一覧です。
[test@cent07 src]$ ll |
参考URL
http://www2s.biglobe.ne.jp/~idesaku/sss/tech/rake/
こうして見ると下から順に処理をしていくようです。
Rakefile を作成したら「rake」コマンドを実行します。
[test@cent07 src]$ rake |
■Rakefileの例
この例で何となくどんな処理をしているのか分かると思います。
こうして見ると「Rakefile」は「Ruby」の構文と「rake」の構文が混ざっています。
前処理に「first_01」と「second_01」のファイルを作成しておきます。
これがないと「firstの処理」及び「secondの処理」でエラーになります。
[test@cent07 src]$ vi Rakefile task :default => “hello” file “hello” => [“first”, “second”] do file “first” => “first_01” do file “second” => “second_01” do [test@cent07 src]$ |
rakeコマンドを実行します。
[test@cent07 src]$ rake |
require
外部のライブラリを読み込みます。
また自分が作った Ruby プログラム(xxxx.rb)を読み込みたい時に使用します。
task : xxxx
■task :spec => ‘spec:all’
「spec」という Rake タスクを実行しています。
「=>」は前提となるタスクを指定しています。
例えば、「task :hello_second => :hello_first」は、「hello_second」を実行するためには、事前に「hello_first」を実行しておく必要があるという意味になります。
■task :default => :spec
「task :default」は、rake コマンドで何もタスクを指定しない場合に実行されるタスクです。
「task :default => :spec」は、何もタスクを指定しない場合は「spec」タスクを実行します。
task :spec => ‘spec:all’ |
これは、タスクを指定しない場合は「spec」タスクを実行し、「spec」タスクを指定した場合は「spec:all」を実行します。
taskだけの場合はアクションはありません。
■再度 task の整理
※勘違いしていたらすみません。
task :spec => ‘spec:all’ ← specは「namespace」の「spec」、allは「namespace :spec」の「all」タスクの事を表わしています。「task :spec」を実行する前に「spec:all」を実行しておきます。
namespace :spec do task :all => targets targets.each do |target| |
■Rakefile(task)の例
2つのタスクを実行する例
[test@cent07 01]$ vi Rakefile task :default => :taskall ← 「rake」コマンドだけ実行した場合、デフォルトの「taskall」が実行されます。 task “first-task” do task “second-task” do [test@cent07 01]$ |
rake実行例
[test@cent07 01]$ rake |
namespace
namespace はタスクの名前空間(名前のこと)を表わすことができます。
→タスクの名前を定義できるということです。
namespace :xxx で、タスク「xxx」に処理を定義することができます。
namespace :spec do ← タスク「spec」
namespace は「end」で閉じます。
namespace は入れ子にできます。
namespace :test01 do
namespace :test02 do
end
end |
targets = []
これは単純に「targets」という配列を要素が空で初期化をしています。
Dir.glob(‘./spec/*’).each do |dir|
Dir.glob でディレクトリを表示することができます。
次の (‘./spec/*’) で「spec」ディレクトリ配下のファイル名を取得することができます。
ちなみに現在の状態です。
[test@cent07 spec]$ pwd |
取得した値を「dir」に入れて each で繰り返し処理を実行します。
next unless File.directory?(dir)
「next」で一番内側の繰り返しを抜けます。
「unless」は「もし~でなければ」という意味です。
「dir」がディレクトリかどうかチェックしています。
ここでの処理はdirの内容がディレクトリでなければ一番内側の繰り返しを抜けるということをやっています。
target = File.basename(dir)
ディレクトリ名を変数「target」に格納します。
target = “_#{target}” if target == “default”
もし「target」の中身が「default」の場合は、先頭にアンダーバー「_」を付けてtarget変数に格納します。
※「default」は Ruby の予約語ではありませんが、Rakeの中で「default」が使われているのでアンダーバーを付けるということでしょうか。
targets << target
target 変数の中身を targets 配列の末尾に追加します。
targets.each do |target|
target 配列の中身を取り出して繰り返し処理をします。
original_target = target == “_default” ? target[1..-1] : target
target[1..-1] は、配列の範囲を指定しています。
- target[1] ← target配列の2番目から
- target[-1] ← target配列の後ろから1番目
返り値は対象の範囲の「配列」です。
※しかしこの場合は「targets」配列ではなく「target」であることに注意が必要です。
つまり、target変数(_default)が入っている場合、「default」で返ってくるという処理をしています。
target == “_default” ? target[1..-1] : targetは、「三項演算子」です。
xx ? yy : zz の三項演算子の形式です。
条件式 ? 真の場合の値 : 偽の場合の値 |
「original_target = target == “_default” ? target[1..-1] : target」の条文を解説すると、
もし target の値が
- 「_default」の場合 → target配列の2番目から最後までを original_target に格納する
- 「_default」以外の場合 → targetの値を original_target に格納する
という処理になります。
つまり、target変数の中身が「_default」の場合は「default」で返ってきて、original_target に格納します。
desc “Run serverspec tests to #{original_target}”
“Run serverspec tests to #{original_target}” でどのターゲットに対して処理をしているのか宣言しています。
RSpec::Core::RakeTask.new(target.to_sym) do |t|
この行は、Ruby で一番苦手な分野です。
「::」は、「クラス」や「モジュール」や「メソッド」の呼出しです。
または「::」は、名前解決をする際に入れ子(ネスト)環境下での場所を特定します。単純に言うと、場所を特定します。
(概念を分かりやすく説明するのは難しいです)
- 「RSpec」クラスを呼び出す場合 → RSpec
- 「RSpec」クラスの中の「Core」クラス or モジュール or メソッドを呼び出す場合 → RSpec::Core
- 「RSpec」モジュールの中の「Core」モジュールの中の「RakeTask」モジュールを呼び出す場合 → RSpec::Core::RakeTask
to_sym は、文字列から「シンボル」へ変換します。
target.to_sym で、「target」変数の中身の文字列をシンボルに変換します。
※Rubyはここらへんの処理が簡単に直感的にできるので柔軟にプログラミングができます。私的には非常に分かりやすくてプログラミングしやすい言語だと思っています。
「RSpec::Core::RakeTask.new(target.to_sym) do |t|」の処理は、target変数の中身をシンボルに変換してRakeTask.newでオブジェクトを作成し、そのオブジェクトを「t」に格納して以下の処理をしています。
ENV[‘TARGET_HOST’] = original_target
original_targetの中身を環境変数 ENV[‘TARGET_HOST’] に格納します。
【例】
take :test do puts ENV[‘TARGET_HOST’] puts ENV[‘TEST’] end |
プログラム実行
$ rake TARGET_HOST=centOS7 TEST=test |
プログラム実行結果
centOS7 test |
t.pattern = “spec/#{original_target}/*_spec.rb”
ファイル「spec/ターゲット名/*.spec.rb」を「t」に対して実行します。
実行する処理は、spec.rbファイル全部です。
serverspec-runnerで更に Serverspec の機能が拡張可能
Serverspec だけでは多数のホストをチェックする際に結果の出力が冗長に感じることがあります。
しかし「serverspec-runner」を導入することで複数台のホストのチェック結果を見やすく出力することが可能になります。
【Serverspec】【serverspec-runner】インストールと基本設定
参考URL
Rakeについての解説が非常に分かりやすかったです。
http://www2s.biglobe.ne.jp/~idesaku/sss/tech/rake/
Serverspecの本
何度も読み返しました。
そのたびに「Ruby」や「RSpec」を勉強してカスタマイズしたいなと思います。
Serverspec【インフラ構成管理ツール】著者:宮下剛輔
まとめ
Serverspecのソースまで理解しようとすると、非常にハードルが上がり難しく感じます。
しかしRakefileのように1行1行を何とか言語化していくと、少しずつ理解できるような気がします。
ただそうは言ってもまだまだハードルは高いです。
コメント