On 05/28/2010 05:00 AM, Luke Kanies wrote:
* Alessandro's presentation caused someone to point out to me
afterward that case statements of this ilk:

case $operatingsytem {
debian: { ... }
redhat: { ... }
}

make a module difficult to extend with support for new operating
system types - you have to modify the module itself in this case.

This situation is not so different from the same problem that occurs with type/provider pairs in the ruby half of puppet. You just have fancier tools to implement the case in the providers.

Pulling the case out into extlookup() is nice for simple case statements -- where you're only looking up the name of one package. OpenSSH on Solaris vs RedHat vs Ubuntu it makes a great solution. For puppet-dashboard on RedHat vs Ubuntu though, extlookup() isn't as clear a winner.

Dashboard doesn't like Ubuntu's rake package (maybe that's a bug? But ignore it for now for this example...) -- it wants the one from rubygems. So now the package lists for rhel/ubuntu differ. Worse still, there's an inter-list dependency where rake needs to be installed via the gem provider, which requires rubygems installed. Modeling that in extlookup() is going to be a worse mess than that case statement -- if nothing else because now you also have to extlookup() the provider=>. Plus potentially a requires=> for other package situations -- the gem provider doesn't need it, but other packages may need specific ordering to install %pre/%post scripts correctly.

If there was a better way to specify a type/provider pattern in puppet code (not ruby), that seems to me like a better solution here. You can do this now, but it looks pretty hackish:

[warning: snippeted code. Don't expect it to work as presented here.
 Original code can be provided if needed.]

class apache2 {
    package { "apache2": alias  => "apache2", ensure => present; }
    ...
    # Include operating-specific aspects
    include "apache2::${operatingsystem}"
}

define apache2::feature($purge = false, $ensure = 'present') {
    search "apache2::${operatingsystem}"
    provider::feature {"$name": purge=>"$purge", ensure=>"$ensure"; }
}

... later, in redhat.pp in the apache module:

class apache2::redhat inherits apache2 {
    Package["apache2"] { name => "httpd" }
    ...
    # Disable the default site
    apache2::redhat::provider::site {"welcome.conf":ensure => absent;}
}

define apache2::redhat::provider::feature($purge = false, $ensure = 'present') {
    $string = "LoadModule ${name}_module /u/l/a2/mod/mod_${name}.so"
    $conf = "/etc/httpd/conf.d/features.conf"
    case $ensure {
'present': { exec { "echo $string >> $conf": unless => "grep '${string}' $conf"; } } 'absent': { exec { "sed -i '\...@^$string$@ d' $conf": onlyif => "grep '${string}' $conf"; } }
    }
    file {
        "/etc/httpd/conf.d/features-${name}.conf":
source => "puppet:///modules/apache2/redhat/features-${name}.conf",
            ensure => $ensure;
    }
}

Of course rather than using ${operatingsystem} you could use an externally-sourced ${apache2provider} selector. Then anyone could extend the "default" apache2 module for their OS via their own "class apache2::redhatfrommysite inherits apache2::redhat { ... }" and use it by changing the external variable. On the down side, they'd have to implement all the define ...::provider::<feature, site, etc> even if they just re-called the parent provider's version of it.

One bad thing about the above is until we get paramaterized classes (assuming they can be multi-included!), you can end up running into multiply-defined uglyness ("Apache2::Feature['foo'] already defined at ...") you have to hack around with an if defined in the source where you want to do the define.


... at least that's where I ended up on a new deployment I'm building after considering the problem for a while. I'd rather keep all my OS-specific configuration in one clearly defined location than spread across multiple files in various locations. YMMV.

--
You received this message because you are subscribed to the Google Groups "Puppet 
Developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/puppet-dev?hl=en.

Reply via email to