Bratty Redhead

the sarcasm is free!

My Ohai Plugin

The plugin at github

When we started the Chef infrastructure automation project last year, a dev team started up at nearly the same time.  I didn’t know enough about Chef to have (much of) an opinion on how others were addressing cookbook issues they faced. So for the first few months, I worked on my problems to solve while the devs worked on theirs.  I did eventually started paying attention to what was going on with the dev team and discovered that they had started to create role names that looked like app_name_env(e.g. riak_prod), causing a role for each app to be created in each environment, but with nearly identical run lists.  They were labeling their attributes with environment and used the roles to sort them out.

So we came up with a quick solution.  We created an attribute called node[:env] and put it in a role called env_dev, env_qa, etc.  And the same goes for other things we needed to set like node[:swimlane] and node[:zone]. Every time a node was created, relevant env attribute roles were added along with the platform_base and any application roles.  We all refactored our code and started using the env variable to sort out environment-specific attributes. This worked well in the short term, for about 6 months.

About 2 months ago, we started planning for provisioning a second data center.  With another data center containing two environments (prod and stage) came a location issue.  Now we have two sets of ntp servers, different DNS servers and a whole host of location-specific coding issues. I went to go add some location-specific roles and started thinking about the refactoring we’d need to do to account for two locations.

As I started to make the first role, I realized that this was quickly becoming an unwieldy solution.  We were configuring the nodes managed by our automation system by hand.  This boggled me. And the number of managed nodes continues to grow.

 

One of the problems we struggle with is that we have no system of record.  We get most of our new server info on spreadsheets from various project teams or ops/mgmt teams.  We can’t call any central system API to get info.  All the servers have static IPs and minimum of two networks. The ops team doesn’t believe in DNS. So we have to keep all of this information somewhere or figure out clever ways to deduce the information we want (or set roles by hand, ugh!).

A secondary problem I had with the roles is that their attributes weren’t set early enough for me to use logic in the attributes file.  Node[:env] didn’t get set until after attributes files were compile which was causing me other problems.

So as I thought about the location role, I rebelled.  I was done setting roles by hand.  UGH!

All of our host names are the same length and contain a rich amount of data encoded in their names.  I thought that there must be a way to extract and label that information for use as node attibutes.  I’m no Ruby genius and I still struggle with anything beyond fancy scripting, but it’s extra fun for me to run at a problem head on and obsess over it. And that’s what I did. 

When I came out of the weekend, I had an oHai plugin that parsed a host name, set 3 top level attributes and 5 nested attributes thatI thought might be useful for logic in cookbooks.  It looks like this:

[root@pxqpkyapp05 tmp]# ohai -f /tmp/plugins/parse_host_plugin.rb  -l debug
[Fri, 24 Jun 2011 19:09:09 -0500] DEBUG: ohai plugin: parse_host: parsing new host pxqpkyapp05
{

  “environment”: “qa”
  “location”: “pismo”,
  “hostdata”: {
    “server_type”: “application”,
    “loc”: “p”,
    “env”: “q”,
    “application”: “Pooky”,
    “platform”: “solaris”
  },
}


I didn’t think this would be useful to anyone but us.  Surely everyone else was using Chef in the cloud, right?  Heck no.  It turns out, as I was chatting with folks at Velocity last week, that several people are data center-bound with encoded host names.  Discussing it, I thought it might be useful to share, even if it would require some tweaking to make it work with any else’s environment.

Basically, I set a hash with environment data and then set variables using a regex on the host name.  I set the environment and location vars separately and then put indexes in the hash for any values I want to add into the hostdata hash.  I took most of our custom logic out, like the node[:zone] logic that no one needs, although I left in a custom piece I had to add for an oddly named environment at a third data center location.  All app names and locations have been changed to protect the innocent (that’s me).

I hope someone else can use it.  It was my first step beyond recipes and I’m rather proud of it. I’ve already had a request from a team mate to move the logic to a library so that we can use it in our host management activities and that’s what I’m working on now.  I’ve created a class and a function that uses the class, but need to translate it to Chef-specific DSL.

Here are some examples of how we’re using them:

 

in the recipe: dnsinfo = search(:dns, “id:#{node.location}”)

in the template:

domain <%= @dnsinfo[“domain”] %>
search <%= @dnsinfo[“search”] %>
<% @dnsinfo[“nameservers”].each do |ns| %>
nameserver <%= ns %>
<% end %>

# Unload unwanted packages
unless node.env == “dev” || node.attribute?(“keep_gcc”)
 package “gcc” do
   action :remove
 end
end

chefsearch = search(“chef_servers”,”env:#{node.env} AND id:#{node.hostdata.loc}*”).first
node.set.chef.my_chef_server = chefsearch[“id”]

node.set.chef.server_url = “http://#{node.chef.my_chef_server}”
node.set.chef.mrepo_url = “http://#{node.chef.my_chef_server}/mrepo”
node.set.chef.proxy_url = “http://#{node.chef.my_chef_server}:8000”

 

This will also come in handy once we’ve migrated to .10 where we can set so many more things within Chef based on environment.  The plugin is phrased in functions as my original plugin file was rather messy with comments and things.  I felt like breaking it down this way made it easier to follow wth was going on.

Please let me know if you find this useful or if you have questions.  This is my first community contribution and so I’m kind of like the kid with the cool shiny thing they want to show everyone.  Look at my shiny!