I had exactly this situation: I wanted to manage application configuration, but developers wanted to be able to alter the configs as necessary, yet still revert to the "real" config when they wanted. It's a snap with a define{}:
# We would like to both distribute configuration files as well as
# enable the developers to make their own changes without having them
# overriden. This define is for doing that. You probably want to
# have good defaults set with File{} so that the file is created with
# the appropriate permissions.
#
# Usage:
#
# managed_file { "/export/home/geek/festus": source => "puppet:///modules/foo/bar" }
#
# In /export/home/geek, two files will be create: README.festus and
# festus-puppet. The README file will contain a message telling the
# reader to touch festus.noupdate to prevent Puppet from updating the
# file. As long as the festus.noupdate file does NOT exist, Puppet
# will ensure that festus matches festus-puppet.
#
define managed_file($source = undef, $content = undef) {
$pdir = inline_template("<%= name.reverse().split('/',2)[1].reverse() %>")
$basename = inline_template("<%= name.split('/')[-1] %>")
file {
"${name}-puppet":
source => $source, content => $content, ensure => present;
"${pdir}/README-${basename}":
ensure => present,
content => "${name} is managed by Puppet.\n\nIf you need to edit\n${name}\nand have your changes persist, touch\n${name}.noupdate\nand Puppet will ignore that file. When you are done with your\ntesting, please have your changes put in Puppet and delete the\n${name}.noupdate\nfile. Thanks.\n\n";
}
exec {
"${name}-sync":
unless => "test -f ${name}.noupdate || cmp -s ${name} ${name}-puppet",
command => "/usr/local/bin/rsync -a ${name}-puppet ${name}",
require => File["${name}-puppet"];
}
}
</pre>