8

I am trying to provision a vagrant VM to allow users to supply their own bash_profile.local but I don't want this file tracked in the vm's vcs repo. I have a tracked bash_profile.local.dist file that they can rename. How can I tell puppet to only create a file if the source file exists? It is currently working correctly but logs an error during provisioning and this is what I'm trying to avoid.

This is the manifest:

class local
{
    file { '.bash_profile.local':
        source => 'puppet:///modules/local/bash_profile.local',
        path => '/home/vagrant/.bash_profile.local',
        replace => false,
        mode => 0644,
        owner => 'vagrant',
        group => 'vagrant',
    }
}
pdizz
  • 4,100
  • 4
  • 28
  • 42

3 Answers3

12

You could abuse file in this way :

$a = file('/etc/puppet/modules/local/files/bash_profile.local','/dev/null')
if($a != '') {
    file { '.bash_profile.local':
        content => $a,
        ...
    }
}
bartavelle
  • 897
  • 8
  • 16
  • 3
    Nice trick, thanks. If anyone's reading this and wondering what's going on, file() will attempt to read each file in turn until it succeeds so if the first file doesn't exist it will read /dev/null which returns ''. – pdizz Dec 12 '13 at 21:41
  • 1
    Why not using the unless or onlyif on the file resource and bash test [function](http://ryanuber.com/04-17-2010/conditional-file-creation-puppet.html) ? – mestachs Dec 17 '13 at 18:02
  • This is great, but I would like to add that if you copy the code in this answer and stick a variable in the path, the single-quotes mean that the variables are not interpreted. Change the single-quotes to double-quotes if you use a variable. (-: – Steve HHH Feb 18 '14 at 06:12
  • 5
    @mestachs : `file` works on the puppetmaster, not on the client, that's the trick. – bartavelle Mar 01 '14 at 19:07
  • In puppet 3.8, is it possible to do this, but include this clause as a chained rule using an arrow operator? i.e. `->` operator – JDS Nov 03 '15 at 18:43
6

This is not exactly what you asked but you can supply multiple paths in the source, so you can have a default empty file if the user didn't supplied his own.

class local
{
    file { '.bash_profile.local':
        source => [
            'puppet:///modules/local/bash_profile.local',
            'puppet:///modules/local/bash_profile.local.default'
        ],
        path => '/home/vagrant/.bash_profile.local',
        replace => false,
        mode => 0644,
        owner => 'vagrant',
        group => 'vagrant',
    }
}
Filipe Giusti
  • 2,923
  • 3
  • 24
  • 18
1

You can try something like this:

file { 'bash_profile.local':
    ensure => present,
    source => ['puppet:///modules/local/bash_profile.local', '/dev/null'],
    path   => '/home/vagrant/.bash_profile.local',
    before => Exec['clean-useless-file'],
}
exec { 'clean-useless-file':
    command => 'rm .bash_profile.local',
    onlyif  => 'test -s .bash_profile.local',
    cwd     => '/home/vagrant',
    path    => '/bin:/usr/bin',
}

If the admin don't make a copy of ".bash_profile.local" available in "modules/local/bash_profile.local", the file resource will use the second source and then create a blank file. Then, the "onlyif" test fails and the exec will remove the useless blank file.

Used this way this code can be a little cumbersome, but it's better than a provisioning failure. You may evaluate if retaining a blank .bash_profile.local file can be okay in your case. I normally use a variation of this, with wget instead of rm, to get a fresh copy of the file from the internet if it was not already made available as a source.

If you're using puppetmaster, be aware you can use it to provision the own server, presenting two versions of the catalog, according to the .bash_profile.local is present or not.

mfandrade
  • 67
  • 1
  • 4