On Mar 6, 1:00 pm, Justin Lloyd <jstn...@gmail.com> wrote: > John, > > I'm running into some snags of my own and your explanations have been > helpful. However, I'd like to ask if you can comment a bit more on the > emphasis Puppet Labs has on parameterized classes versus include. For one, > I'm thinking of modules available via github. Take the > puppetlabs/mcollective module, for example. It's highly parameterized and I > have some "wrapper classes" like this: > > class puppet_base ( $puppet_master = false, $mcollective_client = false > ) { > > class { 'system_base': } # basics needed by all systems > > class { 'puppet': > master => $puppet_master, > require => Class['system_base'], > } > > class { 'mcollective_server': > mcollective_client => $mcollective_client, > } > } > > class mcollective_server ( $mcollective_client => false ) { > package { 'stomp': > ensure => present, > provider => 'gem', > } > > if $mcollective_client { > class { 'activemq': > require => Package['stomp'], > before => Class['mcollective'], > } > } > > class { 'mcollective': # puppetlabs/mcollective module > client => $mcollective_client, > } > } > > This seemed to me like an appropriate use of parameterized classes and a > way of keeping node definitions simple and readable, like so: > > node 'regular-host' { > class { 'puppet_base': > stage => 'first' > } > } > > node 'mco-admin-host': { > class { 'puppet_base': > stage => 'first', > mcollective_client => true, > } > } > > node 'puppet-master' { > class { 'puppet_base': > stage => 'first', > puppet_master => true, > } > } > > I am running into some snags with ensuring curl and rubygems packages are > installed prior to the puppet_base being evaluated (that's a long story), > but that may be more of an issue with better use of stages. > > Can you comment on the above and how it is impacted by your explanations of > includes (and smarter classes) vs. parameterization?
First, I think run stages are a better tool in principle than they are in practice. There is nothing you can do with stages that you cannot also do with ordinary resource / class relationships, and people sometimes get into trouble with run stages because they end up with more implied relationships than they needed or wanted. If people have run stages working well for them then great, but I recommend approaching them with caution. If ordinary relationships can do the job without too much trouble, then I think that's a better bet. Above all, do not use run stages without specific need. Second, here are some of my design principles for classes: 1) 'include' classes wherever a class or definition has either a logical or a functional dependency. That is, 1a) If one class (or definition) refers to variables or resources declared in another, then the former should directly or indirectly 'include' the latter 1b) If the configuration described by one class (or definition) depends for client-side correctness or proper function on separate configuration described by a different class, then the former should directly or indirectly 'include' the latter (even if (1a) does not apply) 2) Declare all needed resource relationships, as specifically as possible. In particular, prefer resource / resource relationships to resource / class and class / class relationships. 3) Define and document modules' and classes' scope and external interfaces. 4) Avoid use of dynamic scoping. Regarding (1): as of 2.7.x, this principle is not usable with parameterized classes. That is my own biggest reason for avoiding them. Also, principle (1) implies that some classes will be 'include'd more than once, which is just fine. The overall result of applying this principle is that you can declare (via 'include' or 'require') any class in any place in your manifest without worrying about parse-order issues or broken configurations (for lack of needed other classes). Not being able to rely on that result is a significant weakness of any class that does not apply principle (1), among them all classes that declare parameterized classes. Regarding (2): this one wil be controversial, at least with regard to cross-module relationships. Looking ahead to (3), however, I consider those resources available for cross-module relationships to be part of modules' external interfaces, to be referenced only if documented. Declaring relationships as precisely as possible gives Puppet the greatest freedom to find an acceptable order of resource application. Ideally, one module would not have to worry about the details of application order within a different module, but it is very hard to keep modules so self-contained without allowing them to balloon to cover huge swaths of configuration space. As for the specifics of your code: A) Classes that are certain to not be subject to my principle (1) are the least problematic when parameterized, though that does not mean that they should not themselves apply principle (1) in their bodies. Perhaps your wrapper classes are in that category. B) I urge you to consider feeding data to your classes via Hiera instead of via class parameters. Becoming familiar with Hiera and using it effectively will pay off. Among other things, Hiera integration into Telly will contribute to enabling you to apply principle (1) to parameterized classes (or so I understand). C) Other than generally objecting to parameterized classes, I don't see anything awful about what you presented. 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+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.