A file managed by puppet that is left alone if customized

76 views
Skip to first unread message

Paul Tötterman

unread,
Apr 24, 2014, 9:33:03 AM4/24/14
to puppet...@googlegroups.com
Hi,

I'm managing workstations using puppet, and I was wondering if there's a better way to do this:

$dir = inline_template('<%=ENV["HOME"]%>') 
define customizable_file($source=undef,$template=undef,$replacemd5='') {
    $tmplname = $template ? {
        undef   => "$name.common",
        default => "$template",
    }
    file { "$tmplname":
        source => $source,
    }
    exec { "cp $tmplname $name":
        onlyif  => "test ! -e $name -o \"$(md5sum $name|cut -d' ' -f1)\" = \"$replacemd5\"",
        path    => ['/bin', '/usr/bin'],
        require => File["$tmplname"],
    }
}
customizable_file { "$dir/foo-$::hostname":
    source     => 'file:///etc/motd',
    template   => "$dir/foo-common",
    replacemd5 => 'e43e23c6d9a376bedd1ae405be4fdf97',
}

What I want to achieve is a file that is managed by puppet, but if the user touches it, puppet stops touching the file. Normal file resource with replace doesn't cut it in this case. replacemd5 should be set to the md5 sum of the previous version of the file. I'd really like to see a custom type for this, that would handle templating some nice way, or at least allow one to specify more that one md5sum of previous versions. Obviously this doesn't work well for files that change often.

So, is there a better way?

Cheers,
Paul

PS. $dir is set to home so that you can dump the contents to a file and puppet apply it to test.

José Luis Ledesma

unread,
Apr 24, 2014, 12:41:05 PM4/24/14
to puppet...@googlegroups.com

Idk if i did understand correctly, but there is the replace parameter in the file resource that may help here.

Regards

--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-users/a5a6e496-5853-4a47-a7fb-14ab5f6c1f4e%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Matthias Saou

unread,
Apr 24, 2014, 1:21:35 PM4/24/14
to puppet...@googlegroups.com
On Thu, 24 Apr 2014 18:41:05 +0200
José Luis Ledesma <joseluis...@gmail.com> wrote:

> Idk if i did understand correctly, but there is the replace parameter
> in the file resource that may help here.

I think you've missed the important bit, like I did initially : The
"replace" parameter set to false will have puppet *never* touch the
file once it's created. What the OP wants it to have puppet keep
updating the file *until it's modified locally*, at which point it
should stop.

Tricky. I can't think of any simple and clean solution from the top of
my head, though I do understand why one would want to do that... I
could actually use that behaviour for the initial ~/.gitconfig files I
create for system users, for example.

Matthias

--
Matthias Saou ██ ██
██ ██
Web: http://matthias.saou.eu/ ██████████████
Mail/XMPP: matt...@saou.eu ████ ██████ ████
██████████████████████
GPG: 4096R/E755CC63 ██ ██████████████ ██
8D91 7E2E F048 9C9C 46AF ██ ██ ██ ██
21A9 7A51 7B82 E755 CC63 ████ ████

Matthew Burgess

unread,
Apr 24, 2014, 2:13:27 PM4/24/14
to puppet...@googlegroups.com


On 24 Apr 2014 18:21, "Matthias Saou" <matt...@saou.eu> wrote:
>
> On Thu, 24 Apr 2014 18:41:05 +0200
> José Luis Ledesma <joseluis...@gmail.com> wrote:
>
> > Idk if i did understand correctly, but there is the replace parameter
> > in the file resource that may help here.
>
> I think you've missed the important bit, like I did initially : The
> "replace" parameter set to false will have puppet *never* touch the
> file once it's created. What the OP wants it to have puppet keep
> updating the file *until it's modified locally*, at which point it
> should stop.
>
> Tricky. I can't think of any simple and clean solution from the top of
> my head, though I do understand why one would want to do that... I
> could actually use that behaviour for the initial ~/.gitconfig files I
> create for system users, for example.

For files in user's home directories I would manage the skeleton files using puppet and then when the user account is created they'll be copied into their home directory. That obviously only works for new users though. It won't account for existing users or for updating the file if it hasn't been touched by the user yet.

It's perhaps a little painful but could you put a comment marker in each file you manage and then have a custom fact that checks for that marker? That is then used to determine whether the File resource is managed or not. Users would have to be told (probably in that same comment marker) that any changes to the file will be undone unless they remove the comment.

Matt

José Luis Ledesma

unread,
Apr 24, 2014, 3:04:19 PM4/24/14
to puppet...@googlegroups.com

Indeed i missed it. Perhaps you can have some custom fact that returns the md5 of the files, so you can detect if it matches the replacemd5. Probably will make the manifest simpler.

Regards,

--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.

jcbollinger

unread,
Apr 25, 2014, 11:54:10 AM4/25/14
to puppet...@googlegroups.com
As stated, your problem is intractable.  There is no reliable way to discern between the user leaving the file untouched and him modifying the file and then modifying it back.  If you want to allow for multiple versions that you are willing update, then you also cannot discern between the user having an untouched version and the user modifying the file to match a different, historical version.

The closest you can come is what you are actually implementing, which is to restrict management to one or more specific versions of the file, as opposed to restricting by whether the user has modified it.  If that's sufficient for you, however, then there is at least one alternative implementation that I can think of: leave a reference copy of the original, Puppet-provided version on the client.  Instead of tracking possibly-many MD5s, just compare the current file to its reference copy to determine whether it's OK to update.  Something like this, maybe:


$dir = inline_template('<%=ENV["HOME"]%>')

define customizable_file(
  $source=undef,
  $reference=undef,
) {
  # The default reference file name is formed by prepending '.' and
  # appending '.ref' to the file name portion of the target path.
  $ref_name = $reference ? {
    undef   => regsubst($name,'^(.*)/([^/]+)$', '\1/.\2.ref')
    default => $reference,
  }
  # This temp file could go anywhere and have any name:
  $tmp_name = "${ref_name}.tmp"
  file { $tmp_name:
    source => $source,
    # ... ownership, mode, etc. if desired ...
  }
  exec { "update customizable file $name":
    command => "cp -p $tmp_name $name && mv $tmp_name $ref_name",

    path    => ['/bin', '/usr/bin'],
    onlyif  => "test ! -e $name || cmp -s $name $ref_name",
    require => File[$tmp_name],
    provider => 'shell'

  }
}

customizable_file { "$dir/foo-$::hostname":
  source     => 'file:///etc/motd',
  reference  => "$dir/foo-common"
}


John

Kenton Brede

unread,
Apr 25, 2014, 2:17:50 PM4/25/14
to puppet...@googlegroups.com
If the end game is allowing users to add to a Puppet controlled file, perhaps you can use concat, similar to the "class motd" example on this page:

https://github.com/puppetlabs/puppetlabs-concat

Kent



--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Kent Brede




Paul Tötterman

unread,
Apr 28, 2014, 4:41:57 AM4/28/14
to puppet...@googlegroups.com

For files in user's home directories I would manage the skeleton files using puppet and then when the user account is created they'll be copied into their home directory. That obviously only works for new users though. It won't account for existing users or for updating the file if it hasn't been touched by the user yet.


$dir is in home just to make this easily testable using puppet apply. The files I'm planning to manage are in /etc and users have sudo rights.

/etc/skel is clearly the right way to handle initial home directory files.

Cheers,
Paul 

Paul Tötterman

unread,
Apr 28, 2014, 4:45:32 AM4/28/14
to puppet...@googlegroups.com
I actually just had a revelation and thought of a better way:

$dir = inline_template('<%=ENV["HOME"]%>') # again, just to make testing using puppet apply easier
file { "$dir/foo":
    source => ["file://$dir/foo.local", 'file:///etc/motd']  # the latter would typically be a puppet:/// URL
}

In case the user wishes to make local modifications that are kept, he needs to `ln foo foo.local` and puppet won't copy from the canonical source.

Cheers,
Paul

Len Rugen

unread,
Apr 28, 2014, 8:50:11 AM4/28/14
to Puppet Users
Look at the creates => option, I use that to drop an initial /etc/my.cnf, but then it can be modified and not regressed by puppet. 


--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages