Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
276 views
in Technique[技术] by (71.8m points)

chef infra - Overriding attributes in the recipe

Let's say I have a default attribute in a cookbook:

default.nginx_upstreams = {
    'service1' => ['service1.server.com'],
    'service2' => ['service2.server.com'],
}

Then it gets modified and overridden in roles and environments until it finally gets to my recipe. There, I compute some additional services that I would like to add to the attribute. If I do something like this:

node.nginx_upstreams.merge! {'service3' => ['service3.server.com']}

then when I try to use the attribute in my template, I get a undefined method 'each' for nil:NilClass in my template when I try to do

<% node.nginx_upstreams.each do |name, servers| %>

Plus, I also get a WARN: Setting attributes without specifying a precedence is deprecated and will be removed in Chef 11.0. The helpful warning tells me how to set attributes at normal precedence (apparently, using node.set["key"] = "value", but doesn't tell me how to specify default or override attributes.

I can get around this problem by doing something like this:

upstreams = node.nginx_upstreams.to_hash
upstreams.merge! {'service3' => ['service3.server.com']}

template "nginx_config" do
    variables({:upstreams=>upstreams})
end

but that feels like a hack. I cannot find any documentation on node.set() beyond this page, which also indicates that you can set both normal and override attributes in the recipe but doesn't say how.

So... how do you properly set attributes (that get deep-merged along with everything else) from inside the recipe? What does the node.set() call actually do, and can I tell it the precedence I want to merge at?

question from:https://stackoverflow.com/questions/14619001/overriding-attributes-in-the-recipe

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

default.nginx_upstreams is the same as default[:nginx_upstreams] and default['nginx_upstreams'] - the convention is to use 1 of the latter two. And as you are using strings further, use them here too.

The way you init nginx_upstreams in attribute file is the same as doing it this way:

default['nginx_upstreams']['service1'] = ['service1.server.com']
default['nginx_upstreams']['service2'] = ['service2.server.com']

And you don't have to init default['nginx_upstreams'] = {} before that. These are not hashes, but attributes, and they are a lot smarter. :)

Modifying attributes from inside the recipe is done like that:

node.default['nginx_upstreams']['service3'] = ['service3.server.com']

You can use set or override instead of default here, if you need to change precedence. Omitting the precedence name (node['nginx_upstreams'] or node.nginx_upstreams) will use the set precedence. But this is deprecated and soon to be removed - that's what the warning is all about. Check out the manual page about attributes, because everything is actually there.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...