Issue #8040 has been updated by Luke Kanies.
(As sent to the list.)
As mentioned in my other email, the solution to this problem should not in any
way require changes to containment semantics, and certainly shouldn't require
class evaluation to indicate class containment. As I said, it used to do that
for the first instance (but not for second, which led to some inconsistencies
and surprises, which is why I removed it). These days, though, in general
classes only contain resources, not other classes. What I can't remember is
how inheritance affects containment, if at all.
Let's be clear on what the original problem was that led us to this:
Fundamentally, we only have a problem in a circumstance like this:
class a { file { "/a": ensure => present }
class b {}
class c { file { "/c": ensure => present }
Class[a] -> Class[b] -> Class[c]
Because Class[b] is empty, the relationship between the resources in A and the
resources in C get lost.
This is a bug that was introduced around 2.7 or 2.8, and it was introduced
because we made an optimization in the graph.
The optimization was needed because the current graph code can have either
containment or dependency edges in it, but not both. The catalog we ship from
the server has containment edges, and all dependencies are specified as
parameters, not edges in the graph.
The transaction creates what we call the relationship graph, which has those
dependency edges, but no containment edges. The way it used to accomplish this
was by essentially multiplying appropriate containment by appropriate
dependency edges. E.g., in this case:
class a {
file { ["/a1", "/a2"]: ensure => present }
} -> class b {
file { ["/b1", "/b2"]: ensure => present }
}
We end up turning our one dependency (Class[a] -> Class[b]) into 4 edges:
File[a1] -> File[b1]
File[a1] -> File[b2]
File[a2] -> File[b1]
File[a2] -> File[b2]
In small catalogs, this isn't really a problem, and might actually result in
fewer edges (e.g., we actually had 4 containment edges in the first graph, and
now have 4 dependency edges, so it's equal).
In large catalogs, though, this multiplication (and note I'm using that word
loosely; you can see the details in the 'splice' method on Catalog) results in
a massive increase in edges, which significantly slows things down.
The optimization done was to add whits as a single collector for those edges,
and thus reduce the overall count.
Unfortunately, this optimization introduced the bug we're all discussing, which
requires the anchor pattern.
The correct fix for this is relatively simple to understand, and should involve
the removal of quite a bit of code, although it might be a bit hard to
implement:
Change the graph handling code so it can correctly handle both dependency and
containment edges. This is relatively simple: Just change the traversal (and
cycle detection) to prefer dependencies over containment.
This way we don't have to multiply edges, which means we don't need whits
(yay!), which means we don't need anchors. Done. We also get to remove the
relationship graph and all related code, which is also a win.
I tried this about 2 years ago, but I couldn't get the cycle detection working.
----------------------------------------
Bug #8040: Classes should be able to contain other classes to provide a self
contained module
https://projects.puppetlabs.com/issues/8040#change-96938
* Author: Jeff McCune
* Status: Accepted
* Priority: Immediate
* Assignee: Patrick Carlisle
* Category: compiler
* Target version: 3.x
* Affected Puppet version: 2.6.0
* Keywords: anchor containment contain graph modules module self-contained
dependency reuse usability forge backlog customer
* Branch:
----------------------------------------
# Overview #
As a module author, I want to build collections of classes for end users
shipped as a module.
As a module end-user, I want to manage resources before and that require the
collection of classes as a self contained unit of functionality.
For example, the end user wants to use a module I write in the following way:
<pre>
node default {
class { 'java': }
->
class { 'activemq': }
->
class { 'mcollective: }
}
</pre>
Where java, activemq, and mcollective are all discrete modules with multiple
classes each. For example, a each module has a class for the packages, a class
for the configuration files, and a class for the running service if there is a
service.
With Puppet 2.6, when a class declares another class, the classes are not
related to each other in any way, containment or dependency.
# Expected Behavior #
The example illustrates the expectation that all resources in the activemq
module are managed after all resources in the java module and before all
resources in the mcollective module.
# Actual Behavior #
Without the Anchor Pattern, when class activemq::service is declared from
within class activemq, the resources float away and are not transitively
related to java or mcollective.
# Suggested Implementation #
It has been expressed that it may be a viable solution for module authors to be
able to specify containment edges in the graph from within the Puppet DSL.
With Puppet 2.6.x and 2.7.x this is not possible. The Anchor Pattern works
around this problem by specifying relationship edges to a resource contained
within the composite class.
# Work Around #
The Anchor Pattern is the current work around for Puppet 2.6.x When a class
declares other classes, it should contain them using this pattern:
<pre>
class activemq {
anchor { 'activemq::begin': }
anchor { 'activemq::end': }
class { 'activemq::package':
require => Anchor['activemq::begin'],
}
class { 'activemq::config':
require => Class['activemq::config'],
notify => Class['activemq::service'],
}
class { 'activemq::service':
before => Anchor['activemq::end'],
}
}
</pre>
--
Jeff McCune
Puppet Labs
@0xEFF
--
You have received this notification because you have either subscribed to it,
or are involved in it.
To change your notification preferences, please click here:
http://projects.puppetlabs.com/my/account
--
You received this message because you are subscribed to the Google Groups
"Puppet Bugs" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/puppet-bugs.
For more options, visit https://groups.google.com/groups/opt_out.