Puppet - Possible to use software design patterns in modules?

Posted by Mike Purcell on Server Fault See other posts from Server Fault or by Mike Purcell
Published on 2012-10-26T00:41:54Z Indexed on 2012/11/04 23:03 UTC
Read the original article Hit count: 389

Filed under:
|

As I work with puppet, I find myself wanting to automate more complex setups, for example vhosts for X number of websites. As my puppet manifests get more complex I find it difficult to apply the DRY (don't repeat yourself) principle. Below is a simplified snippet of what I am after, but doesn't work because puppet throws various errors depending up whether I use classes or defines. I'd like to get some feed back from some seasoned puppetmasters on how they might approach this solution.

# site.pp
import 'nodes'

# nodes.pp
node nodes_dev {
    $service_env = 'dev'
}

node nodes_prod {
    $service_env = 'prod'
}

import 'nodes/dev'
import 'nodes/prod'

# nodes/dev.pp
node 'service1.ownij.lan' inherits nodes_dev {
    httpd::vhost::package::site { 'foo': }
    httpd::vhost::package::site { 'bar': }
}

# modules/vhost/package.pp
class httpd::vhost::package {

    class manage($port) {

        # More complex stuff goes here like ensuring that conf paths and uris exist
        # As well as log files, which is I why I want to do the work once and use many

        notify { $service_env: }
        notify { $port: }
    }    

    define site {

        case $name {

            'foo': {

                class 'httpd::vhost::package::manage':
                    port => 20000
                }
            }

            'bar': {

                class 'httpd::vhost::package::manage':
                    port => 20001
                }
            }
        }
    }
}

That code snippet gives me a Duplicate declaration: Class[Httpd::Vhost::Package::Manage] error, and if I switch the manage class to a define, and attempt to access a global or pass in a variable common to both foo and bar, I get a Duplicate declaration: Notify[dev] error.

Any suggestions how I can implement the DRY principle and still get puppet to work?

-- UPDATE --

I'm still having a problem trying to ensure that some of my vhosts, which may share a parent directory, are setup correctly. Something like this:

node 'service1.ownij.lan' inherits nodes_dev {
    httpd::vhost::package::site { 'foo_sitea': }
    httpd::vhost::package::site { 'foo_siteb': }
    httpd::vhost::package::site { 'bar': }
}

What I need to happen is that sitea and siteb have the same parent "foo" folder. The problem I am having is when I call a define to ensure the "foo" folder exists. Below is the site define as I have it, hopefully it will make sense what I am trying to accomplish.

class httpd::vhost::package {

    File {
        owner   => root,
        group   => root,
        mode    => 0660
    }

    define site() {

        $app_parts = split($name, '[_]')

        $app_primary = $app_parts[0]

        if ($app_parts[1] == '') {
            $tpl_path_partial_app = "${app_primary}"
            $app_sub = ''
        } else {
            $tpl_path_partial_app = "${app_primary}/${app_parts[1]}"
            $app_sub = $app_parts[1]
        }

        include httpd::vhost::log::base

        httpd::vhost::log::app { $name:
            app_primary => $app_primary,
            app_sub     => $app_sub
        }
    }
}

class httpd::vhost::log {

    class base {

        $paths = [ '/tmp', '/tmp/var', '/tmp/var/log', '/tmp/var/log/httpd', "/tmp/var/log/httpd/${service_env}" ]

        file { $paths:
            ensure  => directory
        }
    }

    define app($app_primary, $app_sub) {

        $paths = [ "/tmp/var/log/httpd/${service_env}/${app_primary}", "/tmp/var/log/httpd/${service_env}/${app_primary}/${app_sub}" ]

        file { $paths:
            ensure  => directory
        }
    }
}

The include httpd::vhost::log::base works fine, because it is "included", which means it is only implemented once, even though site is called multiple times. The error I am getting is: Duplicate declaration: File[/tmp/var/log/httpd/dev/foo]. I looked into using exec, but not sure this is the correct route, surely others have had to deal with this before and any insight is appreciated as I have been grappling with this for a few weeks. Thanks.

© Server Fault or respective owner

Related posts about puppet

Related posts about puppetmaster