Puppet Guide
Puppet is a configuration management system. This page documents puppet fundamentals and includes some sample manifests. Printing the puppet configurationpuppet config print
Show the version of Puppetpuppet -V
Show all Puppet FactersPuppet 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 manifestpuppet apply -e 'include module_name'
Check your puppet manifest for code errorspuppet 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 ModulesList 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 puppetpuppet resource service puppet ensure=running enable=true
The Puppet Binary PathAdd 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 pageTo 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 valuesWhen 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',
}
heredocHeredoc 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 arrayTo return a value in the array use $array[1].
$array = ['value1', 'value2', 'value3']
VariablesVariables 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": }
CaseCase 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 requireIn 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 subscribeCan 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'],
}
ParametersYou 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.ppparams.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_reThe 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,
}
}
TemplatesSample 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