The use case i try to illustrate is when to declare some item (eq mysqld service) with a default configuration that could be included on every node (class stripdown in the example, for basenode), and still be able to override this same item in some specific class (eg mysql::server), to be included by specific nodes (eg myserver.local)
I illustrated this use case with the example below, where i want to disable mysql service on all nodes, but activate it on a specific node. But of course, Puppet parsing fails because the Service[mysql] is included twice. And of course, class mysql::server bears no relation to be a child of class stripdown
Is there a way to override the Service["mysql"], or mark it as the main one, or whatever ? I was thinking about the virtual items and the realize function, but it only permits apply an item multiple times, not to redefine or override.
# In stripdown.pp :
class stripdown {
service {"mysql": enable => "false", ensure => "stopped" }
}
# In mysql.pp :
class mysql::server {
service { mysqld:
enable => true,
ensure => running,
hasrestart => true,
hasstatus => true,
path => "/etc/init.d/mysql",
require => Package["mysql-server"],
}
}
# Then nodes in nodes.pp :
node basenode {
include stripdown
}
node myserver.local inherits basenode {
include mysql::server` # BOOM, fails here because of Service["mysql"] redefinition
}
Whenever you find yourself saying "I want this component to behave one way in one node, but a different way in another node", you probably need to be looking at a definition driven by variables, either via conditionals in the class definition, or substitutions in a template.
Unfortunately, your example shows you attempting to use inheritance, which is pretty badly broken in puppet and will cause you a lot of grief here because one of the things that it breaks is variable redefinition in nodes.
UPDATE: old answer details are obsolete
What I'm doing as of 2.7 is to ensure that all variables used by a class are not global variables at all, but rather parameters with reasonable defaults set. You still don't want to use the inheritance built into Puppet, but you can now override particular variables directly from the node definition, and you can even have a primitive form of inheritance manually by having one class take variables and then pass them to an invocation of another class. For example, you would have in your node definitions:
As a commenter noted, there is now also a nifty new feature called Hiera, which allows you to offload defaults into a separate data structure, and you should look into it if you have Puppet 3.2 available. Unfortunately, many Linux distributions are still shipping with 2.6 or 2.7, so this may not yet be an option for you.
Previous answer details preserved below
The way that I generally handle something like this is to create a 'default_parameters.pp' file that has nothing in it but default assignments for a long list of variables, so in this case, it would contain a line something like
$mysql_enabled = false
. This file is then included by the module's init.pp file. Then, the node definitions file would look something like:Then in the class definition for mysql::server you check if
$mysql_enabled
is true, and if so, use a selector onenable
andensure
.This breaks instantly if node myserver.local inherits anything, because that will lock the value of the variables at inherit time, and further changes inside the node definition will have no effect, but otherwise I use this technique all over the place to have individual components behave differently without generating multiple classes.
If you absolutely have to have inheritance, but the list of machines with mysql enabled is small, you can take an alternate route: instead of setting a variable in the node definition, build your selector off of
$fqdn
, with the default to disable, and selected fqdns enabled.Have a go with this:
This of course comes with the caveat that you already have Package["mysql-server"] defined elsewhere was it will fail as written without it due to your
require
statements.The other error I found was that you had too many spaces after the options. There options in the stanza must be aligned no more than 1 space greater than the longest option name.
Give this a go
One thing you may want to look at is Virtual Ressources to get around the multiple definition of ressources. Documentation on that topic can be found : http://reductivelabs.com/trac/puppet/wiki/VirtualResources
Of course, the other way would be to simple create node objects for each host that does not run mysql and then load the stripped class there.