Understanding Puppet Resources, Manifests, Modules and Classes with Examples

In this tutorial, I’ll be explaining about Puppet resources, manifests, modules and classes with examples. Also, I assume that you already have Puppet master/agent nodes installed and ready for use. In order to use Puppet, you need to understand how puppet handles resources and how manifest & modules are created.

Prerequisites:

As I told earlier, you need to have Puppet Master and Agent nodes installed and configured.

Puppet’s Declarative Domain Specific Language  (DSL)

  • Puppet has its own declarative domain specific language that define STATES of a system.
  • Puppet code is written in a file called MANIFESTS and saved with .pp extension (for e.g., site.pp is a main manifest file)
  • Puppet code contain RESOURCES that affect elements of the system (such as file, package, service, user, host, interface, exec etc…). Resources are the fundamental unit of system configurations and each resource describes an aspect of the system.
  • Resources are grouped in CLASSES (named block of Puppet codes) that are stored (organized) in MODULES and they are not used until invoked.
  • Puppet Master creates a CATALOG (generated based on the Puppet code and data) and the clients apply those.

Let us see Puppet terms in detail.

Puppet modules tutorial

Resources

A Resource describes something about the state of the system. For example, whether a certain user or file exists, or a service should be running or enabled, or a package should be installed.

Format of the resource:

resource_type { 'name_of_the_resource':
  argument  => value,
  other_arg => value,
}

Example 1:

file { 'test':
 path => '/tmp/test',
 content => 'An example content',
 }

Example 2:

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

Example 3:

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

Here’s a command to list resource types in Puppet:

# /opt/puppetlabs/puppet/bin/puppet resource --types
augeas
computer
cron
exec
file
filebucket
group
host
interface
k5login
macauthorization
mailalias
maillist
mcx
mount
nagios_command
nagios_contact
nagios_contactgroup
nagios_host
nagios_hostdependency
nagios_hostescalation
nagios_hostextinfo
nagios_hostgroup
nagios_service
nagios_servicedependency
nagios_serviceescalation
nagios_serviceextinfo
nagios_servicegroup
nagios_timeperiod
notify
package
resources
router
schedule
scheduled_task
selboolean
selmodule
service
ssh_authorized_key
sshkey
stage
tidy
user
vlan
whit
yumrepo
zfs
zone
zpool

Manifests

As told earlier, Puppet code is written in Manifest file with .pp extension. The default main manifest file is located at:

# vim /etc/puppetlabs/code/environments/production/manifests/site.pp

More manifest files can be created under /etc/puppetlabs/code/environments/production/manifests/

Classes

Classes contain code blocks that can be invoked from anywhere in the code. Classes provide the facility of code reuse. If you know programming languages like Java or C++, then defining class in Puppet is just the same.

class class_name {
 ::::::::::Puppet code goes here:::::::::
 }

Now, the above class can be included in a Puppet code as below:

include class_name

Modules

Modules helps to organize set of manifests. A module can be added under /etc/puppetlabs/code/environments/production/modules. A large Puppet code can be distributed into multiple manifests and organized using modules (at the bottom of this post, you’ll learn how to Install, configure and start Apache service – where each of these tasks are split into different classes).

Well, let us know try creating a manifest to perform a simple operation.

My First Manifest in Puppet

Example 1: Creating a new file (in site.pp)

Step 1: Login to Puppet Server (Master Node) as a privileged user.

Step 2: Go to /etc/puppetlabs/code/environments/production/manifests

Step 3: Edit site.pp – main manifest file. If you don’t find one, create it.

# vim site.pp

Step 4: Let us write Puppet code to create a file in /tmp/ at Puppet agent node. The code goes as below,

file { "/tmp/myFile":
 ensure => "present",
 owner => "root",
 group => "root",
 mode => "644",
 content => "This is my first manifest to create a file in temp directory",
 }

In the above code, we have used file resource type, with arguments such as ensure, owner, group, mode and content. The file will be created in /tmp.

Step 5: Now the manifest file is ready. Move on to Puppet Agent node and execute the below command.

[Agent]# /opt/puppetlabs/puppet/bin/puppet agent -t
 Info: Using configured environment 'production'
 Info: Retrieving pluginfacts
 Info: Retrieving plugin
 Info: Caching catalog for puppetagent.test.in
 Info: Applying configuration version '1471021726'
 Notice: /Stage[main]/Main/File[/tmp/myFile]/ensure: defined content as '{md5}8eadb0a0feef0bc667702434f816d8e8'
 Notice: Applied catalog in 0.09 seconds

The above output says that the catalog has been applied.

Note: The Puppet Agents will automatically contact Puppet server to receive catalog for configuring themselves. But if you don’t want to wait for the auto-sync, then you may execute the above command.

Step 6: Check whether the file has been created with necessary contents.

# ls /tmp/myFile
/tmp/myFile
# more /tmp/myFile
This is my first manifest to create a file in temp directory

Creating your first Module

Let’s create a module which will install Apache web server on the agent nodes.

Step 1: Change directory to modules folder.

# cd /etc/puppetlabs/code/environments/production/modules

Step 2: Let us create a module named httpd. To do that, we’ll use PuppetForge which requires a naming convention to be followed. For example,

organizationName-moduleName

As we are installing Apache web server, the package to be installed is httpd and my naming convention will be as the one shown below:

mypuppetorg-httpd

Step 3: Run the below command

# /opt/puppetlabs/puppet/bin/puppet module generate mypuppetorg-httpd
We need to create a metadata.json file for this module.  Please answer the
following questions; if the question is not applicable to this module, feel free
to leave it blank.

Puppet uses Semantic Versioning (semver.org) to version modules.
What version is this module?  [0.1.0]
-->

Who wrote this module?  [mypuppetorg]
-->

What license does this module code fall under?  [Apache-2.0]
-->

How would you describe this module in a single sentence?
--> Installs Apache web server and configures it

Where is this module's source code repository?
-->

Where can others go to learn more about this module?
-->

Where can others go to file issues about this module?
-->

----------------------------------------
{
"name": "mypuppetorg-httpd",
"version": "0.1.0",
"author": "mypuppetorg",
"summary": "Installs Apache web server and configures it",
"license": "Apache-2.0",
"source": "",
"project_page": null,
"issues_url": null,
"dependencies": [
{"name":"puppetlabs-stdlib","version_requirement":">= 1.0.0"}
],
"data_provider": null
}
----------------------------------------

About to generate this metadata; continue? [n/Y]
--> Y

Notice: Generating module at /etc/puppetlabs/code/environments/production/modules/httpd...
Notice: Populating templates...
Finished; module generated in httpd.
httpd/Gemfile
httpd/Rakefile
httpd/examples
httpd/examples/init.pp
httpd/manifests
httpd/manifests/init.pp
httpd/spec
httpd/spec/classes
httpd/spec/classes/init_spec.rb
httpd/spec/spec_helper.rb
httpd/README.md
httpd/metadata.json

Step 4: A module will be created. For e.g., httpd and its structure goes as below:

# ls httpd/
 examples  Gemfile  manifests  metadata.json  Rakefile  README.md  spec

Step 5: Customize the module

The step 4 will create a module directory structure and a main manifest file (for module) called init.pp. We’ll just open the file to see how it looks and at the end of the file, you’ll find an empty httpd class.

class httpd {

}

Step 6: Let’s us create separate class for Installing (install.pp), Configuring (configure.pp) and starting (start.pp) Apache service.

Creating sub-class for installing Apache: We’ll create a new manifest file called install.pp (class modulename::install)

# pwd
/etc/puppetlabs/code/environments/production/modules/httpd
# vim manifests/install.pp

Copy and paste the below code:

# == Class: httpd::install
class httpd::install inherits httpd {
package { 'httpd':
ensure => installed,
}
}

Here, sub-class ‘install‘ will inherit the main class httpd. Also, lookout for the syntax package, which means the Puppet Type and ensure attribute ensures that the said package is installed.

Creating subclass for configuring httpd (configure.pp – class modulename::configure)

# pwd
/etc/puppetlabs/code/environments/production/modules/httpd
# vim manifests/configure.pp

Copy and paste the below code to ensure that the httpd.conf file is properly protected.

class httpd::configure inherits httpd{
        file { '/etc/httpd/conf/httpd.conf':
                ensure => file,
                owner => 'root',
                group => 'root',
                mode => '0644',
        }
}

Creating subclass to start httpd service (start.pp – class modulename::start):

# pwd
/etc/puppetlabs/code/environments/production/modules/httpd
#  vim manifests/start.pp

Copy and paste the below code:

class httpd::start inherits httpd{
 service { 'httpd':
 ensure     => running,
 enable     => true,
 hasstatus  => true,
 hasrestart => true,
 require => Package['httpd'],
 }
 }

Now, you have the subclasses created.

  • install.pp – to install httpd package
  • configure.pp – to configure proper permissions for httpd.conf file
  • start.pp – to enabled and start the httpd service.

Step 7: We should now let the main class httpd to know about the subclasses (install, configure and start). To do that, just open the main class of the module and include the sub-classes.

# vim manifests/init.pp

Include statement goes as below:

class httpd {
include httpd::install
include httpd::configure
include httpd::start
}

Step 8: We are done with the classes now. But you need to tell Puppet on which nodes the catalog should be implemented. Here’s how you can do that.

Go to the main manifest file (under /etc/puppetlabs/code/environments/production/manifests)

# vim site.pp

Copy and paste the below code. Here httpd is the main class created for managing Apache web server.

node default {
include httpd
}

That’s it! You may wait until the Puppet Agent nodes download the catalog automatically or you can trigger it manually. Go to Puppet Agent node and execute the below command.

Step 9:

[Agent]# /opt/puppetlabs/puppet/bin/puppet agent -t
 Info: Using configured environment 'production'
 Info: Retrieving pluginfacts
 Info: Retrieving plugin
 Info: Caching catalog for puppetagent.test.in
 Info: Applying configuration version '1472036234'
 Notice: /Stage[main]/Httpd::Install/Package[httpd]/ensure: created
 Notice: /Stage[main]/Httpd::Configure/File[/etc/httpd/conf/httpd.conf]/mode: mode changed '0600' to '0644'
 Notice: /Stage[main]/Httpd::Start/Service[httpd]/ensure: ensure changed 'stopped' to 'running'
 Info: /Stage[main]/Httpd::Start/Service[httpd]: Unscheduling refresh on Service[httpd]
 Notice: Applied catalog in 5.88 seconds

Since, this is your first module, you may want to verify if the package is installed and the service is started properly.

[Agent]# rpm -qa|grep httpd
httpd-tools-2.4.6-40.el7.centos.4.x86_64
httpd-2.4.6-40.el7.centos.4.x86_64
[Agent]# service httpd status
Redirecting to /bin/systemctl status  httpd.service
httpd.service - The Apache HTTP Server
 Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
 Active: active (running) since Wed 2016-08-24 17:29:29 IST; 6min ago

Conclusion

That’s it! Now you know to write your own Puppet modules for install, configuring and enabling the service. However, this tutorial is just a starting point in doing wonders with Puppet. Happy Puppeting!

Updated on September 2, 2017

Was this article helpful?

Related Articles

Comments

Leave a Comment