Issue #5517 has been updated by Andrew Forgue.

Nick Lewis wrote:
> So the change that broke this is eagerly evaluating parameterized classes. 
> This is necessary because lazily evaluating with one syntax, `class { foo: 
> }`, and eagerly evaluating with the other, `include foo`, causes inconsistent 
> behavior.
> 
> Given that we eagerly evaluate parameterized classes, I can't conceive of a 
> model of evaluation that could cause this to work correctly. Essentially the 
> first thing we end up evaluating is class a, at which point we immediately 
> execute the notices, because they're functions. Changing the notices to 
> notify resources can reconcile this behavior in the presence of futures, 
> should we ever choose to implement those. But for notices, I can't see a way 
> this could ever work reasonably.

Why are parameterized classes eagerly evaluated?

> Do you have a concrete use case for this? There may be another way to 
> accomplish the desired behavior, or at least to provide some mechanism to 
> accomplish it.

The use case I was working on is when using an ENC.  We use LDAP as our ENC 
(which doesn't support specifying parameters for classes included by it.  
That's the first problem.  That being said, we essentially have the following:

    node default 
    {
      class { "autofs::sysconfig": basedn => "ou=xxx,o=yyy", master_map => 
"some_master_map_name" }
    }
    
but then some class of machines call them "development" uses different settings 
for the based and master map.

    class development_node
    {
      class { "autos::sysconfig": based => "ou=xxx,o=yyy", master_map => 
"development_master" }
    }

You can't do this with parameterized classes.  Both classes will be included 
and puppet will fail.  So the first hack is this:

    node default
    {
      include autofs::sysconfig::default
    }
    
    class development_node
    {
      include autofs::sysconfig::development
    }
    
    class autofs::sysconfig::default
    {
      class { "autofs::sysconfig": basedn => "ou=xxx,o=yyy", master_map => 
"some_master_map_name" }
    }
  
    class autofs::sysconfig::development inherits autos::sysconfig::default 
    {
      Class["autos::sysconfig"] { master_map_name => "development_master" }
    }

This doesn't work because of this bug.   It doesn't really make much sense, 
other resources can have their attributes overridden by sub classes, it is 
logical and, I think, reasonable to assume that classes can as well (and since 
this used to work in 2.6.1/2 it's a clear regression).  Classes even use the 
exact same syntax as other resources, so not being able to override will be 
very confusing.   Also, I believe parameterized classes are just about useless 
if this isn't possible.

Another use case that is almost identical to the above are tuning parameters.  
We have tuning parameters for our base install, but the presence of another 
class in our ENC causes some tuning parameters to be changed.  Using 
parameterized classes with the ability to override solves this problem 
straightforward and cleanly.  Without it (as we do now), is a messy 
amalgamation of `if !defined(Class["hpc_node"])` or crazy `scope.lookupvar()` 
in template evaluation.  It's a mess.

I believe what you will say to fix this problem is to use Extlookup.  We don't 
use ext lookup for a few reasons.

1. LDAP is our central source of 'truth' in our environment, this is a matter 
of policy and won't be changed, storing configuration details for nodes outside 
of LDAP is not something that we want to do.
1. extlookup isn't flexible enough.  I am looking forward to the work RI is 
doing with Heira, which may help, but it still comes back to problem number 1 
(above).


At the end of the day, we here think it's a failure in the puppet language that 
it can't support this kind of override.  As bad as parameterized classes have 
turned out to be, this is just the nail in the coffin for using them.  I don't 
know what we'll do with scope changes in 2.7 and the global variable mess we 
have since the 0.16.x (?) days.  

If what I'm trying to do can be accomplished in a better way I am totally open 
to hearing about them and being schooled on puppet DSL or systems management 
philosophy.  


----------------------------------------
Bug #5517: behavior change within 2.6 makes it impossible to override class 
parameters of "included" parametrized classes
https://projects.puppetlabs.com/issues/5517

Author: Peter Meier
Status: Investigating
Priority: High
Assignee: 
Category: language
Target version: 2.6.x
Affected Puppet version: 2.6.3
Keywords: parameterized_classes
Branch: 


In 2.6.1 the following recipe:

<pre>
class a(
  $b_c = { 'b' => 'foo' }
) {
  notice $a::b_c
  if $a::b_c {
    notice $a::b_c['b']
  }
}

class b {
  class{'a': b_c => false }
}

class b::c inherits b {
  Class['a']{ b_c => { 'b' => 'bleh' } }
}

class b::d {
  include ::b::c
}

include b::d
</pre>

produces the following output:

<pre>
$ puppet foo.pp 
notice: Scope(Class[A]): bbleh
notice: Scope(Class[A]): bleh
</pre>

Which is what I expected. However with 2.6.3 it produces the following output:

<pre>
# puppet foo.pp 
notice: Scope(Class[A]): false
</pre>

Imho likely the changes for #4778 and #5074 are responsible for that behavior 
change.

However this makes it impossible to overwrite parameters of a "included" 
parametrized class in a subclass. There are only ugly workarounds for that 
problem and I think this should actually work as it did within 2.6.1. Otherwise 
the usefulness of parametrized classes is quite reduced.


-- 
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 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-bugs?hl=en.

Reply via email to