How to Require Another Custom Class Using Puppet - puppet

If I have two class's in my own puppet module and class 'b' has a dependency on class 'a'. How can I express this in my require statement:
# a.pp
class rehan::a {
package { 'javaruntime':
ensure => latest,
provider => chocolatey
}
}
# b.pp
class rehan::b {
file { 'C:\foo':
ensure => present,
require => Package['?????']
}
}
# site.pp
node default {
include rehan::a
include rehan::b
}

If you want to express a dependency of class b on class a (and also ensure that a is in the catalog):
class rehan::b {
require rehan::a
}
If you just one resource on rehan::b to depend on class A:
class rehan::b {
include rehan::a # ensure the class is in the catalog
file { 'C:\foo':
ensure => present,
require => Class['rehan::a'],
}
}
You can also express this relationship anywhere with Class['rehan::a'] -> Class['rehan::b'] (assuming both are included in the catalog).

Related

puppet 4.7 - how can I execute something at the end of a run?

I need to execute something as the very last thing of a puppet apply run. I tried to do that by defining a stage 'last', but the syntax restrictions on declaring a class in resource mode are a problem.
Is there a good way to use stages like this? Or is there some other way to make sure some class is executed last?
for example, this gives me an error for a duplicate declaration(sometimes, and I'm not sure why at this point):
class xyz::firstrun {
exec { 'exec_firstrun':
onlyif => '/usr/bin/test -e /tmp/firstrun.sh',
command => '/tmp/firstrun.sh',
path => ['/usr/bin/','/usr/sbin'],
creates => '/tmp/firstrun.done',
}
}
class { 'xyz::firstrun':
stage => last,
}
Sometimes, the firstrun class runs without error, but in the main stage.
I'm not a big fan of run stages, but they are the the right tool for this job. It's a bit unclear exactly what gives you the duplicate declaration error you describe, but if, for example, your class definition and class declaration both appear in the same file, then that might be a problem.
Here's how a solution using run stages might look:
environments/production/modules/site/manifests/stages.pp
class site::stages {
stage { 'last':
# Stage['main'] does not itself need to be declared
require => Stage['main'],
}
}
environments/production/modules/xyz/manifests/firstrun.pp
class xyz::firstrun {
exec { 'exec_firstrun':
onlyif => '/usr/bin/test -e /tmp/firstrun.sh',
command => '/tmp/firstrun.sh',
path => ['/usr/bin/','/usr/sbin'],
creates => '/tmp/firstrun.done',
}
}
environments/production/manifests/nodes.pp
node 'foobar.my.com' {
include 'site::stages'
include 'something::else'
# Must use a resource-like declaration to assign a class to a stage
class { 'xyz::firstrun':
stage => 'last'
}
}
Note that although include-like class declarations are generally to be preferred, you must use a resource-like declaration to assign a class to a non-default stage. You must therefore also be careful to avoid declaring such classes more than once.
You can use puppet relationship and ordering to do this.
(1) If you want to execute the entire class at the end, you can include your class in init.pp and user ordering arrow (->) to execute it after all other classes.
example:
file: /etc/puppet/modules/tomcat/init.pp
class tomcat {
include ::archive
include ::stdlib
class { '::tomcat::tomcatapiconf': }->
class { '::tomcat::serverconfig': }
}
(2) If you want a specific resource in a class to execute at the end, you can use the same arrow (->) within the class or use before or require in the resource
example:
file { '/etc/profile.d/settomcatparam.sh':
ensure => file,
before => File_line['/etc/profile.d/settomcatparam.sh'],
}
file_line { '/etc/profile.d/settomcatparam.sh':
path => '/etc/profile.d/settomcatparam.sh',
ine => 'export LD_LIBRARY_PATH=/usrdata/apps/sysapps/apr/lib:/usrdata/apps/sysapps/apr-util/lib:/usrdata/apps/sysapps/tomcat-native/lib:$LD_LIBRARY_PATH',
}
OR
exec { 'configure apr-util':
cwd => "/tmp/apr-util-${tomcat::aprutilversion}/",
command => "bash -c './configure --prefix=/usrdata/apps/sysapps/apr-util --with-apr=/usrdata/apps/sysapps/apr'",
} ->
exec { 'make apr-util':
cwd => "/tmp/apr-util-${tomcat::aprutilversion}/",
command => 'make',
}
You can also use combination of before, require and ->. Just make sure you don't create a dependency cycle.

Puppet dependency resolution ordering

I have a couple hosts which have Docker containers on them, so I've defined a class called apps::docker which installs Docker on the hosts:
class apps::docker {
include apps::docker::repository, apps::docker::install,
apps::docker::service
Class["Apps::Docker::Repository"] ->
Class["Apps::Docker::Install"] ->
Class["Apps::Docker::Service"]
Package["Docker"] ~> Service["Docker"]
}
class apps::docker::repository {
apt::source { 'docker':
location => "http://get.docker.io/ubuntu",
key => "A88D21E9",
release => "docker",
repos => "main",
include_src => false
}
}
class apps::docker::install {
package { 'docker':
name => "lxc-docker",
ensure => present
}
class apps::docker::service {
service { 'docker':
provider => 'upstart',
enable => true,
ensure => running,
hasrestart => true,
hasstatus => true
}
}
Pretty simple stuff, actually.
The problem is that when I try to define a class which depends on this class, the execution happens out of order and commands fail. For example, my class profiles::shiningstar::containers depends on apps::docker as defined in profiles::shiningstar:
class profiles::shiningstar {
include apps::docker
include profiles::shiningstar::containers
Class["Apps::Docker"] -> Class["Profiles::Shiningstar::Containers"]
}
Unfortunately, this doesn't work as seen below:
Error: /Stage[main]/Profiles::Shiningstar::Containers::Puppetmaster::Pull/Docker::Image[rfkrocktk/puppetmaster:1.0.5]/Exec[docker pull rfkrocktk/puppetmaster:1.0.5]: Could not evaluate: Could not find command 'docker'
... (similar errors)
Notice: /Stage[main]/Apps::Docker::Repository/Apt::Source[docker]/Apt::Key[Add key: A88D21E9 from Apt::Source docker]/Apt_key[Add key: A88D21E9 from Apt::Source docker]/ensure: created
It's executing things completely out of order. What's wrong with my configuration and how can I specify that ALL of the dependencies of apps::docker must be satisfied before profiles::shiningstar::containers?
You probably want to contain the inner classes instead of just including them.
class apps::docker {
contain apps::docker::repository
contain apps::docker::install
contain apps::docker::service
Class['apps::docker::repository']
->
Class['apps::docker::install']
~>
Class['apps::docker::service']
}
Note that it makes sense (in your case at least) to make the ::install class as a whole notify all of the ::service class. The makes you more flexible in refactoring the respective implementation of those classes.
Edited after first comment - don't try to put chaining arrows between contain statements.
You should use an anchor, that will ensure that all dependencies are built
class apps::docker {
include apps::docker::repository, apps::docker::install,
apps::docker::service
Class["Apps::Docker::Repository"] ->
Class["Apps::Docker::Install"] ->
Class["Apps::Docker::Service"] ->
anchor{"apps::docker":}
Package["Docker"] ~> Service["Docker"]
}

Puppet cannot find parent resource type

I'm trying to set up Puppet to use templates in order to create configuration files for our servers. The current way I am doing this is by using inheritance to pass default values to a class. This allows me to properly separate the data from the rest of the code. An example of this structure is as follows:
class grading_properties(
$home='tomcat-deploy',
$financialScoreHigh = $grading_properties_defaults::financialScoreHigh,
$financialScoreLow = $grading_properties_defaults::financialScoreLow,
$qualityScoreHigh = $grading_properties_defaults::qualityScoreHigh,
$qualityScoreLow = $grading_properties_defaults::qualityScoreLow,
)inherits grading_properties_defaults {
file{"${base}/${home}/company-conf/grading.properties" :
ensure => present,
mode => '0755',
owner => 'root',
group => 'root',
content => template("company/company-conf_pr/grading.properties.erb")
}
}
This class is responsible for generating the "grading.properties" config file based on the "grading.properties.erb" template. The "grading_properties_defaults" class which it inherits looks like this:
class grading_properties_defaults{
$financialScoreHigh = 4
$financialScoreLow = 7
$qualityScoreHigh = 6000
$qualityScoreLow = 4000
}
The problem I am having is when I try to create the class using
class{ "grading_properties" :
financialScoreHigh => 10,
}
from a class in the same module, I get the following error from puppet apply:
Error: Could not find parent resource type 'grading_properties_defaults' of type hostclass in production at /home/git/puppet/modules/company/manifests/grading_properties.pp:1 on node sv1.company.qa0
What is the proper way to reference a class in the same module?
It turns out I simply need to fully qualify my class names in order for puppet to find them. E.g. class grading_properties_defaults should be modulename::grading_properties_defaults
If you aren't in the same puppetfile we must write modulename::classname as example:
class modulename::role {
### CODE HERE ####
}
class role::www inherits modulename::role {
### CODE HERE ####
}
In the same puppetfile you don't need declare modulename
class role {
### CODE HERE ####
}
class role::www inherits role {
### CODE HERE ####
}
Great material about profile and roles https://www.craigdunn.org/2012/05/239/

Resolve conflicting package resource declarations

We are attempting to use the camptocamp/puppet-nagios module, but we're running into a packaging naming conflict between vanilla CentOS repositories and RPMForge/RepoForge. The nsca daemon in CentOS provides the same service as the nagios-nsca package in RepoForge. In attempt to install the RepoForge package yet satisify the Package requirement for nsca resource, I've added this to my node definition:
include ::nagios
package { 'nagios-nsca': ensure => installed, alias => 'nsca', }
include ::nagios::nsca::server
The resulting error is:
Error: Duplicate declaration: Package[nsca] is already declared in
file /tmp/vagrant-puppet-1/modules-0/role/manifests/nagios.pp:45;
cannot redeclare at
/tmp/vagrant-puppet-1/modules-2/nagios/manifests/nsca/server.pp:24
The next test was to use order and calling the class directly from the node:
include ::nagios
package { 'nagios-nsca': ensure => installed, alias => 'nsca', } ->
class {'::nagios::nsca::server' : }
The code in question inside the nagios/manifests/nsca/server.pp file is:
class nagios::nsca::server(
$decryption_method = pick($nagios_nsca_decryption_method, '0'),
) {
include ::nagios::params
# variables used in ERB template
$basename = $nagios::params::basename
if !defined (Package['nsca']) {
package {'nsca':
ensure => installed;
}
}
Any insight as to what's happening here? I can always fork the camptocamp/puppet-nagios code and force the behavior we want, but I'd rather not.
Due to ! defined(Package['title']) not working as expected. I fixed this by giving nagios::nsca::server an additional parameter of nsca_package, including a default value of nsca to preserve current behavior:
--- a/manifests/nsca/server.pp
+++ b/manifests/nsca/server.pp
## -11,6 +11,7 ##
#
class nagios::nsca::server(
$decryption_method = pick($nagios_nsca_decryption_method, '0'),
+ $nsca_package = 'nsca'
) {
include ::nagios::params
## -20,6 +21,7 ## class nagios::nsca::server(
if !defined (Package['nsca']) {
package {'nsca':
+ name => $nsca_package,
ensure => installed;
}
}
Use for this new parameter would be:
node 'my-nagios-server.local' {
include ::nagios
class {'::nagios::nsca::server': nsca_package => 'nagios-nsca', }
}

difference between require and ordering with puppet classes

I want to achieve dependency between puppet classes, so that the classes (their content) get executed in a deterministic way. Reading the documentation I came up with the following two ways:
ORDERING
class Level1 {
Class['Level2']->Class[Level1']
package { "A":
ensure => "installed"
}
}
class Level2 {
include Level3
package { "B":
ensure => "installed"
}
}
class Level3 {
package { "C":
ensure => "installed"
}
}
according to the documentation
-> (ordering arrow) Causes the resource on the left to be applied before the resource on the right. Written with a hyphen and a
greater-than sign.
I expect the following to happen:
Level2 is called before Level1
package B or C get installed (order can be random because it was not specified)
package A gets installed.
REQUIRE
class Level1 {
require Level2
package { "A":
ensure => "installed"
}
}
class Level2 {
require Level3
package { "B":
ensure => "installed"
}
}
class Level3 {
package { "C":
ensure => "installed"
}
}
According to the documentation
cause every resource in the required classes to be applied
before any of the resources in the requiring class.
I expect the following to happen:
Level3 is called by Level2
package C gets installed
Level2 is called by Level1
package B gets installed
package A gets installed
alternative ORDERING
class Level1 {
Class['Level3']->Class['Level2']->Class[Level1']
package { "A":
ensure => "installed"
}
}
class Level2 {
package { "B":
ensure => "installed"
}
}
class Level3 {
package { "C":
ensure => "installed"
}
}
level 1 is needed by level 2
level 2 is needed by level 3
package C gets installed
package B gets installed
package A gets installed
Are my assumptions and conclusions correct?
I've been messing with these kind of dependencies for a while now and they don't seem to behave how I imagine them to behave. Maybe I'm missing something when it comes to the usage of require and -> when used with classes. Any feedback is appreciated!!
EDIT1
staging seems to be a good mechanism for fixing the dependency between two classes (see here), since you have to manually define the stage dependencies between each class pair. How would you use staging with three or four class levels?
EDIT2
Consider this more realistic case, where classes a used as wrappers to install multiple packages at the same time.
Every node is loading some pre-defined role:
node 'some-host' {
include role::processing_machine
}
the role is defined as follows:
class role::processing_machine {
include role::ubuntu_desktop_standard_software
include xorg::lts_12_04_quantal
include software::standard_packages
# define order in which classes should be executed
Class["role::ubuntu_desktop_standard_software"] -> Class["xorg::lts_12_04_quantal"] -> Class["software::standard_packages"] -> Class["role::processing_machine"]
}
and here's the role::ubuntu_desktop_standard_software definition:
class role::ubuntu_desktop_standard_software {
include role
include profile::ubuntu_desktop
include role::server::no_apache
# define order in which classes should be executed.
Class["role"] -> Class["profile::ubuntu_desktop"] -> Class["role::server::no_apache"] -> Class["role::ubuntu_desktop_standard_software"]
}
As you can see, I'm trying to chain multiple classes so that they get executed in a particular order (Class["a"] -> Class["b"]). Previously I've only used include in my classes but puppet would execute the include commands in arbitrary order, so that some commands (which have to run first!) wouldn't run first.
Despite these chaining efforts it still seems like puppet is executing the classes random fashion. What am I doing wrong? Is there a cleaner / better way of defining nodes so that I can be sure they are deployed in a particular, predefined way?
Here is an example :
class L {
package { "C" :
ensure => installed,
require => Package["A", "B",],
}
package { "B" :
ensure => installed,
require => Package["A"],
}
package { "A" :
ensure => installed,
}
}

Resources