Connecting Puppet roles and profiles

Portable Role Craig Dunn introduced the concept of profiles and roles in his blog article Designing Puppet – Roles and Profiles. This diagram shows how the role::portable is made up of five different profiles. It also shows the dependencies between the different profiles. In our last post Puppet roles and profiles to the max. We introduced the roles and profiles required for a multifunctional setup. In this blog post, we are discussing how to connect them together to get good working setups. We are going to use the portable role for this.

Naming your roles and profiles

At this point in time Puppet doesn’t force any naming on your roles and profiles. So you can do anything you like. We prefer to put all roles in a module called roles and all profiles in a module called profiles. This has the following advantages:

  • consistent and clear names
  • profiles and roles are found together

To add more structure, we use subdirectories. Here is a schematic overview from our roles and profiles directory. Roles and Profiles directory structure

In this example, the roles and the profiles look very much the same. The difference is that profiles only contain the middleware software and the role also contains all of the application stuff. In the real world it would be better to include real application names in the roles like for example:

  • role::my_app::portable
  • role::my_app::database::single_node_server
  • role::my_app::weblogic:admin_server

Add profiles to a role

So now we now what to call the profiles and roles, let’s get going. We know we need to add the profiles to the role. Let’s see the code for this:

class role::portable
  contain profile::os_and_network
  contain profile::database::single_node_server
  contain profile::database::application
  contain profile::weblogic::admin_server
  contain profile::weblogic::application

There is one major requirement to get this working. The profiles are not allowed to depend on each other. In practical terms, this means a profile cannot include a require statement for one of the other profiles.

In this code, we contain all the profiles needed to build the role. We use contain instead of require to make sure all of the Puppet classes and resources in a certain profile are applied, before we get to apply another profile. Although using contain makes our Puppet catalog more rigid and increases the chances for a circular dependency, we also noticed more consistent results.

The contain function

The contain function is just like the require, only a bit stronger. In layman’s terms when you use require, Puppet makes sure all resources in the class are applied before going to an other class. But this rule doesn’t apply to subclasses (e.g. a class applied in a class). When you use contain, Puppet makes sure all resources, including the resources specified in (sub)classes, are applied before going to an other class. Check out the Puppet documentation for contain if you need a more thorough understanding of include versus require versus contain.

Manage ordering in the role

Because you are not allowed to manage dependencies in the profiles, all dependencies must be managed in the role. This means we must add explicit ordering for the profiles. Here is the Puppet code:

class role::portable
  # Add ordering
  Class['profile::os_and_network'] ->
  Class['profile::database::single_node_server'] ->

  Class['profile::os_and_network'] ->
  Class['profile::weblogic::admin_server'] ->

Here you see we add the ordering. We use the arrow syntax (->) to make sure the profile::os_and_network is applied before the profile::database::single_node_server etc.

Building your own roles and profiles…

This blog post explained how to connect Puppet roles and profiles. It showed you the generic pattern of:

  • contain all profiles required for the role
  • Add ordering of all profiles It also showed an example of naming and structuring your roles and profiles.

We know from our customers that it is difficult to get started. There is so much to configure and so much install. It is hard to figure out where to start. To help you get going, we have implemented some extensive examples. Check them out.