4
votes

I have a recipe in chef, which I want to use multiple times (in multiple roles), only with a few parameters different. I want to be able to use multiple such roles on the same node.

How can I "parameterize" the recipe? I can't use attributes, because those are on node, so one role would override another's attributes.

2

2 Answers

3
votes

Recommended approach in this case is to use a lightweight resource provider or similar.

I think when the runlist is converged it dedupes any recipes so if you had 6 roles all including the same recipe and added each role to the runlist it would only actually run that recipe once.

Seems like someone asked opscode this before

Brief introduction to LWRP's can be found here, althought that is more executing than creating a new one.

In this case once you have the LWRP you can either create one recipe which calls it multiple times or individual recipes for each call.

You could look to leverage the data model hierarchy of the node to build some sort of object that represents the instances of this you want to run and loop it that way.

0
votes

I found this answer very useful in helping me with a similar use case. I wanted to share a simple example of creating an object to iterate over that PatrickWalker refers to ("...build some sort of object that represents the instances.. and loop..."). I hope this may help someone.

  1. Create an attribute with a value which is a JSON string containing an array for each iteration and each array entry containing the parameters for each iteration.

  2. Iterate over this array in a recipe performing an action using the parameters from the JSON string (you can encapsulate re-usable code in a definition or a LWRP).

Simple Example

Creates one or more files with specific names and contents defined in JSON:

Attribute:

default['config'] = '{"files":[{"name":"/tmp/file_1","content":"file contents 1"},{"name":"/tmp/file_2","content":"file contents 2"}]}'

Recipe:

config = JSON.parse("#{node['config']}")
files = config['files']

files.each do |file|
  file "#{file['name']}" do
    content "#{file['content']}"
  end
end

You can extrapolate this simple example into your own use case.