Hi everyone,
First. Sorry for this long email :-)
I started working on refactoring of how we handle gems loading in
Deltacloud API. This is what I discover:
1. In 'server', we don't use Bundler. If you run Deltacloud using:
'./bin/deltacloudd'
we use the old-school 'require' all over the DC server code (do a "grep
'require ' -r lib/"). Having this, we always use the version of the gem
which is currently available in the system. In most cases is the latest
version available.
2. For 'server' tests, we do use Bundler (we call the Bundler.require in
the Rakefile). So before you run 'rake test' you need to run 'bundle
install'. This is not true, when the user want to execute just one
single test file (ruby tests/.../test.rb) (yeah, he can use 'bundle ruby
...', but srsly, how often you forget to do it ;-). In that case, we
again trust the rubygems and use the system versions.
I think what we currently have is a bit mess :-) I found that up to 50%
of problems, users have with DC installation is handling all various gem
dependencies and versions (tilt, sinatra, rabbit, openstack, etc...).
Also many bugs/jiras are related to breakages caused by incompatible
changes in upstream gems we use.
So. How we can do things better? :-)
*** Idea ***:
Use bundler everywhere. I don't like bundler. But I think currently it
is the only sane way how to manage gems in DC. We should check in the
Gemfile.lock into 'server' dir, create an initialization file with
Bundler.require(:default) and use this to require all gems we do need
for server to operate. Also might we need to remove all "require
'upstream_gem'" in DC, we we load the gems just once (when starting DC).
*** Problems ***:
- Different drivers require different gems. Having them all loaded by
Bundler will increase DC boot time badly and increase the memory DC consume.
Solution:
We can create a 'group' for each driver in Bundler, like:
group :ec2 do
gem 'aws'
end
group :rhevm do
gem 'rbovirt', :version => '...'
end
The the 'driver' method in Deltacloud will need to be a bit smarter and
call the "Bundler.require(driver_symbol)" when the driver is changed.
- We need to make sure that 'gem install deltacloud-core' work properly.
Ruby gems does not play well with Gemfile.lock.
Solution:
We don't need 'gemspec', right? We do need gemspec **only** when we are
building a gem (release). Can we generate 'gemspec' from what we have in
Gemfile.lock before release? In that case we will make sure all gems we
require have the correct versions (the one we tested on).
-------
I think having all gems managed by Bundler and loaded on one place
(initializer) will make managing gems we use easier, where we can track
what exact version we are currently supporting and we can avoid the
issues similar to 'tilt' or 'sinatra'.
There is a good article about clarification how to use gemspec vs Gemfile:
http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/
"When developing a gem, do not check your Gemfile.lock into version control"
vs.
"When developing an app, check in your Gemfile.lock"
In our case, we develop an app, right? The 'gem' we produce is just a
distribution of this app.
What you think? Do you have a better idea?
-- Michal
--
Michal Fojtik <[email protected]>
Deltacloud API, CloudForms