Puppet Practicioner Course - Day 3

Extra reading

Puppet type reference
https://docs.puppetlabs.com/references/latest/type.html

  • very valuable lookup for type information

Puppet Visual Index
https://docs.puppetlabs.com/puppet/latest/reference/lang_visual_index.html

  • great examples of code syntax

Puppet On The edge
http://puppet-on-the-edge.blogspot.be

  • good for bleeding-edge information
Roles and Profiles

This looks at the modular association of nodes with classes via role definitions.

Roles

There's a module called "role". We can then reference the roles in sites.pp or nodes.pp.

A node can only be associated with one role.

node blah.company.com {
  include role::prod-phoenix-webserver
}

Each role can declare multiple profiles

class role::webapp {
  include profile::base
  include profile::webserver
  include profile::monitoring
}
Profiles

Function-specific wrappers to apply consistent settings across multiple nodes/environments

Inheritance

Inherited classes override all resources with whatever is defined in the inherited class
inherited params are used for attributes which will be used by any company/user (e.g. redhat package management is always yum, debian is always apt-get etc). Company/user-specific data should sit in hieradata

General rule of thumb, the only place you would use inheritance is for params.

Module Testing

RSPEC module tests generally don't mock external values such as hieradata lookups.

Unit Testing
require 'spec_helper'
describe('motd', :type => :class) do
  let(:node) { 'testhost.example.com' }
  describe 'when called with no parameters on redhat' do
    let(:facts) { { :osfamily => 'Redhat' } }
    it {
      should contain_file('/etc/motd').with({
        'ensure' => 'file',
        'owner' => 'root',
      }).with_content(/^Welcome to #{node}.*$/)
    }
  end
end

We can mock values such as facts (let(:facts) { { :osfamily => 'Redhat'} }, etc to evaluate them against the puppet code.

Note - unless environment variables (node, facts etc) are explicitly defined in the rspec test, it will not be available for the test. The rspec test does not actually simulate the environment of the node on which it executes, it explicity follows the instructions in the test.

Some example output from a unit test (different to the above example) is below

[master]root@robbie:~/puppetcode/modules/apache # /opt/puppetlabs/puppet/bin/rake spec
/opt/puppetlabs/puppet/bin/ruby -I/opt/puppetlabs/puppet/lib/ruby/gems/2.1.0/gems/rspec-support-3.3.0/lib:/opt/puppetlabs/puppet/lib/ruby/gems/2.1.0/gems/rspec-core-3.3.2/lib /opt/puppetlabs/puppet/lib/ruby/gems/2.1.0/gems/rspec-core-3.3.2/exe/rspec --pattern spec/\{classes,defines,unit,functions,hosts,integration\}/\*\*/\*_spec.rb --color
F

Failures:

  1) apache when called with no parameters on redhat should contain File[apache_config] with ensure => "file" and source => "puppet:///modules/apache/Redhat.conf"
     Failure/Error: should contain_file('apache_config').with({
       expected that the catalogue would contain File[apache_config] with source set to "puppet:///modules/apache/Redhat.conf" but it is set to "puppet:///modules/apache/.conf"
     # ./spec/classes/apache_spec.rb:16:in `block (3 levels) in <top (required)>'

Finished in 1.24 seconds (files took 0.8289 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/classes/apache_spec.rb:11 # apache when called with no parameters on redhat should contain File[apache_config] with ensure => "file" and source => "puppet:///modules/apache/Redhat.conf"

/opt/puppetlabs/puppet/bin/ruby -I/opt/puppetlabs/puppet/lib/ruby/gems/2.1.0/gems/rspec-support-3.3.0/lib:/opt/puppetlabs/puppet/lib/ruby/gems/2.1.0/gems/rspec-core-3.3.2/lib /opt/puppetlabs/puppet/lib/ruby/gems/2.1.0/gems/rspec-core-3.3.2/exe/rspec --pattern spec/\{classes,defines,unit,functions,hosts,integration\}/\*\*/\*_spec.rb --color failed
Acceptance Testing

Validation that the end result meets the requirements of the puppet code.
"Beaker" is a recommended platform for acceptance testing, although difficult to use so be careful.

"serverspec" can be used to validate that the desired state has been achieved. To use serverspec:

  1. puppet agent -t
  2. cd (module); rake spec

Note - to properly test the puppet code, best to use a new server instance (e.g. a newly generated VM, docker container etc), to ensure you aren't generating false positives or false negatives from previous iterations of code execution.

mcollective

Used for initiating tasks (e.g. puppet runs) on remote systems. instead of scheduling it on each node's crontab, these tasks can be centrally batched/scheduled and executed using the mcollective system.

Puppet Enterprise - mcollective is set up for you
Puppet Opensource - you need to configure this manually

ActiveMQ is used for messaging

mco is the mcollective admin client

mco ping can be used to show which systems it can communicate with using mcollective (i.e. application-level ping)

mco rpc service apache stop to stop apache

mco puppet stop to stop the puppet client (this doesn't stop mcollective, just puppet)

mco package install sl to install the steam locomotive package

You can also control which clients/nodes this applies to (i.e. default is to run it on all mcollective clients the system can connect to - this could be bad).