Puppet, setting dependencies
I am starting to setup puppet. I want to set up a dependencies that a mail transfer agent must be installed before that class tries to install or start anything. With puppet, the standard method seems to set a dependency seems to be require blah
. The challenge is I don't use the same MTA on all of my systems. Some of the systems which are actual mail servers I have a full MTA (exim), but the vast majority of my systems have ssmtp installed. What I want do is setup a requirement so that either one of those MTAs is installed and functional before the the foo
class is processed.
Here is a configuration that somewhat demonstrates what i am trying to do.
node default {
if $fqdn in ["mail1.example.org",
"mail2.example.org",
"mail3.example.org"] {
include fullmta # mailhub, and so on
} else {
include ssmtp # really basic send-only mta.
}
include foo # class that requries an mta be installed
}
class foo {
require MTA # FIXME, A valid mta is required.
package { foo: ensure => present, }
... # also a service, and some files, and so on...
}
So in my foo class, how do I require that one of the possible MTAs classes has been processed?
Solution 1:
If you split the MTA logic to a separate class, you can handle the logic there - and your resources can require the MTA class to enforce the dependency relationship.
node default {
include mta
include foo # class that requries an mta be installed
}
class mta {
if $fqdn in ["mail1.example.org",
"mail2.example.org",
"mail3.example.org"] {
include fullmta # mailhub, and so on
} else {
include ssmtp # really basic send-only mta.
}
}
class foo {
package { foo: ensure => present,
require => Class['mta'], }
... # also a service, and some files, and so on...
}
Solution 2:
Use an alias. Something like this:
service { "ssmtp":
...
alias => "MTA",
}
service { "fullmta":
...
alias => "MTA",
}
class foo {
package { foo:
ensure => present,
require => Service["mta"],
...
}
...
}
Solution 3:
You can specify require
dependencies as arrays, in which case Puppet will make sure all dependencies are met before proceeding. In this situation I usually do something like the following:
node default {
include mta
include foo # class that requries an mta be installed
}
class mta {
if $fqdn in ["mail1.example.org",
"mail2.example.org",
"mail3.example.org"] {
package { "conflicting-package-A": ensure => present, }
package { "conflicting-package-B": ensure => absent, }
} else {
package { "conflicting-package-A": ensure => absent, }
package { "conflicting-package-B": ensure => present, }
}
}
class foo {
package { foo: ensure => present,
require => [Package["conflicting-package-A",
"conflicting-package-B"], }
... # also a service, and some files, and so on...
}
This way, you not only make sure that the foo
package is explicitly dependent on both other packages, but you set things up so that if you remove a host from the mail*.example.org
list in the future, that "conflicting-package-A" will be replaced with "conflicting-package-B" automatically.