Puppet class inheritance confusion
I've read the documentation on scope, but I'm still having trouble working this out. I've got two environments that are very similar - so I've got:
modules/django-env/manifests/init.pp
class django-env {
package { "python26":
ensure => installed
}
# etc ...
}
import "er.pp"
modules/django-env/manifests/er.pp
$venvname = "er"
$venvpath = "/home/django/virtualenvs"
class er {
file { "$venvpath/$venvname" :
ensure => directory
}
# etc ...
}
class er-dev {
include er
}
class er-bce-dev {
$venvname = "er-bce"
include er
}
manifests/modules.pp
import "django-env"
manifests/nodes.pp
node default {
# etc ...
}
node 'centos-dev' imports default {
include django-env
include er-bce-dev
include er-dev
}
The result here is that the "inheritance" works - but only the first "er-" item under the 'centos-dev' node is acted upon, I either get er-bce-dev or er-dev, but not both. There must be some basic thing I'm misunderstanding here.
Is it the difference between import and include ? (not sure I understand that)
Solution 1:
Puppet does not support this kind of configuration, but the restriction can be easily bypassed. The reason is in two basic puppet "rules":
- A class can be included only once (subsequent include -statements will do nothing)
- The order of execution is not strictly defined and can even be random
er-dev
and er-bce-dev
both include the class er
. But the class cannot be included two times, so er
class is executed only with the default $venvname = "er"
, or with overridden $venvname = "er-dev"
, but not both.
The solution: Change er
class to a definition (see "Definitions" from Puppet Language Tutorial (http://docs.puppetlabs.com/guides/language_tutorial.html)):
modules/django-env/manifests/er.pp
# Create new er resource definition
define django-env::er($vpath="/home/django/virtualenvs", $vname="er") {
file { "$vpath/$vname" :
ensure => directory
}
# etc ...
}
We do not need the $venvname
and $venvpath
variables, they are specified as default values in the definition. The name django-env::er
adds the definition into django-env
namespace and allows automatic import (see below).
Import and Include
The difference between import
and include
statemens is:
-
import
works with files, and does not execute classes -
include
executes classes - files must be imported before the classes can be included
Note: there is a very strong exception to the last rule: Puppet module lookup. include
statement does automatic imports in many situations. Here are some of them:
-
include foo
tries to import the filemodule_dir/foo/manifests/init.pp
-
include foo::bar
importsmodule_dir/foo/manifests/bar.pp
With these automatic imports and the resource definition, you can define multiple virtual environments very easily. Change node 'centos-dev'
:
node 'centos-dev' imports default {
include django-env
# The er resource with default values:
django-env::er { 'er-bce': }
# Another er resource with different environment name:
django-env::er { 'er-bce-dev': vname => 'bce-dev'}
}
And you can remove basically all import
statements considering django-env
module.
Happy Puppeting!