15

Puppetlabs 文档指出,为了让一个类需要另一个类,您应该使用关系链接语法并在外部节点中声明这两个类。

我有一个 repo 类,它创建每个模块中的许多包所依赖的 yum repo 定义。在每个模块中,我都有一个 Class['repo'] -> Class['modulename'] 语句,并且两个类都在节点中声明。但是,当 puppet 运行时,它并不总是按预期在模块类之前执行 repo 类。为什么不?下面的示例(木偶 2.6.16):

编辑:这个问题似乎有 3 个基本解决方案。

  1. 使用 before/require 元参数将类依赖项替换为资源依赖项(如图灵机的答案所示)。
  2. 删除外部类依赖关系并显式声明内部类之间的依赖关系。
  3. 在 stdlib 模块中使用 Puppetlabs 提供的锚类型来包含一个类,该类允许依赖类使用链接语法创建对外部类的引用。

那么,考虑到 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
4

4 回答 4

6

调试依赖问题的一个很好的起点是指示 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::customto的依赖关系,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'],
    ],
  }
}
于 2012-07-25T16:49:15.090 回答
4

来自puppetlabs 标准库文档

在 Puppet 2.6 中,当一个类声明另一个类时,内部类中的资源不包含在外部类中。这与从较小的类中组合复杂模块的模式产生了不良的交互作用,因为最终用户无法指定外部类和其他模块之间的顺序关系。

锚类型让您可以解决这个问题。通过将任何内部类夹在外部类包含的两个无操作资源之间,您可以确保包含模块中的所有资源。

根据发布的清单,示例如下:

清单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,
  }
}
于 2012-07-26T14:25:00.237 回答
4

您是否考虑过运行阶段作为替代机制?通过运行阶段,您可以将类与“阶段”相关联。默认情况下,一切都发生在阶段。但是您可以设置一个发生在 main 之前的阶段,然后将该类与该“main 之前”阶段相关联。

回购是一个非常好的前阶段候选人。在按照您想要的方式设置存储库之前,您真的不希望检索任何包;如果您正在镜像自己的软件包存储库并落后于官方存储库,这可能会令人头疼。

更棘手的情况是当一个新的 puppetized 服务器在您甚至声明您的 repo 之前意外地获取了一个包,并且它从最新的公共镜像中获取它;然后你的repo 就安装好了(大概你现在已经删除了公共镜像)。因为这台机器“潜入”了一个新的工件,所以很容易出现依赖地狱的情况,一个太新的包正在阻止你关心的包被安装,因为有问题的包不会安装,因为你已经安装了一个太- 新版本和许多包管理器不会为你降级;你必须手动干预。这种情况本质上需要手动调试才能修复;仅仅修复你的傀儡规则是不够的,因为已经造成了损害。

因此,只需将所有 repo 定义与之前的阶段相关联,并完成它。停止跟踪对您的包的依赖项,以便更轻松地进行回购和呼吸。

于 2012-08-03T03:02:51.870 回答
2

通过在 repo 中包含 repo::custom 而不是直接依赖 repo::custom 可以获得什么?

在这样的类中声明类的模式也可能会为您设置重复定义。如果可能的话,我会专注于直接使用 repo::custom 。

于 2012-07-30T11:27:01.693 回答