我继承了一个 Puppet 服务器。它管理着几十台主机,大部分运行良好。
当我说大多数时候,有几位房东在办理入住手续时失败了:
Error: Failed to apply catalog: Could not find dependency File[/etc/postfix/main.cf] for Augeas[set postfix 'relayhost' to 'smtp.mydomain.net']
我仔细研究了一下,确定有问题的类定义位于文件“default.pp”中
postfix::config {
"relayhost": value => "smtp.mydomain.net"
}
现在,我的理解(可能不正确)是,这个文件被每个由 puppet 管理的主机使用,但问题只存在于少数主机上。大多数主机运行正常。
因此,我正在研究问题出在客户端而不是服务器的理论。
显然,首先要检查的是文件 /etc/postfix/main.cf 是否确实存在于问题主机上。答案是肯定的。
我花了一整天时间在 Google 上搜索这个问题,我发现的所有问题往往都是人们在编写清单时犯了错误。我从未发现任何人在使用清单时遇到问题,而清单在其他主机上似乎运行正常。
我是 puppet 的新手(但不是 Linux),发现它很有趣,即使从 puppet 中得到的错误消息可能有些神秘。
欢迎任何帮助。
系统是 CentOS 6,带有 puppet 3.2.3-1
- - 更新 - -
(抱歉回复晚了,因为我在澳大利亚所以时区不同)
好的,根据 Craig 在下面给出的回答,我已经在 puppetmaster 上的 puppet 目录中查找了 main.cf 的实例
root@svd7puppetmaster:/etc/puppet ] # grep -R main.cf *
modules/postfix/manifests/init.pp: file { '/etc/postfix/main.cf':
modules/postfix/manifests/init.pp: source => 'puppet:///modules/postfix/main.cf',
modules/postfix/manifests/config.pp:#configuation file (/etc/postfix/main.cf).
modules/postfix/manifests/config.pp: incl => '/etc/postfix/main.cf',
modules/postfix/manifests/config.pp: require => File['/etc/postfix/main.cf'],
文件内容如下(为了简洁,我删除了标题注释);
root@svd7puppetmaster:/etc/puppet ] # cat modules/postfix/manifests/init.pp
class postfix {
# selinux labels differ from one distribution to another
case $::operatingsystem {
RedHat, CentOS: {
case $::lsbmajdistrelease {
'4': { $postfix_seltype = 'etc_t' }
'5','6': { $postfix_seltype = 'postfix_etc_t' }
default: { $postfix_seltype = undef }
}
}
default: {
$postfix_seltype = undef
}
}
# Default value for various options
if $postfix_smtp_listen == '' {
$postfix_smtp_listen = '127.0.0.1'
}
if $root_mail_recipient == '' {
$root_mail_recipient = 'nobody'
}
if $postfix_use_amavisd == '' {
$postfix_use_amavisd = 'no'
}
if $postfix_use_dovecot_lda == '' {
$postfix_use_dovecot_lda = 'no'
}
if $postfix_use_schleuder == '' {
$postfix_use_schleuder = 'no'
}
if $postfix_use_sympa == '' {
$postfix_use_sympa = 'no'
}
if $postfix_mail_user == '' {
$postfix_mail_user = 'vmail'
}
case $::operatingsystem {
/RedHat|CentOS|Fedora/: {
$mailx_package = 'mailx'
}
/Debian|kFreeBSD/: {
$mailx_package = $::lsbdistcodename ? {
/lenny|etch|sarge/ => 'mailx',
default => 'bsd-mailx',
}
}
'Ubuntu': {
if (versioncmp('10', $::lsbmajdistrelease) > 0) {
$mailx_package = 'mailx'
} else {
$mailx_package = 'bsd-mailx'
}
}
}
$master_os_template = $::operatingsystem ? {
/RedHat|CentOS/ => template('postfix/master.cf.redhat.erb', 'postfix/master.cf.common.erb'),
/Debian|Ubuntu|kFreeBSD/ => template('postfix/master.cf.debian.erb', 'postfix/master.cf.common.erb'),
}
package { 'postfix':
ensure => installed,
}
package { 'mailx':
ensure => installed,
name => $mailx_package,
}
service { 'postfix':
ensure => running,
enable => true,
hasstatus => true,
restart => '/etc/init.d/postfix reload',
require => Package['postfix'],
}
file { '/etc/mailname':
ensure => present,
content => "$::fqdn\n",
seltype => $postfix_seltype,
}
# Aliases
file { '/etc/aliases':
ensure => present,
content => '# file managed by puppet\n',
replace => false,
seltype => $postfix_seltype,
notify => Exec['newaliases'],
}
# Aliases
exec { 'newaliases':
command => '/usr/bin/newaliases',
refreshonly => true,
require => Package['postfix'],
subscribe => File['/etc/aliases'],
}
# Config files
file { '/etc/postfix/master.cf':
ensure => present,
owner => 'root',
group => 'root',
mode => '0644',
content => $master_os_template,
seltype => $postfix_seltype,
notify => Service['postfix'],
require => Package['postfix'],
}
# Config files
file { '/etc/postfix/main.cf':
ensure => present,
owner => 'root',
group => 'root',
mode => '0644',
source => 'puppet:///modules/postfix/main.cf',
replace => false,
seltype => $postfix_seltype,
notify => Service['postfix'],
require => Package['postfix'],
}
# Default configuration parameters
$myorigin = $valid_fqdn ? {
'' => $::fqdn,
default => $valid_fqdn,
}
postfix::config {
'myorigin': value => $myorigin;
'alias_maps': value => 'hash:/etc/aliases';
'inet_interfaces': value => 'all';
}
case $::operatingsystem {
RedHat, CentOS: {
postfix::config {
'sendmail_path': value => '/usr/sbin/sendmail.postfix';
'newaliases_path': value => '/usr/bin/newaliases.postfix';
'mailq_path': value => '/usr/bin/mailq.postfix';
}
}
default: {}
}
mailalias {'root':
recipient => $root_mail_recipient,
notify => Exec['newaliases'],
}
}
和
root@svd7puppetmaster:/etc/puppet ] # cat modules/postfix/manifests/config.pp
define postfix::config ($value, $ensure = present) {
Augeas {
incl => '/etc/postfix/main.cf',
lens => 'Postfix_Main.lns',
notify => Service['postfix'],
require => File['/etc/postfix/main.cf'],
}
case $ensure {
present: {
augeas { "set postfix '${name}' to '${value}'":
changes => "set $name '$value'",
}
}
absent: {
augeas { "rm postfix '${name}'":
changes => "rm $name",
}
}
default: {}
}
}
主机的清单非常简单。为了简洁起见,除非有人要求,否则我不会在这里发布它们。它们几乎只定义网络 IP 和 ntp 服务器。与 postfix 完全无关。它们继承自另一个清单,该清单仅涉及一些 snmp 设置和系统日志记录内容,而后者又继承自 default.pp,其中包含导致问题的 postfix 部分(在本问题的开头显示)(如果我将其注释掉,问题就会消失)
工作主机和非工作主机之间的唯一区别实际上是节点名称及其 IP 地址,否则两个清单是相同的。
如果有人想看这些文件的内容,我可以发布它们的内容。
我还检查了 postfix 模块的可用性:
root@svd7puppetmaster:/etc/puppet ] # puppet module list | grep postfix
├── postfix (???)
我假设由于模块没有以“puppetlabs”为前缀,所以它不是官方模块?我不确定还有什么其他方法可以检查这一点。
- - 更新 - -
很抱歉耽误了这么久,我们的生产系统出现了一些问题,需要一些时间才能解决,所以这件事不得不暂时搁置。
不管怎样,这让我很头疼。我已经使用了两个主机,一个可以正常工作,另一个则出现故障。
我为他们俩创建了完全空的清单:
node myhost1 {
}
应用程序清单如下:
node application {
}
然而,当我在它们上运行 Puppet 代理时,我得到了不同的结果:
[09:32:55 root@myhost01:~ ] # puppet agent --test
Info: Retrieving plugin
Info: Loading facts in /var/lib/puppet/lib/facter/os_maj_version.rb
Info: Loading facts in /var/lib/puppet/lib/facter/iptables_persistent_version.rb
Info: Loading facts in /var/lib/puppet/lib/facter/ip6tables_version.rb
Info: Loading facts in /var/lib/puppet/lib/facter/root_home.rb
Info: Loading facts in /var/lib/puppet/lib/facter/puppet_vardir.rb
Info: Loading facts in /var/lib/puppet/lib/facter/concat_basedir.rb
Info: Loading facts in /var/lib/puppet/lib/facter/pe_version.rb
Info: Loading facts in /var/lib/puppet/lib/facter/iptables_version.rb
Info: Caching catalog for myhost01.mydomain.net
Info: Applying configuration version '1426804333'
Notice: Finished catalog run in 1.00 seconds
和
[root@myhost02 datawarehouse]# puppet agent --test
Info: Retrieving plugin
Info: Loading facts in /var/lib/puppet/lib/facter/os_maj_version.rb
Info: Loading facts in /var/lib/puppet/lib/facter/root_home.rb
Info: Loading facts in /var/lib/puppet/lib/facter/iptables_version.rb
Info: Loading facts in /var/lib/puppet/lib/facter/concat_basedir.rb
Info: Loading facts in /var/lib/puppet/lib/facter/ip6tables_version.rb
Info: Loading facts in /var/lib/puppet/lib/facter/puppet_vardir.rb
Info: Loading facts in /var/lib/puppet/lib/facter/pe_version.rb
Info: Loading facts in /var/lib/puppet/lib/facter/iptables_persistent_version.rb
Info: Caching catalog for myhost02.mydomain.net
Error: Failed to apply catalog: Could not find dependency File[/etc/postfix/main.cf] for Augeas[set postfix 'relayhost' to 'smtp.mydomain.net']
显然,我对 Puppet 工作原理的理解严重不足,因为我无法理解为什么两个具有空清单的主机会表现不同。
无论如何,感谢你们对此事的帮助,但我认为现在我只能把它放到太难的篮子里。
答案1
这肯定是 puppetmaster 的清单出了问题,但据推测触发由于客户端的一些变化,导致在后缀模块的某处对傀儡清单的不同部分进行评估。
在 postfix 模块中的某个地方会有一个 augeas 资源,它依赖于 File['/etc/postfix/main.cf'](需要、通知、订阅等),但由于某种原因,文件 { '/etc/postfix/main.cf': } 资源尚未声明(可能在“if”或其他内容中)。但是,如果没有关于 postfix 模块的更多详细信息,很难猜测是什么。
postfix 模块是来自 puppetlabs 还是 puppetforge?如果是,是哪一个(有很多),哪个版本?如果不是,您能分享一下模块吗?
答案2
您的Error: Failed to apply catalog: Could not find dependency File[/etc/postfix/main.cf] for Augeas[set postfix 'relayhost' to 'smtp.mydomain.net']
意思是您的清单中的某处有一个augeas { "set postfix 'relayhost' to ...."
带有 的文件require File['/etc/postfix/main.cf']
,暗示 puppet 应该首先安装 postfix 主配置,然后设置您的中继主机,而有问题的文件不是您正在应用的目录的一部分。
关于该主题的附注:如果您每次都安装 postfix 主模板,那么让 augeas edit replyhosts:puppet 会在每次运行时编辑 postfix 配置两次。您可能想要研究一下如何使用单个模板,或者在安装 postfix 主配置replace => no
中添加file{}
。
回到你的问题,听起来你好像包括了postfix::config
,但还没有包括postfix
它自己,它(AFAIU)会安装 postfix 主配置。
在破坏由该 puppetmaster 驱动的每个 postfix 配置之前,您可能需要确保您在单独的环境中工作。然后,作为一个大胆的猜测/没有从您的设置中看到太多:编辑您的postfix/manifests/config.pp
添加在postfix::config
定义中的某处:
if (! defined(Class["postfix"])) {
include postfix
}
请注意,它“工作”的节点现在可能会受到重复后缀定义的影响:寻找添加该定义检查的其他包含内容,...
作为免责声明:除非您知道自己在做什么,否则不应编辑 Puppet 清单(考虑到所有注册的客户端都会刷新其配置,...即使在最佳条件下,任何事情都可能中断,...)