Lately I’m working in an environment without direct access to the external network; this is turning out as a great occasion to find out how many cookbooks (both our private cookbooks and the supermarket ones) do stuff at compile time that they shouldn’t.
Now I’m having trouble using the docker cookbook, as it installs a gem at compile time:
# libraries/_autoload.rb
begin
gem 'docker-api', '= 1.28.0'
rescue LoadError
unless defined?(ChefSpec)
run_context = Chef::RunContext.new(Chef::Node.new, {}, Chef::EventDispatch::Dispatcher.new)
require 'chef/resource/chef_gem'
docker = Chef::Resource::ChefGem.new('docker-api', run_context)
docker.version '= 1.28.0'
docker.run_action(:install)
end
end
I’m trying to use this cookbook on a node that cannot reach rubygems.org, so I have a recipe that changes the server to download gems from, but of course my recipe is never run, as everything fails at compile time.
I’d like to submit a pull request to fix this, but I’m not sure of the solution.
The fact is that the docker cookbook doesn’t have any recipes: it has resources and a few helper methods; many of those resources and helpers need the gem to work.
I could change _autoload.rb to install the gem at compile time, thus allowing my recipe to change the gem server, but: how could I change the resources so that they actually use the gem at compile time only?
The first step is obviously to remove the require 'docker'
from the global space and from classes/modules body and put it inside methods. This would avoid everything to fail immediately, but would not be enough: I should also ensure that the resource itself works (that is, compiles) without the gem.
In the end, what should happen is this:
- wrappers of docker should be allowed to optionally prepend recipes that change the way the gem
docker-api
is installed; - then, the gem
docker-api
should be installed before any other recipe that want to use a docker resource; - then, all other recipes should follow.
Could you please give me some advice as for how to proceed?