Notifying Resources within Ruby Block Resource


#1

I have found myself running into the case where I want to notify a specific
resource within a Ruby Block resource.

I can’t see any simple way to do this without modifying the ruby block
provider.

Is there anyway to do this without modifying the provider?


#2

On Nov 14, 2011, at 3:38 PM, bjbq4d@gmail.com bjbq4d@gmail.com wrote:

I have found myself running into the case where I want to notify a specific
resource within a Ruby Block resource.

I can’t see any simple way to do this without modifying the ruby block
provider.

Is there anyway to do this without modifying the provider?

You can do this:

ruby_block "some ruby code" do
  block do
    # the actual stuff in the block
  end
  notifies :action, "resource[other resource]"
end

Note that the notifies goes after the block parameter’s block.


Opscode, Inc
Joshua Timberman, Technical Program Manager
IRC, Skype, Twitter, Github: jtimberman


#3

On Mon, Nov 14, 2011 at 6:32 PM, Joshua Timberman joshua@opscode.comwrote:

You can do this:

ruby_block “some ruby code” do
block do
# the actual stuff in the block
end
notifies :action, "resource[other resource]"
end

Note that the notifies goes after the block parameter’s block.

…or before. Outside of, anyway.

However, the important thing to note is that the notification is
unconditional; if the Ruby block executes, the notification is sent. There
is currently no way (AFAIK) for a Ruby block to change its
updated_by_last_action state to false.


Mark J. Reed markjreed@gmail.com


#4

On Mon, Nov 14, 2011 at 5:38 PM, bjbq4d@gmail.com wrote:

I have found myself running into the case where I want to notify a specific
resource within a Ruby Block resource.

From within a ruby block resource?

http://lists.opscode.com/sympa/arc/chef-dev/2011-01/msg00003.html

At run time

ruby_block “foo” do
block do
resources(:service => “apache2”).run_action(:restart)
end
end


#5

That works perfectly. Thank you.

On Mon, Nov 14, 2011 at 5:44 PM, Bryan McLellan btm@loftninjas.org wrote:

On Mon, Nov 14, 2011 at 5:38 PM, bjbq4d@gmail.com wrote:

I have found myself running into the case where I want to notify a
specific
resource within a Ruby Block resource.

From within a ruby block resource?

http://lists.opscode.com/sympa/arc/chef-dev/2011-01/msg00003.html

At run time

ruby_block “foo” do
block do
resources(:service => “apache2”).run_action(:restart)
end
end


#6

On 2011-11-14 18:44:35, Bryan McLellan wrote:

At run time

ruby_block “foo” do
block do
resources(:service => “apache2”).run_action(:restart)
end
end

Any idea why this does not work for a dynamically defined
resource?

service = “service[daemon_foo]”

ruby_block ‘obligatory_foo’ do
block do
delete.each do |f|
r = Chef::Resource::File.new((plugin_conf_path + f).to_s, run_context)
r.notifies :reload, service
r.run_action :delete
end
end
end

service ‘daemon_foo’ do
action [ :enable, :start ]
supports :reload => true
end

The delete works just fine but notification goes to /dev/null, and the daemon
is restarted if the normal compile time resources trigger a reload.

/Allan

Allan Wind
Life Integrity, LLC
http://lifeintegrity.com


#7

I just ran into this problem myself. It seems that notifications are only
handled by Chef::Runner, in which the runner holds the list of
notifications (in order to check for duplicates) and only its run_action
command can write to the list of notifications.

So when you run, r.run_action you are running the resource without the
runner meaning the notification won’t be handled.

I spent awhile trying to find a way to inject a resource into the runner’s
list of resources or get access to the runner itself but for obvious
reasons you can’t (or it is difficult).

One hack I found that does work is this,

ruby_block ‘obligatory_foo’ do
block do
delete.each do |f|
r = Chef::Resource::File.new((plugin_conf_path +
f).to_s, run_context)
r.run_action
self.notifies :reload, service
self.resolve_notification_references
end
end
end

This actually uses the parent ruby block ‘obligatory_foo’ to make the
notification call, in which self refers to the ruby_block[obligatory_foo].

Bryan

On Wed, Nov 23, 2011 at 3:59 PM, Allan Wind allan_wind@lifeintegrity.comwrote:

On 2011-11-14 18:44:35, Bryan McLellan wrote:

At run time

ruby_block “foo” do
block do
resources(:service => “apache2”).run_action(:restart)
end
end

Any idea why this does not work for a dynamically defined
resource?

service = “service[daemon_foo]”

ruby_block ‘obligatory_foo’ do
block do
delete.each do |f|
r = Chef::Resource::File.new((plugin_conf_path +
f).to_s, run_context)
r.notifies :reload, service
r.run_action :delete
end
end
end

service ‘daemon_foo’ do
action [ :enable, :start ]
supports :reload => true
end

The delete works just fine but notification goes to /dev/null, and the
daemon
is restarted if the normal compile time resources trigger a reload.

/Allan

Allan Wind
Life Integrity, LLC
http://lifeintegrity.com


#8

On Monday, November 28, 2011 at 2:46 PM, Bryan Baugher wrote:

I just ran into this problem myself. It seems that notifications are only handled by Chef::Runner, in which the runner holds the list of notifications (in order to check for duplicates) and only its run_action command can write to the list of notifications.

So when you run, r.run_action you are running the resource without the runner meaning the notification won’t be handled.

I spent awhile trying to find a way to inject a resource into the runner’s list of resources or get access to the runner itself but for obvious reasons you can’t (or it is difficult).

One hack I found that does work is this,
Questions about creating and using resources defined via ruby blocks comes up often enough that I think it’s worthwhile to find a more elegant solution, if possible. Can you guys explain what it is you’re commonly doing with these?

Off the top of my head, I can see two sorts of scenarios:

  1. You need to set a value on a resource during the convergence phase of the Chef run (why?). Adding a means to have lazily evaluated values would be a pretty easy fix.
  2. You need to create multiple resources during converge based on some state created by prior actions in the converge phase (again, why?). An elegant solution to this would require a lot more thought.

I know I’ve asked people about this individually before, but it would be nice to get this on the record and maybe get a feature proposal out of it.

Thanks,


Dan DeLeo


#9

On 2011-11-28 16:34:34, Daniel DeLeo wrote:

Questions about creating and using resources defined via ruby
blocks comes up often enough that I think it’s worthwhile to
find a more elegant solution, if possible. Can you guys explain
what it is you’re commonly doing with these?

Off the top of my head, I can see two sorts of scenarios:

  1. You need to set a value on a resource during the convergence phase of the Chef run (why?). Adding a means to have lazily evaluated values would be a pretty easy fix.
  2. You need to create multiple resources during converge based on some state created by prior actions in the converge phase (again, why?). An elegant solution to this would require a lot more thought.

One concrete case for me was a munin (resource monitoring tool)
cookbook. When you install the munin-node package it will
configure a number plugins using a combination of static and
auto-discovery. In any case I want to control the exact list of
plugins using my a cookbook.

Adding plugins could be done as usual by defining a set of
symlink links from /etc/munin/plugins to where all the available
plugins are installed. The destination directory depends on
platform so you either configure that ahead of time, or detect it
a run-time and use dynamically defined resources.

Removing plugins, on the other hand, can only be done at run-time
when you know what actual plugins were configured. Even if you
looked at the munin-node package to find out all the available
plugins and “blacklist” the ones you do not want (with associated
maintenance as packages change). munin has something they call
wildcard plugins which tags on a suffix of the symbolic link (for
example the name of a network interface).

What I end up doing in the cookbook is diffing the list of
plugins that I want to install (defined in an attribute) with the
ones currently installed, then add or delete the symbolic links
as needed. I do want to use chef resources to mange the links.

I am by no means an expert at this so it could be that I am
missing an obvious better way.

/Allan

Allan Wind
Life Integrity, LLC
http://lifeintegrity.com


#10

I ran into a specific case where my application had scripts that handled
initialization and configuration, as well as having information that chef
needed in order to correctly configure the application. This meant that I
had to do this at run time or rather in a chef resource (bash/execute or
ruby_block).

Ultimately I chose to use ruby_block out of simplicity, that it felt more
like chef to me, it was easier for me, and allowed me to throw errors with
information about the error.

I then decided to create dynamic bash/execute blocks because it was simpler
then handling bash commands myself, and it helps with auditing to see a
resource for every change that is made (especially with chef’s json
reporting).

I then needed a way to restart my service on any change made and so
restarting in the above fashion is simple, chef-like, and helps with
auditing.

Bryan

On Mon, Nov 28, 2011 at 5:34 PM, Daniel DeLeo dan@kallistec.com wrote:

On Monday, November 28, 2011 at 2:46 PM, Bryan Baugher wrote:

I just ran into this problem myself. It seems that notifications are
only handled by Chef::Runner, in which the runner holds the list of
notifications (in order to check for duplicates) and only its run_action
command can write to the list of notifications.

So when you run, r.run_action you are running the resource without the
runner meaning the notification won’t be handled.

I spent awhile trying to find a way to inject a resource into the
runner’s list of resources or get access to the runner itself but for
obvious reasons you can’t (or it is difficult).

One hack I found that does work is this,
Questions about creating and using resources defined via ruby blocks comes
up often enough that I think it’s worthwhile to find a more elegant
solution, if possible. Can you guys explain what it is you’re commonly
doing with these?

Off the top of my head, I can see two sorts of scenarios:

  1. You need to set a value on a resource during the convergence phase of
    the Chef run (why?). Adding a means to have lazily evaluated values would
    be a pretty easy fix.
  2. You need to create multiple resources during converge based on some
    state created by prior actions in the converge phase (again, why?). An
    elegant solution to this would require a lot more thought.

I know I’ve asked people about this individually before, but it would be
nice to get this on the record and maybe get a feature proposal out of it.

Thanks,


Dan DeLeo