Hi, I''m writing puppet modules since a couple of weeks now, so I''m still considering myself as a new comer in this field. It seems that modules I can find on the web or the recipe page on the wiki almost all use a design pattern where the module is shipped in one or several class(es) whose configuration are determined by "global" or nodes variables ala: module: class postfix { ... define package, common files... file { "/etc/postfix/main.cf": content => template("postfix/main.cf.erb") } ... } ... also define other classes and use inheritance... class postfix::mx inherits postfix { File["/etc/postfix/main.cf"] { content => template("postfix/server.main.cf.erb") } } main.cf.erb template: ... my_networks = <%= mynetwork %> relayhost = <%= smarthost %> ... site manifest: node "server.domain.com" { $mynetwork = ''127.0.0.1/8'' $smarthost = ''mail.domain.com'' ... other variables... include postfix ... } But I find myself writing all my modules manifests almost always like that: class postfix { ... define package, common files... define null_sender($mynetwork = ''127.0.0.1'', $smarthost,... ) { file { "/etc/postfix/main.cf": content => template("postfix/main.cf.erb") } } ... define mx(...) { ... } } and using it like this: site manifest: node "server.domain.com" { include postfix postfix::null_sender { "mail": mynetwork => ''127.0.0.1/8'', smarthost => ''mail.domain.com'' } } To me, the second approach has the advantage of allowing documented default values and mandatory parameters. But I''m sure there are drawbacks... So now, the question is, if other more experimented people are writing modules in the first way, what am I missing with the second form? What module design patterns are considered best pratice? Thanks, -- Brice Figureau <brice+puppet@daysofwonder.com> Days of Wonder, http://www.daysofwonder.com/
Brice Figureau schrieb:> Hi, > > I''m writing puppet modules since a couple of weeks now, so I''m still > considering myself as a new comer in this field. > > It seems that modules I can find on the web or the recipe page on the > wiki almost all use a design pattern where the module is shipped in one > or several class(es) whose configuration are determined by "global" or > nodes variables ala: > > module: > class postfix { > ... define package, common files... > file { > "/etc/postfix/main.cf": > content => template("postfix/main.cf.erb") > } > ... > } > ... also define other classes and use inheritance... > class postfix::mx inherits postfix { > File["/etc/postfix/main.cf"] { > content => template("postfix/server.main.cf.erb") > } > } > > main.cf.erb template: > ... > my_networks = <%= mynetwork %> > relayhost = <%= smarthost %> > ... > > site manifest: > node "server.domain.com" { > $mynetwork = ''127.0.0.1/8'' > $smarthost = ''mail.domain.com'' > ... other variables... > > include postfix > ... > } > > But I find myself writing all my modules manifests almost always like > that: > > class postfix { > ... define package, common files... > define null_sender($mynetwork = ''127.0.0.1'', $smarthost,... ) { > file { > "/etc/postfix/main.cf": > content => template("postfix/main.cf.erb") > } > } > ... > define mx(...) { > ... > } > } > > and using it like this: > site manifest: > node "server.domain.com" { > include postfix > > postfix::null_sender { "mail": > mynetwork => ''127.0.0.1/8'', smarthost => ''mail.domain.com'' > } > } > > To me, the second approach has the advantage of allowing documented > default values and mandatory parameters. But I''m sure there are > drawbacks... > > So now, the question is, if other more experimented people are writing > modules in the first way, what am I missing with the second form? > > What module design patterns are considered best pratice?The first approach are "template classes" as specified on the Wiki[1]. This model can be directly mapped to external node classification[2] and it allows you to include the same class in different places as needed. The second approach requires more rigour in stratifying the configuration and can become unwieldy in some situations. Especially when the modeled resource is really a singleton. Can you legally specify multiple instances of "postfix::null_sender"? We all hope that someone will come around with a good idea how to sensibly specify parameterized classes. [1] http://reductivelabs.com/trac/puppet/wiki/GlossaryOfTerms [2] http://reductivelabs.com/trac/puppet/wiki/ExternalNodeClassification Regards, DavidS
Hi David, On Fri, 2007-11-23 at 11:26 +0100, David Schmitt wrote:> Brice Figureau schrieb: > > Hi, > > > > I''m writing puppet modules since a couple of weeks now, so I''m still > > considering myself as a new comer in this field. > > > > It seems that modules I can find on the web or the recipe page on the > > wiki almost all use a design pattern where the module is shipped in one > > or several class(es) whose configuration are determined by "global" or > > nodes variables ala: > > > [snipped design patterns] > > > > To me, the second approach has the advantage of allowing documented > > default values and mandatory parameters. But I''m sure there are > > drawbacks... > > > > So now, the question is, if other more experimented people are writing > > modules in the first way, what am I missing with the second form? > > > > What module design patterns are considered best pratice? > > The first approach are "template classes" as specified on the Wiki[1]. > This model can be directly mapped to external node classification[2] and > it allows you to include the same class in different places as needed.I have yet to discover how external node classification works. Guess I have to read the wiki more thoroughly...> The second approach requires more rigour in stratifying the > configuration and can become unwieldy in some situations. Especially > when the modeled resource is really a singleton. Can you legally specify > multiple instances of "postfix::null_sender"?Yes, you are right. Maybe one can use defined() in the define to check that the resource is not defined and issue an error otherwise. But that''s ugly...> We all hope that someone will come around with a good idea how to > sensibly specify parameterized classes.Yes, I''d really like it would be possible.> > [1] http://reductivelabs.com/trac/puppet/wiki/GlossaryOfTerms > [2] http://reductivelabs.com/trac/puppet/wiki/ExternalNodeClassificationThanks for the documentation pointers, -- Brice Figureau <brice+puppet@daysofwonder.com> Days of Wonder, http://www.daysofwonder.com/
On Fri, November 23, 2007 11:26, David Schmitt wrote:> Brice Figureau schrieb: >> Hi, >> >> I''m writing puppet modules since a couple of weeks now, so I''m still >> considering myself as a new comer in this field. >> >> It seems that modules I can find on the web or the recipe page on the >> wiki almost all use a design pattern where the module is shipped in one >> or several class(es) whose configuration are determined by "global" or >> nodes variables ala: >> [snipped config] >> So now, the question is, if other more experimented people are writing >> modules in the first way, what am I missing with the second form? >> >> What module design patterns are considered best pratice? > > The first approach are "template classes" as specified on the Wiki[1]. > This model can be directly mapped to external node classification[2] and > it allows you to include the same class in different places as needed. > > The second approach requires more rigour in stratifying the > configuration and can become unwieldy in some situations. Especially > when the modeled resource is really a singleton. Can you legally specify > multiple instances of "postfix::null_sender"? >So in the light of what you wrote, how would you do the following: I have a postfix module, that can be either a null_sender or a mx. I want to pass additional configuration directive to the mx. For instance it can use a ldap server for virtual users, it can use amavisd-new, it can authenticate mail through cyrus-sasl or dovecot-sasl, etc... I could use inheritance like this: class postfix { ... common definitions like packages... } class postfix::mx_with_ldap inherits postfix { } class postfix::mx_with_sasl inherits postfix { } But how can I write that I want a mx with ldap _and_ sasl ? I''d have to define a class postfix::with_ldap_and_sasl ? That is not very scalable IMHO. Ins''t it better to have something like the following ?? class postfix { define mx() { ... manage only mx params... } define ldap() { ... manage only ldap side of the matters... } } then my node would look like: node "mx.domain.com" { postfix::mx{ "postfix": ... } postfix::ldap{ "postfix": ... ldap params ... } ... } How experienced puppet modules writers would write this manifests? Many thanks, -- Brice Figureau Days of Wonder, http://www.daysofwonder.com/
On Nov 24, 2007, at 5:55 AM, Brice Figureau wrote:> So in the light of what you wrote, how would you do the following: > > I have a postfix module, that can be either a null_sender or a mx. > I want to pass additional configuration directive to the mx. For > instance > it can use a ldap server for virtual users, it can use amavisd-new, > it can > authenticate mail through cyrus-sasl or dovecot-sasl, etc... > > I could use inheritance like this: > > class postfix { > ... common definitions like packages... > } > > class postfix::mx_with_ldap inherits postfix { > } > > class postfix::mx_with_sasl inherits postfix { > } > > But how can I write that I want a mx with ldap _and_ sasl ?[...]> How experienced puppet modules writers would write this manifests? > Many thanks,Generally speaking, if you can couch the differences in terms of resources, multiple subclasses are the way to go. E.g., if both subclasses need to modify /etc/postfix/main.cf but different lines, then if you model that file as a collection of resources, then each subclass can do whatever it wants as long as they don''t conflict, but if you model it as a single file created using templates, then you can''t use subclasses. It can sometimes be quite difficult, or in some cases impossible, to model those differences as resources, but it''s possible and rewarding in nearly all cases. -- It is said that power corrupts, but actually it''s more true that power attracts the corruptible. The sane are usually attracted by other things than power. -- David Brin --------------------------------------------------------------------- Luke Kanies | http://reductivelabs.com | http://madstop.com
On Sun, Nov 25, 2007 at 05:30:51PM -0600, Luke Kanies wrote:> On Nov 24, 2007, at 5:55 AM, Brice Figureau wrote: > > So in the light of what you wrote, how would you do the following: > > > > I have a postfix module, that can be either a null_sender or a mx. > > I want to pass additional configuration directive to the mx. For > > instance > > it can use a ldap server for virtual users, it can use amavisd-new, > > it can > > authenticate mail through cyrus-sasl or dovecot-sasl, etc... > > > > I could use inheritance like this: > > > > class postfix { > > ... common definitions like packages... > > } > > > > class postfix::mx_with_ldap inherits postfix { > > } > > > > class postfix::mx_with_sasl inherits postfix { > > } > > > > But how can I write that I want a mx with ldap _and_ sasl ? > [...] > > How experienced puppet modules writers would write this manifests? > > Many thanks, > > Generally speaking, if you can couch the differences in terms of > resources, multiple subclasses are the way to go. E.g., if both > subclasses need to modify /etc/postfix/main.cf but different lines, > then if you model that file as a collection of resources, then each > subclass can do whatever it wants as long as they don''t conflict, but > if you model it as a single file created using templates, then you > can''t use subclasses.In the specific case of Postfix, in particular, a small execution of postconf wrapped in a define makes a very tidy way to do this. - Matt
On Nov 23, 2007 11:26 AM, David Schmitt <david@schmitt.edv-bus.at> wrote:> > We all hope that someone will come around with a good idea how to > sensibly specify parameterized classes. > >Something like this? http://reductivelabs.com/trac/puppet/wiki/LanguageEvolution#parameterized-classes Best regards Jose _______________________________________________ Puppet-users mailing list Puppet-users@madstop.com https://mail.madstop.com/mailman/listinfo/puppet-users
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Monday 26 November 2007, José González Gómez wrote:> On Nov 23, 2007 11:26 AM, David Schmitt <david@schmitt.edv-bus.at> wrote: > > We all hope that someone will come around with a good idea how to > > sensibly specify parameterized classes. > > Something like this? > > http://reductivelabs.com/trac/puppet/wiki/LanguageEvolution#parameterized-c >lassesYes and no. This solves only part of the problem. For the other part see Frederic's mail from friday about multi-level defaults. Regards, David - -- The primary freedom of open source is not the freedom from cost, but the free- dom to shape software to do what you want. This freedom is /never/ exercised without cost, but is available /at all/ only by accepting the very different costs associated with open source, costs not in money, but in time and effort. - -- http://www.schierer.org/~luke/log/20070710-1129/on-forks-and-forking -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFHSryd/Pp1N6Uzh0URApLhAKCPHAFymUiBIS/2Zpc13qdy0vscGACfXTS7 lksvGF9flUTKabwhgoSDKiY=+Fa8 -----END PGP SIGNATURE----- _______________________________________________ Puppet-users mailing list Puppet-users@madstop.com https://mail.madstop.com/mailman/listinfo/puppet-users