Hello,

I've been thinking about how best to handle the situation where a
single class is included multiple times from multiple classes who
themselves set resource defaults.  This situation poses an interesting
problem in Puppet because of dynamic scoping rather than lexical
scoping and appears to come up frequently as I travel and work with
the puppet community.  It's also come up quite a bit in my own work
and development of modules for the forge.

I'm looking for feedback from the community as to how best to handle
the unique situation in a maintainable and elegant manner.

This is pretty long, but it's a rather complex problem and fairly
common in my experience, so thanks in advance for taking the time to
read through if you do.

I believe an use case will illustrate the point.

Consider a module, perhaps publicly available in the Forge, which is
extremely common and many other modules require.  A good example is
the configuration of the packaging system for the node to use a local
repository.

# /etc/puppet/modules/localpackagerepository/manifests/init.pp
class localpackagerepository {
  $module = "localpackagerepository"
  file { "/etc/yum/yum.repos.d/local.repo": source =>
"puppet:///modules/${module}/local.repo"; }
}

Other classes will likely establish a relationship in the graph to
this localpackagerepository class to ensure custom packages are
available before trying to manage their state.  For example:

# /etc/puppet/modules/apache/manifests/init.pp
class apache {
  $module = "apache"
  include localpackagerepository
  File {
    owner => "apache",
    group => "apache",
    require => Package["apache"],
    notify => Service["apache"],
  }
  ###
  package { "apache":
    ensure => installed,
    require => Class["localpackagerepository"];
  }
  service { "apache": ensure => running }
  file { "/etc/httpd/httpd.conf": source =>
"puppet:///modules/${module}/apache.conf"; }
}

# /etc/puppet/modules/postfix/manifests/init.pp
class postfix {
  $module = "postfix"
  include localpackagerepository
  File {
    owner => "mail",
    group => "mail",
    require => Package["postfix"],
    notify => Service["postfix"],
  }
  package { "postfix":
    ensure => installed,
    require => Class["localpackagerepository"];
  }
  service { "postfix": ensure => running; }
  file { "/etc/postfix/main.cf": source =>
"puppet:///modules/${module}/main.cf"; }
}

Now, with these three modules we may include them in the node
classification like so:
include apache
include postfix

However, this will behave very differently than the classes included
in a different order:
include postfix
include apache

In the first ordering the localpackagerepository class will take on
the resource defaults of the apache class, while in the second
ordering the localpackagerepository class will take on the resource
defaults of the postfix class.

In both cases there will be a circular dependency (local.repo will
require a package, and the package will require local.repo), which is
clearly an issue.  In either case, local.repo will take on defaults
for owner and group which are invalid.

How are you handling this situation?  How do you think this situation
*should* be handled by puppet?

I can think of a number of work arounds, but they're not ideal and
they don't feel to me like they'll play well with public modules
posted to the forge.

I make the recommendation that classes should include the classes they
depend on, but this appears to be problematic if the class doing the
include sets resource defaults, particularity when setting a
relationship in a default like require, before, subscribe and notify.
This opens up the door for resource cycles.

Perhaps it might be useful to set resource defaults only for the local
scope, and not for any classes which get included into this scope.
How do you feel about this change to the language?

Is there some other organization of the class structure I'm overlooking?

Thanks for your feedback,
-- 
Jeff McCune
http://www.puppetlabs.com/

-- 
You received this message because you are subscribed to the Google Groups 
"Puppet Users" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/puppet-users?hl=en.

Reply via email to