Writing modules: detecting package manager and init system

Say, I want to write a module which installs a package, and runs a service. I want to include most OS-es (well, Linuxes at least). For this, I need to know:

the package manager in use (am I going to add a yum or an apt repo?)

the init system in use (am I going to add config for SysV, upstart, systemd?)

... now, Puppets documentation for packages and for services just claim 'Puppet will usually find this out on its own', however, as I need to code adding that repo, or figure out which init config file to put where, does it actually expose this kind of information anywhere? Looking through facts & code, I don't see it anywhere, and looking at some mature modules they all seem to re-invent the wheel in checking operating systems & going for what should be default there. So, in short, my question is:

Does Puppet itself expose this kind of information anywhere in a module?

And if not, is there a module specifically to do this, which I can use?

... because basically, having just an if $::packagemanager == 'yum' or if $::initsystem == 'upstart' does seem a whole lot cleaner than an entire tree of $::osfamily stuff, with all the possible version comparisons as well.

4 Answers

Package managers allow you to include more than just your software but a ton of metadata and scripts and service config. Look at fpm and bundle everything into one package, then install that with a simple:

package {'whatever':
ensure => present,
}

You can host the packages in a repo and ensure the repo is present, also through puppet, or allow users to state repo locations. Or use the rpm/dpkg providers and use the source parameter, but then you don't get dependency installation.

Trying to auto-detect all of this via Puppet is the first step on the road to insanity. Puppet models state that you declare, it's not great at determining what state to model. Build packages for your supported OSes and include some instructions if someone wants to build for another OS (even if private, future-you will appreciate that), distribute as needed. If you need some tips for how to set up build targets and such, there's the fpm wiki and I wrote up a few tips at my blog.

Comments

I know about package repos, and already have yum & deb repos running, I just need to know whether there is a more generic way of detecting them than a full OS-decision tree/switch. Same for init system (even harder as the default for an OS-version combo might not be what is actually in use).

Let's say, in short: is there a generic way to decide between calling apt::source or yumrepo without having to reinvent the wheel yet again with the decision tree present in oh so many modules. There's enough inspection going on in Puppet, both internally, and with facts, why would it be insanity?

Just drop your repo in /etc/apt/sources.list.d if there's a /usr/bin/apt-get present? Do the same for systemctl.
For many other decisions, finer grained control is needed. You may need to provide different pkg's for different OS-releases, for instance. Design for your expected future.

Existence of a systemctl binary doesn't inidicate which init system is running. Nor does the existence of yum & apt-get indicate which of the 2 is in use (although it's very rare to have them both of course). But, what you're saying is: yes Rikken, you will need to write your own tests yet again.

Check using "systemctl is-system-running", or check for existing packages using "dpkg -l" to be sure. There could still be differences between distro's using RPM or between, say, Debian and Ubuntu that are relevant to you. Are you sure your package will run on *any* version, even in the future?

I have the same problem: I need to know the init system to choose the correct action.
I can think about some different paths:
1. Create a custom fact
2. Find a module which does it
3. Ask Puppet of Facter developers to add a standard fact exposing the init system
For the first way, I should learn Ruby first. I can try, but who knows when I can get something done... I found a module which claim just that - https://forge.puppet.com/hfm/initsystem - But, in fact, it assumes the init system based on OS version, so we're back to the start problem. Maybe we could start a feature request. I have just entered Puppet community, so I'm grasping its ways still.
Hope this gives some starter.
Best regards,
Emerson

Comments

Of course I need it: in my package I only have the binary, and I need to know whether to write stuff to /etc/init.d/my-service or something to /etc/systemd/system/my-service.service for instance. And to get the binary even there: do I need to add an apt or yum repo?