Reputation: 87
I have a Chef DataBag that I'm trying to read and use inside of a chef recipe, and its kicking my ass. Please note: I'm not a programmer, and the use of Chef is my first entry into Ruby.
Based off of the examples I've found online, here is the contents of the databag "AWSProd" that lives in a folder called WEB under the data_bags folder on my Chef server:
{
"id" : "AWSProd",
"hosted_sites" : {
"siteA" : [
{
"site_name" : "siteA",
"site_doc_root_folder" : "siteA",
"site_simlink" : ""
}
],
"siteB" : [
{
"site_name" : "siteB",
"site_doc_root_folder" : "siteB",
"site_simlink" : ""
}
]
}
}
In my recipe, I'm using the following to grab the Databag for use:
WEB = data_bag("WEB")
WEB_env_globals = data_bag_item("WEB", node.chef_environment)
Then I basically want to iterate each site (siteA, siteB, etc) and grab those individual values for site_name, site_doc_root_folder, etc...
I'm trying to just echo the values so I know they work. I tried this:
WEB_env_globals["hosted_sites"].each do |site|
each_sitename = site["site_name"] ## can't convert String into Integer
each_site_doc_root_folder = site["site_doc_root_folder"]
each_site_simlink = site["site_simlink"]
execute "echo each site" do
command "echo #{each_sitename} #{each_site_doc_root_folder} #{each_site_simlink}"
action :run
end
end
But I received a "can't convert String into Integer" error on the line where I have the double ##.
Then I tried replacing that line with something like this:
each_sitename = WEB_env_globals["hosted_sites"][site]["site_name"]
But then I get an "undefined method `[]' for nil:NilClass" error on that line.
I know I'm missing something completely basic with Ruby here, and I've been looking for about an hour for a clear explanation and cant find one. Help me Ruby-Won-Kenobi...
Upvotes: 0
Views: 551
Reputation: 87
Ok, so I got it! Took a little education on Hash Vs Arrays...
Below is the correct ruby block:
WEB_env_globals["hosted_sites"].each do |site,data|
data.each do |hash|
each_sitename = hash["site_name"]
each_site_doc_root_folder = hash["site_doc_root_folder"]
each_site_simlink = hash["site_simlink"]
execute "echo each site #{site}" do
command "echo #{each_sitename} #{each_site_doc_root_folder} #{each_site_simlink}"
action :run
end
end
end
Upvotes: 0
Reputation: 4223
You are using the .each
method on a Hash
, but only capturing the key.
WEB_env_globals['hosted_sites'].each do |key, value|
- but you only gave it a name for the key.
each_sitename = site[....]
- remember that site is the key (a String), so you're calling the []
method on String
which expects an Integer and returns the char at that index.
*You can call .class
on any ruby object to find out what type it is. This is very helpful for troublshooting
So you can change your databag to use an array of hashes:
change your databag:
{
"id" : "AWSProd",
"hosted_sites" : [
{
"site_name" : "siteA",
"site_doc_root_folder" : "siteA",
"site_simlink" : ""
},
{
"site_name" : "siteB",
"site_doc_root_folder" : "siteB",
"site_simlink" : ""
}
]
}
Or leave it alone and try this for your code: (note I also don't use an execute
block for my debugging)
WEB_env_globals["hosted_sites"].each do |sitename, site_array|
site_array.each do |site|
each_sitename = site["site_name"]
each_site_doc_root_folder = site["site_doc_root_folder"]
each_site_simlink = site["site_simlink"]
Chef::Log.debug "#{each_sitename} #{each_site_doc_root_folder} #{each_site_simlink}"
# you could use puts or a higher level log message to make this easier to see in your output.
end
end
Upvotes: 0
Reputation: 54267
In your data bag item, each site is an array of hashes. I don't think this is what you intended, since you would need to access it like:
site[0]["site_name"]
What you probably wanted was a data bag item like:
{
"id" : "AWSProd",
"hosted_sites" : {
"siteA" : {
"site_name" : "siteA",
"site_doc_root_folder" : "siteA",
"site_simlink" : ""
},
"siteB" : {
"site_name" : "siteB",
"site_doc_root_folder" : "siteB",
"site_simlink" : ""
}
}
}
Upvotes: 1