Puppet does not add my service to start up - puppet

I have this puppet module (monit) in which I declare monit service to be enabled (a.k.a to be started when the machine booted)
class monit {
$configdir = "/etc/monit.d"
package {
"monit": ensure => installed;
}
service { "monit":
ensure => running,
enable => true,
require => Package["monit"],
provider => init;
}
file {
'/etc/monit.d':
ensure => directory;
'/etc/monit.conf':
content => template('monit/monitrc.erb'),
mode => 0600,
group => root,
require => File['/etc/monit.d'],
before => Service[monit],
notify => Service[monit],
}
}
I then included with include monit inside default node.
However, when I apply this configuration, puppet is not setting monit as a start up service (use chkconfig --list monit just display 'off' and 'off')
However, if I run puppet apply -e 'service { "monit": enable => true, } ' then monit is added to start up properly.
Am I doing any thing wrong here? (Puppet 2.7.6)
The full configuration can be view at https://github.com/phuongnd08/Giasu-puppet

The issue is probably the provider => init line, which is overriding the default provider for handling services. The init provider is a very simple provider that doesn't support the "enableable" feature, so it can't set a service to start on boot.
See http://docs.puppetlabs.com/references/2.7.6/type.html#service for its capabilities.
In your puppet apply example, you don't specify the provider so it picks the most appropriate for your system - in your case the "redhat" provider that uses chkconfig.
To fix this, remove the provider line from your service {} definition and it will again default to the most appropriate. You only need to specify a provider if it picks incorrectly and then it's best to specify it as a global default.

Related

Docker not installed before running containers with Puppet

I am trying to run a docker container using the puppetlabs/docker module. However when the Puppet agent attempts to run the container I receive the error
Error: Failed to apply catalog: No such file or directory - docker
It would seem that neither the docker daemon nor the docker client are being installed before Puppet attempts to create the container.
An excerpt of the configuration is as follows:
Puppetfile
# frozen_string_literal: true
forge 'https://forge.puppet.com'
# Modules from the Puppet Forge
# ...
mod 'puppetlabs-docker', '4.4.0'
# ...
agent.pp
class profile::runner::agent (
Enum[present, absent] $ensure = present,
String $version = undef,
String $image = undef,
String $container_name = "${facts['group']}-agent",
Array[String] $container_environment = [],
) {
class { 'docker':
version => $version,
}
# ...
docker::run { $container_name:
ensure => $ensure,
image => $image,
env => $container_environment,
net => 'host',
restart => 'unless-stopped',
}
# ...
}
My understanding is that this configuration from the puppetlabs/docker module is supposed to ensure docker is installed before any container is started. I considered making a bug report on the module itself but this issue would surely be so common I'd be surprised if it had not already been reported. So I concluded that I must be doing something incorrect.
I have tried the usual metaparameters but none seem to have any effect and result in the same error. For example I have tried
docker::run { $container_name:
ensure => $ensure,
image => $image,
env => $container_environment,
net => 'host',
restart => 'unless-stopped',
require => Class['docker'], # and also Package['docker']
}
It may be worth mentioning that the Puppet agent is running on RockyLinux so therefore a RedHat OS family. If I remove the docker::run from the configuration and then run the Puppet agent then the catalog is applied successfully but of course the container does not run. Then adding the docker::run back to the configuration and running the agent again will run the container successfully. This is what has indicated to me that there is a dependancy issue that I have not been able to resolve.
Since neither chaining arrows nor metaparameters seem to have an affect in this specific situation I have had to resolve this issue using a guard clause that checks if Docker is installed using the facts provided by the puppetlabs/docker module
if $facts['docker_client_version'] != undef {
docker::run { $container_name:
ensure => $ensure,
image => $image,
env => $container_environment,
net => 'host',
restart => 'unless-stopped',
}
}
This is not ideal as it has the effect of requiring the catalog to be applied twice before the container will be run but it does solve the problem.
Declared classes are not automatically ordered relative to each other or relative to resources declared in the same context. There are good reasons for that, but they are tangential to the question.
However, you can use the same techniques to impose relative ordering on classes that you can use for resources: the before, require, notify, and subscribe metaparameters, and the chaining arrows. For your particular case, you might also be able to use the require function (even if you also use a resource like class declaration of class docker, but in the case, the resource-like declaration must precede the require).
For example, this is a pretty good way to make sure that class docker is applied before every docker::run instance, wherever declared:
class { 'docker':
version => $version,
}
-> Docker::Run<||>
That does, however, have the side effect of realizing any virtual docker::run instances you might have declared. If that's a problem then go with one of the other alternatives.

How to provide a startup service file in Puppet

We have RedHat 7.2 Linux OS and use puppet to perform our tasks. I am using puppet to install some software, which has worked fine and now the final step is to create an OS level service. In earlier versions of RHEL, we used chkconfig but that has been replaced with systemctl. Of course, the recommended way of performing this task is using a service. Since this is a custom software, I have my own startup script that I usually copy over to /etc/init.d, run chkconfig and then startup the service. How do I perform these tasks via Puppet for RedHat 7.2 OS ? I only want to create the service (not start it up or anything). This way, when the server reboots, the service will startup the app.
EDIT :
#redstonemercury for RHEL 7 I would think the following would be required. But your suggestion definitely helps as I was thinking along the same lines.
https://serverfault.com/questions/814611/puppet-generated-systemd-unit-files
file { '/lib/systemd/system/myservice.service':
mode => '0644',
owner => 'root',
group => 'root',
content => template('modulename/myservice.systemd.erb'),
}~>
exec { 'myservice-systemd-reload':
command => 'systemctl daemon-reload',
path => [ '/usr/bin', '/bin', '/usr/sbin' ],
refreshonly => true,
}
In puppet, use a package resource to install the package (assuming it's in repos that you're declaring already), then use a file resource to declare the /etc/init.d file, and put require => Package[<package_resource_name>] as a parameter in the file declaration to ensure the custom file gets created after the package has installed (so doesn't potentially get overwritten by the package's /etc/init.d file). E.g.:
package { 'mypackage':
ensure => present,
}
file { '/etc/init.d/mypackage':
ensure => present,
content => template('mypackage/myinitd'),
require => Package['mypackage'],
}
This is if you want to use a template. For a file, instead of content use source: source => puppet://modules/mypackage/myinitd

Puppet Network module sets enable on every run

Using razorsedge-network (v3.6.0)
On every puppet run, I get the following:
Notice: /Stage[main]/Network/Service[network]/enable: enable changed 'false' to 'true'
Client is running CentOS 7.1, tried with agents 4.2.1 and 4.2.3.
Puppetmaster is PE 2015
It seems to rely on SysV scripts, but that has everything set correctly:
[root#srv08 ~]# service network status
Configured devices:
lo ens160
Currently active devices:
lo ens160
[root#srv08 ~]# echo $?
0
The manifest is called as:
class profiles::networking {
$allinterfaces = split($::interfaces, ',')
$pri_if = $allinterfaces[0]
::network::if::static {$pri_if:
ensure => hiera('network::if::static:ensure'),
ipaddress => hiera('network::if::static:ipaddress'),
netmask => hiera('network::if::static:netmask'),
gateway => hiera('network::if::static:gateway'),
peerdns => true,
dns1 => hiera('network::if::static:dns1'),
dns2 => hiera('network::if::static:dns2'),
domain => hiera('network::if::static:domain'),
}
}
Hiera in turn returns the single value
Because the network service doesn't remain up after you start it. So at each invocation the service is seen as "exited" and puppet is trying to start it again
Not the proper way I am sure, but I 'solved' it by adding this to my manifest:
file_line { 'Kill enabled':
ensure => 'absent',
line => ' enable => true,',
path => '/etc/puppetlabs/code/environments/production/modules/network/manifests/init.pp',
}
So basically remove the enable line. I had to do it in the manifest as the module is controlled by Puppetfile, this will ensure it stays absent.

How to stop Puppet applying a configuration when there is an error?

I am currently hitting, for me, somewhat unintuitive behaviour in Puppet - most likely because I don't completely understand the Puppet ethos yet.
OK I have a simple puppetsimple.sh running in the puppet agent which is applying configurations from puppet master. This is all running smoothly and as expected.
Unintuitive (for me) However when I, as part of setting up master, create an error, and then run puppetsimple.sh in the agent, it will strike the error, notify me of it, and continue to apply all the other changes for that configuration.
This effectively leaves the agent in a broken state, because it pushes ahead even when there is an error.
Is there a setting somewhere to say "hey, if you strike an error, stop, revert to how you were, and carry on your merry way"?
Given the example below. I am intentionally enabling an invalid conf file (.confX) - I get notified of the error, but it continues to populate "index.html" with "Hello World 3".
define a2ensite {
exec { 'a2ensite':
path => [ '/bin', '/usr/bin', '/usr/sbin' ],
command => "a2ensite ${title}",
notify => Service['apache2'],
}
}
class mysite {
include apache
file { '/etc/apache2/sites-available/mysite.example.org.conf':
owner => root,
group => root,
mode => 0644,
source => "puppet:///files/mysite/mysite_apache.conf",
notify => Service['apache2'],
}
a2ensite { 'mysite.example.org.confX': }
file { ['/home/', '/home/www/', '/home/www/mysite.example.org']:
ensure => directory,
owner => root,
group => root,
mode => 0755,
}
file { '/home/www/mysite.example.org/index.html':
owner => www-data,
group => www-data,
mode => 755,
content => "Hello World 3",
}
}
If one reosurce failing means that another resource should not be modified, then that is a dependency relationship that you need to model via require. A failing dependency will cause puppet to skip those resources.
But, in general, puppet does not stop or rollback runs when it hits an error. If you need to rollback, it is on you to either revert to an older puppet configuration or use some other capability to revert the node.

Puppet User ID value and Package

I am trying to do the following using Puppet on an Ubuntu 10.04:
Copy a file that I have to a specific directory which will be owned by a specific user / group that does not exists yet since the package has not been installed
Install the package where it will not remove the directory and file that I created
To accomplish item #1, I basically tell Puppet to create a user and group first before copying the file. But the problem is that if I do not give a specific uid for Puppet, it will randomly pick a number like a number for user and not a number for system package.
So, how do I tell Puppet to choose a uid anything more than 1000?
If this is not possible, how do I tell Puppet not to start the package when it installs it. So I would just let Puppet install the package, but do not start the service, then copy my file, then I will start the service.
The user type has a parameter of system => which defaults to false, but can be set to true. This will generate the user with a UID below 500. Which seems to be what you want.
Ultimately what you'll want to do in my opinion is manage the config directory and the config via puppet as well.
This gives you the ability to do things like such:
package { foo: ensure => present }
file {
fooconfdir:
path => '/path/to/fooconfdir',
ensure => directory,
user => whatev,
group => alsowhatev,
require => Package[foo],
mode => morewhatev;
fooconf:
path => '/path/to/fooconfdir/fooconf',
ensure => present,
user => whatev,
content => template('whatev');
}
service { foo: ensure => running, enable => true, subscribe => File[fooconf] }
What that will do , is install your package then manage the config, then restart the service which will use your new config obviously on restart.

Resources