fbpx

[和訳] Chef 12におけるResourceとProviderの動的解決 #getchef

この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。

本稿は Chef-12 Dynamic Resource and Provider Resolution (2015/02/10) の和訳です。

背景

Chef 12では、'lib/chef/platform/provider_mapping.rb'にあった古いChef::Platformのハッシュマップは非推奨となりました。これにより、ProviderとResolverの動的解決の機構が推奨され、ResourceとProviderのDSLメソッドを通して操作できるようになりました。Chef 11では、プラットフォームのための機能を追加するための共通事項として、Chef::Platformハッシュマップは次のようになっていました。


class Chef
class Platform

class << self attr_writer :platforms def platforms @platforms ||= begin require 'chef/providers' { :mac_os_x => {
:default => {
:package => Chef::Provider::Package::Macports,
:service => Chef::Provider::Service::Macosx,
:user => Chef::Provider::User::Dscl,
:group => Chef::Provider::Group::Dscl
}
},
:mac_os_x_server => {
:default => {
:package => Chef::Provider::Package::Macports,
:service => Chef::Provider::Service::Macosx,
:user => Chef::Provider::User::Dscl,
:group => Chef::Provider::Group::Dscl
}
},
:freebsd => {
:default => {
:group => Chef::Provider::Group::Pw,
:service => Chef::Provider::Service::Freebsd,
:user => Chef::Provider::User::Pw,
:cron => Chef::Provider::Cron
}
},
[...etc for 400 lines...]
}
end
end
[...etc...]

新しい書式の例

Chef 12では、ProviderとResourceのクラスで'provides'メソッドを通して、ProviderとResolverを結びつけるようにしました。いくつか例を上げていきます。

すべてのプラットフォームにResourceを結びつける

ユーザがRecipeに'cookbook_file'と書いたら、すべてのプラットフォームが同じcookbook_file Resourceを得るという最も平凡な例です。


class Chef
class Resource
class CookbookFile < Chef::Resource::File provides :cookbook_file [...etc...] end end end

あるOSにResourceを結びつける

node['os'] Attributeが'solaris2'ならば、ips_package Resourceのみに結びつける例です。


class Chef
class Resource
class IpsPackage < ::Chef::Resource::Package provides :ips_package, os: "solaris2" end end end

複数のplatform_familyにResourceを結びつける

より複雑な例として、provides行がnode['platform_family']をサポートし、値の配列が用いられているものを紹介します。どのようなプラットフォームのRecipeに'yum_package'に書いたとしてもyum_package Resourceに結びつけられる (SolarisでRecipeに'yum_package'に書いたとしても、その種類のResourceを得られる) だけでなく、Red Hat系のplatform_familyでユーザが'package'と書いたとしても'yum_package' Resourceに結びつけられて解決されます。これは、Red Hatで'package "foo"'と書いたら、素のパッケージ検証を行ってあらゆるyum特有のオプションを拒否するような素のChef::Resource::Packageオブジェクトを得るという、Chef 11からのちょっとした変更です。Chef 12では、Red HatではYumPackage Providerのための正しい検証を行うChef::Resource::YumPackageオブジェクトを得られます。


class Chef
class Resource
class YumPackage < Chef::Resource::Package provides :yum_package provides :package, os: "linux", platform_family: [ "rhel", "fedora" ] end end end

任意のNode Attributeに基いてResourceを結びつける

Solaris2において、platform_versionが5.10以下ならばsolaris_packageを使う必要があり、platform_versionが5.11以上ならips_packageを使う必要があるならば、provides行は次のようになります。


class Chef
class Resource
class SolarisPackage < Chef::Resource::Package provides :solaris_package provides :package, os: "solaris2", platform_family: "nexentacore" provides :package, os: "solaris2", platform_family: "solaris2" do |node| # on >= Solaris 11 we default to IPS packages instead
node[:platform_version].to_f <= 5.10 end end end end

ResourceとProviderのprovides行

Resourceファイルのすべてのprovides行について、通常はProviderファイル内の対応するprovides行であるべきです。Resourceは、Resourceのコンストラクタにもはや明示的にProviderを設定すべきではありません。ResourceでのProviderの明示的な定義はまだ動作しますが、Providerの動的解決ではこれは無視されます。Providerファイルでのprovides行がなくても今は動作し、Resource名に基くProviderの決定を壊したりはしませんが、これは非推奨となります。近いうちにChefは警告するようになり、いずれResourceとProviderの両方でprovides行が一致しなければ失敗するようになります。

サポートするprovidesの書式

provides行は、配列か文字列のどちらかに一致する'os'、'platform'、'platform_family'オプションを持ちます。また、Node Objectに渡されて、Nodeに結びつけることができたら真を返すことを期待されるブロックも持ちます。複数のマッチャがある場合、条件がすべて真でなければいけません。複数のprovides行は複数の条件に用いられ、配列の書式は配列の要素のいずれかにもマッチします。


provides :cookbook_file
provides :package, os: "windows"
provides :rpm_package, os: [ "linux", "aix" ]
provides :package, os: "solaris2", platform_family: "smartos"
provides :package, platform: "freebsd"
provides :package, os: "linux", platform_family: [ "rhel", "fedora" ]
provides :package, os: "solaris2", platform_family: "solaris2" do |node|
node[:platform_version].to_f <= 5.10 end

この書式の実装はlib/chef/node_map.rbファイルに含まれています。Chef::NodeMapオブジェクトはNode Objectに基いた条件を挿入されうる値を持つキーバリューストアです(そして、Node Objectがマッチするときのみそれらは回収されます)。

Providerの動的解決

Providerも動的解決を行います。プラットフォームが与えられたProviderをサポートしているかどうか(例:initシステムがsystemdかどうか?)、Providerのprovides?が与えられたResourceをサポートしているかどうか(例:service 'foo'はsysvinitスクリプトかupstartで管理されているかどうか?)を決定するための、Chef::Provider.provides? メソッドとChef::Provider.supports? メソッドを実装する、上書き可能な追加メソッドを持ちます。これはLinuxのinit scriptシステムのようなものを動的に取り扱うためにおおよそ設計されたようなものです。詳細は本稿で取り扱う範囲を越えているので、興味のある方はservice Providerを見てみてください。

LWRPの取り扱い

LWRPを任意の名前に結びつけることができるようになりました! もはやデフォルトの'[cookbook_name]_[provider_filename]'にとらわれず、もし望むなら独自のLWRPをpackage Providerに結びつけることさえできます (たとえそれがドラゴンだとしても----あるプラットフォーム用のpackage ProviderをChef本体に実装し、独自のpackage Providerが新しいChef本体のものと衝突するという、APIの破壊的な変更ではなく、API拡張というマイナーリリースで壊されるような場合を考えてみてください)。次は簡単な例です。

resources/default.rb


actions :run
default_action :run

provides :foo_bar

attribute :thing, kind_of: String, name_attribute: true

providers/default.rb


use_inline_resources

provides :foo_bar

action :run do
Chef::Log.warn new_resource.thing
end

recipes/default.rb


foo_bar "baz"

LWRP Chef 11 後方互換性

Chef 11はResourceにおける'provides'の書式をサポートしているので、コミュニティCookbookやChef 11後方互換性が依然として重要な場所で用いられる機能となるでしょう。Chef 12はResourceのために既に存在していたAPIを改善しただけです。Providerでの'provides'の書式を許可せず、"on_platform:"引数を取るだけです (Chef 12は後方互換のために"on_platform"を"platform"の別名としてサポートします)。LWRPを改名しChef 11後方互換性を維持することは、単純にProviderから'provides'行を削除するか、理想的には'if respond_to?(:provides)'という判定を用いて保護します。

状況

動的なProviderとResolverの機能は依然として開発中で、Chef 12では完成していません。Chef::Platform platform_mapには動的解決に変換して空にする必要があるエントリがまだ残っています。いずれにしろハッシュテーブルは完全に削除する必要があります。
ResourceとProviderの両方で起きている名前からクラスへ変換する謎の魔法は削除されます。実際に用いられるinitシステムに基いて挙動を変更する必要があるCookbookコードを書くための助けとなるDSLヘルパーメソッドとして提供される必要がある、ホストで使われているinitシステムを決定するための有用なヘルパーモジュールがあります。

これらのAPIについての文章は docs.chef.io には現時点では存在していません(もしこれを読んでいるのがJames Scottなら、修正のための連絡をください)。

新規CTA