Using roles and profiles
Well organized Puppet manifests are easy to read; the purpose of a module should be evident in its name. The purpose of a node should be defined in a single class. This single class should include all classes that are required to perform that purpose. Craig Dunn wrote a post about such a classification system, which he dubbed "roles and profiles" (http://www.craigdunn.org/2012/05/239/). In this model, roles are the single purpose of a node, a node may only have one role, a role may contain more than one profile, and a profile contains all the resources related to a single service. In this example, we will create a web server role that uses several profiles.
How to do it…
We'll create two modules to store our roles and profiles. Roles will contain one or more profiles. Each role or profile will be defined as a subclass, such as profile::base
- Decide on a naming strategy for your roles and profiles. In our example, we will create two modules,
roles
andprofiles
that will contain our roles and profiles respectively:$ puppet module generate thomas-profiles $ ln -s thomas-profiles profiles $ puppet module generate thomas-roles $ ln -s thomas-roles roles
- Begin defining the constituent parts of our
webserver
role as profiles. To keep this example simple, we will create two profiles. First, abase
profile to include our basic server configuration classes. Second, anapache
class to install and configure the apache web server (httpd
) as follows:$ vim profiles/manifests/base.pp class profiles::base { include base } $ vim profiles/manifests/apache.pp class profiles::apache { $apache = $::osfamily ? { 'RedHat' => 'httpd', 'Debian' => 'apache2', } service { "$apache": enable => true, ensure => true, } package { "$apache": ensure => 'installed', } }
- Define a
roles::webserver
class for ourwebserver
role as follows:$ vim roles/manifests/webserver.pp class roles::webserver { include profiles::apache include profiles::base }
- Apply the
roles::webserver
class to a node. In a centralized installation, you would use either an External Node Classifier (ENC) to apply the class to the node, or you would use Hiera to define the role:node 'webtest' { include roles::webserver }
How it works…
Breaking down the parts of the web server configuration into different profiles allows us to apply those parts independently. We created a base profile that we can expand to include all the resources we would like applied to all nodes. Our roles::webserver
class simply includes the base
and apache
classes.
There's more…
As we'll see in the next section, we can pass parameters to classes to alter how they work. In our roles::webserver
class, we can use the class instantiation syntax instead of include
, and override it with parameters
in the classes. For instance, to pass a parameter to the base
class, we would use:
class {'profiles::base': parameter => 'newvalue' }
where we previously used:
include profiles::base
Tip
In previous versions of this book, node and class inheritance were used to achieve a similar goal, code reuse. Node inheritance is deprecated in Puppet Version 3.7 and higher. Node and class inheritance should be avoided. Using roles and profiles achieves the same level of readability and is much easier to follow.