How to find nodes by role with knife-solo and chef-solo-search, i.e. search(:node, "role:some_role")?

3.9k Views Asked by At

I'm trying to set up a couple of servers using knife-solo, and I need to use a basic search in a recipe so I can know which servers are implementing a particular role. This seems like the most basic purpose for using search.

I am using chef-solo-search, however I'm not able to find nodes by role as (it seems to be) described in the docs; I am totally stumped. I can hack a solution, but it seems like I am doing something wrong. I built a simplified example to demonstrate my problem.

This does not work...

I created a dummy role roles/test_role.json

{
   "name": "test_role",
   "default_attributes": {},
   "json_class": "Chef::Role",
   "run_list": [],
   "description": "",
   "override_attributes": {}
}

My basic recipe to test searching for nodes with "test_role" role: site-cookbooks/nodesearch/recipes/default.rb

# required for search with knife-solo
include_recipe "chef-solo-search"

# this is now the test code for chef-solo-search shows to search for nodes that implement a role.
# see https://github.com/edelight/chef-solo-search/blob/master/tests/test_search.rb ~ line 208
nodes = search(:node, "role:test_role")

# This creates a line for each node found in the search...
search_content = nodes.map {|node| "id: #{node['id']}  run_list: #{node['run_list']}\n"}.join

# And writes it to a file
file "/var/test_role_nodes.txt" do
  content search_content
  action :create
end

And I have created two nodes:

nodes/node1.json

{
  "id": "node1",
  "run_list": ["recipe[nodesearch]"]
}

nodes/node2.json

{
  "id": "node2",
  "run_list": ["role[test_role]"]
}

When I "cook" node1 (which runs the nodesearch recipe,) I am expecting the search(:node, "role:test_role") search to find node2, but it returns nothing. I have tried moving the node definitions to the data_bags directory because the docs (in places) seem to imply this is necessary, and I have tried all sorts of shenanigans with solo.rb settings, etc. I believe I have set up chef-solo-search per the documented instructions, and I don't get any errors to indicate otherwise. Out of ideas.

But this works...

The only thing I have done that does work is this: rewriting the search recipe from:

nodes = search(:node, "role:test_role")

to this:

nodes = search(:node, "run_list:*role\\[test_role\\]*")

The second form actually gets me the desired results. It's an acceptable workaround, but it seems like a bit of a hack, and it leaves me wondering... either I must be doing something awfully wrong, or all the docs for knife-solo and chef-solo-search are wrong (which seems quite unlikely!)

Can anyone help explain why I can't get any search results using search(:node, "role:test_role") ??

(We've explicitly chosen not to use a chef server solution for a number of carefully-considered reasons.)

2

There are 2 best solutions below

4
On

Chef Solo does not support search:

chef-solo is an open source version of the chef-client that allows using cookbooks with nodes without requiring access to a server. chef-solo runs locally and requires that a cookbook (and any of its dependencies) be on the same physical disk as the node. chef-solo is a limited-functionality version of the chef-client and does not support the following:

  • Node data storage
  • Search indexes <-
  • Centralized distribution of cookbooks
  • A centralized API that interacts with and integrates infrastructure components
  • Authentication or authorization
  • Persistent attributes

Source: http://docs.opscode.com/chef_solo.html

1
On

It does not work because you need to specify this in the node's json file for chef-solo-search to consider it to be a real node object instead of a normal Hash:

"json_class": "Chef::Node"

It will be searchable by roles after this. So basically your example node2 should look like this:

{
  "id": "node2",
  "run_list": ["role[test_role]"]
  "json_class": "Chef::Node"
}

I've noticed this by examining the tests for chef-solo-search which you linked in the last comment of the first answer. The role search test are only run on alpha and beta nodes and not on without_json_class node, and I found the difference, which is that the latter one class assert to a Hash here instead of a Chef::Node.