Agenda
- Puppet Introduction
- Puppet master configuration
- Puppet Language (Basic)
- Puppet Language (Advanced)
- Advanced Puppet
- Open Demo Lab Q&A
What is Puppet?
(Basically a State Machine)
- Automation software
- Written in Ruby(...)
- Designer to manage multiple systems at once
- Master-client architecture or Masterless...
- Excels at Configuration Management
Puppet open source vs commercial
- Several available versions:
- Open Source (Apache License 2.0)
- Commercial
- Current Version 3.1.1, Release Notes
- Main differences/advantages for commercial version
- Easy installation, including dependencies
- Integrated Dashboard
- Some closed-source components
- Support from PuppetLabs
- Satellite6 incorporates puppet(and rpms!)
Puppet Architecture with Version Control Software
(Small view)
All master-agent communication use SSL
Puppet Architecture (II)
- Puppet makes a clear distinction between:
- The desired state (what)
- The procedure to move into that state (how)
- This distinction is shown by the separation between resource types(which defines what we want) and providers( silently realizes them)
Puppet Architecture
No Master Server (masterless)
- An alternative option is to run Puppet client, with no master
- Create files and run them as "scripts"
$ puppet apply manifests.pp
Main features of Puppet
- Idempotency
- Run n times, get the same result n times (get back to known state using the same steps)
- Cross-platform
- All flavors of Linux, BSD, Solaris, HP-UX, Mac OS X...
- ... and even Windows (Better support of Win in 3.x.x)
- Same manifest everywhere
- Script Agnostic
- Declarative language
- No needs to rely on a particular scripting languages(perl,python,ruby)
Facter
And What it does for Puppet
-
Facter provides facts about the system it is running on
- Puppet uses Facter to gather specific details about the system
- Then, it can use those details to make decisions
class hardware {
case $manufacturer {
'VMware, Inc.': {include hardware::vmware}
'HP': {include hardware::hp}
'IBM': {include hardware::ibm}
}
}
Puppet Master Configuration
Puppet Installation requirements
- Puppet will be available from Red Hat tools channel when satellite6 is out
- Available option today:
- The Puppetlabs repository has a more up to date version than epel , and dependencies
Installing the Puppet Master
- Ensure Repositories are setup
$ yum install puppet-server
A Puppet Master service is created and available, so you can start it
$ service puppetmaster start
But don't do it yet! There is some stuff to configure first.
Configuring the puppet master
- Puppet configuration file is /etc/puppet/puppet.conf
- The simplest configuration will just specify the module path and the certificate names:
[main]
modulepath = /etc/puppet/modules
[master]
certname = puppetmaster.example.com
dns_alt_names = puppetmaster,puppetmaster.example.com
Now, we can start the Puppet master and have it create the CA Certificates
Modify additional parameters carefully, ensure DNS (FQDN) is configured accordingly !
Puppet File server
- Puppet can serve files to clients, statically or dinamically( using variables like the facts)
- Using the file resource (more on that later)
Puppet Client - Puppet master configuration
- Configure Puppet client to point to Puppet Master and enable reporting, at /etc/puppet/puppet.conf
[main]
logdir = /var/log/puppet
rundir = /var/run/puppet
ssldir = $vardir/ssl
modulepath = /etc/puppet/modules
report = true
[agent]
server = puppetmaster.example.com
report = true
classfile = $vardir/classes.txt
localconfig = $vardir/localconfig
[master]
certname = puppetmaster.example.com
Puppet Client - Puppet master configuration (II)
- Run agent for the first time, it will request a certificate signed by the Puppet master:
$ puppet agent -t
On the Puppet master, check that the certificate is requested and sign it:
$ puppet cert list
$ puppet cert sign # On Client Validate it works!
$ puppet agent --test
Connection is established. Now, we can enable the puppet service, or run it anytime we want
Automated client certificate hamdling
- Signing every client cert request is...difficult to handle
- There is an option to automatically sign certificates according the domain name of the machine:
cat /etc/puppet/autosign.conf
*.example.com
Centralized manifest and module handling
- When a puppet agent contacts the master, it will first fetch the site.pp manifest from /etc/puppet/manifests/site.pp
- This manifest defines:
- The node definitions
- The classes and resources applying to each system
- Any included class/module/file will then be fetched from the Puppet Master, as needed.
Example site.pp file
## site.pp ##
# Define filebucket 'main':
filebucket { 'main':
server => '.example.com',
path => false,
}
# Make filebucket 'main' the default backup location
# for all File resources:
File { backup => 'main' }
node default {
notify { 'example':
message => 'Hello World!'
}
}
Node groups
- Nodes are defined using the node resource
- Node inheritance allows us to create node groups
- Node inheritance is limited to one parent node
node prod {
notify { 'prod':
message => 'This is a production machine'
}
}
node web inherits prod {
notify { 'web':
message => 'This is a production web server'
}
}
node 'webserver1.example.com' inherits web {}
External Node Classifiers (ENC)
- Managing node groups with the configuration files is exponentially complex of order O(n²) upon number of hosts
- Manually update files each time a new client is added
- Growing wildcards/regexps
- Another option is to use ans ENC
- LDAP
- LDAP
- Arbitrary script as in satellite6
[master]
node_terminus = exec
external_nodes = /usr/local/bin/puppet_node_classifier
Resources
- A resource is the abstraction used by Puppet to define a “state”
- It defines what we want, not how
- A resource has:
- A title
- 1-n attributes, each with value
A resource, explained
user { 'karim':
ensure => present,
uid => '8000',
gid => 'admin',
shell => '/bin/bash',
home => '/rhome/karim',
managehome => true,
}
Core resource types
- There are many predefined resource types we can just use:
file package user group service augeas
notify host exec mount cron ssh_authorized_key
Plus some others. The full list will always be available at
Augeas
the almighty config file editor
- Augeas is a config file editor in a key=value
- Translates a config file into a tree-like structure
- Changing items in this structure reflects into configuration lines
- Where to learn more about Augeas?
- http://augeas.net
Simple augeas rules
augeas { "sshd_config":
require => File['/etc/ssh/sshd_config'],
context => "/files/etc/ssh/sshd_config",
changes => [
"set Port 22",
"set LogLevel VERBOSE",
"set PermitRootLogin yes",
"set PermitEmptyPasswords no"
]
}
augtool
- This is an interactive augeas tool
- Allows us to see the tree-like structure
- Test changes before creating the Puppet manifest
- Interactive help
# augtool
augtool> ls /files/etc/hosts/1
ipaddr = 127.0.0.1
canonical = localhost.localdomain
alias = localhost
augtool> set /files/etc/hosts/1/ipaddr 172.0.0.2
augtool> ls /files/etc/hosts/1
ipaddr = 172.0.0.2
canonical = localhost.localdomain
alias = localhost
Creating simple manifests
- Let's start by writing a simple manifest, with only one resource
package { 'httpd':
ensure => installed,
}
Execute interactively on the client, or place it on the puppet master
Inter-resources requirements
- We can make a resource depend on another resource
package { 'httpd':
ensure => installed,
}
service { 'httpd':
ensure => running,
enable => true,
require => Package ['httpd'],
}
The httpd service will only be started once the httpd package is installed
Resource conditions
- We can make a resource be applied only if a certain condition is met
exec { '/bin/touch /tmp/test':
onlyif => '/usr/bin/test ! -f /tmp/test',
}
/tmp/test is only created if it does not exist as a file
Subscribing to other resources
And notifying other resources
- We can subscribe to changes in other resources, or notify other resources of changes
exec { 'sysctl -p':
alias => 'sysctl',
path => '/sbin',
refreshonly => true,
subscribe => Augeas['sysctl'];
}
augeas { 'sysctl':
context => '/files/etc/sysctl.conf',
changes => [
# Enforcing ExecShield
"set kernel.exec-shield 1",
"set kernel.randomize_va_space 1"
]
}
Subscribing to other resources
And notifying other resources (II)
- An alternative way of doing this...
exec { 'sysctl -p':
alias => 'sysctl',
path => '/sbin',
refreshonly => true,
}
augeas { 'sysctl':
context => '/files/etc/sysctl.conf',
changes => [
# Enforcing ExecShield
"set kernel.exec-shield 1",
"set kernel.randomize_va_space 1"
],
notify => Exec['sysctl -p']
}
Variables
- Variables can be defined, then used later in a manifest
- Simple assignment
$serverXaddr = '172.0.0.45'
augeas { 'test1':
context => '/files/etc/postfix/main.cf',
changes => [
"set relayhost ${serverXaddr}"
]
}
Conditionals and facts: if
- We are creating a variable depending on a fact, and then creating the file using contents from the variable
- A fact is just a variable with a predefined value
if $::is_virtual == 'true' {
$message = 'This is a virtual system'
} else {
$message = 'This is a physical system'
}
file { '/root/isvirt.txt':
content => “Hey man, ${message}”
}
Conditionals and facts: case
case $::operatingsystem {
centos: { $apache = 'httpd'}
# Note that these matches are case-insensitive.
redhat: { $apache = 'httpd' }
debian: { $apache = 'apache2' }
ubuntu: { $apache = 'apache2' }
}
package { 'apache':
ensure => installed,
name => $apache,
}
Puppet Language (Advanced)
Classes
- Classes aggregate several resources into a reusable container
- We can later include those classes as part of a manifest, which will apply them to the machine
- Use them to define services, or common system properties handled as one
node puppetossclient2.example.com
{
include production
include vsftpd
}
A Sample class
class { 'vsftpd':
package { 'vsftpd':
ensure => installed,
}
augeas {'vsftpd.conf':
require => Package ['vsftpd'],
context => '/files/etc/vsftpd/vsftpd.conf',
changes => [
"set anonymous_enable NO",
]
}
service { 'vsftpd':
ensure => running,
enable => true,
require => Augeas ['vsftpd.conf'];
}
}
Modules
- Modules are re-usable bundles of code and data
- By default, Puppet loads all modules in the default path: /etc/puppet/modules
- So we can declare a class in a module, and it will automatically be available
- Modules use a standard directory structure
-> {module}/
-> files/
-> lib/
-> manifests/
-> init.pp
-> {class}.pp
-> namespace/
-> {class}.pp
Example module
-> modules/
-> hardware/
-> manifests/
-> init.pp
-> vmware.pp
-> hp.pp
-> ibm.pp
- Then, the contents of init.pp are:
class hardware {
case $manufacturer {
'VMware, Inc.': { include hardware::vmware }
'ibm': { include hardware::ibm }
'HP': { include hardware::hp }
}
}
File Serving
- We can serve configuration files to clients
- Much like RHN Satellite config files
- Options for storage:
file/filename.txt
From within a module
module/files/filename.txt
FIle Usage
- Create file at /etc/puppet/files/issue
file { '/etc/issue':
ensure => present,
source => 'puppet:///files/issue',
}
If the file is part of a module
- Create under /etc/puppet/modules//files/issue
file { '/etc/issue':
ensure => present,
source => 'puppet:///modules/testmodule/issue',
}
Templates
- We can use templates to deploy files
- Templates use the ERB templating language
- Easy to learn... if you know Ruby
- Templates can use defined variables
- Global variables
- Facts
- Variables defined in the current scope
- Can also include Ruby code
Simple template usage
- Create file modulename/templates/testfile.txt.erb
<%= fqdn %> is the name of this server.
Define file resource using template
file { '/root/testfile.txt':
ensure => present,
content => template('testmodule/testfile.txt.erb'),
}
ERB Language cheat sheet
<% Ruby code -- inline with output %>
<%= Ruby expression -- replace with result %>
<%# comment -- ignored -- useful in testing %>
% a line of Ruby code -- treated as <% line %> (optional)
%% replaced with % if first thing on a line and % processing is used
<%% or %%> -- replace with <% or %> respectively
<%- and -%> suppress leading and trailing whitespace,
including the trailing newline, and can be used interchangeably with <% and %>.
Custom facts in modules
- Create them under modulename/lib/facter/mycustom.rb
- Example:
Facter.add(:iptables_version) do
confine :kernel => :linux
setcode do
version = Facter::Util::Resolution.exec('iptables --version')
if version
version.match(/\d+\.\d+\.\d+/).to_s
else
nil
end
end
end
Auditing
- Puppet can notify changes in resources
- Useful for auditing purposes
- These notifications can be centrally stored
- Satellite6(foreman) does a good job of showing these in the GUI
Setting up audit
- The following lines must be present at the puppet.conf [main] section
archive_files = true
archive_file_server = puppetmaster.example.com
To ensure files are uploaded to the puppet master, add a cron job running puppet inspect every day
Files are archived under /var/lib/puppet/bucket in the puppet master
Before that, files also archived under /var/lib/puppet/clientbucket in the client
Auditing in manifests
- Simply add the audit metaparameter
file { '/etc/hosts':
audit => content,
}
Can audit any resource parameter:
- owner, group
- permissions
- contents
- ...
Checking audit logs
- Check individual logs on each client
- Use the satellite6 dashboard
Scalability
- The default puppetmaster web server does not scale
- Anything > 10 is a BAD IDEA !!!!
- Need to search for alternative options
Extending resources
- Sometimes Puppet doesn't cover some features we need:
- Facts are useful but don't cover everything
- Manifests even with augeas can be more tricky than KISS
- Resources, providers and types can be extended!
- Puppet Forge has many available modules
Extending resources: Example
Final words
- Good information sources: