On Apr 13, 2:42 am, Felix Frank <felix.fr...@alumni.tu-berlin.de>
wrote:
> On 04/13/2011 12:34 AM, jcbollinger wrote:
>
> > You can include unparameterized classes any number of times, and it
> > means the same thing whether you include a class once or a hundred
> > times.  This is one of the fundamental characteristics of Puppet
> > classes, and a feature that I personally put to good use.  There is no
> > reason in principle why you should not be able to include
> > parameterized classes multiple times as well, provided that the
> > parameters are everywhere the same for a given node.  My expectation
> > for such a case would be that the effect is the same as including the
> > class only once, just as for unparameterized classes.
>
> John,
>
> I used to think along the same lines. Not anymore. As a matter of fact,
> I don't think non-parameterized classes should be considered equal to
> their parameterized counterparts. They are different concepts with
> different uses (which are unlike defines', see below).


Given my position that the good use cases for parameterized classes
are specialized and few, I tend to agree about different uses.  That
parameterized and ordinary classes are different concepts appears to
be more a de facto result than a design decision, however.  Other
aspects of Puppet tend to obscure such a distinction.  Consider:

* Puppet uses the same term ("class") and largely the same
infrastructure for ordinary and parameterized classes.

* The Language Guide explicitly comingles the concepts.  It says "In
Puppet 2.6.0 and later, classes are extended to allow the passing of
parameters into classes."  That's a far cry from "a new kind of
resource collection is available", or even from "some classes are
special."

* You can include an ordinary class via the parameterized-class
mechanism (thereby causing Puppet to prevent its inclusion elsewhere),
but you cannot include a parameterized class via 'include', even if it
has default values defined for all its parameters.

* The only way to assign an ordinary class to a run stage is via the
parameterized-class mechanism (which causes Puppet to treat it as a
parameterized class).

* Puppet Labs's official Puppet Style Guide promotes parameterized
classes and largely pushes ordinary ones under the rug.

* Inasmuch as all classes have at least one *meta*-parameter (stage),
Puppet blurs the line between ordinary and parameterized classes.


> It can be useful to be able to include things in multiple places and
> leverage the "singleton" qualities of non-parameterized classes.
> For the things you *do* parameterize, you will typically want to be sure
> it won't get included anywhere far from node level.


I agree, but the Style Guide doesn't appear to do.  It advises against
using "include" at all, leaving only the parameterized class syntax
for including classes (for which it uses the term "declare" instead of
"include").  Following that advice effectively makes *all* classes be
treated as if they were parameterized.  In that context it makes sense
that the Guide recommends that *all* classes be "declared" as close to
node scope as possible, and that classes actively avoid including
(declaring) other classes, but that doesn't make those recommendations
-- especially the second -- good in their own right.


> Being an 0.25 person, I have to rely on dynamic scoping here and there.
> The scoping problems are horrible, so most of the time I end up
> declaring variables near node level and immediately include the class
> that uses those variables.
> Parameterized classes allow for this to be written somewhat more
> explicitly, but I don't expect them to become as flexible (wrt.
> distributed inclusion) as non-parameterized classes (anymore).


The more I consider the problem, the more I think parameterized
classes are the wrong solution.  They address the problem of providing
data to classes by creating a new type of object to which you can
explicitly provide data (if we distinguish between ordinary and
parameterized classes), or by putting substantial restrictions on the
usage of classes to which you can provide data (if we don't
distinguish).  That's not a good solution either way.

Extlookup() is a better solution in several ways, but especially
because it is applicable to any class, and because it doesn't
inherently impose limitations on the classes that use it.  It's in the
Puppet 2.6 core, so anyone who can use parameterized classes can also
use extlookup().

I haven't studied the PDL proposal carefully; perhaps it would be an
even better solution, but I have reservations about it because it is
based on parameterized classes.


> Technically, you can replace each and every parameterized class with a
> define that bears a label "use this only once per node!" (which I've
> done in places with 0.25, as a matter of fact). Yes, it works. Yes, it
> has largely the same effect as a paramerized class.
>
> But that's horrible design practice! Parameterized classes represent
> collections of unique resources. Drawing on the define paradigm to get
> something similar is ugly.


I'd go with "inelegant", but "horrible" and "ugly" are too strong.  I
would have preferred for Puppet to use the existing inelegant
solution, however, instead of introducing a new inelegant solution.
Perhaps parameterized classes' inadequacies can be addressed in some
future version.

I think it's particularly inelegant that the Puppet 2.6 DSL blurs the
distinctions between classes and resources.  Not only is the usage
syntax virtually identical, but even the language with which their use
is described ("declare") is now the same.  I swear I somewhere saw the
phrase "declaring class resources" used in the sense of including
classes (as opposed to declaring resources in their bodies), but I
can't find it now.


> I've talked a to Dan about this during the Berlin Meetup, and it was my
> impression that the vision is that future manifests should
> 1) declare most used classes near node level and
> 2) have interdepending classes produce failures when dependencies are
> missing (whereas in the 0.25 age, you would include dependencies and be
> done with it)


Yes, this is largely what the Style Guide says.  I object particularly
to (2); see my previous comments on that topic in this thread, or
alternatively, tell me what makes it a good idea (other than the
limitations of the current implementation of parameterized classes).


> This sounds very sane to me, but I haven't had a change to really dabble
> in that type of design myself. For this discussion's sake, I'd be
> honestly thankful to see some examples of classes that should both be
> parameterized and multiple-includable. (Yes, I am making up terms as I
> go ;-)


That's a hard request for me to fulfill, because I have trouble coming
up with examples of classes that should be parameterized.  On the
other hand, as a matter of principle I think *all* classes should be
multiple-includable.  Only implementation details argue against it in
practice.

I think often what you might like to do is declare a class's
parameters once, and elsewhere allow other classes to include that
class without redeclaring the parameters.  For instance, perhaps you
have a user::virtual class that on some nodes declares virtual LDAP
users, but on other nodes delares the same virtual users as local.
Such a class might provide a parameter by which the User provider can
be specified.  Other classes that want to realize users should include
user::virtual, but they don't care which User provider is in play.

Now that I came up with that example, I realize that it points to an
improvement that might be doable right away: allow the include
statement to be used with parameterized classes.  That could be
achieved by slightly (but backwards-compatibly) changing the semantics
of "include":

1) The "include" statement expresses a requirement that the specified
class be included in the resulting catalog, but it says nothing about
the class's parameters.

2) If a class is named in at least one "include" statement that is
executed while compiling a catalog, then the effect depends on whether
the named class is "declared" elsewhere in the manifest:

2a) If the class is declared, then include statements referencing it
have no additional effect.

2b) If the class is not declared, then it is treated as if the class
were declared, without any explicit parameters, at the point where the
first include statement appears.  (Fixing the class declaration to the
first include statement is intended to provide backwards
compatibility.)  If such a class declares a parameter for which it
does not define a default value, then an error results.


John

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

Reply via email to