如何在人偶清单中延迟定义 class

how to lazily define a class in a puppet manifest

我有一个具有不同角色的系统,A B C。有一个 class daemon::conf 定义了 conf 并连接了所有 classes 参数的配置,例如

class daemon::conf (
  global_config = {}
  a_config      = {}
  b_config      = {}
  c_config      = {}
) {
concat::fragment {...}
}

所以当我这样做时:

class hg_mysystem::mycluster::hybrid {
  include daemon::A
  include daemon::B
}

我想要:

$ cat /etc/mysystem/config
[Global]
...
[A]
...
[B]
...

每个守护进程都定义为 daemon::A, daemon::B, daemon::C,但它们调用 daemon::conf 时会使用自己的参数,这些参数在 .pp 清单文件中的 hiera 中定义。现在我需要创建一个具有 2 或 3 个角色的节点(写 include daemon::A;include daemon::B 等),但我遇到了 class 重新定义的问题,因为 daemon::conf 在所有 A B 和 C 中定义.

我的第一个想法是在一个节点上定义 class 并添加 if defined(Class['daemon::conf']) {add argument to the defined class} else {class{'daemon::conf'...}} 但我不知道如何从清单创建动态 hiera 变量,或者如何执行 hiera来自清单的样式分配。 我也在搜索如何使用这些虚拟资源对 class 进行惰性初始化,但我不明白这有什么帮助,当 realize 不会覆盖参数但 realize 你只能这样做 realise Class['daemon::conf'] 而不是 realise Class['daemon::conf'] {b_config={...}}。 有什么办法可以用子 classes 重组 daemon::conf,通知另一个 class 根据 classes 的数据构建 conf。

编辑:

我采用了第二种方法,将 daemon::conf 拆分为 daemon::confdaemon::conf::Adaemon::conf::B

class daemon::conf (...) {
  concat { '/etc/daemon/conf':
    owner   => 'root',
    group   => 'root',
    mode    => '0664',
    require => Package['daemon'],
  }

  Concat::Fragment <<| target == '/etc/daemon/config' |>>

  concat::fragment { 'daemon.conf':
    tag     => "daemon.conf",
    target  => '/etc/daemon/config',
    order   => '01',
    content => template('daemon/daemon.conf.erb'),
  }
}

define daemon::conf::A (...) {
  include ::daemon::conf

  @@concat::fragment { "${::hostname}.daemon.conf":
    tag     => "daemon.conf",
    target  => '/etc/daemon/config',
    order   => '20',
    content => template('daemon/daemon.conf-A.erb'),
  }

}

class daemon::conf::B (...) {
  include ::daemon::conf

  concat::fragment { $::hostname:
    tag     => "daemon.conf",
    target  => '/etc/daemon/config',
    order   => '10',
    content => template('daemon/daemon.conf-B.erb'),
  }

}

class daemon::A (
  $A_addr,
  $port,
) {
  include ::daemon::conf

  daemon::conf::A { $::hostname:
    addr => $A_addr,
    port => $port,
  }
}

class daemon::B (
  $B_rack_loc,
) {
  include ::daemon::conf

  class {'::daemon::conf::B':
    B_config => {
      B_rack_location => $B_rack_loc,
    }
  }
}

运行 同一主机组中 3 个节点上的 puppet 我应该得到:

[user@hostname1: ~]$ cat /etc/daemon/config
[Global]
...
[B]
loc = row RO, rack RA, host hostname1
[A/hostname1 ip]
addr=...
port=...
[A/hostname2 ip]
addr=...
port=...
[A/hostname3 ip]
addr=...
port=...

但是我得到了角色 B 以及所有 3 台主机的多个配置。我犯了什么错误以及如何解决?谢谢。是否应该更改“<<| |>>”语句?

任何解决方案都需要适应这样一个事实,即给定 class 参数的 所有 的值是在第一次声明 [=28] 时确定的=] 被评估,无论声明是类似资源的声明还是类似包含的声明。仅当所有在第一次使用类似包含形式的形式后评估的所有声明才允许多重声明,这是在大多数情况下应避免使用类似资源的 class 声明的原因之一。

有多种方法可以考虑这些因素。一种方法是颠倒逻辑:不是让每个 daemon::X class 都声明 daemon::conf,而是集中声明一次,然后将角色列表传递给配置。然后让它根据角色列表声明适当的 daemon::conf::X classes:

class daemon::conf (
  $global_config = {}
  $roles =         []
) {
  concat { ... }
  concat::fragment {...}
  $roles.each { |$role|
    contain "daemon::conf::${role}"
  }
}

另一种方法是完全免除中央 daemon::conf class 声明每个角色配置的责任。这是可能的,因为您正在使用 Concat 从片段构建配置。 puppetlabs::concat 的关键特性之一是 concat::fragment 可以彼此独立地声明,并且 concat 声明它们贡献的文件:

class daemon::conf (
  $global_config = {}
) {
  concat { ... }
  concat::fragment {...}  # general configuration only
}

class daemon::a::conf (...) {
  concat::fragment {...}  # daemon A configs
}

class daemon::b::conf (...) {
  concat::fragment {...}  # daemon B configs
}

class daemon::a (...) {
  include daemon::conf     # (maybe)
  contain daemon::a::conf
  # ...
}

class daemon::b (...) {
  include daemon::conf     # (maybe)
  contain daemon::b::conf
  # ...
}

...