Hi folks, This is a "best practices" question as much as a technical one. I am trying to redefine variables when I include a specific class. The use case is installing php 5.3 on a few select centos 5 boxes while keeping the default php 5.1 install on others. Here is the relevant part of my apache module: --------------------------------------------------------------------- class apache::php inherits apache::base { include apache::params package { ''php'': name => $apache::params::php_package, ensure => installed, require => Package[''httpd''], notify => Service[''httpd'']; ''php-gd'': name => $apache::params::php_gd_package, ensure => installed, require => Package[''php''], notify => Service[''httpd'']; ''php-imap'': name => $apache::params::php_imap_package, ensure => installed, require => Package[''php''], notify => Service[''httpd'']; ''php-ldap'': name => $apache::params::php_ldap_package, ensure => installed, require => Package[''php''], notify => Service[''httpd'']; } } class apache::php53 inherits apache::php { # $os is defined in site.pp. if $::os == ''rhel5'' { # Dirty hack. Yuck. exec { ''/usr/bin/yum -y replace php --replace-with php53u'': onlyif => ''/bin/rpm -q php'', # Class common::redhat::el::el5 installs yum-plugin-replace. require => Class[''common::redhat::el::el5''], notify => Service[''httpd''], } } else { warning ''Class apache::php53 should only ever be defined for RHEL5 and its clones.'' } } class apache::params { case $::os { # .../... ''rhel5'': { $httpd_package = ''httpd'' $httpd_service = ''httpd'' $rootdir = ''/var/www/html'' if defined(Class[''apache::php53'']) { $php_package = ''php53u'' $php_gd_package = ''php53u-gd'' $php_imap_package = ''php53u-imap'' $php_ldap_package = ''php53u-ldap'' } else { $php_package = ''php'' $php_gd_package = ''php-gd'' $php_imap_package = ''php-imap'' $php_ldap_package = ''php-ldap'' } } } } --------------------------------------------------------------------- When I add the apache::php53 to my host (I use LDAP as a node classifier if that matters), php and its extensions get upgraded to 5.3. However, when I add a class that depends on apache::php53, the defined function evaluates as false. class wordpress { # apache::lamp includes apache::php include apache::lamp if $::os == ''rhel5'' { include apache::php53 } # .../... } I understand defined is quite unreliable. So I am wondering if there is a better option (read a working one)? Hardcoding the packages names in class apache::php53 is not enough as I have a bunch of other classes installing additional PHP modules. I suppose I could subclass them as well but things would probably get quite messy quite fast. Thanks, -- Arnaud -- 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.
Arnaud Gomes-do-Vale
2011-Jul-12 10:59 UTC
Re: [Puppet Users] How to avoid the use of defined
Arnaud Gomes-do-Vale <Arnaud.Gomes@ircam.fr> writes:> class wordpress { > # apache::lamp includes apache::php > include apache::lamp > > if $::os == ''rhel5'' { > include apache::php53 > } > # .../... > }Including apache::php53 before apache::lamp fixes the issue. I wouldn''t trust this is rock-solid though; including other classes in the wrong order would probably break this. -- Arnaud -- 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.
On Jul 11, 11:31 am, Arnaud Gomes-do-Vale <Arnaud.Go...@ircam.fr> wrote:> Hi folks, > > This is a "best practices" question as much as a technical one. > > I am trying to redefine variables when I include a specific class. The > use case is installing php 5.3 on a few select centos 5 boxes while > keeping the default php 5.1 install on others.I think it would be more precise to say "I am trying to redefine variables when a specific class *has been* included." The distinction is significant, because it narrows the possible approaches to only a few bad ones. Here''s a good rule of thumb: never use Puppet''s "defined()" function in your manifests. Ever. It is brittle, and it will cause you grief, increasing exponentially with the number of uses.> Here is the relevant part > of my apache module: > > --------------------------------------------------------------------- > class apache::php inherits apache::base { > include apache::params > > package { ''php'': > name => $apache::params::php_package, > ensure => installed, > require => Package[''httpd''], > notify => Service[''httpd'']; > ''php-gd'': > name => $apache::params::php_gd_package, > ensure => installed, > require => Package[''php''], > notify => Service[''httpd'']; > ''php-imap'': > name => $apache::params::php_imap_package, > ensure => installed, > require => Package[''php''], > notify => Service[''httpd'']; > ''php-ldap'': > name => $apache::params::php_ldap_package, > ensure => installed, > require => Package[''php''], > notify => Service[''httpd'']; > } > > } > > class apache::php53 inherits apache::php { > # $os is defined in site.pp. > if $::os == ''rhel5'' { > # Dirty hack. Yuck. > exec { ''/usr/bin/yum -y replace php --replace-with php53u'': > onlyif => ''/bin/rpm -q php'', > # Class common::redhat::el::el5 installs yum-plugin-replace. > require => Class[''common::redhat::el::el5''], > notify => Service[''httpd''], > } > } > else { > warning ''Class apache::php53 should only ever be defined for RHEL5 and its clones.'' > } > > } > > class apache::params { > case $::os { > # .../... > ''rhel5'': { > $httpd_package = ''httpd'' > $httpd_service = ''httpd'' > $rootdir = ''/var/www/html'' > if defined(Class[''apache::php53'']) { > $php_package = ''php53u'' > $php_gd_package = ''php53u-gd'' > $php_imap_package = ''php53u-imap'' > $php_ldap_package = ''php53u-ldap'' > } > else { > $php_package = ''php'' > $php_gd_package = ''php-gd'' > $php_imap_package = ''php-imap'' > $php_ldap_package = ''php-ldap'' > } > } > }} > > --------------------------------------------------------------------- > > When I add the apache::php53 to my host (I use LDAP as a node classifier > if that matters), php and its extensions get upgraded to 5.3. However, > when I add a class that depends on apache::php53, the defined function > evaluates as false. > > class wordpress { > # apache::lamp includes apache::php > include apache::lamp > > if $::os == ''rhel5'' { > include apache::php53 > } > # .../... > > } > > I understand defined is quite unreliable. So I am wondering if there is > a better option (read a working one)? > > Hardcoding the packages names in class apache::php53 is not enough as I > have a bunch of other classes installing additional PHP modules. I > suppose I could subclass them as well but things would probably get > quite messy quite fast.There is no need for subclassing or defined() here. I would approach the problem something like this: --------------------------------------------------------------------- class apache::php { # Nothing from ''apache::base'' is overridden, so it # should be included (if even that is needed) instead of # inherited from. include ''apache::base'' include ''apache::params'' # Resource defaults for Packages in this class Package { ensure => installed, require => Package[''php''], notify => Service[''httpd''] } package { ''php'': name => $apache::params::php_package, require => Package[''httpd'']; ''php-gd'': name => $apache::params::php_gd_package; ''php-imap'': name => $apache::params::php_imap_package; ''php-ldap'': name => $apache::params::php_ldap_package; } if $apache::params::php_package != ''php'' { # Make sure the vanilla ''php'' package is absent # before the alternative (e.g. ''php53'') is installed package { ''php-alt'': name => ''php'', ensure => absent, require => undef, before => Package[''php''] } } } # # ** No class apache::php53 ** # # # class apache::params unchanged, not shown # --------------------------------------------------------------------- Everybody that needs PHP just includes apache::php. If Puppet gets confused about having one package titled ''php'' and a different one named ''php'', then just change the titles so there is no clash. As my manifest shows, I''m not sure "yum replace" is really needed. If it is needed after all, then it shouldn''t be too hard to adjust the above to use it. 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.
Arnaud Gomes-do-Vale
2011-Jul-13 10:34 UTC
Re: [Puppet Users] Re: How to avoid the use of defined
Hi, First, thanks for your help. However I still have some issues with your solution. jcbollinger <John.Bollinger@stJude.org> writes:> few bad ones. Here''s a good rule of thumb: never use Puppet''s > "defined()" function in your manifests. Ever. It is brittle, and it > will cause you grief, increasing exponentially with the number of > uses..../...> There is no need for subclassing or defined() here. I would approach > the problem something like this:> # Resource defaults for Packages in this class > Package { > ensure => installed, > require => Package[''php''], > notify => Service[''httpd''] > }This creates a dependency loop: err: Could not apply complete catalog: Found dependency cycles in the following relationships: Package[php] => Package[httpd], Package[httpd] => Package[php], Package[php] => Package[php-ldap], Package[php-imap] => Package[php-mysql], Package[php-gd] => Package[php-mysql], Package[php-ldap] => Package[php-mysql], Package[php] => Package[php-mysql], Package[httpd] => File[/etc/httpd/conf.d/mod-status.conf], Package[php] => Package[php-mbstring], Package[httpd] => Service[httpd], Package[httpd] => Service[httpd], Package[php-imap] => Service[httpd], Package[php-mysql] => Service[httpd], Package[php-gd] => Service[httpd], Package[php-ldap] => Service[httpd], Package[php] => Service[httpd], File[/etc/httpd/conf.d/mod-status.conf] => Service[httpd], Package[php-mbstring] => Service[httpd], Package[php] => Package[php-imap], Package[php] => Package[php-gd], Package[httpd] => File[/var/www/html]; try using the ''--graph'' option and open the ''.dot'' files in OmniGraffle or GraphViz As far as I understand, Package[''httpd''] (defined in class apache::base) inherits the dependency on Package[''php'']. This is using Puppet 2.6.8; has this changed in 2.7.x?> # ** No class apache::php53 **So how do I tell Puppet which nodes need 5.1 and which need 5.3? With my sample wordpress class I get the following error: err: Could not retrieve catalog from remote server: Error 400 on SERVER: Could not find class apache::php53 in namespaces wordpress at /etc/puppet/modules/wordpress/manifests/init.pp:6 on node testxen1.ircam.fr Looks like using a dummy class definition as a flag won''t work. :-) I could use a variable instead, but I guess the ordering issues would get even worse?> # class apache::params unchanged, not shownSo I''m still using defined().> As my manifest shows, I''m not sure "yum replace" is really needed. If > it is needed after all, then it shouldn''t be too hard to adjust the > above to use it.Actually your solution looks much cleaner than "yum replace". -- Arnaud -- 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.
On Jul 13, 5:34 am, Arnaud Gomes-do-Vale <Arnaud.Go...@ircam.fr> wrote:> Hi, > > First, thanks for your help. However I still have some issues with your > solution. > > > > jcbollinger <John.Bollin...@stJude.org> writes: > > few bad ones. Here''s a good rule of thumb: never use Puppet''s > > "defined()" function in your manifests. Ever. It is brittle, and it > > will cause you grief, increasing exponentially with the number of > > uses. > .../... > > There is no need for subclassing or defined() here. I would approach > > the problem something like this: > > # Resource defaults for Packages in this class > > Package { > > ensure => installed, > > require => Package[''php''], > > notify => Service[''httpd''] > > } > > This creates a dependency loop: > > err: Could not apply complete catalog: Found dependency cycles in the following relationships: Package[php] => Package[httpd], Package[httpd] => Package[php], Package[php] => Package[php-ldap], Package[php-imap] => Package[php-mysql], Package[php-gd] => Package[php-mysql], Package[php-ldap] => Package[php-mysql], Package[php] => Package[php-mysql], Package[httpd] => File[/etc/httpd/conf.d/mod-status.conf], Package[php] => Package[php-mbstring], Package[httpd] => Service[httpd], Package[httpd] => Service[httpd], Package[php-imap] => Service[httpd], Package[php-mysql] => Service[httpd], Package[php-gd] => Service[httpd], Package[php-ldap] => Service[httpd], Package[php] => Service[httpd], File[/etc/httpd/conf.d/mod-status.conf] => Service[httpd], Package[php-mbstring] => Service[httpd], Package[php] => Package[php-imap], Package[php] => Package[php-gd], Package[httpd] => File[/var/www/html]; try using the ''--graph'' option and open the ''.dot'' files in OmniGraffle or GraphViz > > As far as I understand, Package[''httpd''] (defined in class apache::base) > inherits the dependency on Package[''php'']. This is using Puppet 2.6.8; > has this changed in 2.7.x?Fair enough, then move the ''require'' parameter back out of resource defaults into individual Package resources. Using resource defaults is not an essential aspect of the solution.> > # ** No class apache::php53 ** > > So how do I tell Puppet which nodes need 5.1 and which need 5.3? With my > sample wordpress class I get the following error:See below.> err: Could not retrieve catalog from remote server: Error 400 on SERVER: Could not find class apache::php53 in namespaces wordpress at /etc/puppet/modules/wordpress/manifests/init.pp:6 on node testxen1.ircam.fr > > Looks like using a dummy class definition as a flag won''t work. :-) I > could use a variable instead, but I guess the ordering issues would get > even worse?As I wrote, "Everybody that needs PHP just includes apache::php." There is no more apache::php53.> > # class apache::params unchanged, not shown > > So I''m still using defined().Ah. That''s a blunder on my part. These are the alternatives I can think of: 1) Per node, set a global variable that directs which set of PHP packages to use. 2) Use extlookup() to retrieve a flag variable such as described in (1), or else to retrieve the individual PHP package names. 3) Base the PHP package selection on node facts (possibly just $hostname) instead of on defined() 4) Though I don''t favor parameterized classes, you could parameterize apache::php to allow your nodes to direct which set of PHP packages to use; whether this is feasible depends somewhat on how the class is used. Another way to do this might be to stick with apache::php53 as a subclass of apache::php, and use resource overrides. This is clean only if you don''t need the PHP package names in other classes, but it looks like you''re relying on titles instead of names anyway. The result might be something like this: ---- class apache::php { include ''apache::base'' package { ''php'': ensure => installed, require => Package[''httpd''], notify => Service[''httpd'']; ''php-gd'': ensure => installed, require => Package[''php''], notify => Service[''httpd'']; ''php-imap'': ensure => installed, require => Package[''php''], notify => Service[''httpd'']; ''php-ldap'': ensure => installed, require => Package[''php''], notify => Service[''httpd'']; } } class apache::php53 inherits apache::php { # $os is defined in site.pp. if $::os == ''rhel5'' { Package[''php''] { name => ''php53u'' } Package[''php-gd''] { name => ''php53u-gd'' } Package[''php-imap''] { name => ''php53u-imap'' } Package[''php-ldap''] { name => ''php53u-ldap'' } package { ''php-alt'': name => ''php'', ensure => absent, require => undef, before => Package[''php''] } } else { warning ''Class apache::php53 should only ever be defined for RHEL5 and its clones.'' } } # # No class apache::params, at least as pertains to apache::php # ---- RHEL5 nodes that want PHP 5.3 then include apache::php53. It is safe, but unnecessary, for such nodes also to include apache::php. -- 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.
Nigel Kersten
2011-Jul-13 15:23 UTC
Re: [Puppet Users] Re: How to avoid the use of defined
On Wed, Jul 13, 2011 at 3:34 AM, Arnaud Gomes-do-Vale <Arnaud.Gomes@ircam.fr> wrote:> > > # Resource defaults for Packages in this class > > Package { > > ensure => installed, > > require => Package[''php''], > > notify => Service[''httpd''] > > } > > This creates a dependency loop:An option here is to override the require on a per-package basis. If you set a resource default for require, and then separately set require for individual resources, they will overwrite the resource default rather than append to it. You could also use collections to do what you want, this is untested, but something like: Package <| title != "php" |> { require => Package[''php''], notify => Service[''httpd''] } should work I believe. -- Nigel Kersten Product Manager, Puppet Labs Twitter: @nigelkersten *Join us for **PuppetConf *<http://www.bit.ly/puppetconfsig> September 22nd and 23rd in Portland, Oregon, USA. * * -- 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.