How to extend node from within another recipe?


#1

Hi Chefs,

I’m trying to add another port to node[:apache][:listen_ports] from
within my own recipe, e.g. like this:

if not node[:apache][:listen_ports].include? "8080"
  node.override[:apache][:listen_ports] = node[:apache][:listen_ports] <<
"8080"
end

This does not work really well as it requires another chef run to take
effect. I assume this is because it runs after the
/etc/apache2/ports.conf template resource (from the apache2 recipe) has
been created with the orginal node[:apache][:listen_ports] which did not
contain port 8080 at that time yet.

I have also tried to notify the /etc/apache2/ports.conf template resource
after adding port 8080 to the apache listen ports, but this didn’t work as
well:

ruby_block "update apache listen port" do
  block do
    node.override[:apache][:listen_ports] = node[:apache][:listen_ports] <<
"8080"
  end
  notifies :create, resources(:template =>
"#{node[:apache][:dir]}/ports.conf")
  not_if { node[:apache][:listen_ports].include? "8080" }
end

I suspect the resource gets in fact notified, but still has the "outdated"
state as it does not re-evaluate node[:apache][:listen_ports] now that
port 8080 has been added.

Is there a way to do this in a single Chef run?

Thanks,
Torben


#2

On Thursday, October 25, 2012 at 1:58 PM, Torben Knerr wrote:

Hi Chefs,

I’m trying to add another port to node[:apache][:listen_ports] from within my own recipe, e.g. like this:

if not node[:apache][:listen_ports].include? "8080"
  node.override[:apache][:listen_ports] = node[:apache][:listen_ports] << "8080"
end

This does not work really well as it requires another chef run to take effect. I assume this is because it runs after the /etc/apache2/ports.conf template resource (from the apache2 recipe) has been created with the orginal node[:apache][:listen_ports] which did not contain port 8080 at that time yet.

I have also tried to notify the /etc/apache2/ports.conf template resource after adding port 8080 to the apache listen ports, but this didn’t work as well:

ruby_block "update apache listen port" do
  block do
    node.override[:apache][:listen_ports] = node[:apache][:listen_ports] << "8080"
  end
  notifies :create, resources(:template => "#{node[:apache][:dir]}/ports.conf")
  not_if { node[:apache][:listen_ports].include? "8080" } 
end

I suspect the resource gets in fact notified, but still has the “outdated” state as it does not re-evaluate node[:apache][:listen_ports] now that port 8080 has been added.

Is there a way to do this in a single Chef run?

Thanks,
Torben

You have a few options. One is to use attributes in roles, which will be merged in after the attributes files have been read, but before the recipes are read. Arrays will be combined via set union, so you can add more values to the array that way.

Another option is to modify the attribute in a recipe that runs before the apache2 recipe. For example, you can have a local-apache2 cookbook with a recipe that modifies the attributes and then calls include_recipe to run the apache2 recipe.

The final (and probably least good) option is to grab the template resource after it’s been defined and modify it:

template_res = resources(:template => "/etc/apache2/ports.conf")
template_res.variables[:listen_ports] << 8080

or something along those lines.


Daniel DeLeo


#3

On Mon, Oct 29, 2012 at 5:04 PM, Daniel DeLeo dan@kallistec.com wrote:

On Thursday, October 25, 2012 at 1:58 PM, Torben Knerr wrote:

Hi Chefs,

I’m trying to add another port to node[:apache][:listen_ports] from
within my own recipe, e.g. like this:

if not node[:apache][:listen_ports].include? "8080"
  node.override[:apache][:listen_ports] = node[:apache][:listen_ports] <<
"8080"
end

This does not work really well as it requires another chef run to take
effect. I assume this is because it runs after the
/etc/apache2/ports.conf template resource (from the apache2 recipe) has
been created with the orginal node[:apache][:listen_ports] which did not
contain port 8080 at that time yet.

I have also tried to notify the /etc/apache2/ports.conf template resource
after adding port 8080 to the apache listen ports, but this didn’t work as
well:

ruby_block "update apache listen port" do
  block do
    node.override[:apache][:listen_ports] = node[:apache][:listen_ports]
<< "8080"
  end
  notifies :create, resources(:template =>
"#{node[:apache][:dir]}/ports.conf")
  not_if { node[:apache][:listen_ports].include? "8080" }
end

I suspect the resource gets in fact notified, but still has the "outdated"
state as it does not re-evaluate node[:apache][:listen_ports] now that
port 8080 has been added.

Is there a way to do this in a single Chef run?

Thanks,
Torben

You have a few options. One is to use attributes in roles, which will be
merged in after the attributes files have been read, but before the recipes
are read. Arrays will be combined via set union, so you can add more values
to the array that way.

Another option is to modify the attribute in a recipe that runs before the
apache2 recipe. For example, you can have a local-apache2 cookbook with a
recipe that modifies the attributes and then calls include_recipe to run
the apache2 recipe.

The final (and probably least good) option is to grab the template
resource after it’s been defined and modify it:

template_res = resources(:template => "/etc/apache2/ports.conf")
template_res.variables[:listen_ports] << 8080

or something along those lines.


Daniel DeLeo

Thanks! I wasn’t aware of the last method you mentioned, it’s actually
pretty close to what I wanted.

Not sure though if I should make my recipe that much implict so that it
adds its own port under the hood, or if I should rather require explicit
configuration via role attributes. Not sure yet, but let’s see…

Torben