On Tuesday, October 13, 2015 at 12:20:05 PM UTC-5, Ugo Bellavance wrote:
Hi,
I'd need to create a number of directories in a fasion similar to that:
/var/extlogs/$stage/$client-$application
For example, if stages are integration, staging, production and clients are client1 and client2 (there are many morem in reality), I'd like to have puppet create
/var/extlogs/integration/client1-application1
/var/extlogs/integration/client1-application2
/var/extlogs/integration/client2-application1
/var/extlogs/integration/client2-application2
/var/extlogs/staging/client1-application1
/var/extlogs/staging/client1-application2
/var/extlogs/staging/client2-application1
/var/extlogs/staging/client2-application2
/var/extlogs/production/client1-application1
/var/extlogs/production/client1-application2
/var/extlogs/production/client2-application1
/var/extlogs/production/client2-application1
I've created a class that eases the job:
Well no, you've created a defined type. It's very important to understand the difference.
define lsyncd::createdestdirs (
$application = '',
$client = '',
$envstage = '',
) {
file {
'/var/extlogs':
ensure => directory,
owner => "root",
group => "root",
mode => 0755,
}
This is not actually working for you as written. At least, not for more than one combination of 'application', 'client', and 'envstage' per node. You would end up with duplicate declarations at least of File['/var/extlogs'], at least.
file {
"/var/extlogs/${envstage}":
ensure => directory,
owner => "root",
group => "root",
mode => 0755,
require => File['/var/extlogs'],
}
Note that although it is by no means wrong to declare that dependency on the parent directory, Puppet will generate it automatically for you if you omit it. I rely on that in my example code below.
[...] would there be a way to have all the directories created in one directive, by setting $application, $client, and $stage in an array?
So you want to create a directory for every combination of $application, $client, and $stage values? Historically, that sort of thing has been difficult, but there are good ways to handle it in modern Puppet.
I'm currently using puppet 2.7.25 and I'm not using hiera or puppetdb.
Unfortunately, you're stuck in "historically".
Way back in "historically", in fact: the latest Puppet is 4.2. This problem can still be handled, but it's not as clean or easy. Moreover, although puppetdb is not really relevant to the question, Hiera is. In Puppet 2.7, you have four alternatives for providing data for your classes to operate upon (your various 'client', etc. arrays):
- you can build the data directly into your classes; or
- you can parameterize your classes and use resource-like class declarations; or
- you can look up your data via an external service, with hiera() and extlookup() being the most common; or
- you can declare them as variables in a scope visible from your class, such as at node scope or even top scope.
Use of resource-like class declarations has
always been problematic, ever since parameterized classes were first introduced. There are a few specialized cases were it is relatively safe, but I rarely recommend resource-like class declarations to anyone. Since Puppet 2 provided no alternative, parameterized classes were very problematic until the introduction of automated data binding (via Hiera) in Puppet 3.
Extlookup() does not provide for structured data (e.g. arrays), and you're not using Hiera. If you want to be able to have different nodes with different clients, stages, or applications, then you cannot encode these data directly into the class that uses them.
Let's say, therefore, that you will declare
$applications = [ 'application1', 'application2' ]
$clients = [ 'client1', 'client2' ]
$envstages = [ 'integration', 'staging', 'production' ]
at top scope. You could do that via an ENC, but you could also just put such variable definitions in your site.pp or any other manifest `import'ed by it. You might then have a class (really a class) that manages the overall directory set, a defined type whose multiple instances will each manage one of the stage directories, and a helper defined type whose instances manage the ultimate directories for each stage:
class lsyncd::destdirs {
$basedir = '/var/extlogs'
# resource defaults save a bit of typing:
File {
owner => 'root',
group => 'root',
mode => '0755'
}
# The overall base directory
file { $basedir: ensure => 'directory' }
# Since (if) $envstages is an array, this declares one
# lsyncd::stagedir for each element:
lsyncd::stagedir { ${envstages}: basedir => $basedir }
}
define lsyncd::stagedir($basedir) {
# The name of the directory for the stage managed by
# this resource:
$stagebase = "${basedir}/${title}"
# Manage the directory; resource defaults from
# lsyncd::destdirs are still in effect here
file { $stagebase: ensure => 'directory' }
# One resource for this stage for each client:
lsyncd::stageclient { ${client}: stagebase => $stagebase }
}
define lsyncd::stageclient ($stagebase) {
# regsubst() uses a regex substitution to create one result
# string -- in this case a directory name -- for each element
# of $applications. The title and parameter are interpolated
# into the results to form the target directory names.
$appdirs = regsubst($applications, '.*', "${stagebase}/${title}-\1")
# Manage the ultimate directories; resource defaults from
# lsyncd::destdirs are still in effect here
file { ${appdirs}: ensure => 'directory' }
}
John