What goes in a Puppet Role or Profile?

The Roles and Profiles pattern by Craig Dunn is a very common pattern used by Puppet practitioners. I’ve written about it before. One of the most common questions I see is, what goes into a Role or Profile class? Craig’s article provides some guidelines, specifically these two:

 

  • A role includes one or more profiles to define the type of server
  • A profile includes and manages modules to define a logical technical stack

 

Those are pretty helpful, but it’s not an exhaustive list, nor does it describe what is prohibited in each type of class. While the main goal of the pattern is composition, I have my own guidelines I follow that may help others:

Roles

  • No parameters
  • Includes profile classes
  • [Rarely] Ordering of resources that come from two separate profiles
  • Contains nothing else.

Here’s an example role for an application server:

role appX {
  include profile::base
  include profile::apache
  include profile::appX
  Package<| tag == 'profile::apache' |> -> Package <| tag == 'profile::appX' |>
}

Profiles

  • Optional parameters
  • Includes component modules
  • Includes basic resource types (built-in or from component modules)
  • Calls functions, include hiera_*() and lookup()
  • Traverses and manipulates variables to process their data
  • Conditionals (limited)
  • Ordering of resources, within the profile
  • May call other profiles, but should be used sparingly
  • If the code is >100 lines, consider separating the profile class into its own module, or finding an existing component module that include the functionality (100 is a very arbitrary number, feel free to adjust it to a number indicating when you want to start thinking about this option)

Here’s an example of a profile that calls other profiles:

class profile::base {

  # Include OS specific base profiles.
  case $::kernel {
    'linux': {
      include profile::base::linux
    }
    'windows': {
      include profile::base::windows
    }
    'JUNOS': {
      include profile::base::junos
    }
    default: {
      fail ("Kernel: ${::kernel} not supported in ${module_name}")
    }
  }
}

Here’s an example of a more complex profile that has parameters and includes other component modules, basic resources, functions, iteration, conditionals, and even another profile:

class profile::base::linux (
  $yumrepo_url,
  $cron_purge          = true,
  $domain_join         = false,
  $metadata_expire     = 21600, # Default value for yum is 6 hours = 21,600 seconds
  $sudo_confs          = {},
  $manage_firewall     = true,  # Manage iptables
  $manage_puppet_agent = true,  # Manage the puppet-agent including upgrades
) {
  # Manage the basics, but allow users to override some management components with flags
  if $manage_firewall {
    include profile::linuxfw
  }
  if $manage_puppet_agent {
    include puppet_agent
  }

  include ntp
  include rsyslog::client
  include motd

  # SSH server and client
  include ssh::server
  include ssh::client

  # Sudo setup
  include sudo
  $sudo_confs.each |$group, $config| {
    sudo::conf{ $group:
      * => $config,
    }
  }

  yumrepo {'local-el':
    ensure          => present,
    descr           => 'Local EL - x86_64',
    baseurl         => $yumrepo_url,
    enabled         => 1,
    gpgcheck        => 0,
    metadata_expire => $metadata_expire,
  }
  Yumrepo['local-el'] -> Package<| |>

  # Ensure unmanaged cron entries are removed
  resources { 'cron':
    purge => $cron_purge,
  }

  if $domain_join {
    include profile::domain_join
  }
}

Summary

The Roles and Profiles pattern is all about composition. The Style Guide helps you with layout and semantic choices. It doesn’t hurt to add your own rules about content and design, too. There’s no defined Best Practice here, but I hope these guidelines help you shape your own practice. Enjoy!

3 thoughts on “What goes in a Puppet Role or Profile?

  1. I noticed you recently switched to PE. Just a heads up on the ‘Package’ collector with no filter — I did this in a PE infrastructure and got bit when it realized all the PE packages on all the PE servers in my split config. In short order I had both PuppetDB and the Console installed on my master *and* DB *and* Console servers.

    • Wow, that’s good to know! Many of the PE classes are full of surprises, if only because we can’t read their documentation on the forge.

  2. Pingback: Where to store Puppet files and templates | rnelson0

Leave a comment