Provider定義
Resourceで定義したactionのinstall_rbenvとinstall_rubyの内容を実装します。処理の内容は、独自Resource導入前に作成したRecipeのinstall_rbenv.rbとinstall_ruby.rbの内容とほぼ同じです。異なる箇所は、独自Resource導入前はインストールディレクトリやRubyのバージョンをattributeに定義していたものがResourceに定義したattributeを使うように修正した点です。もし、プラットフォーム差異が発生するような場合は、Provider内でプラットフォームの差異を吸収するとよりよいでしょう。
# Resourceで定義したinstall_rbenv actionを実装します
# Providerの action (Resourceで定義したactionのシンボル) ブロック内で処理内容を実装します
action :install_rbenv do
# Resource定義のattributeで指定したパラメータはnew_resource.(attribute名)で取得できます
install_dir = "#{new_resource.install_dir}/rbenv"
env_file = '/etc/profile.d/rbenv.sh'
# 1. 依存パッケージのインストール(install_rbenv.rbレシピからの移植)
# 依存パッケージのインストールはRecipe内で定義します
# 2-1. gitリソースを使ってrbenv本体をインストール先ディレクトリに配置します(install_rbenv.rbレシピからの移植)
git 'install rbenv' do
user 'root'
destination install_dir
repository 'https://github.com/sstephenson/rbenv.git'
not_if "ls #{install_dir}"
end
# directoryリソースを使ってrbenvのプラグインインストール用のディレクトリを作成します(install_rbenv.rbレシピからの移植)
directory "#{install_dir}/plugins" do
owner 'root'
group 'root'
mode 0644
action :create
end
# 2-2. gitリソースを使ってrbenvのプライグインをインストールします(install_rbenv.rbレシピからの移植)
git 'install ruby-build' do
user 'root'
destination "#{install_dir}/plugins/ruby-build"
repository "https://github.com/sstephenson/ruby-build.git"
action :checkout
not_if "ls #{install_dir}/plugins/ruby-build"
end
# 3. rbenv用の環境変数設定スクリプトを配置します(install_rbenv.rbレシピからの移植)
bash 'set rbenv to environment' do
user 'root'
code <<-EOH
echo 'export RBENV_ROOT="#{install_dir}"' >> #{env_file}
echo 'export PATH="$RBENV_ROOT/bin:$PATH"' >> #{env_file}
echo 'eval "$(rbenv init -)"' >> #{env_file}
EOH
not_if "ls #{env_file}"
end
end
# install_ruby actionを実装します
action :install_ruby do
# Resource定義のattributeで指定したパラメータはnew_resource.(attribute名)で取得できます
install_version = new_resource.version
install_dir = "#{new_resource.install_dir}/rbenv"
rbenv_path = "RBENV_ROOT=#{install_dir} #{install_dir}/bin"
# rbenvを使ってRubyをインストールします(install_ruby.rbレシピからの移植)
bash 'install ruby' do
user 'root'
code <<-EOH
#{rbenv_path}/rbenv install #{install_version}
#{rbenv_path}/rbenv rehash
#{rbenv_path}/rbenv global #{install_version}
EOH
only_if do
`#{rbenv_path}/rbenv install -l | grep -wc #{install_version}`.to_i > 0 &&
`#{rbenv_path}/rbenv versions | grep -wc #{install_version}`.to_i == 0
end
# インストールしたRubyを有効にします(install_ruby.rbレシピからの移植)
bash 'switch ruby version' do
user 'root'
code <<-EOH
#{rbenv_path}/rbenv rehash
#{rbenv_path}/rbenv global #{install_version}
EOH
only_if "#{rbenv_path}/rbenv versions | grep -w #{install_version}"
end
end
定義したResourceを使用したRecipe
定義したResourceをRecipeで使用する際のResource名は「cookbook名_Resourceファイル名」です。今回の場合は「rbenv_settings」がResource名です。LWRPを使う前後でRecipeの内容を比較すると、格段に分かりやすくなっていると思います。
# 依存パッケージのインストールをRedHat系とDebian系で分岐
case node[:platform]
when 'redhat', 'centos'
packages = %w( gcc-c++ glibc-headers openssl-devel readline readline-devel zlib zlib-devel )
when 'debian', 'ubuntu'
packages = %w( autoconf bison build-essential libssl-dev libyaml-dev libreadline6 libreadline6-dev zlib1g zlib1g-dev )
end
packages.each do |pkg|
package pkg do
action :install
end
end
# rbenvのインストール
# Resource定義でinstall_rbenvをデフォルトactionにしたので、actionは指定する必要はありません
rbenv_settings 'install rbenv'
# Ruby 2.1.1をインストールして有効にする
rbenv_settings 'install ruby' do
version '2.1.1'
action :install_ruby
end
# 試しにRuby 2.1.0を追加でインストールして有効にしてみる
rbenv_settings 'install ruby' do
version '2.1.0'
action :install_ruby
end
このRecipeを実行したらrbenvを使ってRubyの2.1.1と2.1.0をインストールし、最終的に反映させたRuby 2.1.0が有効になっているかと思います。これで独自のResourceを定義してRecipeを作成し、Chefを実行することができました。
LWRPを使用しているCookbookの例
最後に、LWRPを使用しているCookbookの例をご紹介します。
Opscode CommunityではさまざまなCookbookが提供されています。これらのCookbookでは、LWRPや今回は紹介できなかったChefの機能であるLibrary(Rubyのロジックをメソッド単位で外だしする機能)がよく使われており、Recipeに直接関係のないようなロジックはRecipe外で定義され、Recipeが見やすくなるように工夫されています。コミュニティのCookbookを使ったり、参考にする際にはLWRPを意識してみてください。
- LWRPを使っているCookbookの一例
※執筆時点での情報のため、変更される可能性があります
まとめ
今回はRubyのバージョン管理ツールであるrbenvのCookbookを作成し、LWRPを使って見通しの悪いRecipeをリファクタリングし、見通しのよいRecipeを作成してみました。見通しのよいRecipeを作成すると、どのような環境を構築したいかがより明確になります。また、LWRPを使うことで、別のCookbookからも利用しやすくなり、再利用性も向上します。
これまでChefを使った経験はあるけれど、LWRPを避けていた方はこれを機にLWRPを使ってみてはいかがでしょうか。これからChefを始める方も、Recipeが膨大になってきた際にはLWRPの導入を検討してみてください。
次回は、ScalaのWebアプリケーションフレームワーク「Play Framework」入門の続編です。お楽しみに!
