chef-chruby icon indicating copy to clipboard operation
chef-chruby copied to clipboard

Add a chruby_gem LWRP

Open Atalanta opened this issue 12 years ago • 21 comments

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 avatar Jun 01 '13 18:06 Atalanta

Ignore above comment. That should be for issue #4

Re: LWRP: Postmodern suggests using chruby-exec.

Investigating.

Atalanta avatar Jun 02 '13 08:06 Atalanta

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

postmodern avatar Jun 02 '13 09:06 postmodern

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?

atalanta-cookbooks avatar Jun 02 '13 09:06 atalanta-cookbooks

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

postmodern avatar Jun 02 '13 09:06 postmodern

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?

atalanta-cookbooks avatar Jun 02 '13 10:06 atalanta-cookbooks

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.

postmodern avatar Jun 02 '13 10:06 postmodern

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.

atalanta-cookbooks avatar Jun 02 '13 10:06 atalanta-cookbooks

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

postmodern avatar Jun 02 '13 11:06 postmodern

Tested with 2.0.0-p195 - behaves as expected.

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

  • bash resource
  • execute resource

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 avatar Jun 02 '13 11:06 Atalanta

$ 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 avatar Jun 02 '13 11:06 Atalanta

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?

Atalanta avatar Jun 02 '13 11:06 Atalanta

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.

postmodern avatar Jun 02 '13 11:06 postmodern

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

Atalanta avatar Jun 02 '13 11:06 Atalanta

Just installing the gems should be idempotent?

postmodern avatar Jun 03 '13 04:06 postmodern

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.

Atalanta avatar Jun 03 '13 05:06 Atalanta

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

postmodern avatar Jun 03 '13 05:06 postmodern

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

Atalanta avatar Jun 03 '13 05:06 Atalanta

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".

mdub avatar Jun 20 '13 00:06 mdub

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

databus23 avatar Jun 28 '13 22:06 databus23

@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

timfjord avatar Jul 06 '13 18:07 timfjord

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.

jeroenj avatar Aug 23 '13 10:08 jeroenj