Jim Cheung

Puppet

Editing

Editor

the best one is Geppetto (even I like emacs)

for ruby and .erb files, install Dynamic Languages Toolkit, also need to configure the ruby preferences to enable the source highlighting.

Style Guide

there is The Puppet Language Style Guide

you can check formatting with puppet-lint, and fix with:

$ puppet-lint --fix /etc/puppet/modules

Syntax Checking

$ puppet parser validate

Terms

class

class definition and declaration:

after a class has been defined:

class mysql {
    port => '3306',
}

if you run puppet apply, nothing will happen, because you'll need to declare it, there're two ways to do it:

# without parameters
include mysql
# with parameters
class { 'mysql':
    port => '3307',
}

defined types

Similar to parametrized classes but can be used multiple times (with different titles)

Definition of a define:

define apache::virtualhost (
  $ensure   = present,
  $template = 'apache/virtualhost.conf.erb' ,
  [...] ) {

  file { "ApacheVirtualHost_${name}":
    ensure  => $ensure,
    content => template("${template}"),
  }
}

Declaration of a define:

apache::virtualhost { 'www.example.com':
  template => 'site/apache/www.example.com-erb'
}

variables

environments

data isolation: each environment we can have different paths manifest files, Hiera data and modules.

before 3.6: environment had to be defined in puppet.conf from 3.6: using directory environments from 4.x: only directory environments

default is production, and it doesn't have to be the same as your server environment.

nodes

node is identified by the PuppetMaster by its certname, which defaults to the node's fqdn

node 'web01' {
  include apache
}

We can also define a list of matching names:

node 'web01' , 'web02' , 'web03' {
  include apache
}

or use a regular expression:

node /^www\d+$/ {
  include apache
}

note, node inheritance is not recommended.

node could be fetched from an External Node Classifier (ENC) (like foreman):

# Enable the usage of a script to classify nodes
node_terminus = exec
# Path of the script to execute to classify nodes 
external_nodes = /etc/puppet/node.rb

could be by Hiera:

# in manifests/site.pp
hiera_include('classes')

catalogs

catalog is the complete list of resources, and their relationships.

Get more information

describe

$ puppet describe --list
$ puppet describe file

resource

$ puppet resource user
$ puppet resource user root
$ puppet resource package
$ puppet resource service

modify resource directly:

$ puppet resource service httpd ensure=running enable=true

list configs

$ puppet config print all
$ puppet config print <key>

facter

Facter can give you information of a node, just run:

$ facter

graph

install graphviz:

$ apt-get install graphviz

put graph=true to [agent] section (also set graphdir maybe) of puppet.conf

after puppet agent -t, go /var/lib/puppet/state/graphs, run:

$ dot -Tpng resources.dot -o /tmp/resources.png

logging

simple way to check log is via syslog:

$ tail -f /var/log/syslog

Basics

operational modes

certificates management

common commands:

$ puppet cert list
$ puppet cert list --all
$ puppet cert sign <certname>
$ puppet cert clean <certname>

client certs are under /var/lib/puppet/ssl ($vardir/ssl) server stores client's public certs under /var/libg/puppet/ssl/ca

puppet.conf

Important options

under [main] section:

vardir: Path where Puppet stores dynamic data.
ssldir: Path where SSL certifications are stored.

Under [agent] section:

server: Host name of the PuppetMaster. (Default: puppet)
certname: Certificate name used by the client. (Default is its fqdn)
runinterval: Number of minutes between Puppet runs, when running as service. (Default: 30)
report: If to send Puppet runs' reports to the **report_server. (Default: true)

Under [master] section:

autosign: If new clients certificates are automatically signed. (Default: false)
reports: How to manage clients' reports (Default: store)
storeconfigs: If to enable store configs to support exported resources. (Default: false)

puppet agent

common agent commands:

$ puppet agent --test # Can be abbreviate to -t
$ puppet agent --test --debug
$ puppet agent --test --noop
$ puppet agent --test --environment testing

Common Types

package

package { 'apache':
  name      => 'httpd',  # (namevar)
  ensure    => 'present' # Values: 'absent', 'latest', '2.2.1'
  provider  => undef,    # Force an explicit provider
}

service

service { 'apache':
  name      => 'httpd',  # (namevar)
  ensure    => 'running' # Values: 'stopped', 'running'
  enable    => true,     # Define if to enable service at boot (true|false)
  hasstatus => true,     # Whether to use the init script' status to check
                         # if the service is running.
  pattern   => 'httpd',  # Name of the process to look for when hasstatus=false
}

file

file { 'httpd.conf':
    # (namevar) The file path
    path      => '/etc/httpd/conf/httpd.conf',  
    # Define the file type and if it should exist:
    # 'present','absent','directory','link'
    ensure    => 'present',
    # Url from where to retrieve the file content
    source    => 'puppet://[puppetfileserver]/<share>/path',
    # Actual content of the file, alternative to source
    # Typically it contains a reference to the template function
    content   => 'My content',
    # Typical file's attributes
    owner     => 'root',
    group     => 'root',
    mode      => '0644',
    # The sylink target, when ensure => link
    target    => '/etc/httpd/httpd.conf',
    # Whether to recursively manage a directory (when ensure => directory)
    recurse   => true,
}

exec

exec { 'get_my_file':
    # (namevar) The command to execute
    command   => "wget http://mysite/myfile.tar.gz -O /tmp/myfile.tar.gz',
    # The search path for the command. Must exist when command is not absolute
    # Often set in Exec resource defaults
    path      => '/sbin:/bin:/usr/sbin:/usr/bin',
    # A file created by the command. It if exists, the command is not executed
    creates   => '/tmp/myfile.tar.gz',
    # A command or an array of commands, if any of them returns an error
    # the command is not executed
    onlyif    => 'ls /tmp/myfile.tar.gz && false',
    # A command or an array of commands, if any of them returns an error
    # the command IS executed
    unless    => 'ls /tmp/myfile.tar.gz',
}

user

user { 'joe':
    # (namevar) The user name
    name      => 'joe',  
    # The user's status: 'present','absent','role'
    ensure    => 'present',
    # The user's  id
    uid       => '1001',
    # The user's primary group id
    gid       => '1001',
    # Eventual user's secondary groups (use array for many)
    groups    => [ 'admins' , 'developers' ],
    # The user's password. As it appears in /etc/shadow
    # Use single quotes to avoid unanted evaluation of $* as variables
    password  => '$6$ZFS5JFFRZc$FFDSvPZSSFGVdXDlHe�',
    # Typical users' attributes
    shell     => '/bin/bash',
    home      => '/home/joe',
    mode      => '0644',
}

resource references

can't have 2 resources of the same type with the same name in a catalog.

when we declare:

type { 'name':
  arguments => values,
}

then we need to reference to them like:

Type['name']

examples:

file { 'motd': ... }
apache::virtualhost { 'example42.com': .... }
exec { 'download_myapp': .... }

are referenced, respectively, with

File['motd']
Apache::Virtualhost['example42.com']
Exec['download_myapp']

resource defaults

Type {
    argument => value,
}

examples:

Exec {
  path => '/sbin:/bin:/usr/sbin:/usr/bin',
}

File {
  mode  => 0644,
  owner => 'root',
  group => 'root',
}

class inheritance

example:

class puppet {
  file { '/etc/puppet/puppet.conf':
    content => template('puppet/client/puppet.conf'),
  }
}

class puppet::server inherits puppet {
  File['/etc/puppet/puppet.conf'] {
    content => template('puppet/server/puppet.conf'),
  }
}

dependencies

examples:

before | notify:

package { 'exim':
  before => File['exim.conf'],  
}

file { 'exim.conf':
  notify => Service['exim'],
}

service { 'exim':
}

# which is equivalent to

Package['exim'] -> File['exim.conf'] ~> Service['exim']

require | subscribe:

package { 'exim':
}

file { 'exim.conf':
  require => Package['exim'],
}

service { 'exim':
  subscribe => File['exim.conf'],
}

# which can also be expressed like:

Service['exim'] <~ File['exim.conf'] <- Package['exim']

conditionals

selector:

$package_name = $osfamily ? {
   'RedHat' => 'httpd',
   'Debian' => 'apache2',
   default  => undef,
 }

case:

case $::osfamily {
   'Debian': { $package_name = 'apache2' }
   'RedHat': { $package_name = 'httpd' }
   default: { notify { "Operating system $::operatingsystem not supported" } }
 }

if elsif else:

if $::osfamily == 'Debian' {
   $package_name = 'apache2'
} elsif $::osfamily == 'RedHat' {
  $package_name = 'httpd'
} else {
  notify { "Operating system $::operatingsystem not supported" }
}

comparing

if $::osfamily == 'Debian' { [ ... ] }

if $::kernel != 'Linux' { [ ... ] }

if $::uptime_days > 365 { [ ... ] }

if $::operatingsystemrelease <= 6 { [ ... ] }

in operatior:

if '64' in $::architecture
if $monitor_tool in [ 'nagios' , 'icinga' , 'sensu' ]

and and or:

if ($::osfamily == 'RedHat') and ($::operatingsystemrelease == '5') {
   [ ... ]
}

if ($::osfamily == 'Debian') or ($::osfamily == 'RedHat') {
   [ ...]
}

Trouble Shooting

Re-create the entire client certificate setup

source: http://serverfault.com/questions/515296/puppet-agent-certificate-verify-failure

On the client, delete all stored certs, including the CA:

$ find /var/lib/puppet/ssl -name '*.pem' -exec rm {} \;

On the master, delete any pending CSRs or old client certificates for this client:

$ find /var/lib/puppet/ssl -name agenthost.domain.com.pem -exec rm {} \;

Then, on the client, reconnect to the master and send a CSR:

$ puppet agent -t --waitforcert=60

and when it is waiting (if you have not set autosigning enabled) then on the master approve the CSR so a new client cert is sent back:

$ puppet cert sign agenthost.domain.com

This should make the agent re-download the puppet CA certificates, and re-apply for its own certificate.

More Resources