Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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)

share|improve this question
    
IIRC the FAQ of puppet contained an item that stated that node inheritance has problems and shouldn't be used. But now the FAQ has moved and lost this piece of information along the way. – ptman Jan 16 '11 at 11:24
up vote 11 down vote accepted

Puppet does not support this kind of configuration, but the restriction can be easily bypassed. The reason is in two basic puppet "rules":

  1. A class can be included only once (subsequent include -statements will do nothing)
  2. 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 file module_dir/foo/manifests/init.pp
  • include foo::bar imports module_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!

share|improve this answer
    
Thanks for this! – EMiller Jan 19 '11 at 5:25
    
Shouldn't there be inherits instead of imports default? inherits is also deprecated, but at least it's valid syntax. – Tombart Mar 13 at 12:23

Puppet syntax evolved, since Puppet 3.7 you'll get a lot of deprecation warnings. Keywords import and inherits are deprecated. Instead of using layout like:

 /etc/puppet
   /manifests
      /nodes
      site.pp
   /modules
   puppet.conf

You should use:

 /etc/puppet
   /environments
     /production
       /manifests
          01_base_node.pp
       /modules
       environment.conf
   puppet.conf

Instead of using traditional site.pp config:

import 'nodes/*.pp'

node default {
   classs{'ntp': }
}

you should use standard class (but you can't call it class default as it is a reserved word), a file manifets/01_common.pp:

class common {
  classs{'ntp': }
}

Files are loaded in an alphabetical order, so you should ensure that "base classes" will be loaded first (numbering might be a good idea).

Then instead of defining a node like:

node /^web\d+/ inherits default {
}

use rather (resolves classical multiple inheritance problem, so called diamond problem), e.g. defined in manifests/web.pp

node /^web\d+/ {
  include common
  # include something_else   
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.