# Dynamically include recipes?

**URL:** <https://discourse.chef.io/t/dynamically-include-recipes/1684>\
**Category:** Chef Infra (archive)\
**Created:** [January 10, 2011, 10:58pm UTC](https://discourse.chef.io/t/dynamically-include-recipes/1684 "2011-01-10T22:58:43Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ian\_Marlier](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.chef.io/ian_marlier/32/601_2.png) [@Ian\_Marlier](https://discourse.chef.io/u/Ian_Marlier)\
**Post date:** [January 10, 2011, 10:58pm UTC](https://discourse.chef.io/t/dynamically-include-recipes/1684/1 "2011-01-10T22:58:43Z")

</div>

Hi there, list –

I’m trying to figure out a way to do a (relatively) dynamic include\_recipe  
command. Specifically, the context of this question is a Nagios server, and  
building the service definition files.

I would like to be able to do the following:  
- Get a list of all cookbooks defined in the chef server  
- For each cookbook C, see if that cookbook includes a recipe called  
"nagios"  
- If the cookbook does include a recipe called “nagios”, then do  
include\_recipe “#{C}::nagios”

The idea is that when someone within my organization wants to add a chef  
cookbook to install/configure a new service or a new application, they can  
add the monitoring for that service/application as well – without having to  
alter the nagios cookbook.

I had sort of assumed that I could do this using search(), but it looks like  
cookbooks/recipes aren’t searchable. Sadness. So I’m wondering if anyone  
has suggestions for other ways to make this happen.

(I know that one potential issue is the requirement that metadata.rb also be  
updated. I’m not entirely sure how to deal with that, either. I figured I  
would worry about one problem at a time…)

Thanks!

- Ian

---

<div class="post-metadata">

**Author:** ![Sean\_OMeara](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.chef.io/sean_omeara/32/435_2.png) [@Sean\_OMeara](https://discourse.chef.io/u/Sean_OMeara)\
**Post date:** [January 11, 2011, 12:48am UTC](https://discourse.chef.io/t/dynamically-include-recipes/1684/2 "2011-01-11T00:48:18Z")

</div>

Ian,

You can set arbitrary attributes on nodes within recipes.

so, you can do something like this:

name "appserver-config-a"  
description "appserver-config-a"  
run\_list [  
"recipe[fooservice::client]",  
]

Then, in at the top of your cookbooks/fooservice/client.rb :

node.set[:fooservice][:client].

You can use that attribute from your nagios::server recipe to search for:

fooservice\_clients = search(:node, "fooservice\_client:true")

You have now effectively searched for nodes with the fooservice  
cookbook installed.

-s

On Mon, Jan 10, 2011 at 5:58 PM, Ian Marlier [imarlier@brightcove.com](mailto:imarlier@brightcove.com) wrote:

> Hi there, list --
> 
> I'm trying to figure out a way to do a (relatively) dynamic include\_recipe  
> command. Specifically, the context of this question is a Nagios server, and  
> building the service definition files.
> 
> I would like to be able to do the following:  
> - Get a list of all cookbooks defined in the chef server  
> - For each cookbook C, see if that cookbook includes a recipe called  
> "nagios"  
> - If the cookbook does include a recipe called "nagios", then do  
> include\_recipe "#{C}::nagios"
> 
> The idea is that when someone within my organization wants to add a chef  
> cookbook to install/configure a new service or a new application, they can  
> add the monitoring for that service/application as well -- without having to  
> alter the nagios cookbook.
> 
> I had sort of assumed that I could do this using search(), but it looks like  
> cookbooks/recipes aren't searchable. Sadness. So I'm wondering if anyone  
> has suggestions for other ways to make this happen.
> 
> (I know that one potential issue is the requirement that metadata.rb also be  
> updated. I'm not entirely sure how to deal with that, either. I figured I  
> would worry about one problem at a time...)
> 
> Thanks!
> 
> - Ian

---

<div class="post-metadata">

**Author:** ![Ian\_Marlier](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.chef.io/ian_marlier/32/601_2.png) [@Ian\_Marlier](https://discourse.chef.io/u/Ian_Marlier)\
**Post date:** [January 11, 2011, 2:29am UTC](https://discourse.chef.io/t/dynamically-include-recipes/1684/3 "2011-01-11T02:29:30Z")

</div>

Sean --

Thanks for the reply, but that's a little bit different than what I'm trying  
to do. I'm not actually interested (in this case) in a list of nodes with a  
given cookbook installed.

Instead, what I'm interested in is a list of _cookbooks_ that contain a  
_recipe_ with a given name, so that I can include all of those recipes. In  
my use case, those recipes would define a nagios checkcommand and a nagios  
service.

What I had hoped to do was this:

cookbooks = search(:cookbooks, "recipe:nagios")  
cookbooks.each do |c|  
include\_recipe "#{c}::nagios"  
end

However, the search function doesn't appear to work on cookbooks. I'm  
wondering if there's another way that I can do this.

If there's no way to do this within Chef, I can work around it, for example  
by doing some bash scripting at cookbook upload time -- though that would be  
disappointing, as it would effectively make this recipe only operable in  
certain chef server environments. If there's a "real" way, that would be  
most excellent.

- Ian

On Mon, Jan 10, 2011 at 7:48 PM, Sean OMeara [someara@gmail.com](mailto:someara@gmail.com) wrote:

> Ian,
> 
> You can set arbitrary attributes on nodes within recipes.
> 
> so, you can do something like this:
> 
> name "appserver-config-a"  
> description "appserver-config-a"  
> run\_list [  
> "recipe[fooservice::client]",  
> ]
> 
> Then, in at the top of your cookbooks/fooservice/client.rb :
> 
> node.set[:fooservice][:client].
> 
> You can use that attribute from your nagios::server recipe to search for:
> 
> fooservice\_clients = search(:node, "fooservice\_client:true")
> 
> You have now effectively searched for nodes with the fooservice  
> cookbook installed.
> 
> -s
> 
> On Mon, Jan 10, 2011 at 5:58 PM, Ian Marlier [imarlier@brightcove.com](mailto:imarlier@brightcove.com)  
> wrote:
> 
> > Hi there, list --
> > 
> > I'm trying to figure out a way to do a (relatively) dynamic  
> > include\_recipe  
> > command. Specifically, the context of this question is a Nagios server,  
> > and  
> > building the service definition files.
> > 
> > I would like to be able to do the following:  
> > - Get a list of all cookbooks defined in the chef server  
> > - For each cookbook C, see if that cookbook includes a recipe called  
> > "nagios"  
> > - If the cookbook does include a recipe called "nagios", then do  
> > include\_recipe "#{C}::nagios"
> > 
> > The idea is that when someone within my organization wants to add a chef  
> > cookbook to install/configure a new service or a new application, they  
> > can  
> > add the monitoring for that service/application as well -- without having  
> > to  
> > alter the nagios cookbook.
> > 
> > I had sort of assumed that I could do this using search(), but it looks  
> > like  
> > cookbooks/recipes aren't searchable. Sadness. So I'm wondering if  
> > anyone  
> > has suggestions for other ways to make this happen.
> > 
> > (I know that one potential issue is the requirement that metadata.rb also  
> > be  
> > updated. I'm not entirely sure how to deal with that, either. I figured  
> > I  
> > would worry about one problem at a time...)
> > 
> > Thanks!
> > 
> > - Ian

---

<div class="post-metadata">

**Author:** ![kallistec](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.chef.io/kallistec/32/23_2.png) [@kallistec](https://discourse.chef.io/u/kallistec)\
**Post date:** [January 11, 2011, 5:09pm UTC](https://discourse.chef.io/t/dynamically-include-recipes/1684/4 "2011-01-11T17:09:47Z")

</div>

On Mon, Jan 10, 2011 at 6:29 PM, Ian Marlier [imarlier@brightcove.com](mailto:imarlier@brightcove.com) wrote:

> What I had hoped to do was this:  
> cookbooks = search(:cookbooks, "recipe:nagios")  
> cookbooks.each do |c|  
> include\_recipe "#{c}::nagios"  
> end  
> However, the search function doesn't appear to work on cookbooks. I'm  
> wondering if there's another way that I can do this.

You can't do this with search, but you can use the REST API. For  
example, `knife exec 'pp api.get "cookbooks/_latest"` will print a  
hash of COOKBOOK\_NAME =\> CONONICAL\_URL which you can iterate over to  
get the contents of each cookbook. This will pretty print a hash of  
COOKBOOK\_NAME =\> [RECIPE] for each cookbook:

knife exec -E '(api.get "cookbooks/\_latest").each {|c, url| pp c =\>  
api.get(url).recipe\_filenames}'

You could then filter that for the desired recipes. Note that outside  
of shef/knife exec you need to use `get_rest` instead of just  
`get`--shef aliases that method for brevity.

> If there's no way to do this within Chef, I can work around it, for example  
> by doing some bash scripting at cookbook upload time -- though that would be  
> disappointing, as it would effectively make this recipe only operable in  
> certain chef server environments. If there's a "real" way, that would be  
> most excellent.

Despite the above, if you want to pursue the design you described  
previously (having nagios recipes "sprinkled" throughout your cookbook  
repo), your best bet is to do some analysis up front and modify your  
nagios cookbook accordingly. Even if you can get the list of recipes  
you want from the API, you still need their cookbooks to be listed in  
the metadata for your nagios cookbook in order to have them synced to  
the edge. If you try to do this from within a recipe, you'll need 2  
chef runs to properly converge everything.

> - Ian

HTH,  
Dan DeLeo
