puppet class require fails depending on declaration order

555 views
Skip to first unread message

Bruno Bieth

unread,
Apr 1, 2014, 8:15:41 AM4/1/14
to puppet...@googlegroups.com
Hi,

I've got the following code that works as expected:

class { "c1": }
class { "c2": }

class c1 {
  notice "+++"
}

class c2 {
  require "c1"
  notice "+++"
}


But switching the declaration order of class c1 and c2:

class { "c2": }
class { "c1": }

class c1 {
  notice "+++"
}

class c2 {
  require "c1"
  notice "+++"
}


produces the following error:

Notice: Scope(Class[C1]): +++
Notice: Scope(Class[C2]): +++
Error: Duplicate declaration: Class[C1] is already declared; cannot redeclare at /vagrant/files/aa.pp:4 on node ubuntu1310.nestle.com
Error: Duplicate declaration: Class[C1] is already declared; cannot redeclare at /vagrant/files/aa.pp:4 on node ubuntu1310.nestle.com


Shouldn't puppet be declarative and insensitive to the declaration order?

Bruno

José Luis Ledesma

unread,
Apr 2, 2014, 5:36:34 AM4/2/14
to puppet...@googlegroups.com
hi,


from:


Include-Like vs. Resource-Like

Puppet has two main ways to declare classes: include-like and resource-like.

Note: These two behaviors should not be mixed for a given class. Puppet’s behavior when declaring or assigning a class with both styles is undefined, and will sometimes work and sometimes cause compilation failures.


regards,


--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-users/f2766983-529b-4fd7-a3c0-6f48efd45f25%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
José Luis Ledesma
Message has been deleted

David Portabella

unread,
Apr 2, 2014, 5:57:39 AM4/2/14
to puppet...@googlegroups.com
Oh My God!

you mean that "it's not a bug, it is a feature" ?

jcbollinger

unread,
Apr 2, 2014, 9:23:56 AM4/2/14
to puppet...@googlegroups.com


On Wednesday, April 2, 2014 4:57:39 AM UTC-5, David Portabella wrote:
Oh My God!

you mean that "it's not a bug, it is a feature" ?



It is not a feature in the sense of a desired outcome, but it is the intended behavior.  Specifically, if there is any parameterized-style declaration of a given class, then that must be the first declaration of that class that is evaluated during catalog compilation.  This is analogous to the prohibition on duplicate resource declarations (and note that as a corollary it prohibits multiple parameterized-style declarations of the same class).  Declarations via "include", "require", or "contain" may be evaluated subsequent to a parameterized-style declaration, however, because in that context they do not influence the class's parameter values.

I characterize it as a design flaw in Puppet's parameterized-style class declaration syntax, and based on this issue I have been urging people to avoid parameterized classes ever since they were first introduced.  The situation is somewhat eased in modern (3.x) Puppet, however, where you can leverage hiera to use parameterized classes without the parameterized syntax.  These days I advise people only to avoid parameterized-style declaration syntax (for classes), not necessarily to avoid parameterized classes altogether.


John

Garrett Honeycutt

unread,
Apr 3, 2014, 10:10:50 AM4/3/14
to puppet...@googlegroups.com
On 4/2/14, 3:23 PM, jcbollinger wrote:
>
>
> On Wednesday, April 2, 2014 4:57:39 AM UTC-5, David Portabella wrote:
>
> Oh My God!
>
> you mean that "it's not a bug, it is a feature" ?
>
>
>
> It is not a feature in the sense of a desired outcome, but it /is/ the
> intended behavior. Specifically, if there is any parameterized-style
> declaration of a given class, then that must be the first declaration of
> that class that is evaluated during catalog compilation. This is
> analogous to the prohibition on duplicate resource declarations (and
> note that as a corollary it prohibits multiple parameterized-style
> declarations of the same class). Declarations via "include", "require",
> or "contain" may be evaluated subsequent to a parameterized-style
> declaration, however, because in that context they do not influence the
> class's parameter values.
>
> I characterize it as a design flaw in Puppet's parameterized-style class
> declaration syntax, and based on this issue I have been urging people to
> avoid parameterized classes ever since they were first introduced. The
> situation is somewhat eased in modern (3.x) Puppet, however, where you
> can leverage hiera to use parameterized classes without the
> parameterized syntax. These days I advise people only to avoid
> parameterized-style declaration syntax (for classes), not necessarily to
> avoid parameterized classes altogether.
>
>
> John

Agree with John that you want to completely avoid using the
parameterized style declaration of classes. Better to use 'include'
statements and set all of your params in Hiera.

Here's a link[1] to a talk I gave two years ago about this topic.

[1] - http://www.slideshare.net/gh/20130407-load-puppevtv3andhiera/17

Best regards,
-g

--
Garrett Honeycutt
@learnpuppet
Puppet Training with LearnPuppet.com
Mobile: +1.206.414.8658

David Portabella

unread,
Apr 3, 2014, 11:31:40 AM4/3/14
to puppet...@googlegroups.com
Agree with John that you want to completely avoid using the parameterized style declaration of classes. Better to use 'include'  statements and set all of your params in Hiera. 

That's an interesting discussion, 
but that's not the point of this post.

the point of this post, as I understand it from my colleague,
is that there is a bug in puppet.

on the very least, if that is not a bug, 
puppet should complain with a clear error message of the type "Error: class 'c1' mixes include-like and resource-like declarations",
instead of the incomprehensible error message: "Error: Duplicate declaration: Class[C1] is already declared; cannot redeclare at /vagrant/files/aa.pp:4".


About this note:

http://docs.puppetlabs.com/puppet/latest/reference/lang_classes.html#declaring-classes
Include-Like vs. Resource-Like
Puppet has two main ways to declare classes: include-like and resource-like.
Note: These two behaviors should not be mixed for a given class. Puppet’s behavior when declaring or assigning a class with both styles is undefined, and will sometimes work and sometimes cause compilation failures.

I think that the result of class { java: } and include java are semantically equivalent.
I cannot think of any conceptual reason why these two behaviours could not be mixed for a given class.
Do you have any conceptual reason of why that can be a problem?

I can only think that this is a technical problem in the puppet implementation, that could be fixed.
what prevents puppet to allow mixing these two behaviours for a given class?
(a part from a refactoring of the code...)


Regards,
David

jcbollinger

unread,
Apr 4, 2014, 10:11:39 AM4/4/14
to puppet...@googlegroups.com


On Thursday, April 3, 2014 10:31:40 AM UTC-5, David Portabella wrote:
Agree with John that you want to completely avoid using the parameterized style declaration of classes. Better to use 'include'  statements and set all of your params in Hiera. 

That's an interesting discussion, 
but that's not the point of this post.

the point of this post, as I understand it from my colleague,
is that there is a bug in puppet.

on the very least, if that is not a bug, 
puppet should complain with a clear error message of the type "Error: class 'c1' mixes include-like and resource-like declarations",


But in fact that's not the problem.  The language reference notwithstanding, you CAN mix one resource-like declaration and one or more statement-like declarations of the same class.  Doing so introduces an evaluation-order dependency (the resource-like declaration must be evaluated first), and therefore it is unwise, but it is not in itself an error.

In case it did not catch your eye, I repeat: evaluation-order dependency.  These are the bane of every manifest set, and you should strive to avoid them in any form.  I cannot emphasize that enough.  Resource-like class declarations are a particularly common form of evaluation-order dependency, but others include use of the defined() and ensure_resource() functions, both of which have lately been topics of conversation around here.

 
instead of the incomprehensible error message: "Error: Duplicate declaration: Class[C1] is already declared; cannot redeclare at /vagrant/files/aa.pp:4".



And yet that "incomprehensible" message exactly describes the problem.  If there is a comprehension issue here then it revolves around the semantics of class declarations -- which are indeed more complicated than they might at first seem -- not around that message.  If you understand class declaration semantics then the message is quite clear.  If you don't, then no error message emitted in that situation could be clear.

 

About this note:
http://docs.puppetlabs.com/puppet/latest/reference/lang_classes.html#declaring-classes
Include-Like vs. Resource-Like
Puppet has two main ways to declare classes: include-like and resource-like.
Note: These two behaviors should not be mixed for a given class. Puppet’s behavior when declaring or assigning a class with both styles is undefined, and will sometimes work and sometimes cause compilation failures.

I think that the result of class { java: } and include java are semantically equivalent.
I cannot think of any conceptual reason why these two behaviours could not be mixed for a given class.
Do you have any conceptual reason of why that can be a problem?


The result of those two declarations is semantically equivalent, provided that no declaration of class 'java' has yet been evaluated, which depends on evaluation order and on what other declarations are present in the manifest set.  That proviso is exactly the reason for the quoted recommendation.

Note also that the current language reference includes a best-practices statement that says, in part, "Most users in most situations should use include-like declarations and set parameter values in their external data" (emphasis in the original).  That has not always been there, but I fully agree -- even down to the "most".  For the particular case of class declarations that don't specify any parameters, that can be strengthened to ALL users in ALL situations.

 

I can only think that this is a technical problem in the puppet implementation, that could be fixed.
what prevents puppet to allow mixing these two behaviours for a given class?
(a part from a refactoring of the code...)



You are right that Puppet could put in special-case handling for resource-like class declarations that don't specify any parameters to treat them as fully equivalent to 'include' statements, but I'm not persuaded that doing so would be better.  For that increase in code complexity, you would just make the issue more obscure.  Then, the question would be "why does it work if I don't specify any parameters, but break with a 'duplicate declaration' error when I add one?"  You not only keep the resource-like vs. statement-like issue, but you also get inconsistency within resource-like declarations.

Moreover, special-case handling like that would also allow you to write

class { 'foo': }
class { 'foo': }

whereas it is always an error to write

anything_but_class { 'foo': }
anything_but_class { 'foo': }

Therefore, despite the constraints on resource-like class declarations (for which I, and now PL, generally recommend avoiding their use), I think their current implementation is as good as we can hope to have.


John

David Portabella

unread,
Apr 11, 2014, 11:10:37 PM4/11/14
to puppet...@googlegroups.com
I didn't know about this evaluation-order dependency.
Why does this "evaluation-order dependency" exists in puppet?
Is it done in purpose, or it is a technical problem of the puppet implementation?
Do you have an example where we would want to use this evaluation-order dependency?
Or could puppet completely remove this concept?


about the other part of your post, if I understand your post correctly, you are saying:

1- avoid using parameterized classes 
2- but yes, sometimes you need parameterized classes 
3- but that's not a problem, because the class can take the parameter values from hiera

well, 1 and 2 are in contradiction, isn't it?

and about 3, hiera is not the ultimate solution for data store.
what if you need to compute the parameter values programmatically?


David

jcbollinger

unread,
Apr 14, 2014, 10:43:19 AM4/14/14
to puppet...@googlegroups.com


On Friday, April 11, 2014 10:10:37 PM UTC-5, David Portabella wrote:
I didn't know about this evaluation-order dependency.
Why does this "evaluation-order dependency" exists in puppet?


Do you mean this particular one, or evaluation-order dependencies in general?

Anyway, I started to write a detailed response to this, but it was turning into a novel.  The bottom line is this: it would have been extremely difficult to design or implement Puppet in a way that foreclosed the possibility of users writing evaluation-order dependent manifest sets.  PL could have come closer than they did do, but that's water under the bridge.

 
Is it done in purpose, or it is a technical problem of the puppet implementation?


Evaluation-order dependency is not a design feature, but neither is it really a bug as such.  I would describe it as a characteristic of the problem space.

I don't think PL understood the magnitude of the specific associated evaluation-order dependency problem when they first rolled out parameterized classes in v2.6.0, but they certainly knew that there was one.  On the other hand, earlier versions of Puppet had different evaluation-order dependency issues surrounding classes.  It is a very difficult challenge for Puppet to protect users from all possible unwanted results of manifest evaluation order, while still providing all the desired results of manifest evaluation.

 
Do you have an example where we would want to use this evaluation-order dependency?


No.  It is always best to avoid evaluation-order dependencies in your manifests.

 
Or could puppet completely remove this concept?



PL could remove the language features and built-ins that yield the greatest exposure to evaluation-order problems (e.g. resource-like class declarations and the defined() function), but I don't think they can remove all possibility that the result of compiling a manifest set depends on the order in which classes or the declarations within are evaluated.  They cannot fix the problematic features to be non-problematic, however, as evaluation-order dependency is an inherent consequence of their nature.

As a practical matter, PL is unlikely to remove the problematic features any time in the foreseeable future because the disruption to its user base would be prohibitive.  That is, despite their problems, many people do use and rely on features encumbered with evaluation-order dependency issues.
 


about the other part of your post, if I understand your post correctly, you are saying:

1- avoid using parameterized classes 


No.  I once did say that, but the actual problem is with the resource-like class declaration syntax.  Since Puppet 3.0, parameterized classes can be used without the resource-like syntax, and that's just fine.

 
2- but yes, sometimes you need parameterized classes 


No, you never need to use parameterized classes.  If you are determined to avoid resource-like class declarations, then you can replace each parameterized class in your manifest set with a non-parameterized version that obtains its data via direct hiera() calls.  But that's beside the point, because parameterized classes are not themselves the problem, and not what I was talking about.

My comments were about the resource-like class declaration syntax.  You don't ever need that, either, but under some circumstances it is both convenient and relatively safe.  Specifically, within a module, you can use it -- if you're careful -- to declare internal classes of the module.  Note well: those conditions do not protect you from evaluation-order dependency; they merely allow you to manage it, because you can know and control all the places where internal classes are (supposed to be) used.  And that's why I say only "relatively" safe.

 
3- but that's not a problem, because the class can take the parameter values from hiera
 

well, 1 and 2 are in contradiction, isn't it?


Your interpretation presents a contradiction, but what I am trying to communicate to you does not contain one.

But yes, PL and I both say that your classes should generally obtain non-default class parameter values via hiera, rather than via resource-like declarations.

 

and about 3, hiera is not the ultimate solution for data store.
what if you need to compute the parameter values programmatically?


Hiera's YAML back end is not the ultimate solution, but the Hiera framework can be.  You can plug in pretty much any kind of data lookup or computation.

Alternatively, you can put your computation inside the class, and feed it the input values as parameters.  Or you can make exactly one class responsible for performing any needed computations and declaring the class for which you want to use a resource-like declaration, and any node or other class must declare the wrapper class instead (using 'include' or one of its brethren).

What neither you nor PL can do is render resource-like class declaration syntax devoid of evaluation-order implications.  I'm sorry that that is such a consternation for you.


John

David Portabella

unread,
Apr 15, 2014, 10:21:38 AM4/15/14
to puppet...@googlegroups.com
Ok, I see.

Thanks for all this discussion!


> No, you never need to use parameterized classes.  
> If you are determined to avoid resource-like class declarations, 
> then you can replace each parameterized class in your manifest set with a non-parameterized version that obtains its data via direct hiera() calls.

you mean replacing: 
class tomcat (
  port = hiera('tomcat_port', 7070)
  ssl_port = hiera('tomcat_port', 7071)
) {
  notice $port
  notice $ssl_port
}
by:
class tomcat {
  $port = hiera('tomcat_port', 7070)
  $ssl_port = hiera('tomcat_port', 7071)
  notice $port
  notice $ssl_port
}
?
for a java/scala software developer like me, this does not look a good,
because it makes it more difficult to unit test.
maybe with puppet it is easy to build and pass different hiera data for unit testing?



> Hiera's YAML back end is not the ultimate solution, but the Hiera framework can be.  
> You can plug in pretty much any kind of data lookup or computation.

Ok. I didn't know about this neither. I'll take a look.


so, one specific example,
someone (not me) implemented a class tomcat with parameters port and ssl_port.
I want to use that class, 
and I want that the ssl_port is always port + 1 (I don't want this to be configurable in hiera)
so, in my hiera data, I will specify port, and then I have my class:
class application ($port) {
  class {tomcat:
    port     => $port
    ssl_port => $port+1
  }
  class {nginx:
    ...
  }
  # configuration files...
}

how would you do this without using resource-like class declaration?


> Or you can make exactly one class responsible for performing any needed computations and declaring the 
> class for which you want to use a resource-like declaration, and any node or other class must declare the 
> wrapper class instead (using 'include' or one of its brethren).

I see. similar to the example42 params pattern. you mean something like:
class parameters {
  $port = hiera("port")
  $ssl_port = $port + 1
}

class tomcat {
  include parameters
  notice $parameters::port
  notice $parameters::ssl_port
}



> I'm sorry that that is such a consternation for you.

haha, it's not that I am not consternated, but you know,
I come from an object-oriented and function programming paradigm,
and unlearning is twice as hard as learning. ;)


Regards,
David

Felix Frank

unread,
Apr 15, 2014, 11:45:04 AM4/15/14
to puppet...@googlegroups.com
On 04/15/2014 04:21 PM, David Portabella wrote:
> for a java/scala software developer like me, this does not look a good,
> because it makes it more difficult to unit test.
> maybe with puppet it is easy to build and pass different hiera data for
> unit testing?

Sure, that shouldn't be (much) worse than your usual old unit test. See
https://github.com/TomPoulton/rspec-puppet-unit-testing#mocking-hiera

Cheers,
Felix

jcbollinger

unread,
Apr 15, 2014, 12:21:48 PM4/15/14
to puppet...@googlegroups.com


On Tuesday, April 15, 2014 9:21:38 AM UTC-5, David Portabella wrote:
Ok, I see.

Thanks for all this discussion!


> No, you never need to use parameterized classes.  
> If you are determined to avoid resource-like class declarations, 
> then you can replace each parameterized class in your manifest set with a non-parameterized version that obtains its data via direct hiera() calls.

you mean replacing: 
class tomcat (
  port = hiera('tomcat_port', 7070)
  ssl_port = hiera('tomcat_port', 7071)
) {
  notice $port
  notice $ssl_port
}
by:
class tomcat {
  $port = hiera('tomcat_port', 7070)
  $ssl_port = hiera('tomcat_port', 7071)
  notice $port
  notice $ssl_port
}
?


Yes, that's pretty much what I mean, but it is poor form to put explicit hiera calls in your parameter list, because Puppet (v3+) performs hiera lookups for class parameters automatically (using a key based on class name and parameter name; see http://docs.puppetlabs.com/puppet/3/reference/lang_classes.html#include-like-vs-resource-like).  If you are going to write parameterized classes -- and that's not a bad thing in itself -- then the best form would be more like this:

class tomcat (
  port = 7070
  ssl_port = 7071
) {
  notice $port
  notice $ssl_port
}

Puppet will first attempt to resolve the parameters via hiera keys 'tomcat::port' and 'tomcat::ssl_port', and in each case it will use the declared default value if the lookup fails.  Your alternative form is exactly what I meant by a way to write the same class without parameters.

 
for a java/scala software developer like me, this does not look a good,
because it makes it more difficult to unit test.


In a sense, the non-parameterized version is easier to unit test, because you have fewer cases (depending on how thorough you are).  You have the cases for hiera-provided data either way, and for parameterized class you also have cases for DSL-declared parameter values.

Before this goes too far off on a tangent, though, I reiterate that it is not parameterized classes themselves that are problematic (unless indirectly).  The problem is associated with the resource-like class declaration syntax.  The resource-like syntax can be used even with unparameterized classes, so it really is a separate consideration.

 
maybe with puppet it is easy to build and pass different hiera data for unit testing?



There is, for example, https://github.com/amfranz/rspec-hiera-puppet.  No doubt there are others.  Moreover, because Hiera supports pluggable back ends and is comparatively simple, it is likely that you could build your own without too much trouble if what's already available doesn't suit you.




> Hiera's YAML back end is not the ultimate solution, but the Hiera framework can be.  
> You can plug in pretty much any kind of data lookup or computation.

Ok. I didn't know about this neither. I'll take a look.


so, one specific example,
someone (not me) implemented a class tomcat with parameters port and ssl_port.
I want to use that class, 
and I want that the ssl_port is always port + 1 (I don't want this to be configurable in hiera)


Every parameter of every class is ALWAYS configurable via Hiera (in Puppet 3+).  That was one if the most significant advances in Puppet 3.  You can override whatever Hiera data may be provided via a resource-like class declaration, but that opens you up to problems, as we have been discussing.

 
so, in my hiera data, I will specify port, and then I have my class:
class application ($port) {
  class {tomcat:
    port     => $port
    ssl_port => $port+1
  }
  class {nginx:
    ...
  }
  # configuration files...
}

how would you do this without using resource-like class declaration?



At the present time, I think I would need to write a custom hiera back end that served keys 'tomcat::port' and 'tomcat::ssl_port' with values having the desired relationship, and to insert that into my hiera configuration at higher priority than the YAML back end.  The class 'application' then declares class 'tomcat' as "include 'tomcat'".  Really, though, that's a heck of a PITA for such a small constraint.  Why not just declare both parameters in the normal YAML back end, and verify the proper ports via functional testing?

 

> Or you can make exactly one class responsible for performing any needed computations and declaring the 
> class for which you want to use a resource-like declaration, and any node or other class must declare the 
> wrapper class instead (using 'include' or one of its brethren).

I see. similar to the example42 params pattern. you mean something like:
class parameters {
  $port = hiera("port")
  $ssl_port = $port + 1
}



Yuck!
  1. Unless for some very special need (for which I do not presently have an example), do not use hiera() calls as parameter defaults.
  2. Never set a class parameter default as a function of other class parameter values.  It is not reliable.
But you could do this:

class parameters ($port) {
  $ssl_port = $port +1
}

 
class tomcat {
  include parameters
  notice $parameters::port
  notice $parameters::ssl_port
}




And then the rest of class 'tomcat' uses $parameters::port and $parameters::ssl_port for the HTTP and HTTPS ports?  Ok, but that requires you to modify the 'tomcat' class.  If you're willing to do that, then why introduce a new class as a data intermediary?

My comments about a wrapper class were directed more towards your class 'application' above or something very similar.  The parameter $application::port should in that case be provided by Hiera (else you just move the problem up one level), and you must enforce a restriction that there is no other declaration of class 'tomcat' anywhere in your manifest set.  It's that last bit that tends to be the sticking point, especially if you have a large Puppet code base or use a lot of third-party modules.


John

David Portabella

unread,
May 19, 2014, 7:48:36 AM5/19/14
to puppet...@googlegroups.com
 
 
so, one specific example,
someone (not me) implemented a class tomcat with parameters port and ssl_port.
I want to use that class, 
and I want that the ssl_port is always port + 1 (I don't want this to be configurable in hiera) 
so, in my hiera data, I will specify port, and then I have my class:   

class application ($port) {
  class {tomcat:
    port     => $port
    ssl_port => $port+1
  }
  class {nginx:
    ...
  }
  # configuration files...
}

how would you do this without using resource-like class declaration?

At the present time, I think I would need to write a custom hiera back end that served keys 'tomcat::port' and 'tomcat::ssl_port' with values having the desired relationship, and to insert that into my hiera configuration at higher priority than the YAML back end.  The class 'application' then declares class 'tomcat' as "include 'tomcat'".  Really, though, that's a heck of a PITA for such a small constraint.  Why not just declare both parameters in the normal YAML back end, and verify the proper ports via functional testing?

that's the point. I don't think this is a "small" constraint. I often find this dependency injection use case,
and I don't see an easy solution with puppet.


 
But you could do this:

class parameters ($port) {
  $ssl_port = $port +1
}
 
class tomcat {
  include parameters
  notice $parameters::port
  notice $parameters::ssl_port
}

And then the rest of class 'tomcat' uses $parameters::port and $parameters::ssl_port for the HTTP and HTTPS ports?  Ok, but that requires you to modify the 'tomcat' class.  If you're willing to do that, then why introduce a new class as a data intermediary?

I wrote that just to see if I understood your point. Yes, I cannot modify the 'tomcat' class, so this option is not possible.



Henrik Lindberg

unread,
May 19, 2014, 5:41:25 PM5/19/14
to puppet...@googlegroups.com
On 2014-14-04 16:43, jcbollinger wrote:
>
>
> On Friday, April 11, 2014 10:10:37 PM UTC-5, David Portabella wrote:
>
> I didn't know about this /evaluation-order dependency./
> Why does this "evaluation-order dependency" exists in puppet?
>
>
>
> Do you mean this particular one, or evaluation-order dependencies in
> general?
>
> Anyway, I started to write a detailed response to this, but it was
> turning into a novel.

I did write up a blog post about "ordering" and how puppet works in this
respect.
http://puppet-on-the-edge.blogspot.se/2014/04/getting-your-puppet-ducks-in-row.html

I hope it provides some insights into the internal workings of puppet.

- henrik


jcbollinger

unread,
May 20, 2014, 11:20:02 AM5/20/14
to puppet...@googlegroups.com


On Monday, May 19, 2014 6:48:36 AM UTC-5, David Portabella wrote:
 
 
so, one specific example,
someone (not me) implemented a class tomcat with parameters port and ssl_port.
I want to use that class, 
and I want that the ssl_port is always port + 1 (I don't want this to be configurable in hiera) 
so, in my hiera data, I will specify port, and then I have my class:   

class application ($port) {
  class {tomcat:
    port     => $port
    ssl_port => $port+1
  }
  class {nginx:
    ...
  }
  # configuration files...
}

how would you do this without using resource-like class declaration?

At the present time, I think I would need to write a custom hiera back end that served keys 'tomcat::port' and 'tomcat::ssl_port' with values having the desired relationship, and to insert that into my hiera configuration at higher priority than the YAML back end.  The class 'application' then declares class 'tomcat' as "include 'tomcat'".  Really, though, that's a heck of a PITA for such a small constraint.  Why not just declare both parameters in the normal YAML back end, and verify the proper ports via functional testing?

that's the point. I don't think this is a "small" constraint. I often find this dependency injection use case,
and I don't see an easy solution with puppet.



Well, I suppose that you can always put enough constraints on the solutions you're willing to accept to make it difficult for whatever software you're targeting to handle.

In this case, you want to use an existing class that has more general parameterization than you actually want to allow, and that's really where your problem starts.  Then you're unwilling to rely on the parameter relationship you want to be maintained in the data for separate parameters.  I don't necessarily blame you for that, but it complicates your problem.

Finally, you (sensibly) want to avoid your declarations being sensitive to evaluation order.  I applaud that, but it does take a whole class of alternatives off the table.

The ultimate solution for dependency injection in Puppet is a custom Hiera back end, which I mentioned earlier.  Such a thing can solve your problem.  One specific to this purpose would be pretty quick and easy to write, I think, but if there are more than one or two such constraints to serve then a separate back end for each is not such a great solution.  I can imagine a couple ways to build a more general rules-based back end, but that's suddenly a lot more work.  In the end, though, if you have a complicated problem then you are likely to need a complicated solution.


John

Reply all
Reply to author
Forward
0 new messages