Quick Tip: Define Resources to Notifiy in LWRPs
In this quick tip, I’ll explain why you may need to create resources to notify in a provider, even if the resource exists in a recipe, when using use_inline_resources
in Chef’s LWRP DSL.
I’ll use an example cookbook, notif
, to illustrate. First, I’ve created cookbooks/notif/resources/default.rb
, with the following content.
actions :write
default_action :write
Then, I have written cookbooks/notif/providers/default.rb
like this:
use_inline_resources
action :write do
log 'notifer' do
notifies :create, 'file[notified]'
end
end
Then the default recipe, where I’ll use the resource automatically generated from the resource directory, notif
.
file 'notified' do
content 'something'
action :nothing
end
notif 'doer'
When I run Chef, I’ll get an error like this:
Recipe: notif::default
* file[notified] action nothing (skipped due to action :nothing)
* notif[doer] action write
================================================================================
Error executing action `write` on resource 'notif[doer]'
================================================================================
Chef::Exceptions::ResourceNotFound
----------------------------------
resource log[notifer] is configured to notify resource file[notified] with action create, but file[notified] cannot be found in the resource collection. log[notifer] is defined in /tmp/kitchen/cookbooks/notif/providers/default.rb:4:in `block in class_from_file'
Resource Declaration:
---------------------
# In /tmp/kitchen/cookbooks/notif/recipes/default.rb
12: notif 'doer'
Compiled Resource:
------------------
# Declared in /tmp/kitchen/cookbooks/notif/recipes/default.rb:12:in `from_file'
notif("doer") do
action :write
retries 0
retry_delay 2
default_guard_interpreter :default
declared_type :notif
recipe_name "default"
end
To fix this, I define the file
resource in the provider:
use_inline_resources
action :write do
log 'notifer' do
notifies :create, 'file[notified]'
end
file 'notified' do
content new_resource.name
end
end
Then when I run Chef, it will converge and notify the file resource to be configured.
Recipe: notif::default
* file[notified] action nothing (skipped due to action :nothing)
* notif[doer] action write
* log[notifer] action write
* file[notified] action create
- create new file notified
- update content in file notified from none to 935e8e
--- notified 2015-01-18 05:47:49.186399317 +0000
+++ ./.notified20150118-15795-om5fiw 2015-01-18 05:47:49.186399317 +0000
@@ -1 +1,2 @@
+doer
* file[notified] action create (up to date)
Running handlers:
Running handlers complete
Chef Client finished, 3/4 resources updated in 1.298990565 seconds
Why does this happen?
The reason for this is because use_inline_resources
tells Chef that in this provider, we’re using inline resources that will be added to their own run context, with their own resource collection. We don’t have access to the resource collection from the recipe. Even though the file[notified]
resource exists from the recipe, it doesn’t actually get inherited in the provider’s run context, raising the error we saw before.
We can turn off use_inline_resources
by removing it, and the custom resource will be configured:
action :write do
log 'notifer' do
notifies :create, 'file[notified]'
end
end
Then run Chef:
Recipe: notif::default
* file[notified] action nothing (skipped due to action :nothing)
* notif[doer] action write (up to date)
* log[notifer] action write
* file[notified] action create
- update content in file notified from 935e8e to 3fc9b6
--- notified 2015-01-18 05:47:49.186399317 +0000
+++ ./.notified20150118-16159-r18q7z 2015-01-18 05:50:57.832140405 +0000
@@ -1,2 +1,2 @@
-doer
+something
Notice that the file[notified]
resource wasn’t updated at the start of the run, when it was encountered in the recipe, but it was when notified by the log resource in the provider action, changing the content.
Use inline compile mode!
The use_inline_resources
method in the lightweight provider DSL is strongly recommended. It makes it easier to send notifications from the custom resource itself to other resources in the recipe’s resource collection. Read more about the inline compile mode in the Chef docs.
Also, define the resources that you need to notify when you’re doing this in your provider’s actions. A common example is within a provider that writes configuration for a service, and needs to tell that service to restart.