Atalanta / chef-chruby

Chef Cookbook for the chruby utility
Other
29 stars 25 forks source link

Add a chruby_gem LWRP #5

Open Atalanta opened 11 years ago

Atalanta commented 11 years ago

It would be great to be able to specify gems to install per Ruby:

For example:

chruby_gem "bundler" do ruby "1.9.3-p429" end

Atalanta commented 11 years ago

Ignore above comment. That should be for issue #4

Re: LWRP: Postmodern suggests using chruby-exec.

Investigating.

postmodern commented 11 years ago

I would lean towards a bundler style syntax:

chruby '1.9.3' do
  gem 'foo'
end

chruby '1.9.3', 'jruby' do
  gem 'foo'
end
atalanta-cookbooks commented 11 years ago

There's some restriction around the way LWRPs work - the DSL keyword needs to be chruby_something

How about:

chruby_gem '1.9.3' do
  gem 'foo'
end

chruby_gem ['1.9.3', 'ree'] do
  gem 'bar'
end

Easiest to implement would be:

chruby_gem 'rspec' do
  version ['1.9.3', 'jruby']
end

I think this is how the rbenv_gem works.

What do you think?

postmodern commented 11 years ago

I don't know how LWRPs work, but I would favour the least repetitious / "blocky" syntax.

atalanta-cookbooks commented 11 years ago

chruby-exec doesn't quite behave as I expected:

$ chruby
   1.9.3-p392
 * 1.9.3-p429
   embedded

$ chruby-exec 392 -- gem install chess
Fetching: chess-0.0.3.gem (100%)
Building native extensions.  This could take a while...
Successfully installed chess-0.0.3
1 gem installed
Installing ri documentation for chess-0.0.3...
Installing RDoc documentation for chess-0.0.3...

$ gem list

*** LOCAL GEMS ***

bigdecimal (1.1.0)
chess (0.0.3)
io-console (0.3)
json (1.5.5)
minitest (2.5.1)
rake (0.9.2.2)
rdoc (3.9.5)
ubuntu@ip-10-240-109-90:~$ ruby --versio
ruby: invalid option --versio  (-h will show valid options) (RuntimeError)
ubuntu@ip-10-240-109-90:~$ ruby --version
ruby 1.9.3p429 (2013-05-15 revision 40747) [x86_64-linux]

$ chruby embedded
ubuntu@ip-10-240-109-90:~$ gem list

*** LOCAL GEMS ***

bigdecimal (1.1.0)
bundler (1.1.5)
chef (11.4.4)
chess (0.0.3)
erubis (2.7.0)
highline (1.6.18)
io-console (0.3)
ipaddress (0.8.0)
json (1.5.4)
mime-types (1.23)
minitest (2.5.1)
mixlib-authentication (1.3.0)
mixlib-cli (1.3.0)
mixlib-config (1.1.2)
mixlib-log (1.6.0)
mixlib-shellout (1.1.0)
net-ssh (2.6.7)
net-ssh-gateway (1.2.0)
net-ssh-multi (1.2.0, 1.1)
ohai (6.16.0)
rake (0.9.2.2)
rdoc (3.9.4)
rest-client (1.6.7)
ruby-shadow (2.2.0)
systemu (2.5.2)
yajl-ruby (1.1.0)

I would expect chruby-exec 392 to only install the Gem for that Ruby. But it seems that Gem is available to all Rubies? Is this what you would expect? Or have I missed something?

postmodern commented 11 years ago

Actually this is an artifact of how chruby sets GEM_HOME. chruby doesn't take into account RUBY_PATCHLEVEL, in order to allow re-using gems between patch-level upgrades.

atalanta-cookbooks commented 11 years ago

Aha; So embedded Ruby is also 1.9.3; so if I asked ruby_build to install something other than 1.9.3, and then ran chruby_exec somthingelse -- gem install, we'd get the behaviour I expected.

postmodern commented 11 years ago

Correct. GEM_HOME is defined as $HOME/.gem/$RUBY_ENGINE/$RUBY_VERSION.

Atalanta commented 11 years ago

Tested with 2.0.0-p195 - behaves as expected.

Next question is how to call chruby-exec from Chef. Two obvious options:

chruby-exec is actually a Bash function, I guess, so I'll need to source chruby first. Something like:

bash "Install rspec" do
  user "ubuntu"
  code <<-EOH
  source /etc/profile.d/chruby
  chruby-exec 2.0 -- gem install rspec --no-ri --no-rdoc
  EOH
end
Atalanta commented 11 years ago
$ sudo chef-apply chruby_gem.rb
Recipe: (chef-apply cookbook)::(chef-apply recipe)
  * bash[Install rspec] action run
    - execute "bash"  "/tmp/chef-script20130602-28477-anwnhq"
ubuntu@ip-10-240-109-90:/tmp$ ruby --version
ruby 2.0.0p195 (2013-05-14 revision 40734) [x86_64-linux]
ubuntu@ip-10-240-109-90:/tmp$ gem list rspec

*** LOCAL GEMS ***

rspec (2.13.0)
rspec-core (2.13.1)
rspec-expectations (2.13.0)
rspec-mocks (2.13.1)
Atalanta commented 11 years ago

Wonder what the best way to guarantee idempotence is. Best would be to look at the file or directory it creates, which could be calculated.

Alternative would be to run gem list and look for the thing we're trying to install.

Thoughts?

postmodern commented 11 years ago

Current chruby-exec is a shell script that invokes $SHELL -l -i -c. I have plans to rewrite it as a shell function, that way someone doesn't try to run chruby-exec from dash.

Atalanta commented 11 years ago

Aha okay, so I guess I don't need to source chruby in that case. Any thoughts on idempotence?

postmodern commented 11 years ago

Just installing the gems should be idempotent?

Atalanta commented 11 years ago

Do you mean that Rubygems itself is idempotent? is if bundler is installed, when I try to install bundler, no action will be taken?

I guess I should just look at the core Chef provider and see what that does.

postmodern commented 11 years ago

It will just install the latest version, even if that version is already installed.

Atalanta commented 11 years ago

Right - that's what I thought. Ideally a provider knows if action is needed, to save node convergence time.

mdub commented 11 years ago

Bump! I'm also looking for a reliable way to install gems (like bundler) - ideally at the system level - using the chruby cookbook.

FWIW, my "gem_require" gem (https://github.com/mdub/gem_require) provides an idempotent version of "gem install".

databus23 commented 11 years ago

A simple solution that works for me is the following definition

define :chruby_gem, :action => :install do
  gem_package "chruby #{params[:ruby]}: #{params[:name]}" do
    package_name params[:name] 
    gem_binary "/opt/rubies/#{params[:ruby]}/bin/gem"
    version params[:version] if params[:version]
    action params[:action]
  end
end

The gem_packe resource also handles the idempotency for us:

chruby_gem 'bundler' do
  ruby '1.9.3-p448'
end

Gives me on a second run:

INFO: Processing gem_package[chruby 1.9.3-p448: passenger] action install (vhost::passenger line 2)
DEBUG: gem_package[chruby 1.9.3-p448: passenger] using gem '/opt/rubies/1.9.3-p448/bin/gem'
DEBUG: gem_package[chruby 1.9.3-p448: passenger] found installed gem passenger version 4.0.5 matching passenger (= 4.0.5)
DEBUG: gem_package[chruby 1.9.3-p448: passenger] is already installed - nothing to do
DEBUG: gem_package[chruby 1.9.3-p448: passenger] resetting gem environment to default
timfjord commented 11 years ago

@databus23's solution works great. But i think we can use it without proxy-definition

gem_package 'bundler' do
  gem_binary "/opt/rubies/#{node[:chruby][:default]}/bin/gem"
end
jeroenj commented 11 years ago

This indeed works great, but if you're running chef-client withing a chruby ruby then it is using the correct gem command, but it's used withing the ruby environment you're running.

For now the only workaround is to run chef in a ruby not managed by chruby. In my case on OSX I would need to use the system ruby.