scribble

Holistic Engineering

E-Mail GitHub Twitter

24 Feb 2012
Abusing the Chef API for Fun and Profit

This post is about Chef, but perhaps not in the way you’ve experienced it before. Believe it or not, Chef has a beautiful API underneath all those tools, and very few of us in our day-to-day work exploit the opportunities available to us.

A Quick Start: Chef Search

Chef Search is one of the things that differentiates it from other tools of the same mind. There are a lot of opportunities in our daily environment to (ab)use chef search to automate tasks.

Here’s a small script that looks for all nodes that match a query, and prints their names:

#!ruby

require 'rubygems'
require 'chef/rest'
require 'chef/search/query'

Chef::Config.from_file(File.expand_path("~/.chef/knife.rb"))
query = Chef::Search::Query.new
nodes = query.search('node', ARGV.shift).first rescue []

puts nodes.map(&:name).join("\n")

You can try this out like so:

ruby chef_search_1.rb 'roles:my_role'

And it will print all your nodes that have “role[myrole]” in their `runlist`.

This isn’t very useful by itself. How about a script that does something with those nodes… maybe like printing out their ec2.instance_id’s?

#!ruby

require 'rubygems'
require 'chef/rest'
require 'chef/node'
require 'chef/search/query'

Chef::Config.from_file(File.expand_path("~/.chef/knife.rb"))
query = Chef::Search::Query.new
nodes = query.search('node', ARGV.shift).first rescue []

nodes.each do |node|
  puts node.name
  puts "\tinstance_id: " + node.ec2.instance_id
end

Still not very useful. Are you using EC2 tagging for your cloud machines? If not, you should. Our tags from ec2-describe-instances look something like this (and a lot more stuff I can’t show):

TAG     instance        i-f3220280      Name    backend.test.example.com
TAG     instance        i-f3220280      environment     test

Now, we can extract this information with a variety of tools, like Fog and RightAws. The EC2 API is arguably the simplest, but shelling out to all that java is a time sink. RightAws is my favorite not because it’s pretty code or that it’s especially fancy or elaborate, but because it’s documented.

ri RightAws::Ec2
ri RightAws::Ec2.describe_tags

Gets us what we want.

Anyhow, the below script takes a search, finds out its instance id, and then proceeds to extract and print the tags with rightaws’s `describetags` method. It uses the same environment variables you’d use for the EC2 API Tools, so if you use EC2, you’re probably good to go.

#!ruby

require 'rubygems'
require 'right_aws'
require 'chef/rest'
require 'chef/node'
require 'chef/search/query'

Chef::Config.from_file(File.expand_path("~/.chef/knife.rb"))
query = Chef::Search::Query.new
nodes = query.search('node', ARGV.shift).first rescue []
right_aws = RightAws::Ec2.new(ENV["AWS_ACCESS_KEY_ID"], ENV["AWS_SECRET_ACCESS_KEY"] )

nodes.each do |node|
  puts node.name

  unless (node.ec2.instance_id rescue nil)
    puts "\tNot an EC2 machine"
    next
  end

  puts "\tinstance_id: " + node.ec2.instance_id

  right_aws.describe_tags(:filters => { 'resource-id' => node.ec2.instance_id }).each do |tag|
    puts "\t\t%s:\t%s" % [tag[:key], tag[:value]]
  end
end

So now we have something marginally useful. I’m sure you can come up with all sorts of applications for this! Additionally, check out the code for these classes:

  • Chef::Node
  • Chef::Role
  • Chef::DataBagItem

For a lot more things to explore!


Til next time,
Erik Hollensbe at 15:34

scribble

E-Mail GitHub Twitter