Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I'd like to write a puppet manifest to install and configure an application on target servers.

Parts of this manifest shall be re-usable. Thus I used define for defining my re-usable functionality. Doing so, I've always the problem that there are parts of the definition which are not re-usable.

A simple example is a bunch of configuration files to be created. These file must be placed in the same directory. This directory must be created only once.

Example:

nodes.pp

node 'myNode.in.a.domain' {
  mymodule::addconfig {'configfile1.xml':
    param => 'somevalue',
  }
  mymodule::addconfig {'configfile2.xml':
    param => 'someothervalue',
  }
}

mymodule.pp

define mymodule::addconfig ($param) {

  $config_dir = "/the/directory/"

  #ensure that directory exits:
  file { $config_dir:
    ensure  => directory,
  }

  #create the configuration file:     
  file { $name:
    path    => "${config_dir}/${name}"
    content => template('a_template.erb'),
    require => File[$config_dir],
  }
}

This example will fail, because now the resource file {$config_dir: is defined twice.

As far as I understood, it is required to extract these parts into a class. Then it looks like this:

nodes.pp

node 'myNode.in.a.domain' {

  class { 'mymodule::createConfigurationDirectory':
  }

  mymodule::addconfig {'configfile1.xml':
    param => 'somevalue',
    require => Class ['mymodule::createConfigurationDirectory'],
  }
  mymodule::addconfig {'configfile2.xml':
    param => 'someothervalue',
    require => Class ['mymodule::createConfigurationDirectory'],
  }
}

But this makes my interface hard use. Every user of my module has to know, that there is a class which is additionally required. For this simple use case the additional class might be acceptable. But with growing module complexity (lots of definitions) I'm a bit afraid of confusing the modules user.

So I'd like to know is there a better way to handle this dependencies. Ideally, classes like createConfigurationDirectory are hidden from the user of the modules api.

Or are there some other "Best Practices"/Patterns handling such dependencies?

share|improve this question

2 Answers 2

Break all the functionality into separate files within the module, each file containing one class or defined type. Use resource ordering to manage resources in the correct order.

In your node definition:

class {'mymodule':
  conffile => 'file_name',
}

In your module manifest directory:

init.pp:

# This class does basic setup,
# and optionally allows you to define a config file
class mymodule ( $conffile = undef ) {
  include mymodule::confdir

  if $conffile {
    mymodule::conffile { $conffile: }
  }
}

params.pp:

# This class defines variables
class mymodule::params {
  $confdir = '/path/to/dir'
}

confdir.pp:

# This class creates a conf dir
class mymodule::confdir {
  include mymodule::params

  file { $mymodule::params::confdir:
    ensure = directory,
  }
}

conffile.pp:

# This define creates a config file
define mymodule::conffile($file=$title) {
  include mymodule::params

  file { "${mymodule::params::confdir}/${file}":
    ensure  => present,
    require => Class['mymodule::confdir'],
  }
}
share|improve this answer

Is best if you can take out the config directory from the define. This is an example

class def($config_dir) {
    file { $config_dir:
        ensure => directory
     }   
}

define def::template($file_location) {
     file { $file_location:
         path    => "${def::config_dir}/${file_location}",
         content => 'hi',
         require => Class['def'],
     }   
 }
if $fqdn == 'my_host' {
    class { 'def':
            config_dir => '/tmp/d1'
        }   
    def::template { 'f1.txt':
        file_location => "f1.txt"
    }   
    def::template { 'f2.txt':
        file_location => "f2.txt"
    }   
}

ls  /tmp/d1/
f1.txt  f2.txt
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.