What's the best way to deal with multiple OS's

1,241 views
Skip to first unread message

Jeff Falgout

unread,
Sep 30, 2011, 2:33:50 PM9/30/11
to puppet...@googlegroups.com
We're in the situation of dealing with multiple operating systems (and will likely add another) and I'm quickly realizing that building logic in the manifest to deal with the differences in Red Hat i386 vs Red Hat x86_64 vs SuSE i586 vs SuSE x86_64 vs Mac is getting tedious. For instance, in the sshd_config:

SLES i586 has the sftp-server binary in a different path than the x86_64 version and it's different than RHEL - so I end up with logic as such:

    # Set the SFTP Path
    if $lsbdistid == 'SUSE LINUX' {
       if $architecture == 'x86_64' {
          $sftppath = '/usr/lib64/ssh/sftp-server'
       } else {
          $sftppath = '/usr/lib/ssh/sftp-server'
       }
    } else {
       $sftppath = "/usr/libexec/openssh/sftp-server"
    }


Is there a better way to deal with different OS's or is the long and winding road of config mgmt?

Do people do something like:

include ssh::server::$operatingsystem

class ssh::server::RedHat {
  blah
}

class ssh::server::SLES {
  blah
}


Different modulepath? Different puppet servers based on OS?

Cheers,

Jeff

Aaron Grewell

unread,
Sep 30, 2011, 3:46:20 PM9/30/11
to puppet...@googlegroups.com
We use different manifests per OS.  It makes the underlying logic much simpler, and is easily called by using either the 'kernel' fact or the 'operatingsystem' fact depending.

For things that are the same across supported Linuxes but different on Solaris:
include module::$kernel

Where moduledir/manifests contains linux.pp and sunos.pp.

For things that differ between Linuxes as well:
include module::$operatingsystem

Where moduledir/manifests contains redhat.pp, oel.pp, solaris.pp


--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To post to this group, send email to puppet...@googlegroups.com.
To unsubscribe from this group, send email to puppet-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.

Nigel Kersten

unread,
Sep 30, 2011, 3:57:22 PM9/30/11
to puppet...@googlegroups.com
On Fri, Sep 30, 2011 at 11:33 AM, Jeff Falgout <jtfa...@gmail.com> wrote:
We're in the situation of dealing with multiple operating systems (and will likely add another) and I'm quickly realizing that building logic in the manifest to deal with the differences in Red Hat i386 vs Red Hat x86_64 vs SuSE i586 vs SuSE x86_64 vs Mac is getting tedious. For instance, in the sshd_config:

SLES i586 has the sftp-server binary in a different path than the x86_64 version and it's different than RHEL - so I end up with logic as such:

    # Set the SFTP Path
    if $lsbdistid == 'SUSE LINUX' {
       if $architecture == 'x86_64' {
          $sftppath = '/usr/lib64/ssh/sftp-server'
       } else {
          $sftppath = '/usr/lib/ssh/sftp-server'
       }
    } else {
       $sftppath = "/usr/libexec/openssh/sftp-server"
    }


Is there a better way to deal with different OS's or is the long and winding road of config mgmt?

I tend to follow these paths, depending upon how much actual difference there is between the platforms.


file { '/etc/config':
      owner => $operatingsystem ? {
        'sunos'  => 'adm',
        'redhat' => 'bin',
        default  => undef,
      },
    }

2) Have a separate ::params style subclass where all the logic about the differences exists, and use those variables elsewhere. For some cases like "root_owner" "root_group" I've done top-level global variables instead of within the modules.

3) Have completely separate manifests.


I really think the right answer depends on how much difference you have to cope with across platforms, and how large the conditional parts end up being.

Nate B

unread,
Feb 27, 2017, 7:27:27 AM2/27/17
to Puppet Users, jtfa...@gmail.com, Nathan Basanes
  // , Is there a better way to deal with this in later versions of Puppet?

I lean toward using different manifests for different operating system variations, but like the original poster says, no matter how one organizes the logic, it still gets tedious.

Puppet 4.9 doesn't even seem to have in line selectors: https://docs.puppet.com/puppet/latest/lang_summary.html#selectors

https://duckduckgo.com/?q=inurl%3Ahttps%3A%2F%2Fdocs.puppet.com%2Fpuppet%2Flatest%2F+%22selectors%22&t=h_&ia=web

Should I consider having a different module for each OS, say, a module named appcerts_pkgs_windows and a module named appcerts_pkgs_linux, with different manifests for the variations under each?

The whole point of Puppet is to manage multiple operating systems and variations from a single source. It would surprise me if they didn't have a solution, but I just can't seem to find it.

Joshua Schaeffer

unread,
Feb 28, 2017, 3:01:45 PM2/28/17
to Puppet Users, jtfa...@gmail.com
You can build agnostic code in Puppet and pull operating system specifics from Hiera. For example:

#ls -l hieradata/
total
4
-rw-r--r-- 1 root root 872 Feb 12 18:28 common.yaml
drwxr
-xr-x 1 root root   0 Feb 28 12:31 nodes
drwxr
-xr-x 1 root root  68 Feb 28 12:31 os

#ls -lR hieradata/os
hieradata
/os:
total
0
drwxr
-xr-x 1 root root 20 Feb 28 12:33 arch
-rw-r--r-- 1 root root  0 Feb 28 12:31 debian.yaml
-rw-r--r-- 1 root root  0 Feb 28 12:31 redhat.yaml
-rw-r--r-- 1 root root  0 Feb 28 12:31 windows.yaml

hieradata
/os/arch:
total
0
drwxr
-xr-x 1 root root  0 Feb 28 12:33 i386
drwxr
-xr-x 1 root root 22 Feb 28 12:35 amd64

hieradata
/os/arch/i386:
total
0

hieradata
/os/arch/amd64:
total
0
-rw-r--r-- 1 root root 0 Feb 28 12:34 redhat.yaml

#cat hieradata/os/arch/x86_64/redhat.yaml
---
ssh
::server::sftppath: '/usr/lib64/ssh/sftp-server'

Then create your hiera.yaml file:

---
version
: 5
default:
  datadir
:     "hieradata"
  data_hash
: yaml_data

hierarchy
:
 
- name: "Node specifics"
    path
:   "nodes/%{::trusted.certname}.yaml"

 
- name: "Operating system specifics"
    paths
:
     
- "os/%{facts.os.family}.yaml"
     
- "os/arch/%{facts.os.architecture}/%{facts.os.family}.yaml"

 
- name: "Common defaults"
    path
:   "common.yaml"

You'll want to verify a few items:
  • You may want to use different facts. Take a look at the os map (or any other fact for that matter).
  • Make sure the values of the facts are correct. I just pulled those after some very quick checking. Run "puppet facts" on each machine type and match up the actual value that returns.
  • Make sure your merge strategy is appropriate to what you want. In the example above I can specify ssh::server::sftppath at the ./os/redhat.yaml and ./os/arch/amd64/redhat.yaml version. You can define a default for all redhat operating systems at the higher level and then a specific architecture path at the lower level. based on your merge strategy puppet will return different values.
Then just call lookup in your code:

lookup('ssh::server::sftppath', String, 'unique', '/usr/lib/ssh/sftp-server')

One last note, even with this strategy it can still be tricky to write agnostic code that will work between Windows and Linux as the environments between those two operating systems are so different, but you can modularize at least some of the code.

Garrett Honeycutt

unread,
Mar 2, 2017, 11:41:47 AM3/2/17
to puppet...@googlegroups.com
> --

Hi Jeff,

Most of my modules support a bunch of OS's including Debian, EL,
Solaris, Suse and Ubuntu and at different releases. To do this, I have
to encode a lot of default data into the module.

Consider the following pattern. If you do not specify a value for the
package parameter, it will use the default for that osfamily.

class foo (
$package = undef,
) {

case $::osfamily {
'Debian': { $default_package = 'foo2' }
'RedHat': { $default_package = 'foo' }
default: { fail('foo supports EL and Debian osfamilies') }
}

if $package == undef {
$package_real = $default_package
} else {
$package_real = $package
}

package { $package_real:
ensure => 'present',
}
}

Take a look at my ssh module. It is approved by Puppet and works on 13
different platforms and takes into account the processor type for Suse
as you mentioned above.

https://forge.puppet.com/ghoneycutt/ssh/readme

I tend to use case statements for all of the different platforms and
avoid using subclasses such as foo::debian and foo::redhat.

While I generally opt for putting all configuration into the same
template such as with the ssh module, sometimes the platform differences
are quite different, in which case I use platform specific templates.
For an example of this, check out my Puppet approved module for inittab.

https://forge.puppet.com/ghoneycutt/inittab

Best regards,
-g


--
Garrett Honeycutt
@learnpuppet
Puppet Training with LearnPuppet.com
Mobile: +1.206.414.8658

Michael Watters

unread,
Mar 2, 2017, 4:59:53 PM3/2/17
to Puppet Users, jtfa...@gmail.com
This is pretty much exactly what module data is for.  Check out https://docs.puppet.com/puppet/4.9/lookup_quick_module.html for more details.
Reply all
Reply to author
Forward
0 new messages