オープンソースなシステム自動管理ツール Puppet

第17回リソースタイプの拡張(その3)

前々回は拡張の全体的な流れを、前回はタイプを定義するためのコードについて解説しました。

今回は、プロバイダを定義するためのコードついて、引き続きfilesimpleタイプを元に解説します。

プロバイダでは、カスタム定義されたリソースタイプを適用する場合に、具体的にどのような処理を行うのかを記述します。

サンプルコードの解説

filesimpleタイプ用のプロバイダ/etc/puppet/modules/custom/plugins/puppet/provider/filesimple/posix.rbは、以下のようなRubyコードになっています。このコードについて順次解説していきます。

01: Puppet::Type.type(:filesimple).provide(:posix) do
02: 
03:   desc "Normal Unix-like POSIX support for file management."
04:
05:   def create
06:     File.open(@resource[:name], "w") { |f| f.puts "" } # Create an empty file
07:
08:     # Make sure the mode is correct
09:     should_mode = @resource.should(:mode)
10:     unless self.mode == should_mode
11:
12:       self.mode = should_mode
13:     end
14:   end
15:
16:   def destroy
17:     File.unlink(@resource[:name])
18:   end
19:  
20:   def exists?
21:     File.exists?(@resource[:name])
22:   end
23:  
24:   # Return the mode as an octal string, not as an integer.
25:   def mode
26:     if File.exists?(@resource[:name])
27:       "%o" % (File.stat(@resource[:name]).mode & 007777)
28:     else
29:       :absent
30:     end
31:   end
32:  
33:   # Set the file mode, converting from a string to an integer.
34:   def mode=(value)
35:     File.chmod(Integer("0" + value), @resource[:name])
36:   end
37:  
38: end

1行目では、filesimpleタイプのposixプロバイダの定義を開始しています。プロバイダ名は何でも構わないのですが、分かりやすい名前をつけた方が良いでしょう。また、プロバイダ名とファイル名は同じにする必要はありませんが、Puppetに同梱されているプロバイダは同じになっているものがほとんどですので、同じにしておいた方が分かりやすいと思います。

また、:parentで親クラスを指定することによって、既存のクラスを継承したプロバイダを定義することもできます。

Puppet::Type.type(:package).provide(:dpkg, :parent => Puppet::Provider::Package) do

3行目ではこのプロバイダのドキュメントを記述しています。Puppet標準のリソースタイプでは、ここで記述されたドキュメントが、Puppet WikiのType Referenceの自動生成に利用されています。

5行目から22行目では、create、destroy、exists?の3つのメソッドを定義しています。前回、タイプ定義中でensurableヘルパメソッドを実行すると、ensureパラメータが利用できるようになり、ensureパラメータにによってこの3つのメソッドが呼び出される、と説明しました。ここでは、この3つのメソッドの具体的な実装を記述しています。

createメソッドでは、ファイルの作成とパーミッションの設定、destroyメソッドではファイルの削除、exists?メソッドではファイルの存在確認を行っています。

25行目以降では、modeプロパティに対するgetter/setterメソッドを定義しています。

25行目から31行目がgetterメソッドで、ここではファイルのパーミッションを返しているのがわかります。

33行目から36行目がsetterメソッドで、ファイルのパーミッションをセットするメソッドを定義しています。

このように、タイプで定義されたプロパティに対しては、getter/setterメソッドをセットで定義する必要があります。

複数のプロバイダ

サンプルコードでは示していませんが、ひとつのタイプに対して、環境に応じて複数のプロバイダを定義することができます(例えば、packageタイプにはyum、aptなど、様々なプロバイダが存在します⁠⁠。

プロバイダが複数ある場合でも、通常はユーザが選択する必要はなく、環境に応じて適切なプロバイダが選択されますが、そのためにはプロバイダ側でどういったコードを書けばよいのかを解説します。

プロバイダを特定の環境でのみ有効にする

特定の環境でのみプロバイダを有効にするためには、confineを利用します。

# Facter変数operatingsystemにより、特定のOSでのみ有効に
confine :operatingsystem => [:debian, :solaris]

# Facter変数puppetversionにより、特定バージョンのPuppetでのみ有効に
confine :puppetversion => '0.23.0'

# 特定のファイルが存在している場合にのみ有効に
confine :exists => '/etc/debian_release'

# 特定のメソッドの返り値によって有効に
confine :true  => Puppet.features.rrd?
confine :false => Puppet.features.rails?

また、confineと似ていますが、commandを利用すると、特定の実行バイナリが存在する場合にのみ、プロバイダを有効にすることができます。

command :yum => '/usr/bin/yum'

デフォルトプロバイダ

ユーザに選択させることなく、環境に応じて自動的にデフォルトのプロバイダが決まるようにするためには、defaultforを利用します。

例えば、あるプロバイダをRed Hat系Linuxでのデフォルトとしたい場合には、そのプロバイダのコード中に以下のようなコードを記述します。

defaultfor :operatingsystem => :redhat

リソースタイプの拡張については、今回で終了です。次回はPuppetのスケーラビリティについて解説する予定です。

おすすめ記事

記事・ニュース一覧