Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to install multiple files with a single File-resource

Tags:

puppet

I need to install a number of files into a directory, which is not itself Puppet-managed. The source of each file is under files/ subdirectory of my module.

I'd like to install them all in one go, because their ownership and permissions are all the same. But what do I put for source? I was hoping, simply specifying the directory would work:

  file {[
    "${rcdir}/foo", "${rcdir}/bar",
  ]:
    source => "puppet:///${module_name}/",
    group  => 'wheel',
    owner  => 'root',
    mode   => '0644'
  }

but, unfortunately, Puppet (using 3.7.5 here) is not smart enough to automatically append the foo and the bar appropriately.

Is there a nice way to do it, or do I have to painstakingly enumerate each file? Thank you!

like image 586
Mikhail T. Avatar asked Apr 26 '16 18:04

Mikhail T.


1 Answers

There are multiple techniques to achieving what you are doing here, with advantages and disadvantages to each.

The first, and most explicit, which gives you the ability to configure each file independently as well as see the complete list of files you are managing, is to define each file independently. To reduce the amount of code duplication, you could utilize type defaults (although this is not always appropriate). This would look something like the following:

File {
  group  => 'wheel',
  owner  => 'root',
  mode   => '0644',
}
file { "${rcdir}/foo":
  source => "puppet:///modules/${module_name}/foo",
}
file { "${rcdir}/bar":
  source => "puppet:///modules/${module_name}/bar",
}

This obviously becomes very unwieldy quite quickly though.

A second strategy would be to utilize a defined type. It's a bit of a heavy tool to use for something like this, but it'll do the trick. This would look something like this:

define myclass::file_array (
  $dest_base,
  $source_base,
  $group = 'wheel',
  $owner = 'root',
  $mode  = '0644',
) {
  file { "${dest_base}/${name}":
    source => "${source_base}/${name}",
    group  => $group,
    owner  => $owner,
    mode   => $mode,
  }
}
class myclass (){
  $files_to_manage = ['foo', 'bar', 'baz']
  myclass::file_array { $files_to_manage:
    source_base => "puppet:///modules/${module_name}",
    dest_base   => $rcdir,
  } 
}

This requires you to add in a relatively arbitrary defined type and ends up requiring you to add lots of other parameters if you want to pass through all the properties available to the core file type, however for your situation it would suffice.

However, the simplest, and cleanest way to do what you are attempting is by allowing the file resource to utilize its recursive functionality, and place all the necessary files into their own directory in your module (assuming you have other files that are unrelated to this destination directory). It does require that you allow Puppet to manage the existence of the directory, but it is difficult to imagine that this is a problem for you (as any of this code would fail if the destination directory didn't exist already anyhow). This would look something like this:

file { $rcdir:
  ensure  => directory,
  recurse => true,
  source  => "puppet:///modules/${module_name}/rc_files",
  owner   => 'root',
  group   => 'wheel',
  mode    => '0644',
}
// module directory 'files/rc_files' is where foo and bar would exist

I'm pretty sure that last one is your ideal solution, and you can utilize other aspects of the file resource (https://docs.puppet.com/puppet/latest/reference/type.html#file-attribute-recurse) such as purge to validate that no extra files end up in your destination.

There's other techniques out there, but hopefully one of these will do the trick for you.

like image 174
Josh Souza Avatar answered Nov 15 '22 08:11

Josh Souza