0% found this document useful (0 votes)
33 views51 pages

13 Puppet

Puppet is a configuration management tool that automates infrastructure management using a client-server model, where a Puppet Master manages configurations and Puppet Agents implement them. The document outlines the installation process, configuration settings, SSL certificate setup, and how to create environments and modules within Puppet. It emphasizes the importance of defining node states and managing configurations efficiently through Puppet's architecture and workflows.

Uploaded by

Aslam Ansari
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
33 views51 pages

13 Puppet

Puppet is a configuration management tool that automates infrastructure management using a client-server model, where a Puppet Master manages configurations and Puppet Agents implement them. The document outlines the installation process, configuration settings, SSL certificate setup, and how to create environments and modules within Puppet. It emphasizes the importance of defining node states and managing configurations efficiently through Puppet's architecture and workflows.

Uploaded by

Aslam Ansari
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 51

XIII.

Puppet

1. What is Puppet?

Puppet is a configuration management tool to automate infrastructure management and


configuration i.e., it manages configuration data on other systems, including users, packages,
processes, services. It helps in the concept of Infrastructure as code. Puppet written in Ruby DSL
language, which can be easily managed and configured.

Puppet follows client-server Model, where one machine acts as server known as puppet master and
the other acts as client known as slave or agent machine.

The Puppet Master is a Machine where all manifests will be developed and ready to be
implemented on the agents.

The agent implements Puppet manifests, or files containing Puppet configuration language that
declare the desired state of the node.

Special Features and Work Flow

in Puppet, one can safely run the same set of configuration multiple times on the same machine. In
this flow, Puppet checks for the status of the target machine and will only make changes when there
is any specific change in the configuration.

Puppet Work Flow

Puppet architecture mainly contains following components.

Puppet Master
Puppet Master is the key mechanism which handles all the configuration related stuff. It
applies the configuration to nodes using the Puppet agent.

Catalog
All the configuration changes which are written in Puppet are first converted to a
compiled format called catalog and later those catalogs are applied on the target machine.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
Puppet Agent
Puppet Agents are the actual working machines which are managed by the Puppet master. They
have the Puppet agent daemon service running inside them.

The Work Flow:

The first thing that Puppet master does is to collect the details of
The Puppet agent. Using the factor which is present on all Puppet agents it gets all the machine
level configuration details. All these details are
gathered and sent back to the Puppet master.

Then the puppet master compares the gathered configuration with defined
configuration details, and with the defined configuration it creates a catalog and
sends it to the targeted Puppet nodes.

The Puppet node applies those configurations to get the system into the desired
state.

After puppet agent changing to desired state, that node sends a report back to
the Puppet master. This helps the Puppet master in understanding where the
current state of the system is, as defined in the catalog.

2. INSTALLING PUPPET

Prerequisites
Before we get started with installing Puppet, ensure that you have the following prerequisites:
• Private Network DNS: Forward and reverse DNS must be configured, and every server
must have a unique hostname. If you do not have DNS configured, you must use your hosts
file for name resolution.
• Firewall Open Ports: The Puppet master must be reachable on port 8140.
• Install NTP:Because it acts as a certificate authority for agent nodes, the puppet master
server must maintain accurate system time to avoid potential problems when it issues agent
certificates--certificates can appear to be expired if there are time discrepancies. We will use
Network Time Protocol (NTP) for this purpose.

Install it with the following apt command

sudo apt-get update && sudo apt-get -y install ntp

Install Puppet Master

Download the Puppet Labs package, with the following command

NOTE: For the time being we have taken centos

#yum install -y http://yum.puppetlabs.com/puppetlabs-release-el-6.noarch.rpm

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
Install the package

#yum install -y puppet-server

After installing Puppet server, we can check the file structure as seen below.

Install Puppet Agent:


#yum install -y http://yum.puppetlabs.com/puppetlabs-release-el-6.noarch.rpm

#yum install -y puppet

Memory Allocation
By default, Puppet Server will be configured to use 2GB of RAM. However, if you want to
experiment with Puppet Server on a VM, you can safely allocate as little as 512MB of memory. To
change the Puppet Server memory allocation:
Open /etc/sysconfig/puppetserver and modify these settings:
# Modify this if you'd like to change the memory allocation, enable JMX, etc
JAVA_ARGS="-Xms2g -Xmx2g"

Replace 2g with the amount of memory you want to allocate to Puppet Server. For example, to
allocate 1GB of memory, use JAVA_ARGS="-Xms1g -Xmx1g"; for 512MB, use
JAVA_ARGS="-Xms512m -Xmx512m".
For more information about the recommended settings for the JVM, please see Oracle’s docs on
JVM tuning.
Restart the puppetserver service after making any changes to this file.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
3. Configure Puppet Master

The main configuration file for Puppet is etc/puppet/puppet.conf.


All Puppet related settings such as the definition of Puppet master, Puppet agent, Puppet apply and
certificates are defined in this file.

Puppet configuration file mainly consists of the following config sections.

Main: This is known as the global section which is used by all the commands and
services in Puppet. One defines the default values in the main section which can
be overridden by any section present in puppet.conf file.

Master: This section is referred by Puppet master service and Puppet cert command.

Agent: This section is referred by Puppet agent service.

User: It is mostly used by Puppet apply command as well as many of the less common commands.

Following are the sample examples for config sections on both puppet master and agents.

Example agent config


[main]
certname = agent01.example.com
server = puppet
environment = production
runinterval = 1h

Example master config


[main]
certname = puppetmaster01.example.com
server = puppet
environment = production
runinterval = 1h
strict_variables = true

[master]
dns_alt_names = puppetmaster01,puppetmaster01.example.com,puppet,puppet.example.com
reports = puppetdb
storeconfigs_backend = puppetdb
storeconfigs = true
environment_timeout = unlimited

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
The basic changes to be made on puppet master configuration file
vi /etc/puppet/puppet.conf

[main]
certname = puppetmaster

The basic changes to be made on puppet agent configuration file

vi /etc/puppet/puppet.conf

[agent]

server = puppetmaster

The above commands update the puppet master and agent info in the configuration

4. SSL Sign Certificate Setup

When the Puppet agent software runs for the first time on any Puppet node, it generates
a certificate and sends the certificate signing request to the Puppet master.

The below command from agent will request for the certificate from the master.

# puppet agent --verbose --no-daemonize –onetime

Before the Puppet server is able to communicate and control the agent nodes, it must sign that
particular agent node’s certificate. In the following sections, we will describe how to sign
and check for the signing request.

List Current Certificate Requests.

On the Puppet master, run the following command to see all unsigned certificate requests.

$ sudo puppet cert list

As we have just set up a new agent node, we will see one request for approval. Following
will be the output.

"agent01.example.com" (SHA259)

15:90:C2:FB:ED:69:A4:F7:B1:87:0B:BF:F7:ll:B5:1C:33:F5:76:67:F3:F6:45:AE:07:4B:F

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
6:E3:ss:04:11:8h

It does not contain any + (sign) in the beginning, which indicates that the certificate is
still not signed.

Sign a Request

In order to sign the new certificate request which was generated when the Puppet agent
run took place on the new node, the Puppet cert sign command would be used, with the
host name of the certificate, which was generated by the newly configured node that needs
to be signed.

As we have agent01.example.com’s certificate, we will use the following


Command.

$ sudo puppet cert sign agent01.example.com

Following will be the output.

Notice: Signed certificate request for agent01.example.com

Once the above is done, we have our infrastructure ready in which the Puppet master is
now capable of managing newly added nodes.

5. Creating environments

In the IT industry, we can find different teams like development team, testing team, DB
admin team etc. To manage infrastructure for each team separately we can create environments in
puppet.

Enabling Directory Environments in Open Source Puppet


Directory environments are disabled by default. To enable them, you must:
Edit the config file
Create at least one directory environment

Edit puppet.conf
To enable directory environments, set environmentpath = $confdir/environments in the Puppet
master’s puppet.conf (in the [main] or [master] section).
Optionally, you can also:
Use the basemodulepath setting to specify global modules that should be available in all
environments. Most people are fine with the default value.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
See the section below about settings for more details.
Once you edit puppet.conf, directory environments will be enabled and config file environments
will be disabled.

Create a Directory Environment

You must have a directory environment for every environment that any nodes are assigned to. At
minimum, you should have a production environment. Nodes assigned to non existent environments
cannot fetch their catalogs.
To create your first environment, create a directory named production in your environmentpath. (If
a production directory doesn’t exist, the Puppet master will try to create one when it starts up.)
Once it is created, you can add modules, a main manifest, and an environment.conf file to it.

Restart the Puppet Master


Restart the web server that manages your Puppet master, to make sure the Puppet master picks up
its changed configuration.
Global Settings for Configuring Environments
Puppet uses five settings in puppet.conf to configure the behaviour of directory environments:
•environmentpath is the list of directories where Puppet will look for environments.
•basemodulepath lists directories of global modules that all environments can access by default.
•default_manifest specifies the main manifest for any environment that doesn’t set a manifest
value in environment.conf.
•disable_per_environment_manifest lets you specify that all environments should use a shared
main manifest. This requires default_manifest to be set to an absolute path.
•environment_timeout sets how often the Puppet will refresh information about environments.
It can be overridden per-environment.

Creating an environment

We can create file structure for an environment, running the command

mkdir -p /etc/puppet/environments/production/{modules,manifests}

Sample environment.conf File

[master]
manifest= $confdir/environments/Production/manifests/site.pp
modulepath= $confdir/environments/Production/modules

Where “$confdir” represents “/etc/puppet”.

6. Site.pp
/etc/puppet/environments/Production/manifests/site.pp
Visualpath Training & Consulting.
Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
It is the file where we define the nodes and what changes to be made to get the node to a desired
state in the production environment.

Syntax
# /etc/puppet/environments/production/manifests/site.pp
node 'www1.example.com' {
include common
include apache
include squid
}
node 'db1.example.com' {
include common
include mysql
}

In the example above, only www1.example.com would receive the apache and squid classes, and
only db1.example.com would receive the mysql class.

Node definitions look like class definitions. The general form of a node definition is:
The node keyword
The name(s) of the node(s), separated by commas (with an optional final trailing comma)
An opening curly brace
Any mixture of class declarations, variables, resource declarations, collectors, conditional
statements, chaining relationships, and functions
A closing curly brace

To create a group of multiple nodes for same node definition

node 'www1.example.com', 'www2.example.com', 'www3.example.com' {


include common
include apache, squid
}

Note: The function “include” can call puppet code from the manifests files. It is explained in detail
in the next chapters

7. Modules
/etc/puppet/environments/Production/modules

Modules are how Puppet finds the classes and defined types it can use — it automatically loads any
class or defined type stored in its modules.

It is a directory where we find all the manifest files, templates and files that are required to prepare
the catalog for the nodes.

Creating Modules

By running the command below, we can create the file structure for the module.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
puppet module generate <USERNAME>-<MODULE NAME> --environment <
ENVIRONMENT NAME>
Module Layout
On disk, a module is simply a directory tree with a specific, predictable structure:
❖ <MODULE NAME>
• manifests
• files
• templates
• lib
• facts.d
• tests
• spec

Example
This example module, named “my_module,” shows the standard module layout in more detail:
15. my_module — This outermost directory’s name matches the name of the module.
1. manifests/ — Contains all of the manifests in the module.
1. init.pp — Contains a class definition. This class’s name must match the
module’s name.
2. other_class.pp — Contains a class named my_module::other_class.
3. my_defined_type.pp — Contains a defined type named
my_module::my_defined_type.
4. implementation/ — This directory’s name affects the class names beneath it.
1. foo.pp— Contains a class named my_module::implementation::foo.
2. bar.pp — Contains a class named
my_module::implementation::bar.
2. files/ — Contains static files, which managed nodes can download.
1. service.conf — This file’s source => URL would be
puppet:///modules/my_module/service.conf. Its contents can also be
accessed with the file function, like content =>
file('my_module/service.conf').
3. lib/ — Contains plugins, like custom facts and custom resource types. These will be
used by both the Puppet master server and the Puppet agent service, and they’ll be
synced to all agent nodes whenever they request their configurations. See “Using
Plugins” for more details.
4. facts.d/ — Contains external facts, which are an alternative to Ruby-based custom
facts. These will be synced to all agent nodes, so they can submit values for those
facts to the Puppet master. (Requires Facter 2.0.1 or later.)
5. templates/ — Contains templates, which the module’s manifests can use. See
“Templates” for more details.
1. component.erb — A manifest can render this template with
template('my_module/component.erb').
2. component.epp — A manifest can render this template with
epp('my_module/component.epp'). (The epp function is only available with
the future parser enabled.)
6. tests/ — Contains examples showing how to declare the module’s classes and
defined types.
1. init.pp
2. other_class.pp — Each class or defined type should have an example in the
tests directory.
7. spec/ — Contains spec tests for any plugins in the lib directory.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
8. Manifests
Manifest is a collection of resources which are coupled inside the function or classes to
configure any target system. They contain a set of Ruby code to configure a system.

Writing Manifest files


Puppet programs are called manifests. Manifests are composed of puppet code and their filenames
use the .pp extension.

9. Classes

Classes are named blocks of Puppet code, which are stored in modules for later use and are not
applied until they are invoked by name. They can be added to a node’s catalog by declaring them in
your manifests.

Defining a class makes it available by name, but doesn't automatically evaluate the code inside it.
Before we can use a class, we must define it, which is done with the class keyword, a name, curly
braces, and a block of code:

Class <CLASS NAME> {


... puppet code ...
}

This manifest does nothing.

Declaring a class evaluates the code in the class, and applies all of its resources.
This one actually does something.

We declare the classes in the main manifest file /etc/puppet/manifests/site.pp

node '<AGENT NAME>' {


include <CLASS NAME 1>
include <CLASS NAME 2>
.
.
}

Include Function:

It is used for declaration of one or more classes, which results in evaluating all the resources present
inside those classes and finally add them to a catalog. The way it works is, include function accepts
a class name, list of classes or a comma separated list of class names.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
While defining classes, we should place puppet code in the manifest files which are made of
“ Resources ”

Resources are the fundamental unit for modelling system configurations. Each resource describes
some aspect of a system, like a service that must be running or a package that must be installed. The
block of Puppet code that describes a resource is called a resource declaration.

Simplified syntax
Resource declarations have a lot of features, but beginners can accomplish a lot with just a subset of
these. For more advanced syntax (including expressions that declare multiple resources at once), see
Resources (Advanced).
# A resource declaration:

file { '/etc/passwd':
ensure => file,
owner => 'root',
group => 'root',
mode => '0600',
}

Every resource has a resource type, a title, and a set of attributes:


<TYPE> { '<TITLE>':
<ATTRIBUTE> => <VALUE>,
}

After
The form of a resource declaration is:
The resource type, which is a word with no quotes.
An opening curly brace ({).
The title, which is a string.
A colon (:).
Optionally, any number of attribute and value pairs, each of which consists of:
An attribute name, which is a lowercase word with no quotes.
A => (called an arrow, “fat comma,” or “hash rocket”).
A value, which can have any data type.
A trailing comma.
A closing curly brace (}).

10. Validating the syntax of manifest file(s)

$puppet parser validate [manifest] [manifest ...]

DESCRIPTION
This action validates Puppet DSL syntax without compiling a catalog or syncing any resources. If
no manifest files are provided, it will validate the default site manifest.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
When validating multiple issues per file are reported up to the settings of max_error, and
max_warnings. The processing stops after having reported issues for the first encountered file with
errors.

EXAMPLES
To validate the default site manifest at
/etc/puppet/environments/production/modules/sample_module/manifests/init.pp:
$ puppet parser validate init.pp

To validate two arbitrary manifest files


$ puppet parser validate init.pp vhost.pp

11. Applying modules on Puppet agent

After validating the puppet code, we need the apply that module on the node. To achieve that we
have to run the command

$puppet agent --test

The puppet agent is configured to run at a specific interval. The default is 30 minutes. You can
change how often agent pulls the catalog by modifying the “runinterval” setting.

Example

root@puppetagent: puppet agent --test


Info: Retrieving plugin
Info: Caching catalog for puppetagent
Info: Applying configuration version '135555737643'
Finished catalog run in 0.10 seconds

12. Configuring the run interval

The Puppet agent service defaults to doing a configuration run every 30 minutes. You can configure
this with the runinterval setting in puppet.conf:
# /etc/puppet/puppet.conf
[agent]
runinterval = 2h

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
Disabling and re-enabling Puppet runs

Regardless of how you’re running Puppet agent, you can prevent it from doing any Puppet runs by
running
$sudo puppet agent --disable

You can re-enable it with


$sudo puppet agent --enable.

13. Deep Dive into Puppet Coding

Variables
Syntax

Assignment
$content = "some content\n"

Variable names are prefixed with a $ (dollar sign). Values are assigned to them with the = (equal
sign) assignment operator.

Resolution

file {'/tmp/testing':
ensure => file,
content => $content,
}

In the above example, A file will be created with the information(of any data type) that is stored in
the variable “$content”

Array

If we want to pass multiple parameters in puppet code, Puppet allows the use of arrays in multiple
areas.

Syntax
Arrays are written as comma-separated lists of values surrounded by square brackets. An optional
trailing comma is allowed between the final value and the closing square bracket.

[ 'one', 'two', 'three' ]

The values in an array can be any data type.

Example

you can specify the packages in an array …


Visualpath Training & Consulting.
Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
$enhancers = [ 'screen', 'strace', 'sudo' ]
package { $enhancers:

ensure => 'installed',

14. Conditionals

Conditions are situations when the user wishes to execute a set of statement or code when
the defined condition or the required condition is satisfied. Puppet supports two types of
conditions.

Puppet supports “if” and “unless” statements, case statements, and selectors.

“If” Statements
“If” statements take a Boolean condition and an arbitrary block of Puppet code, and will only
execute the block if the condition is true. They can optionally include elsif and else clauses.

Syntax

if $osfamily == 'redhat' {

package {'httpd':

ensure => 'present',

elsif $osfamily == 'debian'{

Package {'apache2':

ensure => 'present',

else {

notify { 'No Package Found':

The general form of an “if” statement is:


The if keyword
A condition
A pair of curly braces containing any Puppet code
Optionally: the elsif keyword, another condition, and a pair of curly braces containing Puppet
code
Optionally: the else keyword and a pair of curly braces containing Puppet code

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
15. Case Statements
Like “if” statements, case statements choose one of several blocks of arbitrary Puppet code to
execute. They take a control expression and a list of cases and code blocks, and will execute the
first block whose case value matches the control expression.

Syntax
case $operatingsystem {
'Solaris': { include role::solaris } # apply the solaris class
'RedHat', 'CentOS': { include role::redhat } # apply the redhat class
/^(Debian|Ubuntu)$/:{ include role::debian } # apply the debian class
default: { include role::generic } # apply the generic class
}

The general form of a case statement is:


The case keyword
A control expression (see below)
An opening curly brace
Any number of possible matches, which consist of:
A case (see below) or comma-separated list of cases
A colon
A pair of curly braces containing any arbitrary Puppet code
A closing curly brace
Example

16. Selectors
Selector statements are similar to case statements, but return a value instead of executing a code
block. Selectors are useful when the user wishes to specify a resource attribute and variables which
are different from the default values based on the facts or other variables.

Syntax
Selectors resemble a cross between a case statement and the ternary operator found in other
languages.

$rootgroup = $osfamily ? {
'Solaris' => 'wheel',
/(Darwin|FreeBSD)/ => 'wheel',
default => 'root',
}

file { '/etc/passwd':
ensure => file,
owner => 'root',
group => $rootgroup,
}

In the example above, the value of $rootgroup is determined using the value of $osfamily.
The general form of a selector is:

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
A control variable
The ? (question mark) keyword
An opening curly brace
Any number of possible matches, each of which consists of:
A case
The => (fat comma) keyword
A value
A trailing comma
A closing curly brace

17. Relationships and ordering

By default, Puppet applies resources in the order they’re declared in their manifest. However, if a
group of resources must always be managed in a specific order, you should explicitly declare such
relationships with relationship metaparameters.
Syntax: Relationship metaparameters

package { 'openssh-server':
ensure => present,
before => File['/etc/ssh/sshd_config'],
}

Puppet uses four metaparameters to establish relationships, and you can set each of them as an
attribute in any resource. The value of any relationship metaparameter should be a resource
reference pointing to one or more target resources.

before — Applies a resource before the target resource.


require— Applies a resource after the target resource.
notify — Applies a resource before the target resource.
The target resource refreshes if the notifying resource changes.
subscribe — Applies a resource after the target resource. The subscribing resource refreshes if the
target resource changes.

If two resources need to happen in order, you can either put a before attribute in the prior one or a
require attribute in the subsequent one; either approach creates the same relationship. The same is
true of notify and subscribe.
The two examples below create the same ordering relationship:

package { 'openssh-server':
ensure => present,
before => File['/etc/ssh/sshd_config'],
}
file { '/etc/ssh/sshd_config':
ensure => file,
mode => '0600',
source => 'puppet:///modules/sshd/sshd_config',

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
require => Package['openssh-server'],
}

The two examples below create the same notifying relationship:

file { '/etc/ssh/sshd_config':
ensure => file,
mode => '0600',
source => 'puppet:///modules/sshd/sshd_config',
notify => Service['sshd'],
}
service { 'sshd':
ensure => running,
enable => true,
subscribe => File['/etc/ssh/sshd_config'],
}

Since an array of resource references can contain resources of differing types, these two examples
also create the same ordering relationship:

service { 'sshd':
ensure => running,
require => [
Package['openssh-server'],
File['/etc/ssh/sshd_config'],
],
}
package { 'openssh-server':
ensure => present,
before => Service['sshd'],
}

file { '/etc/ssh/sshd_config':
ensure => file,
mode => '0600',
source => 'puppet:///modules/sshd/sshd_config',
before => Service['sshd'],
}

_____________________________________________________________________________

18. ERB Templates

First, let’s adjust the file declaration from the previous section. We’ll remove the source
attribute and replace it with a content attribute.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
file { '/etc/puppet/puppet.conf':

ensure => ensure,

owner => 'root',

group => 'wheel',

mode => '0644',

content => template('puppet:///puppet/puppet.conf.erb'),

The template() function takes a single argument: the URI of the ERB template. The format of that
URI is always puppet:///modulename/filename. The file should be placed in the templates directory
of the module. ERB templates should end with the .erb extension to indicate that the file contains
tags for the ERB template processor.

Let’s create the ERB template file.


$ cd sample_module/templates

$ vi templates/puppet.conf.erb

The contents of the file should look like this:

# Generated by Puppet ERB template processor

[main]

log_level = <%= @loglevel %>

# This is used by "puppet agent"

[agent]

log_level = <%= @agent_loglevel %>

server = <%= @server -%>.example.net

# This is used for "puppet apply"

[user]

log_level = <%= @apply_loglevel %>

Each instance of <%=@variable %> is replaced with the value of the Puppet variable named after
the @sign. The variables named with the @ sign must exist in the same scope (within the
module class) as the template declaration.

There are many other things you can do within an ERB template. You can lookup variables from
another class using the scope.lookupvar() function, or use scope[] as if it was a Hash.

You can call Puppet functions using scope.function_puppet_function(). For example, you could call
the Hiera function to lookup Hiera values within templates (although this practice is strongly
discouraged). This would be done by using scope.function_hiera() to call the same heira() function
we used when introducing Hiera.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
server = <%= scope.function_hiera( ['puppet::server'] ) -%>

Best Practice: Avoid placing direct Hiera calls within the template, as it divides the source of data
for the template between the manifest file and hiera, ensuring confusion. Instead, source the Hiera
variables within the manifest so that all variables are within scope.

As ERB templates were intended for inline Ruby development, you can put any Ruby statement
within <% ... %> tags without the equals sign. Here’s an example that would limit duplicate
assignment of loglevels which don’t differ.

[user]
<% if @apply_loglevel != @loglevel -%>
log_level = <%= @apply_loglevel %>
<% end -%>

By wrapping this line of the template within the Ruby block, it will skip outputting
the configuration line if the loglevel matches the main loglevel, thus simplifying the
configuration file.

Go ahead and test this change right now with puppet apply. You will see the contents
of the puppet configuration file get updated.

19. Iterating over Values

Here’s an example where we use the Ruby each () function to iterate through an array of tags which
should be used to limit which resources are applied to the node, as we discussed in Part I. This
example uses the dash creatively to suppress linefeeds and output multiple Puppet servers on a
single line:

[agent]

tags = <% @taglist.each do |tagname| -%>

<%= tagname + ',' -%>

<% end -%>

You’ll note that we don’t put an @ sign before the variable name. That is because we are not
referencing a variable in the Puppet module class, but instead from the locall loop shown in this
example.

_____________________________________________________________________________

20. Introducing Hiera

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
In Puppet, Hiera is a key-value lookup tool for configuration data. Hiera is integrated into Puppet to
provide dynamic lookup of configuration data for the manifest files.
With Hiera, we can provide node-specific information to a Puppet module. Hiera uses a
customizable hierarchy to lookup the data .\

For example, We can organize our data in this way:

1. Company-wide defaults
2. Operating system specific changes
3. Site-specific information

Creating Hiera Backends

Hiera has two built-in data file backends, YAML and JSON, and then the Puppet data provider.
Each backend support four data types:

1. Arrays
2. Strings
3. true/false (Boolean)
4. Hashes

Let’s go through how to utilize these data types in each backend.

Hiera Data in YAML

The most common way to provide data to Hiera is using the YAML file format. The file has a .yaml
file extension.

Files in YAML format always start with three dashes on the first line. The YAML format utilizes
white spaces indentation to indicate the relationships between data. YAML should always be
written using spaces, never tabs, for indentation.

Here are some examples of strings, Boolean, arrays, and hashes in YAML.

# strings
agent_running: 'running'
# boolean expression
agent_atboot: true
# arrays
puppet_components:
- facter
- puppet
# hash of values
puppet:
ensure: 'present'
version: '4.0.4'
# variable loopup
hostname: %{facts::hostname}

We can organize all the data within a single hash That could look as simple as this:

puppet:

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
agent_running: 'running'
agent_atboot: true
components:
- 'facter'
- 'puppet'

We can see, YAML provides a clean, easy to read way to provide data without too much
complicated syntax.

Configuring Hiera
Puppet looks for a Hiera configuration file at the location specified by the hiera_config
configuration variable. By default this is $codedir/hiera.yaml, or /etc/puppet/code/hiera.yaml in
Puppet.

Backends
The configuration key :backends should provide an array which lists the backend data providers that
Hiera should use. There are three built-in backends, the two data types we discussed previously,
YAML and JSON, plus Hiera can utilize data from Puppet.

If you wish to utilize both built-in file types, you could configure it as follows.
:backends:
- yaml
- json

We will only be utilizing YAML within this book.

Backend Conguration

For each backend data provider, you name in the backends array, you should create a
top-level entry with the name of the provider. For each backend provide a hash of configuration
data.

For the two built-in file-based backends the only configuration key necessary is :datadir, which
identifies the directory in which the data files reside.

:yaml:
:datadir: /etc/puppetlabs/code/environments/%{::environment}/hieradata
:json:
:datadir: /etc/puppetlabs/code/environments/%{::environment}/hieradata

As the files read by each backend must be named differently, you can use the same data directory
for both data sources as shown above.

You’ll note that we’re using the top-level environment variable (defined by puppet master or client)
to allow different environment data in each environment. Let’s go ahead and create the hieradata
directory now in the environment directories we created in the last chapter.

mkdir /etc/puppetlabs/code/environments/test/hieradata
mkdir /etc/puppetlabs/code/environments/production/hieradata

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
For the Puppet backend place the name of a Puppet module which contains the data in a :datasource
configuration key.
:puppet:
:datasource: hieradata

With this configuration variables from a module named heiradata would be accessed for Hiera
lookups. As mentioned previously this is only useful when the module provides dynamic lookup of
data.

Hierarchy

The final mandatory parameter is :hierarchy. The hierarchy defines the priority order for lookup of
configuration data. For single values Hiera will proceed through the hierarchy until it finds a value
and then stop. For arrays and hashes Hiera will merge data from each level of the hierarchy,
selecting the winner of conflicts based on the :merge_behavior configuration setting.

There are two types of data sources: static and dynamic. Static data sources are files explicitly
named in the hierarchy which contain data. Dynamic data sources are files which are named using
interpolation of local configuration data, such as the host‐ name or operating system of the node.

In a larger enterprise, the data lookup hierarchy could be quite complex, however I recommend the
following for a good starting point.

1. Put default values in a file named global.yaml.


2. Put all operating system specific information in a file named for the OS family as returned by
Facter, e.g. RedHat.yaml, Debian.yaml, FreeBSD.yaml, etc.
3. Put information specific to a single node within a file named the full hostname of the node with a
.yaml extension.

You would implement this hierarchy using the following configuration syntax. As you can see, we
are interpolating data provided by Facter to choose which files will be read.

:hierarchy:
- defaults
- "%{::hostname}"
- "%{::osfamily}"
- global

Naturally you can extend this hierarchy to use information like the domain name of the node or any
other facter-provided node value.

If you have multiple backends configured, then Hiera will evaluate the entire hierarchy for the first
configured backend, then evaluate the entire hierarchy in order forthe 2nd configured backend, etc.

Complete Example
Following is a complete example of a Hiera configuration file. This example is what we will use for
the remainder of this book. It enables YAML data input from etc/puppetlabs/code/hieradata, with a
hierarchy that uses host-specific information in preference to operating system family information,
finally defaulting to values global to every host.

---
:backends:

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
- yaml
:yaml:
:datadir: /etc/puppetlabs/code/hieradata
:hierarchy:
- defaults
- "%{facts::clientcert}"
- "%{facts::osfamily}"
- global

______________________________________________________________________________

21. Resource Types

Resource Type: Cron

Description
Installs and manages cron jobs. Every cron resource created by Puppet requires a command and at
least one periodic attribute (hour, minute, month, monthday, weekday, or special). While the name
of the cron job is not part of the actual job, the name is stored in a comment beginning with #
Puppet Name: . These comments are used to match crontab entries created by Puppet with cron
resources.
If an existing crontab entry happens to match the scheduling and command of a cron resource that
has never been synched, Puppet will defer to the existing crontab entry and will not create a new
entry tagged with the # Puppet Name: comment.

Example:
cron { 'logrotate':
command => '/usr/sbin/logrotate',
user => 'root',
hour => 2,
minute => 0,
}

Command
(Property: This attribute represents concrete state on the target system.)
The command to execute in the cron job. The environment provided to the command varies by local
system rules, and it is best to always provide a fully qualified command. The user’s profile is not
sourced when the command is run, so if the user’s environment is desired it should be sourced
manually.
All cron parameters support absent as a value; this will remove any existing values for that field.

hour
(Property: This attribute represents concrete state on the target system.)

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
The hour at which to run the cron job. Optional; if specified, must be between 0 and 23, inclusive.

minute
(Property: This attribute represents concrete state on the target system.)
The minute at which to run the cron job. Optional; if specified, must be between 0 and 59, inclusive.

user
(Property: This attribute represents concrete state on the target system.)
The user who owns the cron job. This user must be allowed to run cron jobs, which is not currently
checked by Puppet.
This property defaults to the user running Puppet or root.
The default crontab provider executes the system crontab using the user account specified by this
property.

Resource type: File

Description
Manages files, including their content, ownership, and permissions.
The file type can manage normal files, directories, and symlinks; the type should be specified in the
ensure attribute.
File contents can be managed directly with the content attribute, or downloaded from a remote
source using the source attribute; the latter can also be used to recursively serve directories (when
the recurse attribute is set to true or local). On Windows, note that file contents are managed in
binary mode; Puppet never automatically translates line endings.
Autorequires: If Puppet is managing the user or group that owns a file, the file resource will
autorequire them. If Puppet is managing any parent directories of a file, the file resource will
autorequire them.

Example:
file { '/etc/inetd.conf':
ensure => link,
target => '/etc/inet/inetd.conf',
}

ensure
(Property: This attribute represents concrete state on the target system.)
Whether the file should exist, and if so what kind of file it should be. Possible values are present,
absent, file, directory, and link.
34. present accepts any form of file existence, and creates a normal file if the file is
missing. (The file will have no content unless the content or source attribute is
used.)
35. absent ensures the file doesn’t exist, and deletes it if necessary.
36. file ensures it’s a normal file, and enables use of the content or source attribute.
37. directory ensures it’s a directory, and enables use of the source, recurse,
recurselimit, ignore, and purge attributes.
38. link ensures the file is a symlink, and requires that you also set the target attribute.
Symlinks are supported on all Posix systems and on Windows Vista / 2008 and
higher. On Windows, managing symlinks requires Puppet agent’s user account to
have the “Create Symbolic Links” privilege; this can be configured in the “User

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
Rights Assignment” section in the Windows policy editor. By default, Puppet agent
runs as the Administrator account, which has this privilege.
Puppet avoids destroying directories unless the force attribute is set to true. This means that if a file
is currently a directory, setting ensure to anything but directory or present will cause Puppet to skip
managing the resource and log either a notice or an error.
There is one other non-standard value for ensure. If you specify the path to another file as the
ensure value, it is equivalent to specifying link and using that path as the target:

Resource Type: exec

Description
Executes external commands.
Any command in an exec resource must be able to run multiple times without causing harm — that
is, it must be idempotent. There are three main ways for an exec to be idempotent:

Example

exec { 'tar -xf /Volumes/nfs02/important.tar':


cwd => '/var/tmp',
creates => '/var/tmp/myfile',
path => ['/usr/bin', '/usr/sbin',],
}

cwd
The directory from which to run the command. If this directory does not exist, the command will
fail

path
The search path used for command execution. Commands must be fully qualified if no path is
specified. Paths can be specified as an array or as a ‘:’ separated list.

creates
A file to look for before running the command. The command will only run if the file doesn’t exist.
This parameter doesn’t cause Puppet to create a file; it is only useful if the command itself creates
a file.

Resource Type: package

Description
Manage packages. There is a basic dichotomy in package support right now: Some package types
(e.g., yum and apt) can retrieve their own package files, while others (e.g., rpm and sun) cannot. For

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
those package formats that cannot retrieve their own files, you can use the source parameter to point
to the correct file.
Puppet will automatically guess the packaging format that you are using based on the platform you
are on, but you can override it using the provider parameter; each provider defines what it requires
in order to function, and you must meet those requirements to use a given provider.
You can declare multiple package resources with the same name, as long as they specify different
providers and have unique titles.

Example
package { 'ntp':
ensure => 'installed',
}

ensure
(Property: This attribute represents concrete state on the target system.)
What state the package should be in. On packaging systems that can retrieve new packages on their
own, you can choose which package to retrieve by specifying a version number or latest as the
ensure value. On packaging systems that manage configuration files separately from “normal”
system files, you can uninstall config files by specifying purged as the ensure value. This defaults to
installed.

Resource Type: notify

Description
Sends an arbitrary message to the agent run-time log.

notify { 'resource title':


name => # (namevar) An arbitrary tag for your own reference; the...
message => # The message to be sent to the...
withpath => # Whether to show the full object path. Defaults...
# ...plus any applicable metaparameters.
}

package { 'apache2':
provider=>'apt',
ensure=>'installed'
}
notify { 'Apache2 is installed.':
}
service { 'apache2':
ensure=>'running'
}
notify { 'Apache2 is running.':
}

name
(Namevar: If omitted, this attribute’s value defaults to the resource’s title.)
An arbitrary tag for your own reference; the name of the message.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
(↑ Back to notify attributes)

message
(Property: This attribute represents concrete state on the target system.)
The message to be sent to the log.
(↑ Back to notify attributes)

withpath
Whether to show the full object path. Defaults to false.
Valid values are true, false.

Resource Type: service


Descritption:
Manage running services. Service support unfortunately varies widely by platform — some
platforms have very little if any concept of a running service, and some have a very codified and
powerful concept. Puppet’s service support is usually capable of doing the right thing, but the more
information you can provide, the better behaviour you will get.

service { ntpd:
ensure => 'running',
enable => true,
}

ensure
(Property: This attribute represents concrete state on the target system.)
Whether a service should be running.
Valid values are stopped (also called false), running (also called true).

enable
(Property: This attribute represents concrete state on the target system.)
Whether a service should be enabled to start at boot. This property behaves quite differently
depending on the platform; wherever possible, it relies on local tools to enable or disable a given
service.
Valid values are true, false, manual, mask.

Resource Type: user

Description
Manage users. This type is mostly built to manage system users, so it is lacking some features
useful for managing normal users.
This resource type uses the prescribed native tools for creating groups and generally uses POSIX
APIs for retrieving information about them. It does not directly modify /etc/passwd or anything.

user { 'agent1':
ensure => 'present',

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
home => '/sbin',
uid => '2',
shell => '/sbin/nologin',
password => '$1$HTQUGYUGYUGwsxQxCp3F/nGc4DCYM/',

ensure
(Property: This attribute represents concrete state on the target system.)
The basic state that the object should be in.
Valid values are present, absent, role.

home
(Property: This attribute represents concrete state on the target system.)
The home directory of the user. The directory must be created separately and is not currently
checked for existence.

uid
(Property: This attribute represents concrete state on the target system.)
The user ID; must be specified numerically. If no user ID is specified when creating a new user,
then one will be chosen automatically. This will likely result in the same user having different UIDs
on different systems, which is not recommended. This is especially noteworthy when managing the
same user on both Darwin and other platforms, since Puppet does UID generation on Darwin, but
the underlying tools do so on other platforms.

shell
(Property: This attribute represents concrete state on the target system.)
The user’s login shell. The shell must exist and be executable.
This attribute cannot be managed on Windows systems.
Requires features manages_shell.

Linux users have their passwords stored as hash in /etc/shadow file. Puppet passes the password
supplied in the user type definition in the /etc/shadow file.
Generate your hash password using openssl command:
#openssl passwd -1
#Enter your password here
Password:
Verifying - Password:
$1$HTQUGYUGYUGwsxQxCp3F/nGc4DCYM

The previous example generate this hash: $1$HTQUGYUGYUGwsxQxCp3F/nGc4DCYM/


Add this hash password to your class as shown (do not forget the quotes)

user { 'test_user':
ensure => present,
password =>'$1$HTQUGYUGYUGwsxQxCp3F/nGc4DCYM/',
}

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
Resource Type: group

Manage groups. On most platforms this can only create groups. Group membership must be
managed on individual users.

group { 'sysadmin':
ensure => present,
gid => '5000',
}

ensure
(Property: This attribute represents concrete state on the target system.)Create or remove the
group.
Valid values are present, absent.

gid
(Property: This attribute represents concrete state on the target system.)
The group ID. Must be specified numerically. If no group ID is specified when creating a new
group, then one will be chosen automatically according to local system standards. This will likely
result in the same group having different GIDs on different systems, which is not recommended.

22. The PUPPET EXCERCISE

Now we are going to work on an exercise which would give us a detailed understanding of Puppet
workflow and its influence on implementing “Infrastructure as Code”

1. Puppet Setup.

1.1 Setup puppet server

The following are the set of commands to setup a puppet server.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
Installing puppet package manager:
#yum install -y http://yum.puppetlabs.com/puppetlabs-release-el-6.noarch.rpm

Installing puppet server:


#yum install -y puppet-server

Creating an environment with the the name “Production” and its file structure
#mkdir -p /etc/puppet/environments/production/{modules,manifests}

Configuring the environments


#cd /etc/puppet/environments/production
#echo "modulepath = /etc/puppet/environments/production/modules" >
/etc/puppet/environments/production/environment.conf
# echo "environment_timeout = 5s" >> /etc/puppet/environments/production/environment.conf

Open puppet.conf and define the puppet server under [main] section and define the
environmentpath and modulepath
[main]
certname = puppetmaster

[master]
environmentpath = $confdir/environments
basemodulepath = $confdir/modules:/opt/puppet/share/modules

In order to communicate with the server one requires to Stop Firewall,


# /etc/init.d/iptables stop

After making all the configurations changes, we need to start the puppet server to apply those
changes.
# service puppetmaster start

1.2 Setup puppet agents


We are taking two nodes where we can make the configuration changes through puppet manifests.
Those are named wiki(centos machine) and wikitest(ubuntu).

Setting up wiki
Installing puppet package manager:
#yum install -y http://yum.puppetlabs.com/puppetlabs-release-el-6.noarch.rpm
Install puppet
#yum install -y puppet

Update the puppetmaster info in puppet.conf so that the agent identify the puppet server.

# vi /etc/puppet/puppet.conf
[main]
server = puppetmaster

Once we done with changing the puppet configuration file , the agent is needed to request for a ssl
certificate from the puppet server.
Run the following puppet command to request cert
# puppet agent --verbose --no-daemonize –onetime

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
Setting up wikitest
Login to wikitest to install puppet

Download the “puppetlabs-release” package for your OS version.


# wget https://apt.puppetlabs.com/puppetlabs-release-trusty.deb

Install the package by running


# sudo dpkg -i puppetlabs-release-trusty.deb

Updating and installing puppet


# sudo apt-get update
# sudo apt-get install puppet

Open the agent configuration file and update the info of puppet master
# vi /etc/puppet/puppet.conf

[agent]
server = puppetmaster

To make puppet ready from the next system bootings run the following command
# puppet agent –enable

Requesting for SSL certificate


# puppet agent --verbose --no-daemonize –onetime

Login to puppet server to sign node certs

To list the ssl certificate requests , use the command below.


# puppet cert –list

The puppet master needs to accept the requests from agents through the command,
# puppet cert sign wiki
# puppet cert sign wikitest

1.3 Testing node definitions.

Login to puppetserver
We can define the nodes and their desired state in nodes.pp file in the main manifests file. In the
following example we are defining the nodes for the production environment .

# vi /etc/puppet/environments/production/manifests/nodes.pp
node 'wiki'{
file { '/info.txt':
ensure => 'present',
content => inline_template("This file was created by puppet at <%= Time.now %>\n"),
}
}

node 'wikitest' {
file { '/info.txt':

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
ensure => 'present',
content => inline_template("This file was created by puppet at <%= Time.now %>\n"),
}
}

We can observe the presence of a new file ‘/info.txt’ on the nodes when we run this manifest file
from the agents.

Login to both puppet agent, wiki & wikitest


# puppet agent --verbose --no-daemonize –onetime

The command will pull all the configuration changes specified in the manifest files in the puppet
master.

On the nodes check for file using the command


# cat /info.txt

2. Manifests.
In this section, we are going to discuss some of the most renowned resources like file, packages
and service.

2.1 Managing Files

For managing the files in puppet, we have a resource type ‘file’. We use different attributes for
efficient use of ‘file’ resource.

Login to puppet server

# /etc/puppet/environments/production/manifests/nodes.pp

node 'wiki' {
file { '/info.txt':
ensure => 'present',
content => inline_template("Created by Puppet at <%= Time.now %>\n"),
}
}

node 'wikitest' {
file { '/info.txt':
ensure => 'present',
content => inline_template("Created by Puppet at <%= Time.now %>\n"),
}
}
Go to both the nodes and execute to apply changes
# puppet agent --verbose --no-daemonize --onetime

2.2 Managing Packages & Services

Package ‘ resource type is to manage the software installations through the attributes like ensure
and name.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
‘ service’ resource type is to manage the services like start, stop and restart .
node 'wiki' {
file { '/info.txt':
ensure => 'present',
content => inline_template("Created by Puppet at <%= Time.now %>\n"),
}
package { 'ntp':
ensure => 'installed',
}
service { ntpd:
ensure => 'running',
enable => true,

}
}

node 'wikitest' {
file { '/info.txt':
ensure => 'present',
content => inline_template("Created by Puppet at <%= Time.now %>\n"),

}
package { 'ntp':
ensure => 'installed',
}
service { ntp:
ensure => 'running',
enable => true,
}
}

2.3 Selectors

For this exercise, we can use selectors to choose a variable based on the facts or other
variables. The following will define different package names based on OS type which can be known
from the facts.

$ntpservice = $osfamily ? {
'redhat' => 'ntpd',
'debian' => 'ntp',
default => 'ntp',
}

node 'wiki' {
file { '/info.txt':
ensure => 'present',
content => inline_template("Created by Puppet at <%= Time.now %>\n"),

package { 'ntp':
ensure => 'installed',

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
}

service { $ntpservice:
ensure => 'running',
enable => true,
}
}

node 'wikitest' {
file { '/info.txt':
ensure => 'present',
content => inline_template("Created by Puppet at <%= Time.now %>\n"),
}

package { 'ntp':
ensure => 'installed',
}

service { $ntpservice:
ensure => 'running',
enable => true,
}
}

2.4 Using classes


The classes can be defined in module’s manifests file or in main manifests’s nodes.pp
file and can be called from the main manifests file.

node 'wiki' {
class { 'linux': }
}

node 'wikitest' {
class { 'linux': }
}

class linux {
$ntpservice = $osfamily ? {
'redhat' => 'ntpd',
'debian' => 'ntp',
default => 'ntp',
}

file { '/info.txt':
ensure => 'present',
content => inline_template("Created by Puppet at <%= Time.now %>\n"),
}

package { 'ntp':
ensure => 'installed',
}

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
service { $ntpservice:
ensure => 'running',
enable => true,
}
}

2.5 Variables
This section deals with usage of variables and calling them from the resources. We are using a
variable ‘$admintools’ to pass the package names to the package resource in the manifest file.

node 'wiki' {
class { 'linux': }
}

node 'wikitest' {
class { 'linux': }
}

class linux {

$admintools = ['git', 'nano', 'screen']

package { $admintools:
ensure => 'installed',
}

$ntpservice = $osfamily ? {
'redhat' => 'ntpd',
'debian' => 'ntp',
default => 'ntp',
}

file { '/info.txt':
ensure => 'present',
content => inline_template("Created by Puppet at <%= Time.now %>\n"),
}

package { 'ntp':
ensure => 'installed',
}

service { $ntpservice:
ensure => 'running',
enable => true,
}
}

3. Modules

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
We can create the manifest files in the main manifests nodes.pp file. But we may need to
work on so many resources of different resources. For simple understanding of this structure we can
use create different modules for specific kind of changes.

3.1 Creating modules


To create a module in the production environment we can use the following set of commands with
the name ‘imran-mediawiki’
# cd /etc/puppet/environments/production/modules
# puppet module generate imran-mediawiki --environment production
# mv imran-mediawiki/ mediawiki
# cd mediawiki
# ls -ltr
# cd manifests
# vi init.pp

The ‘init.pp’ is a file where we place our puppet code.

3.2 Customizing Modules


After creating the module we need to customize it to get a desired state in the nodes.

Login to puppetmaster

# cd /etc/puppet/environments/production/modules/mediawiki/manifests

# vi init.pp
class mediawiki {
$phpmysql = $osfamily ? {
'redhat' => 'php-mysql',
'debian' => 'php5-mysql',
default => 'php-mysql',
}

package { $phpmysql:
ensure => 'present',
}
}

Open nodes.pp file and invoke mediawiki class


# cd /etc/puppet/environments/production/manifests

# vi nodes.pp
node 'wiki'{
class {'linux': }
class {'mediawiki':}

node 'wikitest' {
class {'linux': }
class {'mediawiki':}
}

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
.....................Rest of the file..................

Run puppet agent from both the nodes to verify


# puppet agent --verbose --no-daemonize –onetime

3.3 Conditionals
The conditionals can be used to choose the variable based on the facts or other variables that enable
the puppet master to prepare a catalog with the required information.
Here, we are choosing a package name for different Os family. There are two kinds of conditional
statements in this example selectors and if conditionals.

Login to puppetmaster

# cd /etc/puppet/environments/production/modules/mediawiki/manifests
# vi init.pp

class mediawiki {
$phpmysql = $osfamily ? {
'redhat' => 'php-mysql',
'debian' => 'php5-mysql',
default => 'php-mysql',
}
package { $phpmysql:
ensure => 'present',
}
if $osfamily == 'redhat' {
package {'php-xml':
ensure => 'present',
}
}
}
Run puppet agent from both the nodes to verify
# puppet agent --verbose --no-daemonize –onetime

4. Puppet Forge Modules.

Puppet forge is a collection of different modules developed by professionals across the


world. We can pull them from the puppet forge and can use them to extend the power of puppet.

4.1 Downloading from puppet forge

https://forge.puppet.com/

4.2 Apache module

Login to puppetmaster

We are going to download a puppet module from the puppet forge named ‘puppetlabs-apache’ .
This module can be used across puppet nodes of different OS types.

# cd /etc/puppet/environments/production/modules
The command to downloading the module is below

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
# puppet module install puppetlabs-apache --modulepath
/etc/puppet/environments/production/modules/

We can call this module’s classes from the init.pp file

# ls -ltr
# cd mediawiki/manifests/
# vi init.pp

class mediawiki {
$phpmysql = $osfamily ? {
'redhat' => 'php-mysql',
'debian' => 'php5-mysql',
default => 'php-mysql',
}
package { $phpmysql:
ensure => 'present',
}
if $osfamily == 'redhat' {
package {'php-xml':
ensure => 'present',
}
}
class { '::apache':
docroot => '/var/www/html',
mpm_module => 'prefork',
subscribe => Package[$phpmysql],

}
class {'::apache::mod::php': }
}

Run puppet agent from both the nodes to verify


# puppet agent --verbose --no-daemonize –onetime
# service httpd status (centos)
# service apache2 status (ubuntu)

4.3 VCSREPO MODULE


To pull the code from git repository we need to install the puppet module ‘vcsrepo’.
Login to puppetmaster

# cd /etc/puppet/environments/production/modules
To download the module, run the following command.
# puppet module install puppetlabs-vcsrepo --modulepath
/etc/puppet/environments/production/modules/
The command will download the module to
/etc/puppet/environments/production/modules/

# ls -ltr
# cd mediawiki/manifests/
# vi init.pp

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
class mediawiki {
$phpmysql = $osfamily ? {
'redhat' => 'php-mysql',
'debian' => 'php5-mysql',
default => 'php-mysql',
}
package { $phpmysql:
ensure => 'present',
}
if $osfamily == 'redhat' {
package {'php-xml':
ensure => 'present',
}
}

class { '::apache':
docroot => '/var/www/html',
mpm_module => 'prefork',
subscribe => Package[$phpmysql],
}
class {'::apache::mod::php': }
vcsrepo { '/var/www/html':
ensure => 'present',
provider => 'git',
source => "https://github.com/wikimedia/mediawiki.git"
revision => 'REL1_23'
}
}

Run puppet agent from both the nodes to verify


# puppet agent --verbose --no-daemonize –onetime

4.4 Resource Ordering


The resource ordering enables the puppet master to prepare a catalog that will run the resources in
specified manner.

subscribe — Applies a resource after the target resource. The subscribing resource refreshes if
the target resource changes.

# vi init.pp

class mediawiki {
$phpmysql = $osfamily ? {
'redhat' => 'php-mysql',
'debian' => 'php5-mysql',
default => 'php-mysql',
}
package { $phpmysql:
ensure => 'present',
}
if $osfamily == 'redhat' {
package {'php-xml':

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
ensure => 'present',
}
}
class { '::apache':
docroot => '/var/www/html',
mpm_module => 'prefork',
subscribe => Package[$phpmysql],
}
class {'::apache::mod::php': }
vcsrepo { '/var/www/html':
ensure => 'present',
provider => 'git',
source => "https://github.com/wikimedia/mediawiki.git",
revision => 'REL1_23',
}

file {'/var/www/html/index.html':
ensure => 'absent',
}
}

Run puppet agent from both the nodes to verify

# puppet agent --verbose --no-daemonize –onetime

This puppet run is gonna remove the index.html file after trying vcsrepo so ultimately it will fail.
For this will use resource ordering.

Login to puppetmaster
# cd /etc/puppet/environments/production/modules//mediawiki/manifests
# vi init.pp

class mediawiki {
$phpmysql = $osfamily ? {
'redhat' => 'php-mysql',
'debian' => 'php5-mysql',
default => 'php-mysql',
}
package { $phpmysql:
ensure => 'present',
}
if $osfamily == 'redhat' {
package {'php-xml':
ensure => 'present',
}
}
class { '::apache':
docroot => '/var/www/html',
mpm_module => 'prefork',
subscribe => Package[$phpmysql],
}
class {'::apache::mod::php': }

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
vcsrepo { '/var/www/html':
ensure => 'present',
provider => 'git',
source => "https://github.com/wikimedia/mediawiki.git",
revision => 'REL1_23',
}
file {'/var/www/html/index.html':
ensure => 'absent',
}
File['/var/www/html/index.html'] -> Vcsrepo ['/var/www/html']
}

Run puppet agent from both the nodes to verify

# touch /var/www/html/index.html
# puppet agent --verbose --no-daemonize –onetime

4.5 MYSQL MODULE

Login to puppetmaster

# cd /etc/puppet/environments/production/modules
# puppet module install puppetlabs-mysql --version 3.9.0 --modulepath

/etc/puppet/environments/production/modules/
# ls -ltr
# cd mediawiki/manifests/
# vi init.pp
class mediawiki {
$phpmysql = $osfamily ? {
'redhat' => 'php-mysql',
'debian' => 'php5-mysql',
default => 'php-mysql',
}
package { $phpmysql:
ensure => 'present',
}
if $osfamily == 'redhat' {
package {'php-xml':
ensure => 'present',
}
}
class { '::apache':
docroot => '/var/www/html',
mpm_module => 'prefork',
subscribe => Package[$phpmysql],
}
class {'::apache::mod::php': }
vcsrepo { '/var/www/html':
ensure => 'present',
provider => 'git',
source => "https://github.com/wikimedia/mediawiki.git",

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
revision => 'REL1_23',
}
file {'/var/www/html/index.html':
ensure => 'absent',
}
File['/var/www/html/index.html'] -> Vcsrepo ['/var/www/html']
class {'::mysql::server':
root_password => 'training',
}
}
Run puppet agent from both the nodes to verify
# puppet agent --verbose --no-daemonize –onetime

4.6 FIREWALL MODULE

Login to puppetmaster

# cd /etc/puppet/environments/production/modules
# puppet module install puppetlabs-firewall --modulepath
/etc/puppet/environments/production/modules/
# ls -ltr
# cd mediawiki/manifests/
# vi init.pp
class mediawiki {
$phpmysql = $osfamily ? {
'redhat' => 'php-mysql',
'debian' => 'php5-mysql',
default => 'php-mysql',
}
package { $phpmysql:
ensure => 'present',
}
if $osfamily == 'redhat' {
package {'php-xml':
ensure => 'present',
}
}
class { '::apache':
docroot => '/var/www/html',
mpm_module => 'prefork',
subscribe => Package[$phpmysql],
}
class {'::apache::mod::php': }
vcsrepo { '/var/www/html':
ensure => 'present',
provider => 'git',
source => "https://github.com/wikimedia/mediawiki.git",
revision => 'REL1_23',
}
file {'/var/www/html/index.html':
ensure => 'absent',
}

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
File['/var/www/html/index.html'] -> Vcsrepo ['/var/www/html']
class {'::mysql::server':
root_password => 'training',
}
class { 'firewall': }
firewall { '000 allow http access':
port => '80',
proto => 'tcp',
action => 'accept',
}
}

Run puppet agent from both the nodes to verify

# puppet agent --verbose --no-daemonize –onetime

5. Setup MediaWiki Site.

Now since our mediawiki server is deployed to wiki and wikitest, lets go ahead check that out.
Open up a browser and enter wiki server IP, you should see the mediawiki webpage as shown
below.

Follow the screenshots to setup mediawiki site.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
Enter database password that we have set in our mysql module (‘training’).
- Set Mediawiki website user & password, use password as “training”.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
-After the setup, it will download a file named ‘LocalSettings.php’.
LocalSettings.php file has to be uploaded back to mediawiki site in
/var/www/html/LocalSettings.php location. We can do that manually but we will use template to
push this file through our puppet code.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
6.Templates.

6.1 Setting Variables in Template

- Open localsettings.php file.


- Replace php variables values with puppet variables.

$wgSitename = "<%= wikisitename%>";


$wgMetaNamespace = "<%= wikimetanamespace%>";
$wgServer = "<%= wikiserver%>";
$wgDBserver = "<%= wikidbserver%>";
$wgDBname = "<%= wikidbname%>";
$wgDBuser = "<%= wikidbuser%>";
$wgDBpassword = "<%= wikidbpassword%>";
$wgUpgradeKey = "<%= wikiugradekey%>";

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
-
Login to puppetmaster & create template file.
- Create template directory.
# mkdir /etc/puppet/environments/production/modules/mediawiki/templates.
- Create LocalSettings.erb template file and paste content of LocalSettings.php we just edited.
# vi /etc/puppet/environments/production/modules/mediawiki/templates/LocalSettings.erb

6.2 Declaring template.

- Add template definition in Mediawiki Module.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
# vi /etc/puppet/environments/production/modules/mediawiki/manifests/init.pp

class { 'firewall': }
firewall { '000 allow http access':
port => '80',
Proto => 'tcp',
action => 'accept',
}
file {'LocalSettings.php':
path => '/var/www/html/LocalSettings.php',
ensure => 'file',
content => template('mediawiki/LocalSettings.erb'),
}
- Define variables used in template file.
# vi /etc/puppet/environments/production/manifests/nodes.pp

- Assign variable values for wiki.

node 'wiki'{
$wikisitename = 'wiki'
$wikimetanamespace = 'Wiki'
$wikiserver = "http://192.168.8.12"
$wikidbserver = 'localhost'
$wikidbname = 'wiki'
$wikidbuser = 'root'
$wikidbpassword = 'training'
$wikiugradekey = 'puppet'
class {'linux':}
class {'mediawiki':}
}

- Pull the latest change from wiki.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
# puppet agent --verbose –onetime --no-daemonize
- Go and check the mediawiki website from browser.

7. Hiera

Hiera facilitates to place all the node specific variables in a file other than manifests
files. This makes easier to work on the variables and the manifest files can be used for other
projects without any modification in them.

Here we are removing all the variables from the manifests file and placing those
node specific variables in differently located files.

# vim /etc/puppet/environments/production/modules/mediawiki/manifests/init.pp

class mediawiki {
$wikimetanamespace = hiera('mediawiki::wikimetanamespace')
$wikisitename = hiera('mediawiki::wikisitename')
$wikiserver = hiera('mediawiki::wikiserver')
$wikidbserver = hiera('mediawiki::wikidbserver')
$wikidbname = hiera('mediawiki::wikidbname')
$wikidbuser = hiera('mediawiki::wikidbuser')
$wikidbpassword = hiera('mediawiki::wikidbpassword')
$wikiupgradekey = hiera('mediawiki::wikiupgradekey')

$phpmysql = $osfamily ? {
'redhat' => 'php-mysql',
'debian' => 'php5-mysql',
default => 'php-mysql',
}
}

- Remove variables from nodes.pp file.


- Create Hiera configuration file.

# vi /etc/puppet/hiera.yaml

:backends:
- yaml
:yaml:
:datadir:
:hierarchy:
- "%{clientcert}"
- wikidefault

- Add variables for wiki node in /var/lib/hiera/wiki.yaml

# vi /var/lib/hiera/wiki.yaml
---
mediawiki::wikisitename: wiki
mediawiki::wikisitenamespace: Wiki
mediawiki::wikiserver: http://192.168.1.11
mediawiki::wikidbname: wiki

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
- Add variables for wikitest node in /var/lib/hiera/wikitest.yaml
---
mediawiki::wikisitename: wikitest
mediawiki::wikisitenamespace: Wikitest
mediawiki::wikiserver: http://192.168.1.12
mediawiki::wikidbname: wikitest

- Add common variables in /var/lib/hiera/wikidefault.yaml


---
mediawiki::wikidbserver: localhost
mediawiki::wikidbuser: root
mediawiki::wikidbpassword: training
mediawiki::wikiupgradekey: puppet

- Execute puppet agent to test it.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.
Summary:
✓ Puppet is an open source Configuration Management tool that has majorly adopted by the
huge organisations in implementing DevOps architecture for automation.
✓ We can easily manage and automate infrastructure through puppet master-client model, a
better architecture compared to using scripts.
✓ Puppet has already proven its capability in DevOps life cycles and has been continuing its
saga in automation technologies.
✓ Puppet follows basic Ruby Language. But we can build puppet code in manifests in simple
syntaxes on the puppet master.
✓ Puppet provisions us to define multiple nodes in the main manifest files through the use of
resources. Resources are small pieces of software and can bring desired states in nodes.
✓ Puppet agents pull their catalog from puppet master to make configuration changes. Catalog
is the collection of resources defined to that specific node written in main manifests files.
✓ For making puppet code more readable, it can be written in manifests files in modules
directory (other than main manifests files that is under /etc/puppet). These manifests files
can be invoked from the main manifests file.
✓ The functions include, class can invoke the puppet code in modules manifests
✓ There is a provision in Puppet to create environments. We can make puppet code and can
make it better when dealing with different groups of nodes.
✓ Puppet with its code features like variables, conditionals (if statements, selectors, cases)
makes it much closer to automation process. These features make puppet to act dynamically
based on nodes status.
✓ One more feature of Puppet Hiera - a key/value lookup tool for configuration data, built to
make Puppet better and let you set node-specific data without repeating the values.

Visualpath Training & Consulting.


Flat no: 205, Nilgiri Block,Aditya Enclave, Ameerpet, Hyderabad, Phone No: - +91-970 445 5959, 961 824 5689 E-
Mail ID : [email protected], Website : www.visualpath.in.

You might also like