Cool Chef Tricks: Upgrade Chef With Chef!

Since we had a new release of Chef, I needed to upgrade all my internal testing nodes to the new version. This was quick and painless, because I used Chef to upgrade itself. One reason why it was so easy is because the 0.7.6 release didn't have any changes that break backwards compatibility. Another reason is because the Roles feature introduced in 0.7.0 lets me override attributes on nodes.

6a010536aeb3ae970b0120a52ba549970c-150wi

If you have a node which has attributes set, you can override with a new value applying a role with override_attributes. For example, the Opscode Chef Cookbook sets up attributes for the version of Chef that should be installed. All of my nodes were running 0.7.4, with that version as a node attribute. To upgrade them to 0.7.6, I simply created a couple of roles, one for the server, and one for the clients. These Roles do use the Opscode Chef Cookbook, so you'll need it as well for this to work the same.

chef-client-upgrade.rb:

name "chef-client-upgrade"
description "Use this role to upgrade Chef (client only) to a New Version."
recipes "chef::client"
override_attributes(
  "chef" => { "client_version"=>"0.7.6" }
)

chef-server-upgrade.rb:

name "chef-server-upgrade"
description "Use this role to upgrade Chef (server only) to a New Version."
recipes "chef::server"
override_attributes(
  "chef" => {
    "client_version"=>"0.7.6",
    "server_version"=>"0.7.6"
  }
)

I simply put these two files in my chef-repo/roles directory, run 'rake install', and then run the chef-client (or wait for it to run on interval). On the clients, it will upgrade the Chef gem. On the server, it will update all the Chef gems, as well as modify the Apache/Passenger config to point to the new 0.7.6 directory location. Once complete:

  $ chef-client --version
Chef: 0.7.6

"–version" is a new feature of 0.7.6.

Those of you who were using Chef prior to 0.7.0 may have run across the wiki page about upgrading Chef with Chef. That required a bit more work because of some of the backwards incompatible changes in Chef 0.7.0, but also because Roles weren't implemented yet. This is the evolution of that process, and "should just work" going foward. Another nice thing about having these Roles in my Chef repository is I can update the role with the new version and it will be applied.

This brings to mind another nice trick about roles, in that they can specify just override_attributes. So if I wanted, I could leave out the recipes altogether, and use just one role. What really makes this trick nice, is it can be used to do a "deployment" role, similar to:

name "my_application_deploy"
description "Switch deploy resource action to deploy!"
override_attributes(
  "my_application" => {
    "deploy_action" => "deploy"
  }
)

Because of a change in Chef 0.7.6, applying this role will only add the attribute my_application[:deploy_action] on the nodes while the role is applied. When the role is removed, the attribute goes away and the default in your cookbook, if it is set, is used instead.

Avatar
Joshua Timberman

Joshua Timberman is a Code Cleric at CHEF, where he Cures Technical Debt Wounds for 1d8+5 lines of code, casts Protection from Yaks, and otherwise helps continuously improve internal technical process.