Linux – puppet Could not find dependency

linuxpuppet

I have inherited a puppet server. It has a couple of dozen hosts under management and it is mostly working fine.

When I say mostly there are a few hosts that fail when checking in:

Error: Failed to apply catalog: Could not find dependency File[/etc/postfix/main.cf] for Augeas[set postfix 'relayhost' to 'smtp.mydomain.net']

I have poked around and have determined that the class definition in question is in the file "default.pp"

postfix::config {
    "relayhost": value  => "smtp.mydomain.net"
}

Now, it is my (possibly incorrect) understanding that this file is used by every host that is managed by puppet yet the problem only exists on a handful of hosts. The majority work fine.

Hence, I am working on the theory that the problem is on the client side and not the server.

Obviously, the first thing to check was whether the file /etc/postfix/main.cf actually exists on the problem hosts. It does.

I have spent the day googling for this and all the problems I have found tend to be people making errors while writing manifests. Nowhere have I found anybody that is having trouble with specific hosts using a manifest that apparently works ok on other hosts.

I am new to puppet (but not Linux) and am finding it interesting, even though the error messages you get out of puppet can be somewhat cryptic.

Any help most welcome.

Systems are CentOS 6 with puppet 3.2.3-1

— UPDATE —

(Sorry about the delay in responding, I'm in Australia so timezone differences apply)

OK, so based on the answer given by Craig below, I have grepped the puppet dir on the puppetmaster for instances of 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'],

The content of the files are as follows (I removed the header comments for brevity);

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'],
   }
}

and

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: {}
  }
}

The manifest for the hosts is pretty simple. For the sake of brevity I won't post them here unless asked. They pretty much just define network IP and ntp servers. Nothing related to postfix at all. They inherit from another manifest that is only concerned with some snmp settings and syslogging stuff and that in turn inherits from default.pp which contains the postfix section (shown at the start of this question) that causes the problem (if I comment it out the problem disappears)

The only difference between a working host and a non working host is literally the node name and its IP address, otherwise the two manifests are identical.

I can post the contents of those files if anybody wants to see them.

I also checked the providence of the postfix module:

root@svd7puppetmaster:/etc/puppet ] # puppet module list | grep postfix
├── postfix (???)

I am assuming that since the module is not prefixed by "puppetlabs" then it is not an official module? I am not sure how else to check that.

— UPDATE —

Sorry about the delay, had a bit of drama in our production systems that has taken some time to so this had to put on the backburner.

Anyway, this is doing my head in. I have taken two hosts, one that is working, the other that is failing.

I have created completely empty manifests for them both:

node myhost1 {

}

The application manifest is thus:

node application {

}

Yet, when I run the puppet agent on them both I get different results:

[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

and

[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']

Clearly my understanding of how puppet works is severely lacking because I can't understand why two hosts with empty manifests would behave differently.

Anyway, thanks your help on this guys but I think for now I will just put it in the too hard basket.

Best Answer

Your Error: Failed to apply catalog: Could not find dependency File[/etc/postfix/main.cf] for Augeas[set postfix 'relayhost' to 'smtp.mydomain.net'] means that you have somewhere in your manifests an augeas { "set postfix 'relayhost' to ...." with a require File['/etc/postfix/main.cf'], implying puppet should first install postfix main configuration then set your relayhost, while the file in question is not part of the catalog you're applying.

Side note on that subject: if you install your postfix main template each time, then have augeas edit relayhosts: puppet would edit postfix configuration twice on each run. You may want to investigate on using a single template here, OR adding a replace => no to the file{} installing postfix main configuration.

Back to your problem, it sounds like you're including postfix::config, but haven't included postfix itself, which (AFAIU) would have installed postfix main configuration.

Before breaking every postfix configuration driven by that puppetmaster, you may want to make sure you're working on a separate environment. Then, as a wild guess/not having seen much from your setup: edit your postfix/manifests/config.pp adding somewhere inside postfix::config definition:

if (! defined(Class["postfix"])) {
    include postfix
}

Note the node where it "worked" may now be affected by a duplicate postfix definition: look for other inclusions adding that definition check, ...

As a disclaimer: you shouldn't edit your puppet manifests unless you know what you're doing (considering all registered clients that will refresh their configuration, ... even in the best conditions, anything could break, ...)

Related Topic