Hello, I'm Alan

Chef Gotchas

Tuesday, July 16 2013

I’ve been running chef now for about two years, and I guess things we’re obvious to me until I spoke with some of my colleagues, and realised there are still some gotchas out there. Here are the bigger ones I’ve seen.

Deleting stuff from the filesystem doesn’t make it go away

Most people are using git to manage their chef artefacts and then using a script to upload them to the chef server so they get some source control. Keep in mind that if you delete a file from git, there is nothing to tell chef to remove that artefact.

My work around here for a databag, is to commit an empty hash, for a role, to keep the role’s name and description with no run list or attributes. (Read on for why I’m getting away from using roles altogether)

Chef only manages what you tell it

Using say sphinx for your search engine?

package :sphinx do
  version '2.0.8'
end

service :sphinx do
  action [:enable, :start]
end

Now you’ve gone and switched to elasticsearch, added the appropriate cookbook, and removed the one for sphinx. Just want to remind you that sphinx is still installed and running. In these cases you should reverse the service and installation, and of course on nodes without the package or service its a very quick no-op.

Roles aren’t versioned

You can lock your environments down to use specified cookbooks, and freeze your cookbooks at a specified version so you can safely have unverified cookbooks safely uploaded to your chef server, but you cannot do the same with roles. This is one of the reasons I’m a big fan of the wrapper cookbook concept I first seen mentioned by Jamie Windsor at Riot Games (producers of berkshelf)

The execute method needs a check condition

I don’t yet have a LWRP for stuff installed via npm, so I’m just using the command method at the moment.

command "npm install grunt-cli" do
  execute "npm install grunt-cli"
end

Only problem is this gets ran on every single chef run, which is less than efficient. I probably only want to install it if it is not already installed.

command "npm install grunt-cli" do
  execute "npm install grunt-cli"
  not_if { File.exits?("/usr/bin/grunt-cli") }
end

not_if will evaulate the block passed to it

Using chef to compile packages from source

I see this used a lot, and I used to do it myself. Problem is the number of hacks involved, and slow initial convergence. We have package management, lets use it.

I’d played with fpm, but still found it a lof of work until I was pointed on Twitter to fpm-cookery (if you’ve used hombrew you’ll get the hang of it quick smart). I’ve now setup a simple apt repository, and when I need to use packages that aren’t in the distro I use (such as Ruby 2.0.0p247 and Go 1.1.1), I package them up, test that they are correct, and then make them available to apt-get install on any machine. Also makes writing your cookbooks much, much simpler!

Big ball of mud repos

To be honest I’m not sure how much this one still happens, but once upon a time it was common to see people keep all of the cookbooks in the same big repo as the rest of their chef artefacts.

(Admitedly this was the easier with the tools at the time). Now, with projects such as Berkshelf or Librarian (I much prefer Berkshelf), which resolve dependencies and will do uploads for you. Berkshelf also has a Vagrant plugin so you can fire up a vagrant instance for a cookbook under dev & test easier.

Cron

Unless you specify the minute, hour, day and weekday they default to “*”, so that using cron like:

cron "update_lists" do
  command "rake lists:update"
  hour 3
end

when your intention was to run cron at 3am, you’ll actually end up running it 60 times between 3am and 4am, so don’t forget all the fields you intended to include!