On Mar 5, 2:23 pm, "chris_sny...@sra.com" <chris_sny...@sra.com>
wrote:
> I apologize if this horse has already been beaten to death, but I'm
> new here and very, very confused. I'm just starting to work with
> Puppet and I can not make heads or tails of the language: specifically
> how to use parameterized classes.


My usual advice is to avoid using parameterized classes.  There is a
host of problems associated with their current design.  My
understanding is that there will be substantial improvements on that
front in 'Telly', the next major release, but for now, just don't do
it.

Instead of using class parameters, either make your classes smarter,
or use an exteral data store via hiera or extlookup.


> I've spent a week reading the docs
> and testing manifests and I can't make any progress.  I have a feeling
> that my confusion comes from the fact I have a programming background
> and that my understanding of certain terms (i.e. 'class' and 'scope')
> don't mean the same thing for Puppet as they do everywhere else.


You are probably right.

The usage of the term 'class' in Puppet is not derived from its usage
in many (but not all) object-oriented languages.  Instead, both are
independently derived from from the more general-purpose meaning of
the word (a synonym of "kind").  I suspect Puppet's choice was
intended to evoke the concept of classification (of nodes).

Other documentation and language-design choices make it worse by
muddying the waters.  In particular, I think it was a poor idea to
name Puppet's facility for declaring variant classifications
"inheritance".  Puppet class inheritance is quite different from OO
class inheritance, and you just have to get over the hurdle that the
word means something different here.  Fortunately, class inheritance
is rarely needed or appropriate in Puppet, so you can probably just
pretend it doesn't exist.  In fact, I recommend that you do.

The word "scope" is probably not the same kind of problem for you, but
you may be running into one of these scope-related gotchas:

1) Most blocks in Puppet DSL do not establish their own scopes.  If
you're used to curly-brace programming languages then this takes some
getting used to, but it is useful and appropriate for Puppet.  Only (I
think) these Puppet DSL constructs establish their own scopes: node
declaration bodies, class bodies, and definition bodies.

2) Through version 2.7.x, Puppet uses dynamic scoping.  This is not a
Puppet innovation, but it *has* proved to be a sore thumb.  You will
make your life better if you write DSL code as if there were only two
scopes: local scope and global scope.  Use a fully-qualified name to
refer to any variable not belonging to the local lexical scope.
Starting in Telly, that will be required.

3) That brings us to to the point that all declared classes,
resources, and variables have global visibility.  Thus, Puppet scoping
establishes name spaces and affects name resolution, but does not
limit variable accessibility.

That last point might seem problematic until you grasp that Puppet
classes cannot be multiply declared.  The Puppet docs continue their
flirtation with OO terminology by describing this as all classes being
Singletons.  There is therefore never any issue of choosing the right
"instance" of a class from which to read variable values.  Instances
of defined types could present a problem in this regard, except that
there is no syntax in the DSL for addressing their variables.


> (And I thought I understood the concept of 'declarative language', but
> maybe not.)


There are two main points there:

1) Once anything is defined, it cannot be redefined (even to the same
value) in the same manifest set.

2) Puppet DSL is not executable.  This is a rather fine distinction,
because the DSL interacts with the execution of the Puppet manifest
compiler, and the compiled catalogs strongly influence the execution
of the Puppet agent.  Nevertheless, to become a Puppet master you must
jettison the idea of classes and resources "running".


> Here's an example of what I feel should work:
>
> class bar ($x='default') {
>     notify { "x=${x}": }
>
> }
>
> class foo {
>     notify { 'Inside class foo': }
>     class { 'bar' : x => 'inside foo', }
>
> }
>
> class baz {
>     notify { 'Inside class baz': }
>     class { 'bar' : x => 'inside baz', }
>
> }
>
> class { 'foo' : }
> class { 'baz' : }
>
> However, when I run this I get the following error:
>
>    Duplicate definition: Class[Bar] is already defined in file
> test5.pp at line 10; cannot redefine at test5.pp:15
>
> As I understand it, each class definition has it's own scope.  So why
> can't I declare the same parameterized class from two different
> classes, especially when the parameters are different?


Because all declared classes are global.  Declaring a class in Puppet
is not analogous to instantiating one in, say, C++.  Instead,
declaring a class simply says "the node (is a member of / has) class
<foo>".  (Contrast this with declaring an instance of a defined type.)

It is perfectly fine and consistent for different classes A and B to
both declare that the node is a member of a third, non-parameterized
class (i.e. Puppet allows it).  On the other hand, it is wholly
inconsistent for A to say "the node is a member of class C, and class
C's parameter is 'foo'" while B says "the node is a member of class C,
and class C's parameter is 'bar'".  If ever both A and B are declared
for some node, then they contradict each other about what class C's
parameter is.

A better question would be why classes A and B cannot both declare
class C with the *same* parameters.  That would at least be
consistent, but it is a shortcoming of Puppet's parameterized class
implementation that you cannot do it.


>  If you can't
> do this then what's the point of having them?


Class parameters were implemented to solve some specific problems
related to class data, and especially to work around problems
associated with relying on dynamically-scoped variables to povide data
to classes.

For example, each node has at most one set of DNS servers, but
different nodes supported by the same Puppet manifests may need to
have different sets.  You could write all the data and selection
criteria into the class managing /etc/resolv.conf, but your class is
more easily maintained and reused if instead it pulls the data from
some source outside itself.  Class parameters are one of the places
from which classes can pull such data.  There are others -- most
notably, external data stores such as you can access via Hiera.


> My understanding of the docs and how the scoping rules are moving
> towards 2.8, seems to imply that 'include' is bad and 'parameterized
> classes' are good.  I'm cool with that, in fact I prefer that - it
> matches more of style of coding for other languages.


'Include' vs. parameterized classes has nothing to do with scoping.  I
agree that the current docs seem to push parameterized classes over
'include', but I have it on good authority that that is not PuppetLabs
policy or intention, nor even consistent PuppetLabs internal
practice.  As I understand it, a lot of improvements to parameterized
classes are planned for Telly, among them some that should greatly
reduce the impedance mismatch between 'include' and parameterized
classes.

'Include' is definitely not "bad".  Quite the opposite: at least until
Telly, I strongly recommend that you use only 'include' or its sibling
'require' to assign classes to nodes.  This implies that you should
avoid using parameterized classes, which I also consider excellent
advice, at least for now.

As far as matching coding styles with which you are familiar, I
suggest that you may be better off disciplining yourself to a style
that is less familiar.  You said yourself that your experience with OO
programming languages sometimes inclines you in the wrong direction
with Puppet, so a style that reinforces Puppet's differentness to you
may help you learn faster and more effectively.


> Can somebody please explain what is going on?


Was that sufficient?


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