Puppetlabsのドキュメントには、あるクラスで別のクラスが必要になるには、リレーションシップチェーン構文を使用し、外部ノードで両方のクラスを宣言する必要があると記載されています。
各modoleの多くのパッケージが依存するyumレポ定義を作成するレポクラスがあります。各モジュールには、Class ['repo']-> Class ['modulename']ステートメントがあり、両方のクラスがノードで宣言されています。ただし、puppetを実行すると、期待どおりにモジュールクラスの前にリポジトリクラスが実行されるとは限りません。何故なの?以下の例(パペット2.6.16):
編集:この問題には3つの基本的な解決策があるようです。
では、Puppet v3と、今後もリファクタリングを最小限に抑えたいという願望を考えると、これらのアプローチのどれが最適ですか?
マニフェストpuppettest.pp
:
class { 'repo': }
class { 'maradns': }
class repo {
class { 'repo::custom': }
}
class repo::custom {
yumrepo {'custom':
enabled => 1,
gpgcheck => 0,
descr => "Local respository - ${::architecture}",
baseurl => 'http://repo.nike.local/CentOS/\$releasever/\$basearch';
}
}
class maradns {
Class['repo'] -> Class['maradns::install']
Class['maradns::install'] -> Class['maradns::config']
Class['maradns::config'] ~> Class['maradns::service']
class { 'maradns::install': }
class { 'maradns::config': }
class { 'maradns::service': }
}
class maradns::install {
package { 'maradns':
ensure => present,
}
}
class maradns::config {
file { 'mararc':
ensure => present,
path => '/etc/mararc',
mode => '0644',
owner => root,
group => root,
}
}
class maradns::service {
service { 'maradns':
ensure => running,
enable => true,
hasrestart => true,
}
}
出力:
puppet apply puppettest.pp
err: /Stage[main]/Maradns::Install/Package[maradns]/ensure: change from absent to present failed: Execution of '/usr/bin/yum -d 0 -e 0 -y install maradns' returned 1: Error: Nothing to do
notice: /Stage[main]/Maradns::Config/File[mararc]: Dependency Package[maradns] has failures: true
warning: /Stage[main]/Maradns::Config/File[mararc]: Skipping because of failed dependencies
notice: /Stage[main]/Maradns::Service/Service[maradns]: Dependency Package[maradns] has failures: true
warning: /Stage[main]/Maradns::Service/Service[maradns]: Skipping because of failed dependencies
notice: /Stage[main]/Repo::Custom/Yumrepo[custom]/descr: descr changed '' to 'Local respository - x86_64'
notice: /Stage[main]/Repo::Custom/Yumrepo[custom]/baseurl: baseurl changed '' to 'http://repo.test.com/CentOS/\$releasever/\$basearch'
notice: /Stage[main]/Repo::Custom/Yumrepo[custom]/enabled: enabled changed '' to '1'
notice: /Stage[main]/Repo::Custom/Yumrepo[custom]/gpgcheck: gpgcheck changed '' to '0'
notice: Finished catalog run in 2.15 seconds
依存関係の問題をデバッグするための良い出発点は、依存関係グラフを生成するようにpuppetに指示することです。
puppet apply --graph --noop manifest.pp
dot -Tpng /var/lib/puppet/state/graphs/relationships.dot -o relationships.png
これを行うと、クラスrepo:custom
に依存関係情報がまったくないことがわかります。
maradns::install
はrepo
クラスに依存していませんが、repo::custom
クラスには依存していません。repo::custom
はrepo
に依存していないためです。
新しいクラス宣言構文class {'classname':}
は依存関係を設定せず、include classname
構文と同じように動作します。
したがって、依存関係をrepo::custom
からrepo
に設定するか、maradns::install
クラスに直接repo:custom
クラスに依存するように指示します。
しかし、あなたはもっと問題にぶつかるでしょう。クラスへの依存は、このクラスが適用されていることを確認するだけです。ただし、含まれているリソースに依存関係は設定されません。
私はあなたのケースを次のようにモデル化します:
class { 'repo:custom': }
class { 'maradns': }
class repo {
}
class repo::custom {
yumrepo {'custom':
enabled => 1,
gpgcheck => 0,
descr => "Local respository - ${::architecture}",
baseurl => 'http://repo.nike.local/CentOS/\$releasever/\$basearch';
}
}
class maradns {
class{[
'maradns::package',
'maradns::config',
'maradns::service',
]:}
}
class maradns::package {
package { 'maradns':
ensure => present,
require => Yumrepo['custom'],
}
}
class maradns::config {
file { 'marac:config':
ensure => present,
mode => '0644',
owner => root,
group => root,
}
}
class maradns::service {
service { 'maradns':
ensure => running,
enable => true,
hasrestart => true,
require => [
Package['maradns'],
File['mararc:config'],
],
}
}
代替メカニズムとして 実行ステージ を検討しましたか?実行ステージを使用すると、クラスを「ステージ」に関連付けることができます。デフォルトでは、すべてがmainステージで発生します。ただし、メインの前に発生するステージを設定してから、そのクラスを「メインの前」のステージに関連付けることができます。
レポは前段階の本当に良い候補です。リポジトリが希望どおりに設定される前に、パッケージが取得されることは本当に望ましくありません。独自のパッケージリポジトリをミラーリングしていて、公式リポジトリに遅れをとっている場合は、大きな頭痛の種になる可能性があります。
トリッキーなシナリオは、レポを宣言する前に、新しいパペット化されたサーバーが誤ってパッケージをフェッチし、それが最新のパブリックミラーから取得される場合です。次に、yourリポジトリがインストールされます(おそらく、パブリックミラーを削除しました)。このマシンは新しいアーティファクトを「忍び込む」ため、依存関係地獄の状況が簡単に発生する可能性があります。新しいパッケージが、気になるパッケージのインストールを停止している場合です。問題のパッケージは、すでにインストールされているためインストールされないためです。 -新しいバージョンと多くのパッケージマネージャーはあなたのためにダウングレードしません。手動で介入する必要があります。この状況を修正するには、基本的に手動でデバッグする必要があります。ダメージが発生するため、パペットルールを修正するだけでは不十分です。
したがって、すべてのリポジトリ定義をbeforeフェーズに関連付けて、それで完了します。パッケージへの依存関係の追跡を停止して、リポジトリと呼吸を容易にします。
Puppet 2.6では、クラスが別のクラスを宣言すると、内部クラスのリソースは外部クラスに含まれません。これは、エンドユーザーが外部クラスと他のモジュールの間の順序関係を指定することを不可能にするため、より小さなクラスから複雑なモジュールを構成するパターンとうまく相互作用しません。
アンカータイプを使用すると、これを回避できます。外部クラスにare含まれている2つのno-opリソースの間に内部クラスを挟むことで、モジュール内のすべてのリソースが確実に含まれるようにすることができます。
投稿されたマニフェストに基づく例は次のとおりです。
マニフェストpuppettest.pp
:
class { 'repo': }
class { 'maradns': }
class repo {
anchor { 'repo::begin': } ->
class { 'repo::custom': } ->
anchor { 'repo::end': }
}
class repo::custom {
yumrepo {'custom':
enabled => 1,
gpgcheck => 0,
descr => "Local respository - ${::architecture}",
baseurl => 'http://repo.nike.local/CentOS/\$releasever/\$basearch';
}
}
class maradns {
Class['repo'] -> Class['maradns::install']
Class['maradns::install'] -> Class['maradns::config']
Class['maradns::config'] ~> Class['maradns::service']
class { 'maradns::install': }
class { 'maradns::config': }
class { 'maradns::service': }
}
class maradns::install {
package { 'maradns':
ensure => present,
}
}
class maradns::config {
file { 'mararc':
ensure => present,
path => '/etc/mararc',
mode => '0644',
owner => root,
group => root,
}
}
class maradns::service {
service { 'maradns':
ensure => running,
enable => true,
hasrestart => true,
}
}
Repo :: customに直接依存するのではなく、repo :: customをリポジトリに含めることで何が得られますか?
そのようなクラス内でクラスを宣言するパターンも、重複した定義を設定している可能性があります。可能であれば、repo :: customを直接使用することに焦点を当てます。