LoginSignup
57
56

More than 5 years have passed since last update.

[LWRPによる]続・ChefでSourceから何かをインストールするCookbookのウォークスルー

Last updated at Posted at 2013-05-01

この記事は最終更新から1年以上経過しています。 気をつけてね。

前回 ChefでSourceから何かをインストールするCookbookのウォークスルー で、IRCサーバのngircdをインストールするためにtarballを展開してmakeするサンプルを出しました。

折角なので同じことを LWRP(Lightweight Resources and Providers) で表すことでLWRPについて解説をしてみます。

これもGithubでCookbookを確認できます。タグはv0.2.1higanworks-cookbooks/ngircd_smartos(v0.2.1)

LWRPの取り扱い

前回作成したレシピでは以下の事をやりました。

  1. tarballをダウンロード
  2. coufigure && make && make install

LWRPは関数みたいに捉えられがちなので、一連のconfigure, makeを使いまわせるようにまとめておくところかな? と思われていたりしますが、実はそうではありません。

そういうのは Definitions であったり、 Librariesの役回りですね、LWRPの考え方とはまた別の話です。

Resoucesの定義

さてResoucesです。
Chefはレシピのnew_resourceと現状のcurrent_resouceを比較してConvergeするフレームワークなので、そこを中心に考えていきます。

前回のngircdのレシピで大事な要素だったのはなんでしょうか。
リモートのリポジトリ? コンフィグのオプション? makeのやり方? それらは実際のところResouceの定義とは関連が無くても困りません。

極端な話、ngircdのバイナリが目当ての場所にあればOKです。

ngircdについてのAttributes

Resourceは決まりました、ではそれの持つ要素をつけて行きましょう。
目当てのバージョンやincludeしているライブラリを定義可能にして、適切なものにしたいですね。

とりあえずVersion情報を取ります。

Shell-Out
$ ngircd -V
ngIRCd 20.2-IRCPLUS+SSL+SYSLOG+ZLIB-x86_64/pc/solaris2.11
Copyright (c)2001-2013 Alexander Barton (<alex@barton.de>) and Contributors.
Homepage: <http://ngircd.barton.de/>

This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
ひどいよ、Ops怒るよ。

20.2-IRCPLUS+SSL+SYSLOG+ZLIB、このへんからngircdバイナリの要素を定義できそうです。

Versionを要素に

バイナリにattibute[version]を持たせるためにパースしてみます。

Irb-Out
> `ngircd -V`.split[1].split('-')[0]
=> "20.2"

アーカイブのバージョンと一致していて良い感じです。

includeしているライブラリを要素に

バイナリにattibute[option]を持たせるためにパースしてみます。

Irb-Out
> `ngircd -V`.split[1].split('-')[1].split('+')
=> ["IRCPLUS", "SSL", "SYSLOG", "ZLIB"]

これはまあ、SSLあたりに気をつければいいかなと思いつつ、一応Arrayに。

レシピに書く内容

Recouceattributsを決めたので、レシピには次のように書けばあとはよろしくやってくれるようにします。

recipes/binary.rb
ngircd_smartos_binary 'ngircd' do
  action :create
  version '20.2'
  options ["SSL"]
end

current_resouceversionが違う、またはoptionのアレイに目的のものが入っていなければConvergenceを起こしてもらいます。
もちろんバイナリ本体が無ければ手段は特に問わないので置くようにという事でもあります。

LWRP版Cookbook[ngircd]をウォークスルー

比較しやすいよう前回のレシピをほぼ使いまわしつつ、LWRP[NgircdSmartosBinary]を作りました。
順に注釈を入れてみます。

attributes

attributesは大きく変わってません。version,optionsの省略時に使うデフォルトの値を追加したこと、arch_fileの指定でversionを使いまわせるようにしたくらいです。

attributes/default.rb
## base settings
default['ngircd']['prefix_dir'] = '/opt/local'
default['ngircd']['conf_dir'] = ::File.join(node['ngircd']['prefix_dir'], 'etc')
default['ngircd']['version'] = '20.2'
default['ngircd']['config_options'] = ["SSL"]


## repository
default['ngircd']['site_url'] = 'http://ngircd.barton.de/pub/ngircd/'
default['ngircd']['arch_file'] = "ngircd-#{node['ngircd']['version']}.tar.gz"

## for tempolary working
default['ngircd']['working_dir'] = ::File.join(Chef::Config[:file_cache_path], 'ngircd')

Resources

さてresourceですが、シンプルです。
指定できるActions、それと要素の型やデフォルト値、必須かどうかをここで定義します。

resources/binary.rb
actions :create, :delete

default_action :create

attribute :version, :kind_of => String, :default => node['ngircd']['version']
attribute :options, :kind_of => Array, :default => node['ngircd']['config_options']

Cookbookのresouces/以下に定義したリソースは、Chef実行時にはNameSpaceが与えられます。大雑把にcookbookの名前+ファイル名に変換されるので覚えておくとよいです。

Providers

そしてツケを全部払う場所Providersです。DefinitionsLibrariesによるリファクタリングの余地は十分にありますが前回レシピの使い回しということで。

まずはざっと眺めるだけで、だいたい何をしているかわかると思います。ちなみにaction :deleteの部分は作ってません、unlinkで済むんですが。

providers/binary.rb
action :create do
  directory node['ngircd']['working_dir'] do
    action :create
  end

  unless new_resource.version == @current_resource.version and new_resource.options - @current_resource.options == []
    ::Chef::Log.info "Install ngircd"
    node.set['ngircd']['arch_file'] = "ngircd-#{new_resource.version}.tar.gz"

    remote_file ::File.join(node['ngircd']['working_dir'], node['ngircd']['arch_file']) do
      action :create
      source node['ngircd']['site_url'] + node['ngircd']['arch_file']
    end

    bash 'make and install ngircd' do
      action :run
      flags '-ex'
      cwd node['ngircd']['working_dir']
      code <<-EOH
tar xzf #{node['ngircd']['arch_file']}
cd #{::File.basename(node['ngircd']['arch_file'], '.tar.gz')}
./configure #{node['ngircd']['configure_flags']}
make -j2
make install
EOH
    end

    ## clean up workdir
    directory ::File.join(node['ngircd']['working_dir'], ::File.basename(node['ngircd']['arch_file'], '.tar.gz')) do
      action :delete
      recursive true
    end

    new_resource.updated_by_last_action(true)
  end
end

def load_current_resource
  @current_resource = Chef::Resource::NgircdSmartosBinary.new(new_resource.name)
  if ::File.exist?(::File.join(node['ngircd']['prefix_dir'], 'sbin/ngircd'))
    @current_resource.version `ngircd -V`.split[1].split('-')[0]
    @current_resource.options `ngircd -V`.split[1].split("-")[1].split("+")
  else
    @current_resource.version '0.0'
    @current_resource.options []
  end
end

action :create do

レシピにこのResouceが定義されていた時に:createに対して何をするか、そのままですね。

unless new_resource.version == @current_resource (以下略

まさにここで new_resourceと現状のcurrent_resouceを比較 が行われます。
違った場合、とにかくnew_resourceに合わせるように処理を書いていきます。

def load_current_resource

ちょっと一番下に飛んで、def load_current_resourceです。
@current_resourceを読むとこのdefが呼ばれます、既存のバイナリに対してattributesを収集していますね。

node.set['ngircd']['arch_file']

リモート取得対象のattributeをsetで上書きします。attributesすべてをリビルドすることもできますが手っ取り早さでsetを使いました。

remote_file ::File.join(node['ngircd']['working_dir'], node['ngircd']['arch_file']) 以降

ここで前回のレシピが役に立つ、というかほぼ使いまわしです。

ポイントとしては

  • bash 'make and install ngircd' に実行条件がない、action :runにしている。
    • ここに入った時点で無条件で実行してOKですよね。
  • remote_fileがnotifyしない
    • 同上な感じです、順序も変えてます。
  • ## clean up workdir
    • ビルド後は一応掃除しておこうかなと、追加してます。

new_resource.updated_by_last_action(true)

レシピ内でnotifyのフラグを立てます。
ngircd_smartos_binarynotificationをさせる場合に必要ですが、何かしらConversion実行がなされる時は無条件で立てておくのがよいでしょう。

実行してみる

前述のレシピの内容を実行しました。chef-shellでもOKです。

バイナリがない状態で実施 or なにかオプションが違う、バージョンが違う場合

action :createの内容がすべて実行されました。

Shell-out
$ chef-solo -c solo.rb -o 'ngircd_smartos::binary' 
Starting Chef Client, version 11.4.4
[2013-05-01T23:18:01+09:00] WARN: Run List override has been provided.
[2013-05-01T23:18:01+09:00] WARN: Original Run List: []
[2013-05-01T23:18:01+09:00] WARN: Overridden Run List: [recipe[ngircd_smartos::binary]]
Compiling Cookbooks...
Converging 1 resources
Recipe: ngircd_smartos::binary
  * ngircd_smartos_binary[ngircd] action create

Recipe: <Dynamically Defined Resource>
  * directory[/var/tmp/chef/ngircd] action create (up to date)
  * remote_file[/var/tmp/chef/ngircd/ngircd-20.2.tar.gz] action create (up to date)
  * bash[make and install ngircd] action run
    - execute "bash" -ex "/tmp/chef-script20130501-84816-19exjd8"

  * directory[/var/tmp/chef/ngircd/ngircd-20.2] action delete
    - delete existing directory /var/tmp/chef/ngircd/ngircd-20.2

Chef Client finished, 3 resources updated

もう一度実行してみる、up to date

new_resouce == current_resource と判断したのでとくに影響のある動作はしてませんね。

Shell-out
$ chef-solo -c solo.rb -o 'ngircd_smartos::binary' 
Starting Chef Client, version 11.4.4
[2013-05-02T00:53:41+09:00] WARN: Run List override has been provided.
[2013-05-02T00:53:41+09:00] WARN: Original Run List: []
[2013-05-02T00:53:41+09:00] WARN: Overridden Run List: [recipe[ngircd_smartos::binary]]
Compiling Cookbooks...
Converging 1 resources
Recipe: ngircd_smartos::binary
  * ngircd_smartos_binary[ngircd] action create (up to date)
Recipe: <Dynamically Defined Resource>
  * directory[/var/tmp/chef/ngircd] action create (up to date)
Chef Client finished, 0 resources updated

おわりに

LWRPの勘所、ひいてはConvergenceを実現する為のリソース比較について伝わったでしょうか。

OpsCode公式やCommunity Cookbookではもっと沢山の - 例えばmongodbのShardingをLWRPで定義するなど - 色々と面白い例が見られます。
chef_gemリソースを使えば少々のgemならレシピ/Providers内で使えるので、定義と収束の基本を押さえておけばとても便利にLWRPを活用することができるかも?

57
56
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
57
56