Define an attribute with another attribute

Hi Team,

In my environment file, I have defined an attribute say ['app']['web'] = 'nginx' and in another environment file ['app']['web'] = 'apache'

My intention is to create a recipe which will run on any environment. Inside the recipe I'm defining one attribute. So while running this recipe in the first environment i want to define node.default['cluster']['nginx']['endpoint'] and in second environment it should be node.default['cluster']['apache']['endpoint']

I used the following
node.default['cluster'][node['app']['web']]['endpoint']

But this is not working. Is there any way I can achieve this ?

Unless you need to have both an nginx config and a apache config at the same time you can just use attribute and override it from your environment file.

Default['cluster']['endpoint'] = ''
In your environment file just do this to override the value, the name of the attribute doesn't really matter so much just the value of the attribute.
Override['cluster']['endpoint'] = 'new value'

You can also do

Default['cluster']['endpoint'] = node['cluster']['nginx']['endpoint']

To set the value of the cluster endpoint value to that of the nginx endpoint value.

It's going to depend on node['app']['web']. If you have

node['app']['web']['endpoint'], I suspect that node['app']['web'] isn't
just a string, but rather a hash. Easy to fix, but first, I'm not sure
precisely certain what you mean by apache and nginx. Are these just
human-friendly labels? Are they package names? Are they service names?

If they are the names of the actual packages, I'd do something like

default['cluster']['web']['package']

or perhaps

default['cluster']['web']['service']

if it's just the name of the desired service. Ensure that whichever you
choose is either going to be set to a string or something that can be
cast to a string.

Then try

node['cluster'][node['app']['web']['daemon']]['endpoint'] or even
node['cluster'][node['app']['web']['daemon'].to_s]['endpoint']

Actual code that's similar and has worked (that probably has more
".to_s" than it needs).

node['jdk']['versions'].each do |key, value|

[snip]

package
node['jdk']['packages'][node['platform_family'].to_s][key.to_s]['package'].to_s
do
version
node['jdk']['packages'][node['platform_family'].to_s][key.to_s]['version'].to_s
end

where these attributes are defined.

default['jdk']['packages']['debian'] = {
'oracle7' => {
'package' => 'oracle-j2sdk1.7',
'version' => '1.7.0+update55',
},
}
default['jdk']['packages']['rhel'] = {
'oracle7' => {
'package' => 'jdk',
'version' => '2000:1.7.0_55-fcs',
},
}

default['jdk']['versions'] = {
'oracle7' => true,
}

@kencrouch Thank you for your detailed update. I didn't fully understood about the .to_s method. I'm a beginner on this and apologize for that.

In the environment file I defined the attribute

"override_attributes": {
"app":{"web":"nginx"}
}

In recipe, defining the another attribute

node.default['cluster'][node['app']['web']]['endpoint'] = "somevalue"

===
But during the converge it failed to get the value of node['app']['web'] and throwing the error
undefined method `' for nil:NilClass

Could you let me know what modification I need to make inorder to work this

[theonlyjyothish] theonlyjyothish
https://discourse.chef.io/u/theonlyjyothish
December 6

@kencrouch https://discourse.chef.io/u/kencrouch Thank you for your
detailed update. I didn't fully understood about the .to_s method. I'm a
beginner on this and apologize for that.

Adding ".to_s" returns a string representation of your object. It can
sometimes force something that isn't what you intended to "work" enough
that you can see what's happening. :slight_smile:

node.default['cluster'][node['app']['web']]['endpoint'] = "somevalue"

instead of

node.default['cluster'][node['app']['web']]['endpoint'] = "somevalue"

try using something like

node.default['cluster'][node['app']['web']['service'].to_s]['endpoint']
= "somevalue"

Basically, since you have

node['app']['web']['endpoint']

you might not want to use

node['app']['web']

as a string in the name of an attribute. Instead use

node['app']['web']['SOMETHING'] where SOMETHING could be 'name',
'package', 'daemon', 'service', 'whatever' (but not endpoint).