Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

puppet inheritance VS puppet composition

Tags:

puppet

I just came cross puppet inheritance lately. A few questions around it:

  1. is it a good practice to use puppet inheritance? I've been told by some of the experienced puppet colleagues Inheritance in puppet is not very good, I was not quite convinced.

  2. Coming from OO world, I really want to understand under the cover, how puppet inheritance works, how overriding works as well.

like image 602
Shengjie Avatar asked Jun 22 '12 10:06

Shengjie


2 Answers

  1. That depends, as there are two types of inheritance and you don't mention which you mean.

    1. Node inheritance: inheriting from one node fqdn { } definition to another. This in particular is strongly recommended against, because it tends to fail the principle of least surprise. The classic example that catches people out is this:

      node base {
        $mta_config = "main.cf.normal"
        include mta::postfix  # uses $mta_config internally
      }
      node mailserver inherits base {
        $mta_config = "main.cf.mailserver"
      }
      

      The $mta_config variable is evaluated in the base scope, so the "override" that is being attempted in the mailserver doesn't work.

      There's no way to directly influence what's in the parent node, so there's little benefit over composition. This example would be fixed by removing the inheritance and including mta::postfix (or another "common"/"base" class) from both. You could then use parameterised classes too.

    2. Class inheritance: the use for class inheritance is that you can override parameters on resources defined in a parent class. Reimplementing the above example this way, we get:

      class mta::postfix {
        file { "/etc/postfix/main.cf":
          source => "puppet:///modules/mta/main.cf.normal",
        }
        service { ... }
      }
      
      class mta::postfix::server inherits mta::postfix {
        File["/etc/postfix/main.cf"]:
          source => "puppet:///modules/mta/main.cf.server",
        }
        # other config...
      }
      

      This does work, but I'd avoid going more than one level of inheritance deep as it becomes a headache to maintain.

    3. In both of these examples though, they're easily improved by specifying the data ahead of time (via an ENC) or querying data inline via extlookup or hiera.

  2. Hopefully the above examples help. Class inheritance allows for overriding of parameters only - you can't remove previously defined resources (a common question). Always refer to the resource with a capitalised type name (file { ..: } would become File[..]).

    Also useful is that you can also define parameters to be undef, effectively unsetting them.

like image 53
Dominic Cleal Avatar answered Nov 25 '22 11:11

Dominic Cleal


At first, I am just specifying differences between the two, Inheritance is an "is-a" relationship and Composition is a "has-a" relationship.

1) In puppet inheritance is single inheritance that means, we cannot derive from more than one class. Inheritance is good in the puppet, but we should aware of where it applies. For example, Puppet docs section ["Aside: When to Inherit" at this link https://docs.puppetlabs.com/puppet/latest/reference/lang_classes.html#aside-when-to-inherit], They actually name exactly two situations where inheritance should happen:

  • when you want to overwrite a parameter of a resource defined in the parent class
  • when you want to inherit from a parameters class for standard parameter values

But please note some important things here:

  • In puppet their is a difference between the Node and class inheritance.

  • Recent new version from puppet doesn't allow for the Node inheritance please check this https://docs.puppetlabs.com/puppet/latest/reference/lang_node_definitions.html#inheritance-is-not-allowed.

2) Composition on the other hand, is the design technique to implement has-a relationship. which we can do using the include puppet keyword and also, with class { 'baseclass': }, the later one is, if you want to use parameters.

(Please note: In puppet, we can use "include" multiple times but not the "class" syntax, as puppet will complain with duplicate class definitions)

So which is (either inheritance or composition) is better to use in Puppet: It depends on the context i mean, what puppet code you are writing at the moment and understanding the limitations of the puppet inheritance and when to use composition.

So, i will try to keep all this in few points:

1) At first, puppet uses single inheritance model.

2) In puppet, the general consensus around inheritance is to only use it when you need to inherit defaults from Base/Parent

3) But look at this problem where you want to inherit defaults from parent:

class apache {
}

class tomcat inherits apache {
}

class mysql inherits tomcat {
}

class commerceServer inherits mysql {
}

At first glance this looks logical but note that the MySQL module is now inheriting defaults and resources from the tomcat class. Not only does this make NO sense as these services are unrelated, it also offers an opportunity for mistakes to end up in your puppet manifests.

4) So the better approach is to simply perform an include on each class (I mean composition) you wish to use, as this eliminates all scope problems of this nature.

Conclusion: We can try and simplify our puppet manifests by using inheritance, this might be sufficient, but it’s only workable up to a point.If you’re environment grows to hundreds or even thousands of servers, made up over 20 or 30 different types of server, some with shared attributes and subtle differences, spread out over multiple environments, you will likely end up with an unmanageable tangled web of inherited modules. At this point, the obvious choice is composition.

Go thru these links, it helps to understand puppet composition and inheritance in a good manner (personally they helped me):

  1. Designing Puppet - It is really good,http://www.craigdunn.org/2012/05/239/
  2. Wiki link: http://en.wikipedia.org/wiki/Composition_over_inheritance
  3. Modeling Class Composition with Parametrized Classes : https://puppetlabs.com/blog/modeling-class-composition-with-parameterized-classes

I am basically a programmer, personally a strong supporter of Inversion of Control/Dependency Injection, which is the concept/pattern which can be possible thru the composition.

like image 41
user3278897 Avatar answered Nov 25 '22 11:11

user3278897