Puppet manifests are often hard enough without having to worry about deploying to multiple operating systems. Small variations can be easy enough with selectors:
file { "ntp.conf": path => $operatingsystem ? { "solaris" => "/etc/inet/ntp.conf", default => "/etc/ntp.conf", }, owner => "root", group => "root", mode => 644, source => "file:///modules/ntp/ntp.conf", }You can even deploy different files elegantly with variable/fact interpolation and multiple source file paths.
file { "ntp.conf": # ..snip.. source => [ "file:///modules/ntp/ntp.conf.$operatingsystem", "file:///modules/ntp/ntp.conf", ], }Puppet will search through the source files, looking first for
ntp.conf.Solaris
, ntp.conf.RedHat
etc. before moving
to the generic ntp.conf
.
But sooner or later, you'll need to include or exclude entire resources based on the platform. You can go down the slippery slope of if and case statements... but resist, that way madness lies.
Don't use conditionals for including and excluding resources
Now I've got that blanket statement out there, try this out for size:
class foo { include "foo::$operatingsystem" } class foo::common { file { "foo.conf": path => $operatingsystem { "solaris" => "/opt/csw/etc/foo.conf", default => "/etc/foo/foo.conf", }, # etc... } } class foo::redhat inherits foo::common { # No changes } class foo::solaris inherits foo::common { file { "bar.conf": path => "/opt/csw/etc/bar.conf", } }Then just
include foo
from your node definition (though you're using an ENC, right?).
This is my preferred approach, including for decisions not based on OS (such as
architecture perhaps). It lets you easily work out which resources are
included in a system's configuration just by looking at the classes applied to
it (/var/lib/puppet/classes.txt
) and helps you ensure resources
are consistent across platforms.