Implementing Recursive Directory Mirroring in Puppet for Configuration Management


2 views

When managing multiple configuration files in Puppet, the traditional approach of declaring each file individually becomes cumbersome:

file { 'conf0':
    path => '/etc/foo/conf0',
    ensure => file,
    source => 'puppet:///modules/module_name/etc/foo/conf0',
}

file { 'conf1':
    path => '/etc/foo/conf1',
    ensure => file,
    source => 'puppet:///modules/module_name/etc/foo/conf1',
}

This method creates maintenance overhead and doesn't scale well with growing numbers of configuration files.

Puppet's file resource type supports recursive directory management through the recurse parameter:

file { '/etc/foo':
    ensure  => directory,
    source  => 'puppet:///modules/module_name/etc/foo',
    recurse => true,
    purge   => false,
    force   => false,
}

This single resource declaration will:

  • Create the /etc/foo directory if it doesn't exist
  • Mirror all files from puppet:///modules/module_name/etc/foo
  • Maintain the same directory structure as in the source

For more control over the recursive copy operation, consider these additional parameters:

file { '/etc/foo':
    ensure       => directory,
    source       => 'puppet:///modules/module_name/etc/foo',
    recurse      => remote,
    recurselimit => 5,
    purge        => true,
    force        => true,
    owner        => 'root',
    group        => 'root',
    mode         => '0644',
}

Key parameters explained:

  • recurse => remote: Only copy files from the Puppet master
  • recurselimit: Controls depth of recursion
  • purge: Remove unmanaged files from directory
  • force: Allow purging of subdirectories

Here's a complete module example for managing Apache configuration files:

class apache::config {
    file { '/etc/apache2':
        ensure       => directory,
        source       => [
            "puppet:///modules/site_apache/${::fqdn}/etc/apache2",
            "puppet:///modules/site_apache/etc/apache2",
            "puppet:///modules/apache/etc/apache2"
        ],
        recurse      => remote,
        recurselimit => 3,
        purge        => false,
        owner        => 'root',
        group        => 'root',
        mode         => '0644',
    }
}

This implementation:

  • Uses multiple source locations with failover
  • Limits recursion depth to 3 levels
  • Preserves existing unmanaged files
  • Sets proper permissions

When implementing recursive directory management, watch for these potential problems:

  • Permission errors: Ensure the Puppet agent can read the source files
  • Performance impact: Large directories may slow catalog application
  • File conflicts: Multiple sources may cause unexpected results

For debugging, use Puppet's --debug flag to see file operations in detail.


When managing multiple configuration files in Puppet, declaring each file individually becomes tedious quickly. Consider this typical scenario:

file { 'conf0':
    path => '/etc/foo/conf0',
    ensure => file,
    source => 'puppet:///modules/module_name/etc/foo/conf0',
}

file { 'conf1':
    path => '/etc/foo/conf1',
    ensure => file,
    source => 'puppet:///modules/module_name/etc/foo/conf1',
}

Puppet's file resource type has built-in capabilities for recursive directory management. Here's the solution you're looking for:

file { '/etc/foo':
    ensure  => directory,
    recurse => true,
    purge   => false,
    source  => 'puppet:///modules/module_name/etc/foo',
    owner   => 'root',
    group   => 'root',
    mode    => '0644',
}

Let's break down the important parameters:

  • recurse => true: Enables recursive directory copying
  • purge => false: Prevents deletion of unmanaged files (set to true for strict mirroring)
  • source: Points to the module's files directory structure

For more complex scenarios, consider these additional parameters:

file { '/etc/foo':
    ensure               => directory,
    recurse             => true,
    recurselimit        => 5,       # Limit recursion depth
    purge               => true,    # Remove unmanaged files
    force               => true,    # Overwrite directories with files
    ignore              => ['temp*','.bak'], # Patterns to ignore
    sourceselect        => 'first', # Source selection behavior
    show_diff           => true,    # Show file differences
}

You can combine multiple source locations:

file { '/etc/foo':
    ensure  => directory,
    recurse => true,
    source  => [
        'puppet:///modules/module_name/etc/foo',
        'puppet:///files/global_configs/foo'
    ],
}

For systems requiring specific permissions:

file { '/etc/foo':
    ensure  => directory,
    recurse => true,
    source  => 'puppet:///modules/module_name/etc/foo',
    owner   => 'appuser',
    group   => 'appgroup',
    mode    => '0750',
}

If files aren't being copied as expected:

  1. Verify the source path exists in your module's files directory
  2. Check Puppet server file permissions
  3. Test with puppet agent --test --debug for detailed output
  4. Ensure the target directory isn't managed by another resource