Gems and Chef
I found myself needing to ensure a gem was installed during compile time in a chef run, and which would then become available during convergence. After driving around the googlemobile for a while, I finally found Seth Vargo’s breakdown of the issue.
In addition, in Chef 12.1, there are some changes to the way the chef_gem
resource
operates 1. While this came up as something to pay attention to, our infrastructure
is still operating on chef 11.18.
In my particular circumstance, I was dealing with some pure ruby code in the cookbook’s
library/
. They were plain ruby classes that didn’t inherit from Chef’s resource
or provider classes like an HWRP would. The ruby classes are accessed in chef via
a method monkeypatched into the Chef::Recipe class. I’m not a huge fan of this
pattern, but I didn’t design the system, I just have to build with it.
I was attempting to use a gem within one of my pure ruby classes. I was able to
add a recipe to install the chef_gem
within the monkeypatched Chef::Recipe
.
Although that feels a bit awkward, it works. However! It appears that Chef evaluates
the plain ruby code at multiple times, so if my gem isn’t in the load path, then
chef will throw an exception.
In Seth Vargo’s post, he suggests one solution as moving the require
statement
to the method that uses the gem. My solution was probably just as smelly, but it
uses the methods available on rubygems to determine whether to require
a gem.
Given a gem named fungus
, your require
statement looks like:
1 | require 'fungus' if Gem::Specification.any? { |g| g.name == 'fungus' } |
I think that solution is just as smelly as requiring
a gem within a method,
with the advantage that the if
statement will make it clear that something specific
is actually going on with that gem. With the proper comments about why we have
to check that the gem is available, then I am signalling to the next developer what
terrible things I was thinking about to make that particular bit of code work.
-
The basic gist is that gems won’t necessarily be installed at compile time. Per Chef, this change in behavior is more in line with what folks are doing with library cookbooks, and only requiring gems in an LWRP or HWRP provider. ↩