There are too many Puppet Modules out there that suck, says Tim Sharpe.

I think he may have a point actually. Writing decent Puppet modules isn't something that occurs naturally - it's pretty easy to write a module that does a job on your system at this exact point in time, but what if your systems expand? It would be good to have some open logic in there.

Some time ago I adopted a module layout introduced to me by Dom Cleal of Red Hat - one which broke out operating specific items into a separate file. It was a nice structure because you could easily add a different operating system to a module with no change to init.pp.

Today, along with inspiration from Tim Sharpe's article, I've taken that a step further to come up with my current Puppet Module model. This does go back to a case statement for the initial support decision matrix, but I think it works well because you quickly and easily establish, and fail softly, which operating systems are supported by your module. I've also coded this module template to use the newer parameterized class layout, and taken into account that Puppet Console [Dashboard] doesn't yet support parameterized classes.

Here's an example of a module that pulls some variables from the Console:

init.pp

class dns {
    case $operatingsystem {
        'scientific', 'redhat', 'centos': {
            $supported = true
        }
        default: {
            $supported = false
            notify { "${module_name}_unsupported":
                message => "The ${module_name} module is not supported on ${operatingsystem}",
            }
        }
    }

    # Gather some variables from ENC
    if ( $::dns_zones ) {
        $zones = split($::dns_zones, ',')
    }
    else {
        $zones = 'undef'
    }

    if ( $supported == true ) {
        class { "dns::${operatingsystem}":
            zones            => $zones,
            allow_query_nets => $allow_query_nets,
        }
    }
}

class dns::common ( $packages, $daemon = 'named',
                    $datadir = '/var/named',
                    $owner = 'root', $group = 'root', $mode = 0640,
                    $ensure = 'running', $enable = 'true',
                    $zones, $allow_query_nets )
{
    package { [ $packages ]:
        ensure => installed,
    }
    # zones - define a CS list in the ENC as parameter dns_zones
    if ! ( $zones == 'undef' ) {
        dns::zone { $zones:
            dir   => "${datadir}/master",
            owner => $owner,
            group => $group,
        }
    }

    service { 'named':
        name   => $daemon,
        ensure => $ensure,
        enable => $enable,
    }
}

scientific.pp

class dns::scientific ( $zones, $allow_query_nets ) {
    class { 'dns::common':
        packages         => [ 'bind97' ],
        owner            => 'named',
        group            => 'named',
        zones            => $zones,
        allow_query_nets => $allow_query_nets,
    }
}

zone.pp

define dns::zone ( $dir, $owner, $group ) {
    file { "${dir}/${title}":
        source  => "puppet:///modules/dns/${title}",
        owner   => $owner, group => $group,
        require => File [ "${dir}" ],
        notify  => Service [ 'named' ],
    }
}


Comments

comments powered by Disqus