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.
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:
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
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::database::application'] Class['profile::os_and_network'] -> Class['profile::weblogic::admin_server'] -> Class['profile::weblogic::application'] end
Here you see we add the ordering. We use the arrow syntax (
->) to make sure the
profile::os_and_network is applied before the
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.