chef-infracookbook

Chef - Source a Script


I am having issues installing Ruby 2.1 using rbenv and Chef. I thought I would use RVM. When installing RVM we need to source a script if we are going to use it immediately.

source /path/to/rvm/script

How would you do this in Chef?

I tried but without success. I believe this is a sourcing problem because the cookbook breaks the first time but runs fine the second time. This should be because the RVM script is sourced in the.bash_profile and when login it source the script and RVM becomes available.

bash "Source RVM Script: source /etc/profile.d/rvm.sh" do
  code "source /etc/profile.d/rvm.sh"
end
==> default: * bash[source /etc/profile.d/rvm.sh] action run
==> default: [2021-06-03T15:26:00+00:00] INFO: bash[source /etc/profile.d/rvm.sh] ran successfully
==> default:
==> default:     - execute "bash"
==> default:   * bash[Install Ruby 2.1.10] action run
==> default:     [execute]
==> default: bash: line 1: rvm: command not found
==> default:
==> default:
==> default: ================================================================================
==> default:
==> default: Error executing action `run` on resource 'bash[Install Ruby 2.1.10]'
==> default:
==> default: ================================================================================
==> default:
==> default:
==> default: Mixlib::ShellOut::ShellCommandFailed
==> default:
==> default: ------------------------------------
==> default:
==> default: Expected process to exit with [0], but received '127'
==> default:
==> default: ---- Begin output of "bash"  ----
==> default:
==> default: STDOUT:
==> default:
==> default: STDERR: bash: line 1: rvm: command not found

Details

The simple RVM recipe I wrote:

# sudo apt-get install software-properties-common
apt_package "software-properties-common"


# sudo apt-add-repository -y ppa:rael-gc/rvm
# sudo apt-get update
apt_repository 'rvm' do
  uri 'ppa:rael-gc/rvm'
  action :add
end

# sudo apt-get install rvm
apt_package "rvm"

# sudo usermod -a -G rvm $USER
group "rvm" do
  append true
  members "vagrant"
end

bash "source /etc/profile.d/rvm.sh" do
  code "source /etc/profile.d/rvm.sh"
end

bash "Install Ruby 2.1.0" do
  code "rvm install 2.1.0"
end

Platform:

# -*- mode: ruby -*-
# vi: set ft=ruby :

cookbook_path = "/Volumes/Dev/Work/GF/Projects/gf-cookbook"

Vagrant.configure("2") do |config|
  config.vm.provider "virtualbox" do |vbox|
    vbox.memory = 1024 * 4
    vbox.cpus = 2
  end

  config.vm.provision "chef_solo" do |chef|
    # chef.install = false
    chef.custom_config_path = "#{cookbook_path}/config.chef"
    chef.cookbooks_path = ["#{cookbook_path}/berks-cookbooks"]
    chef.nodes_path = "#{cookbook_path}/nodes"
    chef.add_recipe "gf"
  end
end


Solution

  • shell commands during convergence time (chef-client run) are running in a sub-shell. so when you execute the following

    bash "source /etc/profile.d/rvm.sh" do
      code "source /etc/profile.d/rvm.sh"
    end
    

    it takes affect only in the current sub-shell. that is why the preceding bash resource does not pick anything that was set during source /etc/profile.d/rvm.sh.

    you can solve this by running both commands on the same shell like so

    bash "rvm" do
      code "source /etc/profile.d/rvm.sh && rvm install 2.1.0"
    end
    

    or by leveraging the flag property to perform a login like so

    bash "source /etc/profile.d/rvm.sh" do
      code "source /etc/profile.d/rvm.sh"
    end
    
    bash "Install Ruby 2.1.0" do
      code "rvm install 2.1.0"
      flags "-l"
    end
    

    what you posed works for you on a second chef-client run since it reads the user profile after it was configured on the first (failed) run.