Hi all, I''m currently redoing our puppet setup and trying to start with new design from the ground up to implement all of the puppet 2.6+ goodness, but I''m getting tripped up with the complexity of the design. I want to do things the right way, but I don''t want to introduce additional complexity, which is what I feel like I''m doing. The best example I can come up with is for an NTP module, since puppet docs use it a lot. I''ll just describe how I imagine it should work from my understanding of the style guide and the parameterized class documentation, and hopefully someone can help clear it up a bit by either telling me I''m on the right track or that I''m hitting the crack pipe a bit too hard. For the sake of simplicity, I''ve left out ntp::server, but it looks the same as ntp::client. Here''s how it looks: modules/ntp/params.pp defines the usual stuff: - $supported = true for supported OS - per-os package name/version default - per-os service name default - default config file path - default ntp server to be used in the template that generates the config files modules/ntp/file.pp - inherits ntp::params - uses template to generate and copy $ntp::params::config_file (which uses data from ntp::params) - notifies Class["ntp::client::service"] on config file change modules/ntp/package.pp - inherits ntp::params - installs $ntp::params::package_name (aliases it Package["ntp"]) - notifies Class["ntp::client::service"] on package installation modules/ntp/client/service.pp - inherits ntp::params - makes sure $ntp::params::service_name is running (aliases it Service["ntp_client"] modules/ntp/client/init.pp - includes ntp::params - checks to make sure $ntp::params::supported is set, exiting if not - includes ntp::file ntp::package, ntp::client::service So is this "correct" or is it just unnecessarily complicated? The goal is to include only "ntp::client" for a node, and then let ntp::client call in all of the other ntp classes as needed. My main confusion here is how I specify something like a different ntp server or something for an ntp client. What worries me is that I have the relationship chained like this: ntp::client --(includes)--> ntp::file --(inherits)--> ntp::params I use an ENC, so if I want to use parameterized classes to tell ntp::client to use a different ntp server from the default, I wanted to output something like: classes: ntp::client ntpserver: 0.pool.ntp.org but "ntpserver" isn''t really a parameter of ntp::client, it''s a parameter of ntp::params, which ntp::client accesses through ntp::file. Would I just do something like classes: ntp::client ntp::params ntpserver: 0.pool.ntp.org What I''d really like to do is to use the first syntax and just have ntp::client pass the "ntpserver=0.pool.ntp.org" parameter into ntp::file, which would then pass it into ntp::params, so that ntp::params::ntpserver would be the server I specified in the ENC output. Is there a way to achieve this? I wanted to have the ENC script depend as little as possible on the internal organization of the ntp module so that I can say "here''s your ntp server. I don''t care what subclass you use it in. Just take it and use it where you need it." I feel like even my question is completely muddled, so if I''ve made something so unclear you can''t understand what I''m asking, please don''t hesitate to ask for clarification. Thanks very much, David -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To view this discussion on the web visit https://groups.google.com/d/msg/puppet-users/-/mMgmIDOpV18J. 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. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
Thomas Bendler
2011-Oct-04 16:37 UTC
Re: [Puppet Users] (mostly) philosophical design question
Hi David, 2011/10/3 David Ressman <ressman@gmail.com>> [...] > I''m currently redoing our puppet setup and trying to start with new design > from the ground up to implement all of the puppet 2.6+ goodness, but I''m > getting tripped up with the complexity of the design. I want to do things > the right way, but I don''t want to introduce additional complexity, which is > what I feel like I''m doing. The best example I can come up with is for an > NTP module, since puppet docs use it a lot. I''ll just describe how I imagine > it should work from my understanding of the style guide and the > parameterized class documentation, and hopefully someone can help clear it > up a bit by either telling me I''m on the right track or that I''m hitting the > crack pipe a bit too hard. For the sake of simplicity, I''ve left out > ntp::server, but it looks the same as ntp::client. > [...] >since I switched to Eclipse/Gepetto module development I do something like this fo init.pp: # Class: backup # # This module manages backup # # Parameters: usageType # # Actions: Setup backup # # Requires: common module # # Sample Usage: class { backup: usageType = "baculaClient" } # # [Remember: No empty lines between comments and class definition] class backup( $usageType = "none" ) { #todo: ZZZ Module finished but untested $localOS = $operatingsystem ? { CentOS => true, RedHat => true, Scientific => true } if $localOS { case $usageType { "baculaServer": { include backup::bacula include backup::bacula::client include backup::bacula::server } "baculaStorage": { include backup::bacula include backup::bacula::storage } "baculaClient": { include backup::bacula include backup::bacula::client } } } else { notice("$localOS not support in module $module_name") } } So I use a service based setup instead of a product based setup. It is not final because the main idea is to say, this node should get a backup client and a site specific configuration decide which product should be used. The main problem from my point of view is to find a design approach which strictly separate generic from site specific code but I''m still in a design development phase ;). Regards, Thomas -- 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. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
jcbollinger
2011-Oct-04 17:51 UTC
[Puppet Users] Re: (mostly) philosophical design question
On Oct 3, 11:53 am, David Ressman <ress...@gmail.com> wrote:> Hi all, > > I''m currently redoing our puppet setup and trying to start with new design > from the ground up to implement all of the puppet 2.6+ goodness, but I''m > getting tripped up with the complexity of the design. I want to do things > the right way, but I don''t want to introduce additional complexity, which is > what I feel like I''m doing. The best example I can come up with is for an > NTP module, since puppet docs use it a lot. I''ll just describe how I imagine > it should work from my understanding of the style guide and the > parameterized class documentation, and hopefully someone can help clear it > up a bit by either telling me I''m on the right track or that I''m hitting the > crack pipe a bit too hard.As I analyze the current style guide as a whole, I find that it is designed around these design principles: 1) An ENC will be used 2) Every class to be applied will be specified in the ENC output 3) Use of dynamic scoping is strictly avoided Also, it makes the assumption that 4) parameterized classes are generally desirable Indeed, several of the guidelines seem geared specifically to make manifest sets using parameterized classes work smoothly, which seems to me to be putting the cart before the horse. Anyway, many of the style guidelines can be applied to a manifest set that does not adhere to all of those, but you must the understand that the result does not follow the spirit of the guide.> For the sake of simplicity, I''ve left out > ntp::server, but it looks the same as ntp::client. > > Here''s how it looks: > > modules/ntp/params.pp > defines the usual stuff: > - $supported = true for supported OS > - per-os package name/version default > - per-os service name default > - default config file path > - default ntp server to be used in the template that generates the > config files > > modules/ntp/file.pp > - inherits ntp::params > - uses template to generate and copy $ntp::params::config_file (which uses > data from ntp::params) > - notifies Class["ntp::client::service"] on config file change > > modules/ntp/package.pp > - inherits ntp::params > - installs $ntp::params::package_name (aliases it Package["ntp"]) > - notifies Class["ntp::client::service"] on package installation > > modules/ntp/client/service.pp > - inherits ntp::params > - makes sure $ntp::params::service_name is running (aliases it > Service["ntp_client"] > > modules/ntp/client/init.pp > - includes ntp::params > - checks to make sure $ntp::params::supported is set, exiting if not > - includes ntp::file ntp::package, ntp::client::service > > So is this "correct" or is it just unnecessarily complicated? The goal is to > include only "ntp::client" for a node, and then let ntp::client call in all > of the other ntp classes as needed.It is not correct in my book for your various classes to inherit ntp::params. Class inheritance should *only* be used to override resource properties. For any other purpose, classes should *include* other classes if they need access to their members. Either way, I observe that ntp::params must not itself be parameterized. If it is parameterized then your only recourse is to declare it at top level, and before any of the classes that rely on it. Furthermore, it runs against the grain of the style guide to design for clients to include only "ntp::client". I personally prefer that approach, but if you stick to it then trying to closely adhere to the style guide at the same time may cause you trouble.> My main confusion here is how I specify something like a different ntp > server or something for an ntp client. What worries me is that I have the > relationship chained like this: > > ntp::client --(includes)--> ntp::file --(inherits)--> ntp::params > > I use an ENC, so if I want to use parameterized classes to tell ntp::client > to use a different ntp server from the default, I wanted to output something > like: > > classes: > ntp::client > ntpserver: 0.pool.ntp.org > > but "ntpserver" isn''t really a parameter of ntp::client, it''s a parameter of > ntp::params, which ntp::client accesses through ntp::file. Would I just do > something like > > classes: > ntp::client > ntp::params > ntpserver: 0.pool.ntp.orgNot if your other classes are inheriting from or including ntp::params. If they merely reference its variables then just list it first among the classes and hope for the best. Are you ready to give up on parameterized classes yet? The PL style guide explicitly recommends against extlookup(), but you''re looking at a good use case for it, or for a similar data injection mechanism such as hiera.> What I''d really like to do is to use the first syntax and just have > ntp::client pass the "ntpserver=0.pool.ntp.org" parameter into ntp::file, > which would then pass it into ntp::params, so that ntp::params::ntpserver > would be the server I specified in the ENC output. Is there a way to achieve > this?No, because you can only include a parameterized class once for any given node, and you cannot inherit from it. If ntp::params is parameterized so that it can accept the server name as a parameter, then ntp::params (and its parameters) must be specified at top level, by your ENC. It is certainly possible for you to pass the ''ntpserver'' parameter to class ntp::client, and down the chain from there, but that leaves you with a thorny issue of ensuring that each parameterized class referenced by another is included exactly once for each node. I suspect this is why the style guide recommends avoiding one class including others.> I wanted to have the ENC script depend as little as possible on the > internal organization of the ntp module so that I can say "here''s your ntp > server. I don''t care what subclass you use it in. Just take it and use it > where you need it."That''s very difficult when you are using parameterized classes. It is impossible with parameterized classes if "I don''t care what subclass" covers "I don''t care if multiple subclasses ...."> I feel like even my question is completely muddled, so if I''ve made > something so unclear you can''t understand what I''m asking, please don''t > hesitate to ask for clarification.I think your question is reasonably clear, just broad and multifaceted. The answer is that some significant aspects of your design just aren''t compatible with parameterized classes. Other aspects will work, but are not IMO a good idea. I have some general suggestions, but hear this first: 1) It is far from clear that Puppet''s parameterized class implementation can reasonably be characterized as "goodness" (your word). It solves a rather specific problem that not everybody has and nobody *needs* to have, and using it places constraints on your manifest design that using unparameterized classes does not. 2) The current Puppet style guide is heavily influenced by the limitations imposed by parameterized classes, and to some extent it seems wrongheadedly geared specifically toward promoting parameterized class use (as opposed to simply using them as a means to an end). I therefore suggest that you develop your own style. I recommend that your style minimize the use of parameterized classes, or even avoid it altogether if it can. (That also requires avoiding run stages, since only parameterized classes can be assigned stages.) Plan instead for classes to obtain data via extlookup(), hiera, or indeed *any* other mechanism than class parameterization. If you are uncertain which to choose then go with hiera. Your NTP module is a good place to work out most of the details. John -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To post to this group, send email to puppet-users@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.