# How to access attributes later in a recipe from where they're set

**URL:** <https://discourse.chef.io/t/how-to-access-attributes-later-in-a-recipe-from-where-theyre-set/1846>\
**Category:** Chef Infra (archive)\
**Created:** [May 19, 2011, 12:48pm UTC](https://discourse.chef.io/t/how-to-access-attributes-later-in-a-recipe-from-where-theyre-set/1846 "2011-05-19T12:48:27Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Edward\_Sargisson](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.chef.io/edward_sargisson/32/570_2.png) [@Edward\_Sargisson](https://discourse.chef.io/u/Edward_Sargisson)\
**Post date:** [May 19, 2011, 12:48pm UTC](https://discourse.chef.io/t/how-to-access-attributes-later-in-a-recipe-from-where-theyre-set/1846/1 "2011-05-19T12:48:27Z")

</div>

Hi all,  
I’m a bit confused about when Ruby gets compiled, how this interacts  
with attributes and how to get attribute data that is saved early in  
the recipe to be available later in the recipe.

My desired outcome is to have the recipe create a volume from a  
snapshot, grab the resulting volume id and insert it into the backup  
script so that new backups can snapshot the new volume.

Early in my recipe I have this:  
aws\_ebs\_volume “app\_db\_volume” do  
  
end

The aws\_ebs\_volume resource saves the resulting EBS volume id to node data.

Later on I have - this is where I grab the volume id that was saved  
and put it into the snapshot:  
template “/usr/local/sbin/app\_db\_snapshot.sh” do  
source "snapshot.sh.erb"  
mode 0744  
owner "root"  
group "root"  
variables({  
:directory =\> “/var/lib/postgresql/8.4/main”,  
:description =\> “Apps Database QA”,  
:volume\_id =\> node[:aws][:ebs\_volume][:app\_db\_volume][:volume\_id]  
})  
end

I had this running fine in a node that had already successfully  
attached to the volume and saved the volume id… When I ran it on a  
brand new node I get:  
FATAL: NoMethodError: undefined method `[]’ for nil:NilClass  
This happens just as soon as the processing gets to the recipe but  
before it does anything at all.

My hyptothesis is that the recipe is being compiled by Ruby and it’s  
not finding the node data and thus the error.

So, how do I access node data from earlier in the recipe? Or do I need  
to break this code into a separate recipe?

Thanks in advance,  
Edward

---

<div class="post-metadata">

**Author:** ![Bryan\_McLellan](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.chef.io/bryan_mclellan/32/81_2.png) [@Bryan\_McLellan](https://discourse.chef.io/u/Bryan_McLellan)\
**Post date:** [May 19, 2011, 3:05pm UTC](https://discourse.chef.io/t/how-to-access-attributes-later-in-a-recipe-from-where-theyre-set/1846/2 "2011-05-19T15:05:47Z")

</div>

On Thu, May 19, 2011 at 5:48 AM, Edward Sargisson [esarge@pobox.com](mailto:esarge@pobox.com) wrote:

> Early in my recipe I have this:  
> aws\_ebs\_volume "app\_db\_volume" do  
>   
> end

What is this useful content? Is this Ruby?

There are a couple ways to run ruby code that get executed at  
different time, either just including it or putting it in a  
ruby\_block. [1]

It would be easier to assist you with the full cookbook available to  
read, such as a gist.

Bryan

[1] [The power of Chef and Ruby | btm.geek](http://blog.loftninjas.org/2011/02/16/the-power-of-chef-and-ruby/)

---

<div class="post-metadata">

**Author:** ![Vladimir\_Girnet](https://avatars.discourse-cdn.com/v4/letter/v/e19b73/32.png) [@Vladimir\_Girnet](https://discourse.chef.io/u/Vladimir_Girnet)\
**Post date:** [May 19, 2011, 6:48pm UTC](https://discourse.chef.io/t/how-to-access-attributes-later-in-a-recipe-from-where-theyre-set/1846/3 "2011-05-19T18:48:54Z")

</div>

I run into similar issue some time ago, but I could manage it by  
defining require attribute at role level.

It looks like attribute  
"node[:aws][:ebs\_volume][:app\_db\_volume][:volume\_id]" is set/created  
only after resource "aws\_ebs\_volume" is executed first time.  
But at compile time Chef wants to assign to "volume\_id" this attribute,  
which is undefined yet.

I think you may try to define a generic value for this attribute at the  
beginning of the recipe, but I'm not sure that "volume\_id" will be  
re-evaluated at aws resource execution.

A better way may be to call attribute directly in template file.  
Template resource will run after aws resource, which will ensure  
attribute is already defined.

Hope this helps.

On 5/19/2011 3:48 PM, Edward Sargisson wrote:

> Hi all,  
> I'm a bit confused about when Ruby gets compiled, how this interacts  
> with attributes and how to get attribute data that is saved early in  
> the recipe to be available later in the recipe.
> 
> My desired outcome is to have the recipe create a volume from a  
> snapshot, grab the resulting volume id and insert it into the backup  
> script so that new backups can snapshot the new volume.
> 
> Early in my recipe I have this:  
> aws\_ebs\_volume "app\_db\_volume" do  
>   
> end
> 
> The aws\_ebs\_volume resource saves the resulting EBS volume id to node data.
> 
> Later on I have - this is where I grab the volume id that was saved  
> and put it into the snapshot:  
> template "/usr/local/sbin/app\_db\_snapshot.sh" do  
> source "snapshot.sh.erb"  
> mode 0744  
> owner "root"  
> group "root"  
> variables({  
> :directory =\> "/var/lib/postgresql/8.4/main",  
> :description =\> "Apps Database QA",  
> :volume\_id =\> node[:aws][:ebs\_volume][:app\_db\_volume][:volume\_id]  
> })  
> end
> 
> I had this running fine in a node that had already successfully  
> attached to the volume and saved the volume id.. When I ran it on a  
> brand new node I get:  
> FATAL: NoMethodError: undefined method `' for nil:NilClass  
> This happens just as soon as the processing gets to the recipe but  
> before it does anything at all.
> 
> My hyptothesis is that the recipe is being compiled by Ruby and it's  
> not finding the node data and thus the error.
> 
> So, how do I access node data from earlier in the recipe? Or do I need  
> to break this code into a separate recipe?
> 
> Thanks in advance,  
> Edward

---

<div class="post-metadata">

**Author:** ![Edward\_Sargisson](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.chef.io/edward_sargisson/32/570_2.png) [@Edward\_Sargisson](https://discourse.chef.io/u/Edward_Sargisson)\
**Post date:** [May 20, 2011, 5:20am UTC](https://discourse.chef.io/t/how-to-access-attributes-later-in-a-recipe-from-where-theyre-set/1846/4 "2011-05-20T05:20:10Z")

</div>

Hi Bryan and Vladimir,  
I didn't include the contents of the aws\_ebs\_volume resource as I'm  
fairly sure they're not relevant. As Vladimir said, the effect of tha  
aws\_ebs\_volume resource is that the volume id gets saved into  
node[:aws][:ebs\_volume][:app\_db\_volume][:volume\_id].

Vladimir's idea of setting an default attribute didn't work. The  
receip compiled and ran but the resulting file had no value for the  
volume\_id.  
I looked at the ruby\_block resource but I can't see that helping  
because I need to poke the attribute into a template resource.  
What did work was using the attribute directly in the recipe. This  
isn't ideal because I wanted to use that template in a number of  
places with different volume ids .

Thanks a lot for the help.  
Cheers,  
Edward

On Thu, May 19, 2011 at 11:48 AM, Vladimir Girnet  
[vgirnet@tacitknowledge.com](mailto:vgirnet@tacitknowledge.com) wrote:

> I run into similar issue some time ago, but I could manage it by defining  
> require attribute at role level.
> 
> It looks like attribute  
> "node[:aws][:ebs\_volume][:app\_db\_volume][:volume\_id]" is set/created only  
> after resource "aws\_ebs\_volume" is executed first time.  
> But at compile time Chef wants to assign to "volume\_id" this attribute,  
> which is undefined yet.
> 
> I think you may try to define a generic value for this attribute at the  
> beginning of the recipe, but I'm not sure that "volume\_id" will be  
> re-evaluated at aws resource execution.
> 
> A better way may be to call attribute directly in template file. Template  
> resource will run after aws resource, which will ensure attribute is already  
> defined.
> 
> Hope this helps.
> 
> On 5/19/2011 3:48 PM, Edward Sargisson wrote:
> 
> > Hi all,  
> > I'm a bit confused about when Ruby gets compiled, how this interacts  
> > with attributes and how to get attribute data that is saved early in  
> > the recipe to be available later in the recipe.
> > 
> > My desired outcome is to have the recipe create a volume from a  
> > snapshot, grab the resulting volume id and insert it into the backup  
> > script so that new backups can snapshot the new volume.
> > 
> > Early in my recipe I have this:  
> > aws\_ebs\_volume "app\_db\_volume" do  
> >   
> > end
> > 
> > The aws\_ebs\_volume resource saves the resulting EBS volume id to node  
> > data.
> > 
> > Later on I have - this is where I grab the volume id that was saved  
> > and put it into the snapshot:  
> > template "/usr/local/sbin/app\_db\_snapshot.sh" do  
> > source "snapshot.sh.erb"  
> > mode 0744  
> > owner "root"  
> > group "root"  
> > variables({  
> > :directory =\> "/var/lib/postgresql/8.4/main",  
> > :description =\> "Apps Database QA",  
> > :volume\_id =\> node[:aws][:ebs\_volume][:app\_db\_volume][:volume\_id]  
> > })  
> > end
> > 
> > I had this running fine in a node that had already successfully  
> > attached to the volume and saved the volume id.. When I ran it on a  
> > brand new node I get:  
> > FATAL: NoMethodError: undefined method `' for nil:NilClass  
> > This happens just as soon as the processing gets to the recipe but  
> > before it does anything at all.
> > 
> > My hyptothesis is that the recipe is being compiled by Ruby and it's  
> > not finding the node data and thus the error.
> > 
> > So, how do I access node data from earlier in the recipe? Or do I need  
> > to break this code into a separate recipe?
> > 
> > Thanks in advance,  
> > Edward
