hornet136
2011-Aug-01 18:10 UTC
[Puppet Users] Class inheritance or virtual resources to manage apache modules
I want to start out with an apache class that will disable all modules except for a pre-defined list, thus establishing a baseline of active modules. Then as needed, other classes could enable a module that they require that would have been disabled by the baseline state. Its possible several classes may try to enable the same module (1 or more classes needing module1 could be on a single node) What is the ''right'' way to do this? I''ve played with virtual resources and class inheritance. I hope to avoid class inheritance if possible as virtual resources seems to be the correct way to do this kind of thing. I however have had troubles with doing that and have ultimately ended up with the following using inheritance: class apache2::modules { # list apache modules to enable $enable_apachemods = [ "module1", "module2", "module3", ] # list apache modules to disable, basically all modules would be listed here by default $disable_apachemods = [ "module4", "module5", "module6", ] # Process list of apache modules to enable a2mod { $enable_apachemods: ensure => "present", notify => Exec["apache2reload"] } # Process list of apache modules to disable a2mod { $disable_apachemods: ensure => "absent", notify => Exec["apache2reload"] } } Then as I have other classes defined that require a specific apache module they should simply set it to ''present''. class application1 { include apache2::modules::app1 ... } class apache2::modules::app1 inherits apache2::modules { A2mod[''module4''] { ensure => ''present'', require => Package[''modulepackage''] } } class application2 { include apache2::modules::app2 ... } class apache2::modules::app2 inherits apache2::modules { A2mod[''module4''] { ensure => ''present'', require => Package[''modulepackage''] } } I get the following error when I do it this way: Error 400 on SERVER: Parameter ''ensure'' is already set on A2mod[module4]... cannot redefine at.... -- 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-Aug-02 15:23 UTC
[Puppet Users] Re: Class inheritance or virtual resources to manage apache modules
On Aug 1, 1:10 pm, hornet136 <hornet...@gmail.com> wrote:> I want to start out with an apache class that will disable all modules > except for a pre-defined list, thus establishing a baseline of active > modules. > Then as needed, other classes could enable a module that they require > that would have been disabled by the baseline state. > Its possible several classes may try to enable the same module (1 or > more classes needing module1 could be on a single node) > > What is the ''right'' way to do this? I''ve played with virtual > resources and class inheritance. > I hope to avoid class inheritance if possible as virtual resources > seems to be the correct way to do this kind of thing.From your description, class inheritance seems clearly to be the correct way to do what you want, especially if the only alternative being considered is virtual resources. The pattern to recognize is that you want all nodes to have certain resources, but you want to assign different property values to some of those resources on certain nodes. Sometimes you can handle that kind of situation with conditionals, extlookup(), or class parameters, but your case practically screams for class inheritance. Virtual resources, on the other hand, are for when only some nodes will want certain resources, and they should not be defined at all for other nodes. As a special case, virtual resources are good for when there are multiple distinct, non-exclusive places where a decision to assign the same resource to a node can be made. Note the distinction with respect to your requirements: resources defined differently (using inheritance) vs. resources maybe not defined at all (using virtual resources).> I however have had troubles with doing that and have ultimately ended > up with the following using inheritance: > > class apache2::modules { > > # list apache modules to enable > $enable_apachemods = [ "module1", "module2", "module3", ] > > # list apache modules to disable, basically all modules would be > listed here by default > $disable_apachemods = [ "module4", "module5", "module6", ] > > # Process list of apache modules to enable > a2mod { $enable_apachemods: ensure => "present", notify => > Exec["apache2reload"] } > > # Process list of apache modules to disable > a2mod { $disable_apachemods: ensure => "absent", notify => > Exec["apache2reload"] } > > } > > Then as I have other classes defined that require a specific apache > module they should simply set it to ''present''. > > class application1 { > include apache2::modules::app1 > ... > > } > > class apache2::modules::app1 inherits apache2::modules { > A2mod[''module4''] { ensure => ''present'', require => > Package[''modulepackage''] } > > } > > class application2 { > include apache2::modules::app2 > ... > > } > > class apache2::modules::app2 inherits apache2::modules { > A2mod[''module4''] { ensure => ''present'', require => > Package[''modulepackage''] } > > } > > I get the following error when I do it this way: > > Error 400 on SERVER: Parameter ''ensure'' is already set on > A2mod[module4]... cannot redefine at....Yes, no node can include two different subclasses that override the same property of the same resource, so you woul get that error when a node includes both Class[''application1''] and Class[''application2'']. You''re pretty close, though. The correct way to approach this is to generalize the subclasses so that they can be shared: class apache2::modules::module4 inherits apache2::modules { A2mod[''module4''] { ensure => ''present'', require => Package[''modulepackage''] } } class application1 { include ''apache2::modules::module4'' } class application2 { include ''apache2::modules::module4'' } Note how this also provides better encapsulation apache''s resources, in that application-related classes don''t need to know anything about the internal details of the apache2::modules class. Note also how the application1 and application2 classes now read so cleanly and clearly. If there are groups of modules that you *always* want to enable together, then you can do that via a single subclass, following the general model above. Beware, however, of "always" some day becoming "usually". 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.
Karen Loomans
2011-Aug-03 02:11 UTC
Re: [Puppet Users] Re: Class inheritance or virtual resources to manage apache modules
Hi, I believe I have a related problem. What is the correct way to extend your example, to handle the situation where each application class needs to set a different var? For example I''m writing a module whereby I need to include sections of template based on what applications are installed on the server. So for example I currently have: class syslog { ... $include_networker = '''' $siem_collector_ipaddr = '''' file { $syslog_config: owner => ''root'', group => ''root'', mode => ''0644'', content => template("syslog/${operatingsystem}/${cust_os_major_version}/config.erb"), require => [ Package[$syslog_pkg] ], } ... } #== My erb template contains the standard syslog plus the following sections at the end: <% if !include_networker.empty? then %> # NetWorker requirements daemon.notice /dev/console daemon.notice /nsr/logs/messages daemon.notice operator local0.notice /nsr/logs/summary local0.alert root, operator <% end -%> <% if !siem_collector_ipaddr.empty? then %> # SIEM requirements *.debug @<%= siem_collector_ipaddr %> <% end -%> #== class syslog::add_config inherits syslog { # Do something to set the params in the template if required ????? # I have tried different approaches including appending each application to an array and modifying template to read it (which doesn''t work); setting # application specified params to be picked up in the template etc. # This resets the content of the file resource in syslog # to enable the application inclusions in the template to be picked up. # File[$syslog_config] { content => template("syslog/${operatingsystem}/${cust_os_major_version}/config.erb") } } #== class siem ($siem_collector_ipaddr) { ... include ''syslog::add_config'' ... } #== class networker { ... $include_networker = 1 include ''syslog::add_config'' ... } #== The vars $include_networker and $siem_collector_ipaddr in class syslog do not get set. I should add that I am aware augeas will be suggested for syslog configs :) but we have both RHEL 5/6 and Solaris 10 servers, and I''m yet to fully evaluate it to ensure it will suit all our needs for all platforms. Thanks in advance, Karen -- 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-Aug-03 17:11 UTC
[Puppet Users] Re: Class inheritance or virtual resources to manage apache modules
On Aug 2, 9:11 pm, Karen Loomans <ka...@loomans.org> wrote:> I believe I have a related problem. What is the correct way to extend your > example, to handle the situation where each application class needs to set a > different var?In Puppet, class inheritance is appropriate ONLY where it involves overriding resource parameters. There is no way to override or redefine variables, though you can shadow them with other variables having the same local name. Furthermore, I don''t think it''s possible even to test the value of a class-scoped variable unless its class is included for the node. Although templates can test whether particular classes are included, I consider that bad form, and it is likely eventually to cause you trouble. The best thing to do in your case is to devise a better manifest design, ideally one that has no horizontal dependencies between scopes. I also recommend that you modify your manifests and templates to refer to all variables via their fully-qualifed names, for I suspect that some of your confusion arises because you are not referencing the variables you think you''re referencing. See below for some specific suggestions.> For example I''m writing a module whereby I need to include > sections of template based on what applications are installed on the > server. So for example I currently have: > > class syslog { > ... > $include_networker = '''' > $siem_collector_ipaddr = '''' > > file { $syslog_config: > owner => ''root'', > group => ''root'', > mode => ''0644'', > content => > template("syslog/${operatingsystem}/${cust_os_major_version}/config.erb"), > require => [ Package[$syslog_pkg] ], > } > ... > } > > #==> > My erb template contains the standard syslog plus the following sections at > the end: > > <% if !include_networker.empty? then %> > > # NetWorker requirements > daemon.notice /dev/console > daemon.notice /nsr/logs/messages > daemon.notice operator > local0.notice /nsr/logs/summary > local0.alert root, operator > <% end -%> > <% if !siem_collector_ipaddr.empty? then %> > > # SIEM requirements > *.debug @<%= siem_collector_ipaddr %> > <% end -%> > > #==> > class syslog::add_config inherits syslog { > > # Do something to set the params in the template if required ????? > # I have tried different approaches including appending each > application to an array and modifying template to read it (which doesn''t > work); setting > # application specified params to be picked up in the template etc. > > # This resets the content of the file resource in syslog > # to enable the application inclusions in the template to be picked > up. > # > File[$syslog_config] { content => > template("syslog/${operatingsystem}/${cust_os_major_version}/config.erb") } > } > > #==> > class siem ($siem_collector_ipaddr) { > ... > include ''syslog::add_config'' > ... > } > > #==> > class networker { > ... > $include_networker = 1 > include ''syslog::add_config'' > ... > } > > #==> > The vars $include_networker and $siem_collector_ipaddr in class syslog do > not get set. I should add that I am aware augeas will be suggested for > syslog configs :) but we have both RHEL 5/6 and Solaris 10 servers, and I''m > yet to fully evaluate it to ensure it will suit all our needs for all > platforms.A lot of people seem to address problem of this kind by building the target file in pieces, with each class involved contributing the pieces relevant to it. That''s especially suited to applications that understand configuration directories, with every file therein contributing configuration directives. Apache httpd, yum, and many versions of cron are among such applications. Some other applications'' configuration languages provide an "include" statement or the like that accepts globs, whereby you can set up the same thing. For such applications, each of your classes can just manage its own file in the appropriate conf directory, and you''re done. Even if your application needs everything in the same file, like syslogd does, there is still help for you. You should look into the puppet-concat module, which is designed for just this case. See http://www.devco.net/archives/2010/02/19/building_files_from_fragments_with_puppet.php and especially https://github.com/puppet-modules/puppet-concat . It is possible that going through the exercise of converting all your relative variable names into fully-qualified ones would help you come up with some other alternative. It is likely that it would help you understand the problem, and it would be good preparation for eventual adoption of Puppet 2.8. Good Luck, 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.