Puppet: conditional restart of service - puppet

Is it possible to conditionally skip refresh events on a service resource? Or alternatively: Is it possible to prevent a service resource inside a class to be refreshed when the class is notified?
Context: I have a Puppet module containing the following manifest (simplified):
class foo(
Boolean pre_process_service = true,
Boolean auto_restart_service = true
) {
if $pre_process_service {
exec { 'process config':
... # details including a pretty complex command - should be hidden in my module
notify => Service['foo'],
}
}
service { 'foo':
ensure => 'running',
enable => true,
}
}
which might be used like so:
file { 'config':
... # copies config from somewhere
}
class { 'foo':
auto_restart_service => false,
subscribe => File['config'],
}
How can I avoid restarting the service when the user specifies auto_restart_service => false?
Note that the user of the module decides how to provide the configuration (copying files, checking out a Git repository,...) so I can't do that inside my module. Instead the class subscribes to the resource providing the configuration. As long as the user goes with the default of auto_restart_service = true everything works fine and even disabling the preprocessing of the configuration works correctly. However, when the user specifies auto_restart_service = false the service will still restart since the service resource is refreshed when the class is notified. Wrapping the service resource into an if block like I did with the exec resource doesn't work either since the service resource does multiple things:
It starts the service if it isn't running
It enables the service if it isn't enabled
It restarts the service if notified
I only want to conditionally prevent (3) from happening while always doing (1) and (2). Is there a way to do this?

I don't think there's a way to not refresh the service when you notify the class. However, you can try to conditionally override how Puppet should restart the service with the restart attribute of the service resource.
Something like this:
if $auto_restart_service {
# Let the provider handle the restart
$_attr = {}
} else {
# Let Puppet execute `true` instead of actually restarting the service
$_attr = { 'restart' => '/usr/bin/true' }
}
service { 'foo':
ensure => 'running',
enable => true,
* => $_attr,
}

The idea from tectux is really nice. I've enhanced the if conditions. I have decided to use script for custom fact.
modules/autofs/facts.d/autofs.sh
#!/bin/sh
DECISION=`test -f /usr/bin/docker && /usr/bin/docker ps -q |grep -q . && echo no`
if [ "x$DECISION" == "x" ] ; then
DECISION=yes
fi
echo '{'
echo ' "autofs": {'
echo " \"do_automatic_restart\": \"$DECISION\""
echo ' }'
echo '}'
So, the output of the script
# modules/autofs/facts.d/autofs.sh
{
"autofs": {
"do_automatic_restart": "yes"
}
}
Now we can use the custom fact
if $facts['autofs']['do_automatic_restart'] == "no" {
$_attr = { 'restart' => "logger puppet agent: automounter is NOT going to be RESTARTED due to active containers on a host" }
} else {
$_attr = {}
}

Related

Puppet dependency loop when needing to notify a service from a class that first needs the service to be running

I am trying to build a module that uses the usual install->config->service pattern but with a twist. After the service starts there is more configuration done via an admin API. Unfortunately the vendor product also then requires some of the results of that API invocation to be edited into some config XML files which requires a service restart. So I have install->config->service->admin->service which is of course a dependency loop. Is there a clean way to do this? I've resorted to having to exec{'/sbin/service ... restart'} in the admin class. Not clean at all:
anchor { 'pingfederate::begin': } ->
class { '::pingfederate::install': } ->
class { '::pingfederate::config': } ~>
class { '::pingfederate::service': } ->
class { '::pingfederate::admin': } ->
anchor { 'pingfederate::end': }
and then exec {'/sbin/service pingfederate restart':}
See https://github.com/n2ygk/puppet-pingfederate

manage hosts file on Windows using Puppet

I'm trying to manage my hosts file on a Windows machine using Puppet and Hiera. My problem is that I have never really used Hiera and I'm struggling with parsing the data content into a proper format.
The relevant section in hieradata/hiera.yaml looks like this:
myhosts : [
'host1 1.2.3.4',
'host2 2.3.4.5',
'host3 3.4.5.6']
I have code that uses a host module, but it also depends on a class that I don't have, so naturally it doesn't work.
class hosts::module (
$myhosts = hiera('myhosts'),
)
{
define update_hosts {
$value = split($name,' ')
host {
"${value[0]}" : ip => "${value[1]}",
}
}
update_hosts { $myhosts :; }
}
I have tried using the file resource instead of the host resource, and also tried doing it without any class, but for some reason I am getting this error
Error: Could not retrieve catalog from remote server: Error 500 on SERVER:
Server Error: Evaluation Error: Error while evaluating a Resource Statement,
Evaluation Error: Error while evaluating a Resource Statement, Duplicate
declaration: File[C:\Temp\tmp.txt] is already declared in file
/etc/puppetlabs/code/environments/production/manifests/site.pp:4; cannot redeclare
at /etc/puppetlabs/code/environments/production/manifests/site.pp:4
at /etc/puppetlabs/code/environments/production/manifests/site.pp:4:1
at /etc/puppetlabs/code/environments/production/manifests/site.pp:10 on node puppet-agent
As you can see, it claims that I have a duplicate declaration, but the weird thing is that it says it has a problem with the same line. It thinks it's declaring the same thing twice for some reason.
This is the code I have now (I know it won't work but the error doesn't really sound related)
define hosts_update($content) {
file { 'C:\Temp\tmp.txt' :
ensure => file,
content => $content,
}
}
hosts_update{ hiera('myhosts'):
content => split($name," "),
}
Any idea how to do this right?
fixed it.
site.pp
include update_hosts
init.pp
class update_hosts::host
(
$hosts = hiera('hosts_list'),
)
{
update_host { $hosts :; }
}
host.pp
define update_host {
​
$value = split($name,' ')
​
host {
"${value[0]}" : ip => "${value[1]}",
target => "C:/Windows/System32/drivers/etc/hosts"
}
}

Overload puppet default parameter in module

I want to use my own Jenkins plugin server to source plugins from. I'm using the puppet-jenkins module, but I can't seem to change the default plugin host value
The code on github has this in manifests/params:
class jenkins::params {
..
$default_plugins_host = 'https://updates.jenkins-ci.org'
..
}
So when I use this class, if I say:
class { 'jenkins':
default_plugins_host => "https://myhost.local"
}
I get Puppet (err): Invalid parameter
Or, if I try to define the value using capscase:
Jenkins::Params {
default_plugins_host => "https://specificallybrokenhost.com"
}
it isn't used by puppet. I tested this by giving it a plugin host that didn't exist, expecting the plugin installation to fail; but it was able to get plugins successfully (my assumption is that it still used jenkins-ci.org)
I was able to get this working by coping the entire module locally within library-jenkins/puppet-jenkins and changing the value, but i'd prefer not to have to resort to that
I'm using puppet-librarian and Puppet 3.3, if that helps.
the params.pp file stores private variables. This cannot be overridden.
Looking over the module is appears you can change the url from lines 67-82 of plugin.pp
if $version {
$plugins_host = $update_url ? {
undef => $::jenkins::default_plugins_host,
default => $update_url,
}
$base_url = "${plugins_host}/download/plugins/${name}/${version}/"
$search = "^${name} ${version}$"
}
else {
$plugins_host = $update_url ? {
undef => $::jenkins::default_plugins_host,
default => $update_url,
}
$base_url = "${plugins_host}/latest/"
$search = "${name} "
}
$plugins_host will use update_url if it's defined instead of default_plugins_host. if you make a default on the plugin define type you can change the default_plugins_host to update_url like so;
Jenkins::Plugin {
source_url => 'mycompany.jenkins.com',
}
I haven't tested this myself. So, let me know if it works.

Puppet; Call another .pp

So I am using the https://forge.puppetlabs.com/pdxcat/nrpe module to try to figure out automation of NRPE across hosts.
One of the available usages is
nrpe::command {
'check_users':
ensure => present,
command => 'check_users -w 5 -c 10';
}
Is there anyway to make a "group" of these commands and have them called on specific nodes?
For example:
you have 5 different nrpe:command each defining a different check, and then call those specific checks?
I am basically trying to figure out if I could group certain checks/commands together instead of setting up a ton of text in the main sites.pp file. This would also allow for customized templates/configurations across numerous nodes.
Thanks!
EDIT:
This is the command and what it's supposed to do when called on with the 'check_users' portion. If I could have a class with a set of "nrpe:command" and just call on that class THROUGH the module, it should work. Sorry, though. Still new at puppet. Thanks again.
define nrpe::command (
$command,
$ensure = present,
$include_dir = $nrpe::params::nrpe_include_dir,
$libdir = $nrpe::params::libdir,
$package_name = $nrpe::params::nrpe_packages,
$service_name = $nrpe::params::nrpe_service,
$file_group = $nrpe::params::nrpe_files_group,
) {
file { "${include_dir}/${title}.cfg":
ensure => $ensure,
content => template('nrpe/command.cfg.erb'),
owner => root,
group => $file_group,
mode => '0644',
require => Package[$package_name],
notify => Service[$service_name],
}
}
What version are you talking about? In puppet latest versions, inheritance is deprecated, then you shouldn't use it.
The easiest way would be to use "baselines".
Assuming you are using a manifests directory (manifest = $confdir/manifests inside your puppet.conf), simply create a $confdir/manifests/minimal.pp (or $confdir/manifests/nrpe_config.pp or whatever class name you want to use) with the content below:
class minimal {
nrpe::command { 'check_users':
ensure => present,
command => 'check_users -w 5 -c 10',
}
}
Then just call this class inside your node definitions (let's say in $confdir/manifests/my_node.pp) :
node 'my_node.foo.bar' {
include minimal
}

overriding Parameters in puppet modules

I want to override parameters of base nodes. What I want to get is a pattern like this:
# File manifests/nodes.pp
node myDefault {
class { 'my::common::puppet_setup':
service => 'enable',
pushable => 'disable',
}
# Do lots of default things ...
}
node 'myFirstNode' inherits myDefault {
# Do something ...
}
node 'mySecondNode' inherits myDefault {
class { 'my::common::puppet_setup::params':
service => 'disable',
pushable => 'enable',
}
}
I understood the the puppet documentation, i could do this by writing my module like this:
# File modules/my/manifests/common/puppet_setup.pp
class my::common::puppet_setup (
$pushable = $my::common::puppet_setup::params::pushable,
$service = $my::common::puppet_setup::params::service,
) inherits my::common::puppet_setup::params {
# package that configures puppet node
# input value validation
validate_re($pushable, ['^enable$', '^disable$', '^ignore$', ])
validate_re($service, ['^enable$', '^disable$', '^ignore$', '^cron$', ])
# setup puppet, start or disable agent, put ssh keys for push ...
}
class my::common::puppet_setup::params {
$pushable = 'enable'
$service = 'enable'
$puppetserver = 'puppet.my.site.de'
case $::osfamily {
'Debian': {
}
default: {
fail("not implemented yet for {::operatingsystem}")
}
}
}
The Documentations on puppet website says:
When a derived class is declared, its base class is automatically declared first (if it wasn’t already declared elsewhere).
But i get this error (some indentation added):
mySecondNode# puppet agent --test --environment dev_my
Error: Could not retrieve catalog from remote server:
Error 400 on SERVER: Duplicate declaration:
Class[My::Common::Puppet_setup::Params] is already declared;
cannot redeclare at /.../puppet/manifests/nodes.pp:16 on node mySecondNode
Warning: Not using cache on failed catalog
Error: Could not retrieve catalog; skipping run
I'm reading on this for a week and i guess my understanding ist totally wrong somewhere, although i used the puppetlabs ntp modules as an example.
what am i missing?
You should check Inheritance section from http://docs.puppetlabs.com/puppet/latest/reference/lang_node_definitions.html
Puppet treats node definitions like classes. It does not mash the two together and then compile the mix; instead, it compiles the base class, then compiles the derived class, which gets a parent scope and special permission to modify resource attributes from the base class.
One of the good solutions is to use roles and profiles, there's a great blog post about it:
http://garylarizza.com/blog/2014/02/17/puppet-workflow-part-2/
You can use virtual resources :
http://docs.puppetlabs.com/guides/virtual_resources.html

Resources