Deploying Multiple files using Chef and Arrays

This post is one of a number of posts I’m making on nifty little tricks for Chef beginners.  These posts will try and detail solutions to common problems I found when learning Chef.  Hopefully I will save some people some time.

When I first started using Chef I would write the same lines of code over and over again to deploy files to a server.  This code would look something like the following:

cookbook_file "/etc/test/file1.txt"
   source "/my/files/file1.txt"

While this works for a few files it soon becomes unmanageable when you need to deploy more than a few.  The easiest way to keep your recipe nice and tidy is to create an array of the files and loop through the array performing the Chef action on the file that’s needed.  This will reduce the number of lines in your recipe and will be easier to maintain going forward.  This looks like this:

# Location of the files and templates within the cookbook
# the following location would translation to files/default/my/files

# Location to deploy to

# Array of the files that require to be deployed
file_array = [

# For each file in the array
file_array.each do |this_file|
   cookbook_file "#{etc_directory}/" + this_file do
      source "#{files_directory}/#{this_file}"

The inner code works with cookbook_file, template or anything else you may need to do multiple times.


Creating Directories Including Parents using Chef on Windows

I’ve recently been building some test environments on Microsoft Windows 2008 R2 using Chef. One thing that Chef misses is an easy way to create parent directories if needed when creating a directory.

The standard method of creating a directory will not work if D:\foo\bar doesn’t already exist:

directory "D:\\foo\\bar\\buzz" do
   action :create

You can create a parent directories by placing each element of a path into an array, then loop through the array creating each folder:

%w[ D:\\foo \\foo\\bar \\foo\\bar\\baz ].each do |path|
   directory path do
      action :create

I already had my path declared in a variable for other uses. I didn’t want to store it twice and I didn’t want to create a block of Ruby to try and break the path up from the variable.

After some research I discovered that its easier to simply run the New-Item command in a PowerShell block:

# Location of the install and patch directory

# Create the directory, including parents
powershell_script "create_install_directoy_if_not_exists" do
   guard_interpreter :powershell_script
   code "New-Item -ItemType Directory -Path #{install_directory} -Force"
   not_if "Test-Path #{install_directory}"

This will create the directory, including parent directories if needed. On Windows this appears to be the easiest way of coping with missing parent directories.