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.