Puppet Guide.txt - Notepad

Puppet Guide

Puppet is a configuration management system. This page documents puppet fundamentals and includes some sample manifests.

Printing the puppet configuration
puppet config print

Show the version of Puppet
puppet -V

Show all Puppet Facters
Puppet Facters hold useful information on endpoints such as the type of operating system, amount of RAM, number of hard disks etc. Similar to WMI in Windows.
Show all puppet facts:
facter
Show particular facts:
facter osfamily timezone

The Puppet agent updates every 30 mins on endpoints. To force the update, type:
puppet agent --test
Add --noop if you just want to see what the Puppet run would do, without actually enforcing any configuration changes (a PowerShell whatif equivalent).

Apply a particular manifest
puppet apply --test init.pp

Apply a module's init.pp manifest
puppet apply -e 'include module_name'

Check your puppet manifest for code errors
puppet parser validate init.pp

Client Certificates
Puppet agents need to have their certificate signed by the Puppet Master to function. To show pending client certificate requests on the puppet master type:
puppet cert list
To sign a client certificate request on the Puppet Master type:
puppet cert sign cert_name
List all clients attached to a Puppet Server:
puppet cert list --all

Puppet Modules
List installed Puppet modules:
puppet module list
List installed Puppet modules and their dependencies:
puppet module list -tree
Search for a module in the forge:
puppet module search module_name
Install a particular module:
puppet module install module_name

How to turn the Puppet agent on at startup and start the service using puppet
puppet resource service puppet ensure=running enable=true

The Puppet Binary Path
Add the the puppet binary path (/opt/puppetlabs/bin) to your ~/.bashrc so you can run puppet without typing the full path (ie with the command "puppet").

site.pp
The site.pp file in production/manifests runs against all agents. To add one of your custom manifests to this file you can call it within the node default {. For example class {'install_apps':} would call the install_apps init.pp file. class {'install_apps::another_class':} would call another_class file within the install_apps manifest folder.

Sample manifest for installing multiple apps
class install_apps {
$apps = ['screen', 'vim', 'git']
package { $apps:
ensure => 'installed',
}
}

Sample If statement
class Apache_Type {
if $osfamily == 'debian' {
package { 'apache2':
ensure => 'latest'
}
}
elseif $osfamily == 'redhat' {
package { 'httpd':
ensure => 'latest'
}
}
}

Using facter variables in a HTML page
To use a facter variable in a HTML page you can use the below puppet code (sub in your desired facter instead of OSfamily):
This is a <%= @osfamily %> computer.

Sample manifest to create a file
Note that the full path for the file would be /etc/puppetlabs/code/environments/production/modules/file_deploy/files/file_deploy, Puppet shortens the path to /modules and the files directory is excluded.
class file_deploy {
file { '/tmp/file.txt':
ensure => file,
source => 'puppet:///modules/file_deploy/file_deploy',
}
}

Sample manifest to create a user
user {'username':
groups => ['group1', 'group2'],
managehome => true,
password => pw_hash('Password1','SHA-512','random'),
}

Resource default values
When specifying resource default values use uppercase for the first letter of the resource name. In the below manifest the file resource would inherit these default values for owner and node.
File {
owner => 'root',
mode => '0600',
}

heredoc
Heredoc can be used to create a variable that is composed of multiple lines.
$sample_heredoc = @(END)
sample line one
sample line two
END

Declaring an array
To return a value in the array use $array[1].
$array = ['value1', 'value2', 'value3']

Variables
Variables need to start with a lower case letter or an underscore. In a notify statement variables must go inside braces eg:
notify {"The ${service} is running": }

Case
Case can be used to make a selection:
case $facts['os']['family'] {
'RedHat' : { notify {"Redhat OS": }}
'Debian' : { notify {"Debian OS": }}
default : { fail( 'Your OS is untested')}
}

Selector
$time = $facts['os']['family'] ? {
'Redhat' => 'ntpd',
'Debian' => 'ntp',
notify { "The time daemon is ${time}": }

Matching and regular expressions
== match
!= not equal to
=~ /name/ contains
=~ /^name$/ is exactly
=~ /^www\d/ starts with www then a digit

Lambdas and Iteration
each ( $facts['disks'] ) | $name, $props | {
notify { "The disk is named ${name} and is ${props['size']} big." :}

Meta-parameters - before or require
In the below example, package must run before file, and file cannot run before package.
package { 'pkg1' : before => File ['file1'], }
file { 'file1' : require => Package ['pkg1'], }
service { 'service1' :}

Meta-parameters - notify or subscribe
Can be used to install a package, load a custom file orrestart service after file change.
package { 'ntp' :
before => File['/etc/ntpd.conf']
}
file { '\etc\ntpd.conf' :
content => $ntp_conf,
notify => Service['NTP_Service'],
}
service { 'NTP_Service':
ensure => 'running',
subscribe => File[/etc/ntpd.conf'],
}

Parameters
You can specify parameters at the beginning of a class eg:
class new_class ($var = 'value' ) {
You can also pass parametized values to another class. The below subclass passes a value of testing into the msg variable and runs it inside the time class.
class { 'time':
msg => 'testing',
}

Inheritance from params.pp
params.pp sits in the manifests directory. You can declare variables in this subclass eg:
class time::params {
$var1 = 'test1'
$var2 = 'test2'
}
You can then reference these variables in init.pp:
class time (
$word1 = $time::params::var1,
$word2 = $time::params::var2,)
inherits time::params {
file { '/tmp/var.txt':
ensure => 'present',
content => $word1,
}
}

Validation with validate_re
The below example validates the $msg variable which contains "test", against "allowed1" and "allowed2", which fails as "test" does not match those strings exactly.
class time ( $msg = 'test' ) {
$allowed_text = ['^allowed1$', '^allowed2$']
validate_re( $msg, $allowed_text )
file { '/tmp/time.conf':
ensure => 'present',
content => $msg,
}
}

Templates
Sample Inline Template:
class motd {
$down_time = '23:00'
$motd = "@(END)
Servername is <%=@facts['networking']['fqdn'] %>
The server will be shutdown at <%=@down_time %>
END"
file { '/root/motd.txt':
ensure => 'file',
content => inline_template($motd),
}
}

Sample ERB template (Ruby):
include tempy::admin_file
class tempy::admin_file (
$ntp_local_server = 'some_ip',
$ntp_regional_server = ['site1','site2','site3'],
$monitor = false,
) {
file { '/tmp/admin_file.txt' :
ensure => 'file',
content => template('tempy/ntp.conf.erb'),
}
}

The ERB template file mentioned in the above ERB template - tempy/templates/ntp.conf.erb:
server <%=@ntp_local_server%> iburst prefer
<% @ntp_regional_server.each do [t] -%>
server <%=t%>
<% end -%>
some static info
<% if @monitor == false -%>
disable monitor
<% end -%>

Sample EPP Template (Puppet)
include epp
class epp {
$down_time ='23:00'
$motd = @(END)
Server name is <%= $facts['networking']['fqdn'] %>
The server will be shutdown at <%=$down_time %>
END
file { "/tmp/motd':
ensure => 'file',
content => inline_epp($motd, { 'down_time' => '17:00',} ),
}
}

Unit testing with rspec-puppet

Unit testing allows you the peace of mind of knowing that even minor changes in your Puppet code will not break compilation of the Puppet catalog.

Bundler is an exit from dependency hell, and ensures that the gems you need are present.
gem install bundler

You specify your dependencies in a Gemfile in your project's root.

Install all of the required gems from your specified sources:
bundle install

Now use bundler exec rake. From the output select your test and run bundler exec again eg:
bundler exec rake spec:class:some_code

Unit testing will now begin!

Looping through a resource using a hash

Note, in your YAML data spacing is a pain here (should be 6 for path and program).

YAML file:

profiles::base::install_prog:
  ‘First prog’:
        path: ‘/some/path’
        program: ‘some_program’
  ‘2nd prog’:
        path: ‘/some/path2’
        program: ‘some_program2’

In Manifest:

  Optional[Hash] $lograte_replace = undef,
  $install_prog.each |$key, $value| {
    file { $key:
      ensure    => present,
      path => $value[‘path’],
      program => $value[‘program’],
    }
  }

Looping array data through a resource

In the manifest:

$my_parameters.each |$param|{
  ExampleResource { $param[‘title’]:
    ensure => $param[‘ensure’],
    value    => $param[‘value’],
    }
  }
}

The array in hiera:

profiles::sample::my_parameters:
  - title: 'sample1'
    ensure: 'present'
    value: '1'
  - title: 'sample2'
    ensure: 'present'
    value: '2'

Troubleshooting the Catalog

The below command can be run on the agent to view the catalog, including roles, profiles and resources applied and their values.

puppet catalog download