Dynamically updating a Role with the chef_role resource -- Having issues (solved)


I am attempting to update default attributes set in a chef role dynamically. I have a ruby_block that is creating a hash to pass in to pass into the chef_role resource. Unfortunately, when attempting to do this with a lazy evaluation I get the is the “DelayedEvaluator” object with the path to the locally cashed recipe. I’ve used lazy evaluation before, but this is a first for me.

Within the ruby_block I and using:

node.run_state['dynamic_hash'] = newly_built_hash_variable

And the chef_role looks like this:

chef_role 'role_name' do default_attributes "name_of_cb": { "myattr": lazy { node.run_state['dynamic_hash'] } action :create end

I end up with a attribute in the role that looks like this:

{ "name_of_cb": { "myattr": "<#Chef::DelayedEvaluator:0x6afe38@/var/chef/cache/cookbooks/name_of_cb/recipes/recipe.rb:33>" } }

Instead of this:

{ "name_of_cb": { "myattr": { "attr1": "dynamic", "attr2": "keys", "attr3": "values", } } }

So, my idea is to call the chef_role resource from within the ruby_block that is creating the hash I am attempting to pass. I’ve seen it done with other resources, but my attempts with the chef_role have been unsuccessful. I’m currently getting this error:

uninitialized constant Chef::Resource::ChefRole

So, I’m obviously missing something. I have spent way too much time trying to over come this little road block, and things that have worked before do not seem to be working.

Any pointers or ideas, even a change in how I’m doing this would be helpful.



Well, I managed to work this one out. Just had to take a couple steps back.

Turns out I had the lazy evaluation in the wrong place.

chef_role ‘role_name’ do
default_attributes “name_of_cb”: { “myattr”: lazy { node.run_state[‘dynamic_hash’] } }
action :create

I had tried to move it before but had issues there as well. Tried this:

chef_role ‘role_name’ do
default_attributes lazy { “name_of_cb”: { “myattr”: node.run_state[‘dynamic_hash’] } }
action :create

It didn’t like the node.run_state without the lazy immediately wrapping the attribute.

So, I had to got back to my ruby_block and wrap the hash output into:

node.run_state[‘dynamic_hash’] = { “name_of_cb”: { “myattr”: newly_built_hash_variable } } }

and then I could run this without issue:

chef_role ‘role_name’ do
default_attributes lazy { node.run_state[‘dynamic_hash’] }
action :create

Hope this helps someone stuck with this kind of issue in the future.


I would highly recommend only using roles for very static and unchanging things, there are many posts out there about how roles are evil and they are to some extent. I use roles personally very sparingly and use them for things that essentially do not change as there is no safe way to test this. If I need to make a real change say switching from java 7 to java 8 I would create a brand new role called java8. Then I could have the 2 exist alongside each other and orchestration can intelligently cut some of it over before updating all nodes. If something bad happens you can easily roll back.

Oh I’ve seen a role wreak some havoc. Usually very aggrivating, and sometimes a little funny.

This is more of a one off kind of thing. It only supports one cookbook utilized by one system. This was more of a way to give our team easy access to update a list of files we sync between internal and external networks. The list only accepts specific input, filters out garbage entries, and notifies us of those entries. The list is self healing. So, if it happens to be completely wiped out it will rebuild itself on the next run. I know there was a hundred other/better ways to do, but I used this more as a learning experience. Plus, worst case for us is that it stops working.