Background

In Chef, when a resource is defined all its attributes are evaluated during compile time and the execution of the resource takes place in converge phase. So if the value of a particular attribute is changed in converge (and not in compile) the resource will be executed with the old value.

Note: In Chef 11, there is a feature coming up called lazy evaluator which will allow you to evaluate an attribute during converge instead of compile phase.

Update: This feature is implemented and the documentation can be found here.

Example problem:

Lets consider this situation where there are two steps involved in a recipe. Step 1 is a Ruby block that changes a node attribute. Rubyblocks get executed in converge phase. Step 2 is a Chef resource that makes use of the node attribute that was changed in Step 1

Without any modification to the code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
node[:test][:content] = "old content"

# Step 1
ruby_block "step1" do
  block do
    node[:test][:content] = "new content"
  end
end

# Step 2
file "/tmp/some_file" do
  owner "root"
  group "root"
  content node[:test][:content]
end

The file resource will still have the old content as it is set in the compile phase.

With hacked code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
node[:test][:content] = "old content"

# Step 1
ruby_block "step1" do
  block do
    node[:test][:content] = "new_content"

    # Dynamically set the file resource attribute
    # Obtain the desired resource from resource_collection
    file_r = run_context.resource_collection.find(:file => "/tmp/some_file")
    # Update the content attribute
    file_r.content node[:test][:content]
  end
end

# Step 2
file "/tmp/some_file" do
  owner "root"
  group "root"
  content node[:test][:content]
end

The file resource will now have the updated content. This may not be a cleaner way to do things. There might be other workarounds which will avoid hacking the resource collection like this. I had a situation where I had to dig in and find a way to dynamically change the resource attribute. The lazy evaluator will make things simpler. For people who is not ready to adopt Chef 11 yet, this method of hacking will provide a workaround.

Comments