Puppet: managing directories recursively

This is not very obvious from Puppet's TypeReference, but you can manage directories in a very interesting way:

  • Recursively copy a directory from the filestore to a client _and_
  • remove all unmanaged files
Still not very interesting, but please see the light:
  • You can deploy an empty directory,
  • Fill this directory using seperate file resources, possibly from other modules (or even other nodes, if you use exported resources)
  • Everything puppet did not put into the directory gets removed.
This yields, very effectively, a fully managed directory with lots of flexibility.
We're using this approach for all sorts of configuration directories, including:
  • APT's sources.list.d and apt.conf.d
  • Debian-Apache2's sites-available/sites-enabled
  • Debian-Exim4's conf.d (including subdirectories)
  • Bacula director/Munin configuration (in combination with the concatenated_file type)
For this to work, you need to do a little bit of work:
  • prepare a directory in your module filestore which will be the (usually empty) source directory
    I often put a README file in there, explaining what's going on.
  • add this code snippet for managing the target directory:
    file { "/etc/exim4/conf.d":
      ensure => directory, # so make this a directory
      recurse => true, # enable recursive directory management
      purge => true, # purge all unmanaged junk
      force => true, # also purge subdirs and links etc.
      owner => "root",
      group => "root",
      mode => 0644, # this mode will also apply to files from the source directory
      # puppet will automatically set +x for directories
      source => "puppet:///exim/exim4-conf.d-empty",
    }
    
  • add one or more file resources which deploy files into the target directory, example:
    file { "/etc/exim4/conf.d/router/400_testrouter":
      ensure => present,
      owner => "root",
      group => "root",
      mode => 0644,
      source => "puppet:///exim/exim4-conf.d/router/400_testrouter",
    }
    
Because puppet looks for those file resources which manage a sub-dir of the managed directory it is also possible to define a sub-directory with unmanaged files, which will then not get removed - no magic involved here:
file { "/etc/exim4/conf.d/acl":
  ensure => directory,
  owner => "root",
  group => "root",
  mode => 0755,
}