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」入門の続編です。お楽しみに!