This is a text-only version of the following page on https://raymii.org:
---
Title       : 	Chef: search in recipe based on roles or recipes
Author      : 	Remy van Elst
Date        : 	08-10-2013
URL         : 	https://raymii.org/s/tutorials/Chef_search_in_recipe_on_roles_or_recipes.html
Format      : 	Markdown/HTML
---



Chef supports a very powerfull search syntax which allows you for example to
search all nodes with the graphite-server role and get their IP addresses. This
tutorial shows you how to search based on a role a node has or a recipe a node
has, plus an example config file with erb syntax. It has an example cookbook
which sets up collectd as client and graphite as server. It shows you how to use
the search function of Chef to get the IP addresses of the graphite servers and
place those in the collectd config files. This technique is applicable to all
kinds of services that use a client-server model, for example, munin, haproxy,
zabbix and many more.

<p class="ad"> <b>Recently I removed all Google Ads from this site due to their invasive tracking, as well as Google Analytics. Please, if you found this content useful, consider a small donation using any of the options below:</b><br><br> <a href="https://leafnode.nl">I'm developing an open source monitoring app called  Leaf Node Monitoring, for windows, linux & android. Go check it out!</a><br><br> <a href="https://github.com/sponsors/RaymiiOrg/">Consider sponsoring me on Github. It means the world to me if you show your appreciation and you'll help pay the server costs.</a><br><br> <a href="https://www.digitalocean.com/?refcode=7435ae6b8212">You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $100 credit for 60 days. </a><br><br> </p>


Lets say you want to build a graphite server which gets data from a lot of
collectd clients. You can hard code it in the `collectd.conf` file, but this is
not preferred, what if your graphite server changes? What if you want to add a
graphite server and have all your clients automagically also send data to that
server? Here is where the following comes in handy.

You can use [this graphite cookbook][2]. If you add the `graphite` recipe to a
node, it will install everything needed for a graphite server, including the web
ui. Now, you can also create a role `graphite_server` and add the recipe to
that, then add the role to a node. This way you have a graphite server running.

collectd 5.1 or higher is required for graphite support. My environment
currently runs mostly on Ubuntu 12.04 LTS, which has collectd 4 in the
repositories. Therefore I build a package myself, but there are also PPA's
available. I also run my own repositories, so I can just use the `collectd-core`
package, if you don't have a collectd 5.1 or higher package then the following
example won't work for you.

This very simple cookbook installs the collectd package and sets the config
file. Take a look at it:

    
    
    package "collectd-core" do
        action :install
    end
    
    service "collectd" do
      supports :start =>true, :restart => true, :stop => true
      action [:enable, :start]
    end
    
    node.set[:collectd][:client] = true
    
    graphite_servers = search(:node, 'recipes:"graphite"')
    
    template "/etc/collectd/collectd.conf" do
        source "collectd.conf.erb"
        owner "root"
        group "root"
        mode 0644
        notifies :restart, "service[collectd]"
        variables(
            :graphite_servers => graphite_servers
        )
    end
    

The following line does the search magic:

    
    
    graphite_servers = search(:node, 'recipes:"graphite"')
    

It searches the Chef server for all nodes with the `graphite` recipe and makes
that available in this cookbook. Then it passes it on to the template, which we
will discuss below. If you don't want to search on recipes but for example on
roles, you can use the following code:

    
    
    graphite_servers = search(:node, 'role:graphite-server')
    

or on an attribute set in the node:

    
    
    graphite_servers = search(:node, 'graphite_server:true')
    

Now the template (`collectd.conf.erb`) is a standard collectd template with some
erb to enumerate the information in the `graphite_servers` variable. Skip to the
bottom to see it:

    
    
    # Managed by Chef for node <%= node['fqdn'] -%>.
    # Do not edit manually, your changes will be overwritten.
    Hostname <%= node['fqdn'] -%>
    FQDNLookup false
    Interval 30
    ReadThreads 1
    LoadPlugin syslog
    LogLevel info
    LoadPlugin cpu
    LoadPlugin df
    LoadPlugin disk
    LoadPlugin entropy
    LoadPlugin interface
    LoadPlugin irq
    LoadPlugin load
    LoadPlugin memory
    LoadPlugin processes
    LoadPlugin rrdtool
    LoadPlugin swap
    LoadPlugin users
    LoadPlugin network
    LoadPlugin iptables
    LoadPlugin uptime
    LoadPlugin "write_graphite"
    <Plugin "write_graphite">
    <% @graphite_servers.each do |graphite_server| -%>
     <Carbon>
       Host "<%= graphite_server['ipaddress'] -%>"
       Port "2003"
       EscapeCharacter "_"
       SeparateInstances true
       StoreRates false
       AlwaysAppendDS false
     </Carbon>
     <% end -%>
    </Plugin>
    

This part starts a loop, which will loop trough all the values in the array it
got from the cookbook:

    
    
    <% @graphite_servers.each do |graphite_server| -%>
    

Then this part does another lookup to get the node's IP address:

Host "<%= graphite_server['ipaddress'] -%>"

You can change that to get any other attribute from a node, in this example we
need the IP address.

This last part ends the loop:

    
    
     <% end -%>
    

This will result in a config file with all the graphite servers you have in your
Chef environment. One of the big plus points is that you can add or remove
graphite servers whenever you want without the nodes having issues. Need to
scale up a few servers? Just deploy some new nodes and all the clients will use
them. Scaling down? No issue, all the clients will stop using them without
manual action.

This technique is very applicable to other client-server models, like Munin. Or,
any other setup like this.

   [1]: https://www.digitalocean.com/?refcode=7435ae6b8212
   [2]: https://github.com/hw-cookbooks/graphite

---

License:
All the text on this website is free as in freedom unless stated otherwise. 
This means you can use it in any way you want, you can copy it, change it 
the way you like and republish it, as long as you release the (modified) 
content under the same license to give others the same freedoms you've got 
and place my name and a link to this site with the article as source.

This site uses Google Analytics for statistics and Google Adwords for 
advertisements. You are tracked and Google knows everything about you. 
Use an adblocker like ublock-origin if you don't want it.

All the code on this website is licensed under the GNU GPL v3 license 
unless already licensed under a license which does not allows this form 
of licensing or if another license is stated on that page / in that software:

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Just to be clear, the information on this website is for meant for educational 
purposes and you use it at your own risk. I do not take responsibility if you 
screw something up. Use common sense, do not 'rm -rf /' as root for example. 
If you have any questions then do not hesitate to contact me.

See https://raymii.org/s/static/About.html for details.