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
- by
facter
(facts):$ facter
(access with$::operatingsystem
) - by puppet code: simply
$user = 'root'
- in Hiera backend:
$log_server = hiera(log_server)
- built-in: something like
$environment
,$servername
,$settings::<name>
(settings inside master'spuppet.conf
)
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
- masterless: install
puppet
and just usepuppet apply
- master/client: install
puppetmaster
andpuppet
on different servers
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
- Use the metaparameters
before
,require
,notify
,subscribe
- Use the Chaining arrows (compared to the above metaparamers:
->
,<-
,<~
,~>
) - Use run stages
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.