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


#1

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


#2

On Thu, May 19, 2011 at 5:48 AM, Edward Sargisson 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] http://blog.loftninjas.org/2011/02/16/the-power-of-chef-and-ruby/


#3

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


#4

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 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