Ti Leggett
2013-Jan-28 16:24 UTC
[Puppet Users] Referencing a variable from one class in another
I have one module, kibana, that defines a file snippet for the apache module to fulfill (e.g., /etc/https/conf.d/kibana.conf). The apache::params class defines a variable of the path of where this snippet should be placed, $config_d. The snippet uses this variable in its definition. However, it seems that the snippet never resolves the $apache::params::config_d variable, and I''m guessing because the order of instantiation isn''t right. I''ve tried requiring the apache class from the snippet, which seems it would enforce proper ordering, and I''ve tried inheriting the kibana::apache class from apache::params. The former still doesn''t resolve and the latter throws an agent error. What is the proper way for using a variable in one class in another class when manifests/nodes.pp definitions of the classes can''t be guaranteed? Here are snippets of the class definitions I''m using: http://pastie.org/5910079 -- 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+unsubscribe@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
Calvin Walton
2013-Jan-28 16:56 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Mon, 2013-01-28 at 08:24 -0800, Ti Leggett wrote:> I have one module, kibana, that defines a file snippet for the apache > module to fulfill (e.g., /etc/https/conf.d/kibana.conf). The apache::params > class defines a variable of the path of where this snippet should be > placed, $config_d. The snippet uses this variable in its definition. > However, it seems that the snippet never resolves the > $apache::params::config_d variable, and I''m guessing because the order of > instantiation isn''t right. I''ve tried requiring the apache class from the > snippet, which seems it would enforce proper ordering, and I''ve tried > inheriting the kibana::apache class from apache::params. The former still > doesn''t resolve and the latter throws an agent error. What is the proper > way for using a variable in one class in another class when > manifests/nodes.pp definitions of the classes can''t be guaranteed? > > Here are snippets of the class definitions I''m using: > http://pastie.org/5910079Variable references like $apache::params::config_d are parse-order dependant. The class apache::params has to be parsed on the master before you reference the variable. (Order of application doesn''t matter, so you don''t need to use ''require'') The fix is trivial, just add an "include apache::params" (or even just "include apache") at the top of your kibana::apache class, like so: # modules/kibana/manifests/apache.pp class kibana::apache ( $version = $kibana::params::parameters[''version''], ) { include apache::params @file { $kibana::params::apache_config: ... However, this conflicts with the class {} style declarations in your apache/manifests/init.pp file. For best results, you should switch those to use the "include" method as well. -- Calvin Walton <calvin.walton@kepstin.ca> -- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
Ti Leggett
2013-Jan-28 17:00 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Jan 28, 2013, at 10:56 AM, Calvin Walton <calvin.walton@kepstin.ca> wrote:> The fix is trivial, just add an "include apache::params" (or even just > "include apache") at the top of your kibana::apache class, like so: > > # modules/kibana/manifests/apache.pp > class kibana::apache ( > $version = $kibana::params::parameters[''version''], > ) { > include apache::params > @file { $kibana::params::apache_config: > ... > > However, this conflicts with the class {} style declarations in your > apache/manifests/init.pp file. For best results, you should switch those > to use the "include" method as well.Thanks for the response. Can multiple classes include the same class. Let''s say I instantiate the apache class from manifests/nodes.pp which in turns includes apache::params. Can kibana include apache::params then as well with no conflict. I know you can''t do this with the class {} style declarations. Also, I thought the class {} style declarations were the preferred way or is that just in the nodes.pp file? -- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
Calvin Walton
2013-Jan-28 17:07 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Mon, 2013-01-28 at 11:00 -0600, Ti Leggett wrote:> On Jan 28, 2013, at 10:56 AM, Calvin Walton <calvin.walton@kepstin.ca> wrote: > > > The fix is trivial, just add an "include apache::params" (or even just > > "include apache") at the top of your kibana::apache class, like so: > > > > # modules/kibana/manifests/apache.pp > > class kibana::apache ( > > $version = $kibana::params::parameters[''version''], > > ) { > > include apache::params > > @file { $kibana::params::apache_config: > > ... > > > > However, this conflicts with the class {} style declarations in your > > apache/manifests/init.pp file. For best results, you should switch those > > to use the "include" method as well. > > > Thanks for the response. > > Can multiple classes include the same class. Let''s say I instantiate > the apache class from manifests/nodes.pp which in turns includes > apache::params. Can kibana include apache::params then as well with no > conflict. I know you can''t do this with the class {} style > declarations. Also, I thought the class {} style declarations were the > preferred way or is that just in the nodes.pp file?Yes, with the "include" syntax, you can include a class multiple times from different places with no conflicts. It''s a no-op if the class is already included. The "include" method is the preferred syntax (in my opinion, but I''m sure other share it), due to this feature - particularly if you''re using hiera to pull configuration in. The only time you should be using the class {} syntax is if you need to pass in class parameters and can''t use hiera. -- Calvin Walton <calvin.walton@kepstin.ca> -- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
Luke Bigum
2013-Jan-28 17:12 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Monday, January 28, 2013 5:00:24 PM UTC, Ti Leggett wrote:> > Thanks for the response. > > Can multiple classes include the same class. Let''s say I instantiate the > apache class from manifests/nodes.pp which in turns includes > apache::params. Can kibana include apache::params then as well with no > conflict. I know you can''t do this with the class {} style declarations. > Also, I thought the class {} style declarations were the preferred way or > is that just in the nodes.pp file?Yes, they can. That''s the main selling point for the "include class" syntax. And you are right, you can''t use the class {...} syntax more than once or you get a duplicate definition error. However, let me warn you against going overboard with having classes include other classes from other modules. It can be annoying to track down where resources coming from for any given node if you''ve got cross module inclusion: kibana includes httpd includes mod_ssl includes openssl includes somethingelse includes ... How did this get on here? A cleaner way might be to declare cross module relationships using the Arrow operators: class kibana::apache { Class[apache::params] -> Class[kibana::apache] ... } And then you make a house rule to have all your classes instantiated in your node definitions: node woof { class kibana class apache::params } If apache::params is missing, you''ll get an error saying so. It also fits rather nicely into an ENC if you want to go in that direction now / later. -Luke -- 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+unsubscribe@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
Calvin Walton
2013-Jan-28 17:17 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Mon, 2013-01-28 at 09:12 -0800, Luke Bigum wrote:> On Monday, January 28, 2013 5:00:24 PM UTC, Ti Leggett wrote:> However, let me warn you against going overboard with having classes > include other classes from other modules. It can be annoying to track down > where resources coming from for any given node if you''ve got cross module > inclusion: kibana includes httpd includes mod_ssl includes openssl includes > somethingelse includes ... How did this get on here? > > A cleaner way might be to declare cross module relationships using the > Arrow operators: > > class kibana::apache { > Class[apache::params] -> Class[kibana::apache] > ... > } > > And then you make a house rule to have all your classes instantiated in > your node definitions: > > node woof { > class kibana > class apache::params > } > > If apache::params is missing, you''ll get an error saying so. It also fits > rather nicely into an ENC if you want to go in that direction now / later.While this is a good idea in general, it doesn''t solve Luke''s original problem. In order to reference a variable $apache::params::something from inside the kibana::apache class, you need the apache::params class to be parsed on the puppet master before the kibana::apache class. This is a parse-time ordering problem, not a run-time ordering problem. The only way to force parse-time ordering right now is to do a direct include, unfortunately. -- Calvin Walton <calvin.walton@kepstin.ca> -- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
jcbollinger
2013-Jan-29 14:51 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Monday, January 28, 2013 11:17:03 AM UTC-6, Calvin Walton wrote:> > On Mon, 2013-01-28 at 09:12 -0800, Luke Bigum wrote: > > On Monday, January 28, 2013 5:00:24 PM UTC, Ti Leggett wrote: > > > However, let me warn you against going overboard with having classes > > include other classes from other modules. It can be annoying to track > down > > where resources coming from for any given node if you''ve got cross > module > > inclusion: kibana includes httpd includes mod_ssl includes openssl > includes > > somethingelse includes ... How did this get on here? > > > > A cleaner way might be to declare cross module relationships using the > > Arrow operators: > > > > class kibana::apache { > > Class[apache::params] -> Class[kibana::apache] > > ... > > } > > > > And then you make a house rule to have all your classes instantiated in > > your node definitions: > > > > node woof { > > class kibana > > class apache::params > > } > > > > If apache::params is missing, you''ll get an error saying so. It also > fits > > rather nicely into an ENC if you want to go in that direction now / > later. > > While this is a good idea in general, it doesn''t solve Luke''s original > problem. In order to reference a variable $apache::params::something > from inside the kibana::apache class, you need the apache::params class > to be parsed on the puppet master before the kibana::apache class. This > is a parse-time ordering problem, not a run-time ordering problem. >Exactly.> > The only way to force parse-time ordering right now is to do a direct > include, unfortunately. > >Yes, but I''m not sure I would say "unfortunately" there. The problem is not so much with any limitation of Puppet DSL in this area, but rather an issue of module design and manifest set architecture. I mean, one should be very careful and deliberate about designing modules such that their classes need to rely on class variables of other modules'' classes. Indeed, it is probably a poor idea to implement such a design unilaterally -- instead, the module providing the class variables should be designed and implemented in anticipation of that usage as well. That probably means centralizing all variables intended for cross-module reference in one well-known class, documenting their names and value ranges, and committing to avoiding incompatible changes there. John -- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
Ti Leggett
2013-Jan-29 15:07 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Jan 29, 2013, at 8:51 AM, jcbollinger <John.Bollinger@stJude.org> wrote:>> The only way to force parse-time ordering right now is to do a direct >> include, unfortunately. >> > > > Yes, but I''m not sure I would say "unfortunately" there. The problem is not so much with any limitation of Puppet DSL in this area, but rather an issue of module design and manifest set architecture. > > I mean, one should be very careful and deliberate about designing modules such that their classes need to rely on class variables of other modules'' classes. Indeed, it is probably a poor idea to implement such a design unilaterally -- instead, the module providing the class variables should be designed and implemented in anticipation of that usage as well. That probably means centralizing all variables intended for cross-module reference in one well-known class, documenting their names and value ranges, and committing to avoiding incompatible changes there. >I''m not sure I fully agree with this from a design standpoint. In object-oriented programming, one of the design principles is that variables relating to the object are encapsulated within the object and exposed or not depending on how they should be accessed. IMHO, it also makes it more obfuscated when you''re accessing say the SSL CA cert path variable and that''s in some ''common'' module that everything has to include. Granted it makes it easier on the module developer - just always in include the common module and your variables should be there - but it also makes it less explicit. I would argue, if you''re writing a module that depends on using the SSL CA cert path you have some dependency on the SSL module and should have some understanding of what that module does and the ramifications of using that module, so you should explicitly include that module for that dependency. In just about every language you must include the external modules/libraries you depend on for functionality outside the standard norm. In puppet the standard norm - the stdlib.h equivalent if you will - I would consider to be facter variables. You want to use LDAP or SSL or Kerberos? You best include those modules explicitly and figure out what you can use from them - ldap.h <> ldap::params, ssl.h <> ssl::params, etc. Standardize how you create these public puppet ''headers'' and use them explicitly and appropriately that way. At least that''s my 2c. -- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
Matthew Pounsett
2013-Jan-29 18:42 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Tuesday, 29 January 2013 10:07:29 UTC-5, Ti Leggett wrote:> > I''m not sure I fully agree with this from a design standpoint. In > object-oriented programming, one of the design principles is that variables > relating to the object are encapsulated within the object and exposed or > not depending on how they should be accessed. IMHO, it also makes it more > obfuscated when you''re accessing say the SSL CA cert path variable and > that''s in some ''common'' module that everything has to include. Granted it > makes it easier on the module developer - just always in include the common > module and your variables should be there - but it also makes it less > explicit.How would you handle variables that wouldn''t otherwise be tied to a module? An example I ran into when I was doing our first deployment was the path to various shells. They vary from OS to OS, but rarely (if ever) need a whole module to manage them. The paths get referenced in many places, such as when adding users or installing scripts (erb used in the bangpath). I''ve found it useful to have things like $::site::params::bash and $::site::params:tcsh for shells, and other site-wide variables for other things. It means I only need to put the case logic to figure out the path based on the OS in one place, and not have it scattered around several modules that all need to figure out the same thing. -- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
Ti Leggett
2013-Jan-29 18:58 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Jan 29, 2013, at 12:42 PM, Matthew Pounsett <matt.pounsett@gmail.com> wrote:> > > On Tuesday, 29 January 2013 10:07:29 UTC-5, Ti Leggett wrote: > I''m not sure I fully agree with this from a design standpoint. In object-oriented programming, one of the design principles is that variables relating to the object are encapsulated within the object and exposed or not depending on how they should be accessed. IMHO, it also makes it more obfuscated when you''re accessing say the SSL CA cert path variable and that''s in some ''common'' module that everything has to include. Granted it makes it easier on the module developer - just always in include the common module and your variables should be there - but it also makes it less explicit. > > How would you handle variables that wouldn''t otherwise be tied to a module? > > An example I ran into when I was doing our first deployment was the path to various shells. They vary from OS to OS, but rarely (if ever) need a whole module to manage them. The paths get referenced in many places, such as when adding users or installing scripts (erb used in the bangpath). I''ve found it useful to have things like $::site::params::bash and $::site::params:tcsh for shells, and other site-wide variables for other things. It means I only need to put the case logic to figure out the path based on the OS in one place, and not have it scattered around several modules that all need to figure out the same thing. >I include that in the module that installs the shell packages and configures them, in my case, I call it base. In other words, the variables should be as close to the things they affect or are affected by. Just because every node might include base (or site) doesn''t mean every variable you''ll ever want to use should be in there. That, to me, creates a messier and more confusing dependency relationship between modules that use a variable and what that variable ultimately affects. -- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
Matthew Pounsett
2013-Jan-29 22:19 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Tuesday, 29 January 2013 13:58:20 UTC-5, Ti Leggett wrote:> > I include that in the module that installs the shell packages and > configures them, in my case, I call it base. In other words, the variables > should be as close to the things they affect or are affected by. Just > because every node might include base (or site) doesn''t mean every variable > you''ll ever want to use should be in there. That, to me, creates a messier > and more confusing dependency relationship between modules that use a > variable and what that variable ultimately affects.If you have a module that installs and configures those shells, then great. But many systems come with those shells preinstalled, and there''s nothing to manage. Perhaps shells were a bad example, since one of tcsh or bash may need to be added to an OS by puppet. What about the path to sed? That''s part of the base OS for all systems I manage, but the path varies from OS to OS. It seems overly cumbersome to me to create an entire module just to assign one variable, and then repeat that for a dozen or so other variables with similar circumstances. It seems cleaner to have a single small module that contains site-wide definitions that aren''t obviously tied to modules of their own. -- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
Ti Leggett
2013-Jan-30 14:32 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Jan 29, 2013, at 4:19 PM, Matthew Pounsett <matt.pounsett@gmail.com> wrote:> > > On Tuesday, 29 January 2013 13:58:20 UTC-5, Ti Leggett wrote: >> I include that in the module that installs the shell packages and configures them, in my case, I call it base. In other words, the variables should be as close to the things they affect or are affected by. Just because every node might include base (or site) doesn''t mean every variable you''ll ever want to use should be in there. That, to me, creates a messier and more confusing dependency relationship between modules that use a variable and what that variable ultimately affects. >> > If you have a module that installs and configures those shells, then great. But many systems come with those shells preinstalled, and there''s nothing to manage. Perhaps shells were a bad example, since one of tcsh or bash may need to be added to an OS by puppet. What about the path to sed? That''s part of the base OS for all systems I manage, but the path varies from OS to OS. It seems overly cumbersome to me to create an entire module just to assign one variable, and then repeat that for a dozen or so other variables with similar circumstances. It seems cleaner to have a single small module that contains site-wide definitions that aren''t obviously tied to modules of their own. >If the package or service comes standard with many OSes (my standard is the bare bones basic set, not the ''default'') then I would argue they should go in the module that configures all of those base packages/services. However, I still don''t think that that module is a suitable place for all possible variables that another package may want to use at some point in the future... possibly. Take for instance examples I''m currently using: Apache''s configuration directory (/etc/httpd/conf.d on RH, /etc/apache2/conf.d on Deb) or rsyslog directories or RADIUS directories or SSL certificate paths or any number of packages that are completely optional on some hosts. All of these are completely optional, some hosts may not install them, some may, some may install alternatives to them (syslog or syslog-ng), but when they''re installed and used the variables within are very critical. I don''t think these variables should be shoved into the base module just because it''s already being used on every host. They should be left in the module that it matters to, because if you need that variable, you should be pulling in that module anyway - why put in an apache snippet (and need the apache config dir) if you''re not already running apache and therefor pulling in that module. -- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
jcbollinger
2013-Jan-30 15:31 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Tuesday, January 29, 2013 9:07:29 AM UTC-6, Ti Leggett wrote:> > > On Jan 29, 2013, at 8:51 AM, jcbollinger wrote: > > >> The only way to force parse-time ordering right now is to do a direct > >> include, unfortunately. > >> > > > > > > Yes, but I''m not sure I would say "unfortunately" there. The problem is > not so much with any limitation of Puppet DSL in this area, but rather an > issue of module design and manifest set architecture. > > > > I mean, one should be very careful and deliberate about designing > modules such that their classes need to rely on class variables of other > modules'' classes. Indeed, it is probably a poor idea to implement such a > design unilaterally -- instead, the module providing the class variables > should be designed and implemented in anticipation of that usage as well. > That probably means centralizing all variables intended for cross-module > reference in one well-known class, documenting their names and value > ranges, and committing to avoiding incompatible changes there. > > > > I''m not sure I fully agree with this from a design standpoint. In > object-oriented programming, one of the design principles is that variables > relating to the object are encapsulated within the object and exposed or > not depending on how they should be accessed.Indeed so. Do be aware, however, that Puppet DSL is not an object-oriented language. Among other things, it has no language-enforced encapsulation at all, and Puppet "classes" are not classes in the OO sense of the term. Puppet has no accessor methods (or any methods at all, actually), so the only external interface that modules can provide consists of the data relied upon and and declared by the module. Inasmuch as one can apply OO principles even in contexts that are not natively OO, however, my advice cleaves closely to OO orthodoxy by recommending well-defined and documented component interfaces and discretionary observation of encapsulation (since the language won''t enforce it). The only way to adhere more strictly to OO principles would be for modules to avoid relying on each others'' data at all. That''s a nice ideal, but it is often not practical to apply as an absolute requirement. Such a recommendation would not have been responsive to the question, anyway.> IMHO, it also makes it more obfuscated when you''re accessing say the SSL > CA cert path variable and that''s in some ''common'' module that everything > has to include.If OO is the ideal design approach (which is not at all clear, but you brought it up) then it would dictate that related data be grouped into objects. That''s the most fundamental and incontrovertible principle of OO -- you can have OO without inheritance, without polymorphism, even without enforced encapsulation, but you can''t have it without *objects*. Puppet''s analogs of objects are classes and resources. Ergo, if one wants to pursue an OO strategy then classes should contain and own their own data. More generally, modules aren''t modular if they have to rely on all their data being provided by some other module. Nevertheless, it doesn''t really matter which class in which module is documented to provide the data of interest. As long as the module documents it and commits to those details remaining stable, it amounts to the same thing I described.> Granted it makes it easier on the module developer - just always in > include the common module and your variables should be there - but it also > makes it less explicit. I would argue, if you''re writing a module that > depends on using the SSL CA cert path you have some dependency on the SSL > module and should have some understanding of what that module does and the > ramifications of using that module, so you should explicitly include that > module for that dependency. In just about every language you must include > the external modules/libraries you depend on for functionality outside the > standard norm. In puppet the standard norm - the stdlib.h equivalent if you > will - I would consider to be facter variables. You want to use LDAP or SSL > or Kerberos? You best include those modules explicitly and figure out what > you can use from them - ldap.h <> ldap::params, ssl.h <> ssl::params, etc. > Standardize how you create these public puppet ''headers'' and use them > explicitly and appropriately that way.And now that you drop the idea of a common data module, we come back around to using other modules'' classes'' variables. Are you honestly arguing that it is better to analyze class implementations and pull out variables willy-nilly than to define and rely on documented interfaces? I think you owe a penance at the OO altar. John -- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
Ti Leggett
2013-Jan-30 16:21 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Jan 30, 2013, at 9:31 AM, jcbollinger <John.Bollinger@stJude.org> wrote:> >> I''m not sure I fully agree with this from a design standpoint. In object-oriented programming, one of the design principles is that variables relating to the object are encapsulated within the object and exposed or not depending on how they should be accessed. >> > > Indeed so. Do be aware, however, that Puppet DSL is not an object-oriented language. Among other things, it has no language-enforced encapsulation at all, and Puppet "classes" are not classes in the OO sense of the term. Puppet has no accessor methods (or any methods at all, actually), so the only external interface that modules can provide consists of the data relied upon and and declared by the module. > > Inasmuch as one can apply OO principles even in contexts that are not natively OO, however, my advice cleaves closely to OO orthodoxy by recommending well-defined and documented component interfaces and discretionary observation of encapsulation (since the language won''t enforce it). The only way to adhere more strictly to OO principles would be for modules to avoid relying on each others'' data at all. That''s a nice ideal, but it is often not practical to apply as an absolute requirement. Such a recommendation would not have been responsive to the question, anyway. >I''m aware that Puppet DSL is much more declarative than OO, but in this particular light there is a lot of cosmetic lip-service to typical OO design - classes, inheritance (though limited), paramerterized instantiation of classes - which is why I brought that up. I''m fine with using those concepts and what their limitations are in the Puppet implementation. I''m also not advocating to adhere more strongly to OO ideals. At the end of the day, Puppet, for me at least, is a configuration management system. In that light it is more critical for me that it do that well than adhere to some design principle rigidly just because. And one of the things that makes a good config mgmt system work well is reducing the duplication of data that can cause inconsistencies. If a rigid adherence to OO (or declarative or imperative or whatever) design principles makes that hard or impossible, it should be carefully examined. A huge way I''ve seen config mgmt break down is when data is duplicated in multiple places and a need to change or update that data is needed and one or two spots are forgotten about making things break or behave badly causing me more time debugging what should have been a simple (and consistent) change.>> IMHO, it also makes it more obfuscated when you''re accessing say the SSL CA cert path variable and that''s in some ''common'' module that everything has to include. >> > > If OO is the ideal design approach (which is not at all clear, but you brought it up) then it would dictate that related data be grouped into objects. That''s the most fundamental and incontrovertible principle of OO -- you can have OO without inheritance, without polymorphism, even without enforced encapsulation, but you can''t have it without objects. > > Puppet''s analogs of objects are classes and resources. Ergo, if one wants to pursue an OO strategy then classes should contain and own their own data. > > More generally, modules aren''t modular if they have to rely on all their data being provided by some other module. Nevertheless, it doesn''t really matter which class in which module is documented to provide the data of interest. As long as the module documents it and commits to those details remaining stable, it amounts to the same thing I described. >Agreed (See above), but if every module has to define ssl_ca_path every time they need it, I don''t want that methodology because when I need to change or update ssl_ca_path, I need to remember every module that defined and update it instead of updating in the one location that all dependent modules pull from. Sure I can define all this in one common module that every module that has a ''public'' variable places stuff in, or I can define it in hiera and every module pulls it from there (though there are inheritance issues there that makes it less ideal), but at the end of the day I think we agree you should pick a method, document it, and stick to it.>> Granted it makes it easier on the module developer - just always in include the common module and your variables should be there - but it also makes it less explicit. I would argue, if you''re writing a module that depends on using the SSL CA cert path you have some dependency on the SSL module and should have some understanding of what that module does and the ramifications of using that module, so you should explicitly include that module for that dependency. In just about every language you must include the external modules/libraries you depend on for functionality outside the standard norm. In puppet the standard norm - the stdlib.h equivalent if you will - I would consider to be facter variables. You want to use LDAP or SSL or Kerberos? You best include those modules explicitly and figure out what you can use from them - ldap.h <> ldap::params, ssl.h <> ssl::params, etc. Standardize how you create these public puppet ''headers'' and use them explicitly and appropriately that way. >> > > And now that you drop the idea of a common data module, we come back around to using other modules'' classes'' variables. Are you honestly arguing that it is better to analyze class implementations and pull out variables willy-nilly than to define and rely on documented interfaces? I think you owe a penance at the OO altar. >I''m arguing that no more than I would argue having to delve into the source code of openssl in order to use it in my C program - that''s what the header is for. I''m arguing to define your class implementations such that the nitty gritty of that class'' implementation need not be inspected in order for another module to make use of it, not mash all the public bits in to one globally public class that has no nitty gritty bits to implement. In my example <module>::params is considered the header for the module (granted a header that exposes values, but that can''t be helped due to the declarative nature of the DSL). There should be no implementation in that sub-module and even <module> should reference that ''header'' to get the variables it needs to do its work. But I''ll still pay penance at the OO altar for all my past transgressions against and abuses of it. -- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
jcbollinger
2013-Jan-30 20:33 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Wednesday, January 30, 2013 10:21:44 AM UTC-6, Ti Leggett wrote:> > > On Jan 30, 2013, at 9:31 AM, jcbollinger wrote: > [...] > > And now that you drop the idea of a common data module, we come back > around to using other modules'' classes'' variables. Are you honestly > arguing that it is better to analyze class implementations and pull out > variables willy-nilly than to define and rely on documented interfaces? I > think you owe a penance at the OO altar. > > > > I''m arguing that no more than I would argue having to delve into the > source code of openssl in order to use it in my C program - that''s what the > header is for. I''m arguing to define your class implementations such that > the nitty gritty of that class'' implementation need not be inspected in > order for another module to make use of it,Well I''m glad that''s cleared up, then.> not mash all the public bits in to one globally public class that has no > nitty gritty bits to implement. In my example <module>::params is > considered the header for the module (granted a header that exposes values, > but that can''t be helped due to the declarative nature of the DSL). There > should be no implementation in that sub-module and even <module> should > reference that ''header'' to get the variables it needs to do its work. But > I''ll still pay penance at the OO altar for all my past transgressions > against and abuses of it. > >Maybe we''re just having a terminology problem. Puppet has no concept of sub-modules, and the only construct available to hold reference-able, non-global variables is the class. Indeed, even modules themselves are a Puppet implementation detail -- the DSL has no concept of them except as top-level namespaces (but top-level namespaces often map to classes, either instead of or in addition to mapping to modules). So, would you care to explain how your <module>::params then differs from "mash[ing] all the public bits in to one globally public class that has no nitty gritty bits to implement"? Are you suggesting separate ::params classes shadowing multiple different classes in the same module? Are you conflating class *parameters* with class *variables*? John -- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
Ti Leggett
2013-Jan-30 21:41 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Jan 30, 2013, at 2:33 PM, jcbollinger <John.Bollinger@stJude.org> wrote:>> not mash all the public bits in to one globally public class that has no nitty gritty bits to implement. In my example <module>::params is considered the header for the module (granted a header that exposes values, but that can''t be helped due to the declarative nature of the DSL). There should be no implementation in that sub-module and even <module> should reference that ''header'' to get the variables it needs to do its work. But I''ll still pay penance at the OO altar for all my past transgressions against and abuses of it. >> > > > Maybe we''re just having a terminology problem. Puppet has no concept of sub-modules, and the only construct available to hold reference-able, non-global variables is the class. Indeed, even modules themselves are a Puppet implementation detail -- the DSL has no concept of them except as top-level namespaces (but top-level namespaces often map to classes, either instead of or in addition to mapping to modules). > > So, would you care to explain how your <module>::params then differs from "mash[ing] all the public bits in to one globally public class that has no nitty gritty bits to implement"? Are you suggesting separate ::params classes shadowing multiple different classes in the same module? Are you conflating class parameters with class variables? >Let''s go back to my original example from http://pastie.org/5910079#. Not stated in that code snip (for conciseness) is a module, kibana. Among other things it needs to install an apache configuration to make it a useful piece of software and that configuration is in the kibana::apache sub-class in the form of a snippet that is tagged such that the apache module can instantiate it later on at the proper time (there''s an alternative to this method). In order to do this, the kibana::apache class needs to know where to install this configuration file so that the apache process can load it. That location I chose to place in a variable, $config_d, in the apache module in a sub-class (sorry for the improper nomenclature before) apache::params. To solve my original problem I simply add: include ''apache::params'' right above the @file snippet in kibana::apache and everything is happy. I think everyone can agree that is the right solution to the problem that I posed; however, both you and Luke strongly suggested against having modules include other module''s variables willy nilly and instead move those variables that multiple modules need to reference into a globally included class, we''ll call it globals::. This class, I assume (correct me if I assume wrong), would always be instantiated before all others, say in the nodes.pp file, to ensure that all subsequent modules could resolve the variable appropriately. I would assume in that class you would have all of these ''global'' variables that multiple modules make use of so you''d have (eventually) a long list in this one class: class globals { $apache_config_d = ''/etc/httpd/conf.d'' $openldap_schema_d = ''/etc/openldap/schemas'' $rsyslog_d = ''/etc/rsyslog.d'' $ssl_ca_path = ''/etc/pki/tls/certs'' ... } And in my kibana::apache class I would reference ${globals::apache_config_d}. If all of those assumptions are true, I''m curious why this solution is any better? The only benefit that I can see is that when writing a new module you don''t trouble making sure you''ve loaded the proper prerequisites for variable resolution because it should already be done. You''re still including another classes variables, albeit in this only ever one other class. The other alternative that has been alluded to in a pure programmatic way is that none of those variables should be shared between modules and each module should have their own local variable to use. I''ll consider this proposed as only for the purist and not really tractable in any real complex environment. What I proposed is only semantically different than the above but, in my mind, is a cleaner (you don''t have one huge file that has all variables) and more explicit (you are required to include the class that has the variable you care about when writing your module). It leaves the variables closest to the module that has the most influence over that variable - the variable $ssl_ca_path is directly dictated by the openssl package (which can only be in one module) and so it should remain as close to the module that contains that package. As another tangent, I mentioned there was an alternative to having the kibana apache configuration be served from kibana module and that is to move the kibana config into the apache module. That would solve the cross-module variable referencing, but again, in my head that removes the element further from the thing that most influences it - the kibana apache configuration certainly requires and makes use of the apache module, but the kibana module has more influence over the kibana apache configuration itself. -- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
Luke Bigum
2013-Jan-31 10:03 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Wednesday, January 30, 2013 9:41:31 PM UTC, Ti Leggett wrote:> > On Jan 30, 2013, at 2:33 PM, jcbollinger wrote: > > >> not mash all the public bits in to one globally public class that has > no nitty gritty bits to implement. In my example <module>::params is > considered the header for the module (granted a header that exposes values, > but that can''t be helped due to the declarative nature of the DSL). There > should be no implementation in that sub-module and even <module> should > reference that ''header'' to get the variables it needs to do its work. But > I''ll still pay penance at the OO altar for all my past transgressions > against and abuses of it. > >> > > > > > > Maybe we''re just having a terminology problem. Puppet has no concept of > sub-modules, and the only construct available to hold reference-able, > non-global variables is the class. Indeed, even modules themselves are a > Puppet implementation detail -- the DSL has no concept of them except as > top-level namespaces (but top-level namespaces often map to classes, either > instead of or in addition to mapping to modules). > > > > So, would you care to explain how your <module>::params then differs > from "mash[ing] all the public bits in to one globally public class that > has no nitty gritty bits to implement"? Are you suggesting separate > ::params classes shadowing multiple different classes in the same module? > Are you conflating class parameters with class variables? > > > > Let''s go back to my original example from http://pastie.org/5910079#. Not > stated in that code snip (for conciseness) is a module, kibana. Among other > things it needs to install an apache configuration to make it a useful > piece of software and that configuration is in the kibana::apache sub-class > in the form of a snippet that is tagged such that the apache module can > instantiate it later on at the proper time (there''s an alternative to this > method). In order to do this, the kibana::apache class needs to know where > to install this configuration file so that the apache process can load it. > That location I chose to place in a variable, $config_d, in the apache > module in a sub-class (sorry for the improper nomenclature before) > apache::params. To solve my original problem I simply add: > > include ''apache::params'' >For this specific example I would not model it this way. I would make the Apache module provide an interface to allow other modules to add to itself. I would make something like an ''apache::vhost'' or ''apache::extra_conf_file'', which is just a wrapper around a Puppet File and a notify => Service[]. Thus the implementation of how to create/manage Apache config files (like their location) is wholly contained in the Apache module and other modules don''t have to "know" specific details. That design may not scale out for more complex examples though. Looking at my own modules I should really practice what I preach because all too often I just drop a file in /etc/httpd/conf.d from anywhere I please ;-) right above the @file snippet in kibana::apache and everything is happy. I> think everyone can agree that is the right solution to the problem that I > posed; however, both you and Luke strongly suggested against having modules > include other module''s variables willy nilly and instead move those > variables that multiple modules need to reference into a globally included > class, we''ll call it globals::. This class, I assume (correct me if I > assume wrong), would always be instantiated before all others, say in the > nodes.pp file, to ensure that all subsequent modules could resolve the > variable appropriately. I would assume in that class you would have all of > these ''global'' variables that multiple modules make use of so you''d have > (eventually) a long list in this one class: > > class globals { > $apache_config_d = ''/etc/httpd/conf.d'' > $openldap_schema_d = ''/etc/openldap/schemas'' > $rsyslog_d = ''/etc/rsyslog.d'' > $ssl_ca_path = ''/etc/pki/tls/certs'' > ... > } > > And in my kibana::apache class I would reference > ${globals::apache_config_d}. If all of those assumptions are true, I''m > curious why this solution is any better? The only benefit that I can see is > that when writing a new module you don''t trouble making sure you''ve loaded > the proper prerequisites for variable resolution because it should already > be done. You''re still including another classes variables, albeit in this > only ever one other class. The other alternative that has been alluded to > in a pure programmatic way is that none of those variables should be shared > between modules and each module should have their own local variable to > use. I''ll consider this proposed as only for the purist and not really > tractable in any real complex environment. > > What I proposed is only semantically different than the above but, in my > mind, is a cleaner (you don''t have one huge file that has all variables) > and more explicit (you are required to include the class that has the > variable you care about when writing your module). It leaves the variables > closest to the module that has the most influence over that variable - the > variable $ssl_ca_path is directly dictated by the openssl package (which > can only be in one module) and so it should remain as close to the module > that contains that package. > > As another tangent, I mentioned there was an alternative to having the > kibana apache configuration be served from kibana module and that is to > move the kibana config into the apache module. That would solve the > cross-module variable referencing, but again, in my head that removes the > element further from the thing that most influences it - the kibana apache > configuration certainly requires and makes use of the apache module, but > the kibana module has more influence over the kibana apache configuration > itself.-- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
Ti Leggett
2013-Jan-31 14:31 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Jan 31, 2013, at 4:03 AM, Luke Bigum <Luke.Bigum@lmax.com> wrote:> For this specific example I would not model it this way. I would make the Apache module provide an interface to allow other modules to add to itself. I would make something like an ''apache::vhost'' or ''apache::extra_conf_file'', which is just a wrapper around a Puppet File and a notify => Service[]. Thus the implementation of how to create/manage Apache config files (like their location) is wholly contained in the Apache module and other modules don''t have to "know" specific details. > > That design may not scale out for more complex examples though. Looking at my own modules I should really practice what I preach because all too often I just drop a file in /etc/httpd/conf.d from anywhere I please ;-) >Ah! Now that''s the difference I was looking for. Thanks! -- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
jcbollinger
2013-Jan-31 14:39 UTC
Re: [Puppet Users] Referencing a variable from one class in another
On Wednesday, January 30, 2013 3:41:31 PM UTC-6, Ti Leggett wrote:> > > On Jan 30, 2013, at 2:33 PM, jcbollinger wrote: > > > Maybe we''re just having a terminology problem. Puppet has no concept of > sub-modules, and the only construct available to hold reference-able, > non-global variables is the class. Indeed, even modules themselves are a > Puppet implementation detail -- the DSL has no concept of them except as > top-level namespaces (but top-level namespaces often map to classes, either > instead of or in addition to mapping to modules). > > > > So, would you care to explain how your <module>::params then differs > from "mash[ing] all the public bits in to one globally public class that > has no nitty gritty bits to implement"? Are you suggesting separate > ::params classes shadowing multiple different classes in the same module? > Are you conflating class parameters with class variables? > > > > Let''s go back to my original example from http://pastie.org/5910079#. Not > stated in that code snip (for conciseness) is a module, kibana. Among other > things it needs to install an apache configuration to make it a useful > piece of software and that configuration is in the kibana::apache sub-class > in the form of a snippet that is tagged such that the apache module can > instantiate it later on at the proper time (there''s an alternative to this > method). In order to do this, the kibana::apache class needs to know where > to install this configuration file so that the apache process can load it. > That location I chose to place in a variable, $config_d, in the apache > module in a sub-class (sorry for the improper nomenclature before) > apache::params. To solve my original problem I simply add: > > include ''apache::params'' > > right above the @file snippet in kibana::apache and everything is happy. I > think everyone can agree that is the right solution to the problem that I > posed; however, both you and Luke strongly suggested against having modules > include other module''s variables willy nilly and instead move those > variables that multiple modules need to reference into a globally included > class, we''ll call it globals::.No, neither Luke nor I recommended any such thing. I don''t even see how you could tag Luke with that, though I do now see how you could have misunderstood my own remarks that way. My original comment about "centralizing all variables intended for cross-module reference in one well-known class, documenting their names and value ranges, and committing to avoiding incompatible changes there" was made and intended to be interpreted in the context of designing an individual module, so that the "one well-known class" is *for that module*. My apologies for being unclear. A per-module ::params class, as you seem to be advocating, is completely consistent with my recommendation. Even with that alternative, however, it is best to minimize cross-module class references (as Luke previously said), and I particularly like the example he just offered for a means of doing so. I''m inclined to think that it would be less prone to tricky parse-order issues and dependency cycles (or insufficient dependencies) than what you describe doing in your kibana module. John -- 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+unsubscribe@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users?hl=en. For more options, visit https://groups.google.com/groups/opt_out.