Hello Puppet users, I had talked with Luke about this scenario and was wondering how others would/are handling something like this. Imagine a scenario where all servers will have a specific postfix configuration except for a server or two or three. So, you want to define a file "/etc/postfix/main.cf" and specify the source from your dist tree. But for those exceptional servers, you want to use a different file from dist.>From my understanding, the best way to handle this currently is to have astandard.pp that is your most generic description of a server and have that specify the inclusion of a postfix.pp. And in that postfix.pp, have a File definition, test the hostname using tagged to specify the alternate file and use the regular file as the default case. Unfortunately, this leaves node specific information tied in with a service rather than where you''d expect it (with the node). The other thing you can do is define a postfix-normal.pp and postfix-alternate.pp and in each node, use an include to define which one you want. That''s doable. How are others handling this situation? Is there another way to solve this? -- DK
Digant C Kasundra wrote:> Hello Puppet users, > > I had talked with Luke about this scenario and was wondering how others > would/are handling something like this. > > Imagine a scenario where all servers will have a specific postfix > configuration except for a server or two or three. So, you want to define > a file "/etc/postfix/main.cf" and specify the source from your dist tree. > But for those exceptional servers, you want to use a different file from > dist. > >>From my understanding, the best way to handle this currently is to have a > standard.pp that is your most generic description of a server and have that > specify the inclusion of a postfix.pp. And in that postfix.pp, have a File > definition, test the hostname using tagged to specify the alternate file > and use the regular file as the default case. Unfortunately, this leaves > node specific information tied in with a service rather than where you''d > expect it (with the node). > > The other thing you can do is define a postfix-normal.pp and > postfix-alternate.pp and in each node, use an include to define which one > you want. That''s doable.There are a few different ways to solve the problem, and all of them bring with them their own complexities. By far the best way to solve this kind of problem in general is to generate the file correctly for each host, but that''s not always appropriate, as is likely the case for postfix''s configuration. So, you''re next decision is, template or full file? For simple differences, you can use a template instead of a normal configuration file; the template can only make decisions based on variable values (now that I think about it, they should probably have access to tags and the list of defined classes), and in some ways this just punts the complexity. If you choose full files, you have basically two options: Specifically choose the file you want in your Puppet configuration, or specify all possible files in the correct search order. Puppet files support multiple sources, so you can specify them in the order you want: file { "/etc/postfix/main.cf": source => [".../$hostname.cf", ".../main.cf"] } This isn''t the best option, though, because you''ve punted the complexity to the filesystem, and you''ll never know from looking at the configuration which file a given host will get. Note also that I don''t think many people are using this, as it''s *very* cfengine. So, the best option is usually to associate hosts and files in your Puppet configuration. I agree with your desire to avoid having node-specific information in your postfix classes, so you want some kind of middleman. For only two options, you can use tags, but tags can only be on or off, so it''s cumbersome to use them for more than two cases. Right now, I think the only real option is to use variables: class mailserverA { $posttype = A include mailserver } class mailserverB { $posttype = B include mailserver } node hostA { include mailserverA } node hostB { include mailserverB } class mailserver { file { "/etc/postfix/main.cf": source => $posttype ? { A => ".../mainA.cf", B => ".../mainB.cf" } } } Note that this takes advantage of Puppet''s dynamic scoping, not exactly the best part of Puppet''s language, but it''s the only want to get behaviour like this. Is that sufficient? -- Someday I want to be rich. Some people get so rich they lose all respect for humanity. That''s how rich I want to be. --Rita Rudner --------------------------------------------------------------------- Luke Kanies | http://reductivelabs.com | http://madstop.com
> So, the best option is usually to associate hosts and files in your > Puppet configuration. I agree with your desire to avoid having > node-specific information in your postfix classes, so you want some kind > of middleman. For only two options, you can use tags, but tags can only > be on or off, so it''s cumbersome to use them for more than two cases. > Right now, I think the only real option is to use variables: > > class mailserverA { > $posttype = A > include mailserver > } > class mailserverB { > $posttype = B > include mailserver > } > node hostA { > include mailserverA > } > node hostB { > include mailserverB > } > class mailserver { > file { "/etc/postfix/main.cf": > source => $posttype ? { > A => ".../mainA.cf", > B => ".../mainB.cf" > } > } > } > > Note that this takes advantage of Puppet''s dynamic scoping, not exactly > the best part of Puppet''s language, but it''s the only want to get > behaviour like this. > > Is that sufficient? >That still leaves me with having to specify "which flavor" for each node, and that gets cumbersome. The more of these we have, the more and more each node has to specify flavors (or if not node, than wherever the deviation happens). What we really want is to go ahead and say: class stanford { include mailserverA, otherstuff, etc, etc2 } node basenode { include stanford } node default inherits basenode { } node generic1 inherits basenode { } ... node genericn inherits basenode { } node weirdo1 inherits basenode { include mailserverB } Or something similar, so that I only have to redefine or set a variable or flag or something in the oddballs. -- DK
--On Thursday, September 14, 2006 6:44 PM -0700 Digant C Kasundra <digant@stanford.edu> wrote:>> So, the best option is usually to associate hosts and files in your >> Puppet configuration. I agree with your desire to avoid having >> node-specific information in your postfix classes, so you want some kind >> of middleman. For only two options, you can use tags, but tags can only >> be on or off, so it''s cumbersome to use them for more than two cases. >> Right now, I think the only real option is to use variables: >> >> class mailserverA { >> $posttype = A >> include mailserver >> } >> class mailserverB { >> $posttype = B >> include mailserver >> } >> node hostA { >> include mailserverA >> } >> node hostB { >> include mailserverB >> } >> class mailserver { >> file { "/etc/postfix/main.cf": >> source => $posttype ? { >> A => ".../mainA.cf", >> B => ".../mainB.cf" >> } >> } >> } >> >> Note that this takes advantage of Puppet''s dynamic scoping, not exactly >> the best part of Puppet''s language, but it''s the only want to get >> behaviour like this. >> >> Is that sufficient?Would something like this work: class mailserver { file { "/etc/postfix/mail.cf": source => $posttype ? { weirdo => ".../main-weirdo.cf", default => ".../main.cf" } } } class baseclass { include mailserver, etc, etc, etc } node basenode { include baseclass } node genericservers inherits basenode { } node weirdosever inherits basenode { $posttype = "weirdo" }
Digant C Kasundra wrote:> > That still leaves me with having to specify "which flavor" for each node, > and that gets cumbersome. The more of these we have, the more and more > each node has to specify flavors (or if not node, than wherever the > deviation happens). What we really want is to go ahead and say: > > class stanford { > include mailserverA, otherstuff, etc, etc2 > } > > node basenode { > include stanford > } > node default inherits basenode { > } > > node generic1 inherits basenode { > } > > ... > > node genericn inherits basenode { > } > > node weirdo1 inherits basenode { > include mailserverB > } > > Or something similar, so that I only have to redefine or set a variable or > flag or something in the oddballs.I see what you''re saying now, and the only way I think it would work is to change your inheritance tree, because superclass code gets interpreted before subclass code. class stanford { include mailserverA, otherstuff, etc, etc2 } node basenode { include stanford } node default inherits basenode { } node generic1 inherits basenode { } node weirdnode { include mailserverB include stanford } node weirdo1 inherits weirdnode { } I know this still isn''t ideal, because you effectively have to duplicate whatever''s in ''basenode'' in your weirdnode definition. But this at least works with relatively minimal duplication and gets you the behaviour you want. If Puppet ever becomes a two-pass interpreter, this process will become much easier. -- Morgan''s Second Law: To a first approximation all appointments are canceled. --------------------------------------------------------------------- Luke Kanies | http://reductivelabs.com | http://madstop.com
Digant C Kasundra wrote:> > Would something like this work: > > class mailserver { > file { "/etc/postfix/mail.cf": > source => $posttype ? { > weirdo => ".../main-weirdo.cf", > default => ".../main.cf" > } > } > } > > class baseclass { > include mailserver, etc, etc, etc > } > > node basenode { > include baseclass > } > > node genericservers inherits basenode { > } > > node weirdosever inherits basenode { > $posttype = "weirdo" > }No, because the basenode code is evaluated before the weirdoserver code is evaluated, so $posttype will always be undefined when mailserver is evaluated. If you move essentially everything into a base class, instead of a base node, then you can include your weirdo classes in your weirdo nodes, and then include the base class. The weird classes will get evaluated first, setting their weird values and then evaluating the normal classes. Then when you include the base class, it will see that the normal mailserver class has already been evaluated and skip it. -- I am a kind of paranoiac in reverse. I suspect people of plotting to make me happy. --J. D. Salinger --------------------------------------------------------------------- Luke Kanies | http://reductivelabs.com | http://madstop.com
On Thu, Sep 14, 2006 at 04:38:43PM -0700, Digant C Kasundra wrote:> The other thing you can do is define a postfix-normal.pp and > postfix-alternate.pp and in each node, use an include to define which one > you want. That''s doable.I go with this, but I don''t name things like ''normal'' and ''alternate''. I describe the actual purpose of the configuration. So, I might have ''postfix-workstation'' and ''postfix-server'' -- that might be 100-to-1, distribution wise, but I don''t think in terms of ''normal'' and ''unusual''. I figure that if I need to do it, it''s not unusual, it''s just a different system configuration, and I need a description of that configuration. - Matt
On 14/09/06 16:38 -0700, Digant C Kasundra wrote: <snip>> Imagine a scenario where all servers will have a specific postfix > configuration except for a server or two or three. So, you want to define > a file "/etc/postfix/main.cf" and specify the source from your dist tree. > But for those exceptional servers, you want to use a different file from > dist. >What kind of scenario are you looking at? I work with a fairly large cluster of Postfix boxen, and might be able to figure out a better solution for you here. Devdas Bhagat
On Thu, 2006-09-14 at 20:25 -0500, Luke Kanies wrote:> So, the best option is usually to associate hosts and files in your > Puppet configuration. I agree with your desire to avoid having > node-specific information in your postfix classes, so you want some kind > of middleman. For only two options, you can use tags, but tags can only > be on or off, so it''s cumbersome to use them for more than two cases. > Right now, I think the only real option is to use variables: > > class mailserverA { > $posttype = A > include mailserver > } > class mailserverB { > $posttype = B > include mailserver > } > node hostA { > include mailserverA > } > node hostB { > include mailserverB > } > class mailserver { > file { "/etc/postfix/main.cf": > source => $posttype ? { > A => ".../mainA.cf", > B => ".../mainB.cf" > } > } > }Why not make the class mailserver a define mailserver { $posttype } ? That way mailserverA and mailserverB can pass the variable parts into the define cleanly as a parameter. That avoids relying on dynamic scoping; if all mailservers need to be tagged as the same thing, the define could also add a tag that''s independent of the $posttype. David
> I go with this, but I don''t name things like ''normal'' and ''alternate''. I > describe the actual purpose of the configuration.Yeah, I don''t either. The colorful names were to make a point, not actual names I was considering. -- DK
On Fri, Sep 15, 2006 at 10:09:02AM -0700, Digant C Kasundra wrote:> > I go with this, but I don''t name things like ''normal'' and ''alternate''. I > > describe the actual purpose of the configuration. > > Yeah, I don''t either. The colorful names were to make a point, not actual > names I was considering.That''s OK. I''ve just seen people actually consider using those names as configuration types, "because that''s what they are". The results have never been pretty. - Matt
--On Saturday, September 16, 2006 6:01 AM +1000 Matthew Palmer <mpalmer@hezmatt.org> wrote:> On Fri, Sep 15, 2006 at 10:09:02AM -0700, Digant C Kasundra wrote: >> > I go with this, but I don''t name things like ''normal'' and ''alternate''. >> > I describe the actual purpose of the configuration. >> >> Yeah, I don''t either. The colorful names were to make a point, not >> actual names I was considering. > > That''s OK. I''ve just seen people actually consider using those names as > configuration types, "because that''s what they are". The results have > never been pretty. > > - MattWe''re using postfix-general-configuration-used-most-places and postfix-basic-configuration-but-with-masquerading-turned-off :) -- DK
On Fri, Sep 15, 2006 at 01:04:34PM -0700, Digant C Kasundra wrote:> > > --On Saturday, September 16, 2006 6:01 AM +1000 Matthew Palmer > <mpalmer@hezmatt.org> wrote: > > > On Fri, Sep 15, 2006 at 10:09:02AM -0700, Digant C Kasundra wrote: > >> > I go with this, but I don''t name things like ''normal'' and ''alternate''. > >> > I describe the actual purpose of the configuration. > >> > >> Yeah, I don''t either. The colorful names were to make a point, not > >> actual names I was considering. > > > > That''s OK. I''ve just seen people actually consider using those names as > > configuration types, "because that''s what they are". The results have > > never been pretty. > > We''re using postfix-general-configuration-used-most-places and > postfix-basic-configuration-but-with-masquerading-turned-off > > :)I''m going to take that smiley as meaning that you''re joking, so as to save the last shreds of my sanity from the thought that one day I''m going to end up at a site that has used those exact names... - Matt