Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Puppet Include vs Class and Best Practices

Tags:

puppet

When should I be using an include vs a class declaration? I am exploring creating a profile module right now, but am struggling with methodology and how I should lay things out.

A little background, I'm using the puppet-labs java module which can be found here.

My ./modules/profile/manifests/init.pp looks like this:

class profile {

  ## Hiera Lookups
  $java_version = hiera('profile::jdk::package')

  class {'java':
    package => $java_version,
  }
}

This works fine, but I know that I can also remove the class {'java': block of the code and instead use include java. My question relates around two things. One, if I wanted to use an include statement for whatever reason, how could I still pass the package version from hiera to it? Second, is there a preferred method of doing this? Is the include something I really shouldn't be using, or are there advantages and disadvantages to each method?

My long term goal will be building out profile like modules for my environment. Likely I would have a default profile that applies to all of my servers, and then profiles for different application load outs. I could include the profiles into a role and apply things to my individual nodes at that level. Does this make sense?

Thanks!

like image 243
Merakel Avatar asked Oct 18 '17 16:10

Merakel


People also ask

What is include in puppet?

Include is to tell puppet to apply the class "ntp" to a node and class is to declare the class, the behavior of this class (like ensure file, package, user etc...)

In which puppet artifact can you declare classes?

You can declare classes in node definitions, at top scope in the site manifest, and in other classes or defined types.

What is the benefit of grouping resources into classes when using puppet?

In Puppet, classes are code blocks that can be called in a code elsewhere. Using classes allows you reuse Puppet code, and can make reading manifests easier.

What are puppet classes give example?

Puppet classes are defined as a collection of resources, which are grouped together in order to get a target node or machine in a desired state. These classes are defined inside Puppet manifest files which is located inside Puppet modules.


1 Answers

When should I be using an include vs a class declaration?

Where a class declares another, internal-only class that belongs to the same module, you can consider using a resource-like class declaration. That leverages your knowledge of the implementation details of the module, as you need to be able to prove that no other declaration of the class in question will be evaluated before the resource-like one. If ever that constraint is violated, catalog building will fail.

Under all other circumstances, you should use include or one of its siblings, require and contain.

One, if I wanted to use an include statement for whatever reason, how could I still pass the package version from hiera to it?

Exactly the same way you would specify any other class parameter via Hiera. I already answered that for you.

Second, is there a preferred method of doing this?

Yes, see above.

Is the include something I really shouldn't be using, or are there advantages and disadvantages to each method?

The include is what you should be using. This is your default, with require and contain as alternatives for certain situations. The resource-like declaration syntax seemed good to the Puppet team when they first introduced it, in Puppet 2.6, along with parameterized classes themselves. But it turns out that that syntax introduced deep design problems into the language, and it has been a source of numerous bugs and headaches. Automatic data binding was introduced in Puppet 3 in part to address many of those, allowing you to assign values to class parameters without using resource-like declarations.

The resource-like syntax has the single advantage -- if you want to consider it one -- that the parameter values are expressed directly in the manifest. Conventional Puppet wisdom holds that it is better to separate data from code, however, so as to avoid needing to modify manifests as configuration requirements change. Thus, expressing parameter values directly in the manifest is a good idea only if you are confident that they will never change. The most significant category of such cases is when a class has read data from an external source (i.e. looked it up via Hiera), and wants to pass those values on to another class.

The resource-like syntax has the great disadvantage that if a resource-like declaration of a given class is evaluated anywhere during the construction of a catalog for a given target node, then it must be the first declaration of that class that is evaluated. In contrast, any number of include-like declarations of the same class can be evaluated, whether instead of or in addition to a resource-like declaration.

Classes are singletons, so multiple declarations have no more effect on the target node than a single declaration. Allowing them is extremely convenient. Evaluation order of Puppet manifests is notoriously hard to predict, however, so if there is a resource-like declaration of a given class somewhere in the manifest set, it is very difficult in the general case to ensure that it is the first declaration of that class that is evaluated. That difficulty can be managed in the special case I described above. This falls into the more general category of evaluation-order dependencies, and you should take care to ensure that your manifest set is free of those.

There are other issues with the resource-like syntax, but none as significant as the evaluation-order dependency.


Clarification with respect to automated data binding

Automated data binding, mentioned above, associates keys identifying class parameters with corresponding values for those parameters. Compound values are supported if the back end supports them, which the default YAML back end in fact does. Your comments on this answer suggest that you do not yet fully appreciate these details, and in particular that you do not recognize the significance of keys identifying (whole) class parameters.

I take your example of a class that could on one hand be declared via this resource-like declaration:

class { 'elasticsearch':
  config => { 'cluster.name' => 'clustername', 'node.name' => 'nodename' }
}

To use an include-like declaration instead, we must provide a value for the class's "config" parameter in the Hiera data. The key for this value will be elasticsearch::config (<fully-qualified classname> :: <parameter name>). The associated value is wanted puppet-side as a hash (a.k.a. "associative array", a.k.a. "map"), so that's how it is specified in the YAML-format Hiera data:

elasticsearch::config:
    "cluster.name": "clustername"
    "node.name":    "nodename"

The hash nature of the value would be clearer if there were more than one entry. If you're unfamiliar with YAML, then it would probably be worth your while to at least skim a primer, such as the one at yaml.org.

With that data in place, we can now declare the class in our Puppet manifests simply via

include 'elasticsearch'
like image 68
John Bollinger Avatar answered Oct 08 '22 13:10

John Bollinger