Alfred
Alfred

Reputation: 21406

How to override node attribute value within ruby block / using a value of variable in ruby block?

I am using Chef of AWS OpsWorks. I have a custom attribute JSON like below;

{
    "custom_attributes": {
        "custom_attribute_1": "default_value"
    }
}

and, I can use #{node[:custom_attributes][:custom_attribute_1]}" to print / use that value anywhere in my recipes. Then, I want to change that value and I can achieve it by mentioning it in default.rb file inside attributes directory of my cookbook, like below;

override['custom_attributes']['custom_attribute_1'] = "overridden_value"

Now, if I print / use this attribute, new value will get reflected. This works well.

Lets consider I haven't overridden the value and trying to use a ruby block for this like below;

ruby_block 'test_block' do
    block do
        node.override['custom_attributes']['custom_attribute_1'] = "overridden_value"
    end
    action :run
end

log 'message' do
    message "attribute value = #{node[:custom_attributes][:custom_attribute_1]}"
    level :info
end

Now, if we take a look at log, it will show default_value instead of overridden_value. If my understanding is clear, its happening because of compile and convergence phases. Can somebody show me how to fix this issue?

Thanks.

EDIT

As per my research, I understand that the attribute assignment is happening at compile phase and ruby block evaluation is happening at converge phase. In that case, can somebody show me how to override / create new attribute using Chef Lazy? Below is a blog I came across;

https://blog.alanthatcher.io/lazy-is-good/

Upvotes: 2

Views: 376

Answers (1)

Mr.
Mr.

Reputation: 10142

can somebody show me how to override / create new attribute using Chef Lazy?

you can use lazy evaluation

In some cases, the value for a property cannot be known until the execution phase of a Chef Infra Client run. In this situation, using lazy evaluation of property values can be helpful. Instead of a property being assigned a value, it may instead be assigned a code block. The syntax for using lazy evaluation is as follows:

property_name lazy { code_block }

where lazy is used to tell Chef Infra Client to evaluate the contents of the code block later on in the resource evaluation process (instead of immediately) and { code_block } is arbitrary Ruby code that provides the value.

so you might want to use lazy as follows

log 'message' do
    message lazy { "attribute value = #{node[:custom_attributes][:custom_attribute_1]}" }
    level :info
end

Upvotes: 1

Related Questions