But reusing modules can sometimes cause a bit of a headache and bad temper. Especially when building a service from modules that were written by someone else (as in http://forge.puppetlabs.com), you may notice that the module does almost everything the service is required to do but then the module does just a tiny bit too much, e.g. tweaks a start-up script that your service manifests are going to modify.In a situation like this you want to keep the majority of the module’s functionality and only alter some of its behaviour. In Puppet this can be done through class inheritance.
Example issue
Class apache::proxy in Apache module declares a resource /etc/httpd/conf/mods-enabled/proxy.conf that configures default mod_proxy behaviour:
class apache::proxy {
file { '/etc/httpd/conf/mods-enabled/proxy.conf':
source => "puppet:///modules/apache/proxy.conf"
}
Your service called myapp requires a special configuration for mod_proxy so you decide to define your own version of the same file:
class myapp {
include apache::proxy
file { '/etc/httpd/conf/mods-enabled/proxy.conf':
source => "puppet:///services/myapp/proxy.conf"
}
This is confusing for Puppet because it cannot decide which of the two resource declarations it should be using and this causes an error ‘File[/etc/httpd/conf/mods-enabled/proxy.conf] is already defined; cannot redefine at…”
Workaround: non-parameterised class
You can override resources with class inheritance by creating a subclass that inherits resources from the parent class.
class myapp::apache inherits apache::proxy {
file { '/etc/httpd/conf/mods-enabled/proxy.conf':
source => "puppet:///services/myapp/proxy.conf"
}
Then instead of calling the class with the statement include apache::proxy you call the override class with the statement include myapp::apache in the service manifest.
Workaround: parameterised class
When using parameterised classes e.g. ‘class apache::proxy (var1, var2)‘ subclass is called slightly differently because you cannot pass the parameter to subclass without causing a conflict with the parent class.Here is the parameterised apache::proxy class:
class apache::proxy (var1, var2) {
file { '/etc/httpd/conf/mods-enabled/proxy.conf':
source => "puppet:///modules/apache/proxy.conf"
}
This class is otherwise the same as the non-parameterised apache::proxy class except that you have to pass values for parameters var1 and var2 when calling the class. Calling the class with parameters uses the following syntax:
cssclass { 'apache::proxy':
var1 => 'param1',
var2 => 'param2';
}
But when you want to override the resource in parameterised class apache::proxy and resource override is defined in myapp::apache as per the example above (see Workaround: non-parameterised class) you must call both classes apache::proxy and myapp::apache separately and let Puppet merge these classes.In service manifests of myapp I’d call both class apache::proxy with parameters and class myapp::apache without parameters:
cssclass { 'apache::proxy':
var1 => 'param1',
var2 => 'param2';
}
include myapp::apache
Summary
The above would be implemented in Puppet manifests something like the following.file:///puppet/modules/apache/manifests/apache-proxy.pp:
class apache::proxy (var1, var2) {
file { '/etc/httpd/conf/mods-enabled/proxy.conf':
source => "puppet:///modules/apache/proxy.conf"
}
file:///puppet/services/myapp/manifests/myapp.pp:
cssclass myapp::apache inherits apache::proxy {
file { '/etc/httpd/conf/mods-enabled/proxy.conf':
source => "puppet:///services/myapp/proxy.conf"
}
class myapp {
class { 'apache::proxy':
var1 => 'param1',
var2 => 'param2';
}
include myapp::apache
}
This blog is written exclusively by the OpenCredo team. We do not accept external contributions.