[Puppet Users] Re: Negate or uninclude a class

jcbollinger
Tue, 19 Oct 2010 16:00:16 -0000

On Oct 18, 10:24 am, Bruce Richardson <itsbr...@workshy.org>
wrote:
> Class inheritence *only* makes sense if you want to
> override the properties of resources.

It appears that we agree there.

I add that one property shared by most resources is "ensure", by which
relevant resources can be ensured absent / disabled (among other
things).

>   The OP wants not to include a
> whole class; what you''re telling him to do is not uninclude the
class,
> but to try and override properties in every resource owned by the class,
> so as to make the class effectively do nothing.

The OP asked about how to "uninclude" a whole class -- that is, given
the class being included in one part of a manifest, how to elsewhere
cause it to not be included after all.  We agree that cannot be done.
One alternative approach is to include the class conditionally in the
first place, a different alternative is to override it where needed.
*Neither* is what the OP actually asked for.

The subclass approach definitely does not override the superclass to
do nothing.  Much to the contrary, it overrides the superclass so that
together (whether the superclass is directly included or not) they
ensure the correct configuration for a system that is not, in the
example, an LDAP client.  In other words, the servers are configured
as non-clients, rather than leaving their client status unmanaged.
There will be file differences between clients and non-clients, and
possibly differences in such things as installed packages and service
configuration.  It is wise to manage those differences, whether
whether via subclassing or otherwise.

>  There are any number of
> reasons why that''s not a smart thing to do, but here are several
that
> occur to me immediately.

[...]

All the reasons cited boil down to this: the superclass and subclass
must be structured suitably and be tightly coupled in order to work
correctly.  This is true generally of Puppet subclassing.  It may
constitute too great a barrier for some uses, but that does not
invalidate the approach in general.  How that relates to the OP''s
problem depends on his manifests.

> Your exmaple cannot achieve the same effect as not including a class;
> the empty files you''d litter the filesystem with is only one
example.
> Forcibly negating everything in a class is not the same as not including
> it.  Why not just not include it?

The subclass approach indeed does not have the same effect as not
including a class in the first place, but that''s not exactly what the
OP asked for.  As described above, it also wouldn''t be the best
practice, because it would leave client status unmanaged on the
servers.

Whatever problems the subclass appoach has, though, empty files is not
one of them.  Perhaps you''re looking at how in my simplified example I
overrode the "source" property of a File resource.  That contemplates
a situation where you want the file present in any case, but with
different content (e.g. /etc/nsswitch.conf).  If you only want the
file present at all in one case or the other then you would override
the "ensure" property instead.

> > For example, although Bruce''s main suggestion could be used
if for
> > some reason it were important to avoid subclasses, really in that case
> > something akin to his define-based suggestion (but without subclasses)
> > would be better.  That way, if the LDAP client somehow gets turned on
> > on your LDAP server, then Puppet will turn it back off.  Unconfigured
> > means "I don''t care"; it must not be confused with
"off".  The
> > subclass usage pattern above achieves the same thing with no
> > conditional inclusions and no define, plus it''s safe against
inclusion
> > of "ldap::client" by other parts of the manifest.
>
> I''m sorry, but I think you are quite wrong and your
recommendations are
> very unwise.

Then we will have to agree to disagree on that point.  It is
altogether independent of the subclassing question, however, and I
think it very important, so I repeat: "Unconfigured means ''I
don''t
care''; it must not be confused with ''off''."

For example, if it is important that a system not be configured as an
LDAP client, then its manifests should affirmatively make that so.  It
is not sufficient just to leave the client configuration out of its
manifest.  What if an admin (or a bad Puppet manifest) enables the
LDAP client on a system that should not have it?  Or what if one wants
to convert a client to a server?  You do not need to use subclasses to
address the problem (the define-based approach could do it), but
merely omitting the client configuration from the machine''s manifest
doesn''t cut it.

> I have no objection to class inheritance at all, although
> the way it works in puppet is often misunderstoon and it is often
> overused as a result.

We agree on this.  All too often, Puppeteers inherit from a class
where it would be better to include that class.

>  Your proposed example is definitely not a good
> use of class inheritance.

My example was a schematic of the form, not a practical one of a
particular solution.  I vigorously maintain, however, that a direct
consequence of the design of Puppet''s subclassing a feature is that
when you use subclasses properly, you do not need or want to
conditionally include superclass vs. subclass.  If a superclass and
subclass don''t work together correctly when both are included in the
same manifest, then they are constructed poorly.  It is primarily that
usage model that my example was intended to illustrate, and if you
disagree with the propriety of that model (leaving aside its
application to the present problem) then I think you are missing some
of the power and benefits of subclasses.

[...]

> By far the simplest and safest way not to include a whole class is the
> "if $ldap_enabled { include ldap::client }" method; it has no bad
side
> effects, it works no matter how the internals of the ldap::client
> change, it''s a tiny bit of code.

If avoiding inclusion of a certain class under certain circumstances
is indeed what you want to do, then all the methods Puppet provides to
do so are pretty much equivalent to that.  Doing so would be
independent of the details of the class in question, and it would not
require much code.  All that is agreed.

That approach must be applied everywhere that class in question may be
included, however.  Depending on the manifests, that could present a
maintenance problem (but probably not in the OP''s case).  Moreover, it
would leave the client status unconfigured for some systems.  That
might be acceptable if Puppet is used primarily for provisioning, but
it prevents Puppet from *maintaining* the (non-)client state.

An approach involving subclassing is not necessarilly viable or
appropriate, but if done right it involves solves the problem of
maintaining state after provisioning, it does not require attention to
where the superclass may be included, and it is simple to express in a
node configuration.  It does require more code overall, but that''s
because it *does* more.  The additional code is all encapsulated in
the classes'' module.  It is not useful to conditionally include super-
vs. subclass in this case; one or both classes are broken if they
don''t have the correct result when both are included in the same
manifest.

A non-subclass approach that also maintains non-client state after
provisioning would require roughly as much code as the subclass
approach would, because it must address the same configuration
details.  Such an approach would rely on conditional inclusion of one
class vs. another, with the associated benefits and drawbacks.  The
only reason I see to prefer this alternative would be if the structure
of the proposed superclass is too complicated for subclassing to be
viable, but I''m having trouble seeing how that would not also present
a problem for writing an independent non-client class.


Regards,

John