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.
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!
informative article