Behaviour of node attributes from json file


I have some troubles to understand how attributes from json node files are
manage by chef.

My first use case is I have one and only one server using mdns, so I have to
open mdns port on my firewall.
So I declare this port on it node file attributes, as follow

name 'ssh-server’
run_list(‘recipe[firewall]’, ‘recipe[ssh::server]’)
default_attributes(:firewall => {:rules => [{ :dst_port => ‘ssh’ }]})

“name” : “dev.local”,
“chef_type” : “node”, “json_class”: “Chef::Node”,
“run_list” : [ “role[ssh-server]” ],
“normal” : {“firewall”: {“rules”: [{“protocol”: “udp”, “dst_port”:

Problem, after chef-client run, only mdns port is open, not other role ones
(like ssh port).

If I want the right result, I have to write :
“name” : “dev.local”,
“chef_type” : “node”, “json_class”: “Chef::Node”,
“run_list” : [ “role[ssh-server]” ],
“normal” : {“firewall”: {“rules”: [
{“protocol”: “udp”, “dst_port”: “mdns”},
{“dst_port”: “ssh”},
The ssh part is duplicated with the role attribute.

On IRC, someone points to me my node attributes are « normal » and so take
precedence over « default » role ones.
2nd try, this time with « default » on role attributes.
This time, only recipe or role attributes are loaded, not node ones.
Same behaviour with « override ».

I decide to investigate a little more. And it’s a very mess for me…
I run the following chef configuration :

After « knife node from file » which load default, normal and override node
attributes, « knife node show » see correct values for all types.
When running « chef-client », only default node attributes are seens,
overloading totally other role or recipes attributes, without deep merge.
After « chef-client », « knife node show » see only normal attributes. Default
and override are reset on each run.
If this reset is done just at the beginning of the run before the deep-merge,
this behaviour may explain why override and default attributes are not seens
at all.

At this time and because node attribute behaviour, my chef config becomes more
and more unmaintainable.
On each node with only one « private/custom » attributes (here mdns, but later
vpn server, x509 certificates, user account…), I have to duplicate in it node
file all the attributes calculated normally by deep-merge at runtime.
Modifying one recipe or role attributes and all related « custom » nodes must
be rewritten (in my case, changing the default ssh port).

My questions now :

  1. Why json node file attributes are not deeply merged with others (role and
    recipe) ?
  2. Related to 1., how I can manage per node attributes in this case ?
  3. Why default and override node attributes are reset on each run and not
    normal ones ?
  4. What is the real workflow for attributes, I’m just totally lost by it
    behaviour =(

Thanks a lot for your answers !

Nicolas VINOT