如何使用Puppet参数化类来强制应用资源的顺序?

时间:2012-07-24 17:01:00

标签: puppet

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

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

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

  1. 使用依赖于资源依赖项替换类依赖项 before / require元参数(如turingmachine的回答所示)。
  2. 删除外部类依赖项并显式声明依赖项 内部阶级之间。
  3. 使用stdlib模块中Puppetlabs提供的锚类型 包含一个允许依赖类创建引用的类 使用链接语法到外部类。
  4. 那么考虑到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 个答案:

答案 0 :(得分: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::customrepo的依赖关系,要么指示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'],
    ],
  }
}

答案 1 :(得分:4)

来自puppetlabs stdlib documentation

  

在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,
  }
}

答案 2 :(得分:4)

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

回购是一个非常好的前一阶段候选人。您真的不希望在您的存储库按照您想要的方式设置之前检索任何包;如果您正在镜像自己的包装回购并且滞后于官方回购,那将是一个巨大的麻烦。

更棘手的情况是,一个新的木偶化服务器在你甚至宣布你的回购之前意外地抓取了一个包,它从最新的公共镜像中得到它;然后安装你的 repo(可能你现在已经删除了公共镜像)。因为这台机器“偷偷摸摸”了一个新的工件,所以很容易出现依赖性地狱情况,因为太新的软件包会阻止你关心的软件包被安装,因为有问题的软件包将无法安装因为你已经安装了 - 新版本和许多软件包管理器不会为您降级;你必须手动干预。这种情况基本上需要手动调试来修复;只是修复你的傀儡规则是不够的,因为伤害已经完成。

因此,只需将所有回购定义与之前阶段相关联,然后完成。停止跟踪您的包裹上的依赖关系以便更好地恢复和呼吸。

答案 3 :(得分:2)

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

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