Thursday, March 29, 2012

Opscode Chef client within an rbenv environment

Ruby dependencies and versions on distro's aren't always maintained to our liking. I've had problems deploying Chef on CentOS appliances running ruby on rails apps that break when the packages for Chef are installed. I know the problem should be fixed so dependencies can be handled correctly, but that's not always going to happen as quickly as we'd like. So I adapted the default CentOS bootstrap script to install Chef within an rbenv environment.

Hopefully I won't need to ever do this for Debian.

Since this is limited to CentOS I have the following hard-coded condition in the recipe[chef-client::service]

*** service.rb.orig 2012-03-29 22:36:48.000000000 +0100
--- service.rb 2012-03-18 14:29:20.000000000 +0000
***************
*** 50,55 ****
--- 50,60 ----
    init_content = IO.read("#{node["languages"]["ruby"]["gems_dir"]}/gems/chef-#{chef_version}/distro/#{dist_dir}/etc/init.d/chef-client")
    conf_content = IO.read("#{node["languages"]["ruby"]["gems_dir"]}/gems/chef-#{chef_version}/distro/#{dist_dir}/etc/#{conf_dir}/chef-client")
  
+   # We're always using rbenv on CuntOS, so ensure the service does too
+   if platform?("centos") then
+  conf_content = "#{conf_content}\nexport PATH=\"$HOME/.rbenv/bin:/usr/local/bin:$PATH\"\neval \"$($HOME/.rbenv/bin/rbenv init -)\"\nrbenv shell $(rbenv versions | tail -n 1| grep -Eo '\w+\.\w+\.\w+-\w+')\n"
+   end
+ 
    file "/etc/init.d/chef-client" do
      content init_content
      mode 0755

Adapt the following bootstrap script as needed, and use at your own risk.

bash -c -x -e '
<%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%>

#
# EXAMPLE BOOTSTRAP LINE
#
# knife bootstrap -N your_host -E development -r 'role[base-server]','role[lsb]' --template-file ~/scm/git/chef/bootstrap/centos5-rbenv.erb your_host_fqdn

#
# CONFIGURATION
#
export RBENV_VERSION="1.9.3-p125"

#
# MAIN
#
[ -f /usr/bin/git ] || yum -y install git
if [ ! -d ~/ruby-build ]; then
 cd ~/
 git clone git://github.com/sstephenson/ruby-build.git
 cd ~/ruby-build
 ./install.sh
fi
if [ ! -d ~/.rbenv ]; then
 cd ~/
 git clone git://github.com/sstephenson/rbenv.git .rbenv

 echo "export PATH=\"\$HOME/.rbenv/bin:/usr/local/bin:\$PATH\"" >> ~/.bash_profile
 echo "export PATH=\"\$HOME/.rbenv/bin:/usr/local/bin:\$PATH\"" >> ~/.zshenv

 echo "eval \"\$(\$HOME/.rbenv/bin/rbenv init -)\"" >> ~/.bash_profile
 echo "eval \"\$(\$HOME/.rbenv/bin/rbenv init -)\"" >> ~/.zshenv

 echo "source \$HOME/.bash_profile" >> ~/.bashrc
 echo "rbenv shell $RBENV_VERSION" >> ~/.bashrc

 echo "source \$HOME/.zshenv" >> ~/.zshrc
 echo "rbenv shell $RBENV_VERSION" >> ~/.zshrc
fi

export PATH="$HOME/.rbenv/bin:/usr/local/bin:$PATH"
eval "$($HOME/.rbenv/bin/rbenv init -)"

if  $HOME/.rbenv/bin/rbenv versions | grep -q $RBENV_VERSION && [ -x $HOME/.rbenv/shims/ruby ] ; then
 eval "`$HOME/.rbenv/bin/rbenv sh-shell $RBENV_VERSION`"

else
 export CONFIGURE_OPTS="--disable-install-doc"
 #export MAKEOPTS="-j$(cat /proc/cpuinfo | grep ^processor | tail -n1 | awk \"{print $3 + 2}\")"
 rm -rf /tmp/ruby-build*
 rbenv install $RBENV_VERSION &
 while [ ! -d /root/.rbenv/versions/1.9.3-p125/lib/ruby/1.9.1 ]; do
  sleep 5
  echo "Waiting for ruby-build to complete."
 done
 $HOME/.rbenv/bin/rbenv sh-shell $RBENV_VERSION
fi

if [ ! -f /usr/bin/chef-client ]; then
 rpm -qa epel-release | grep -q epel-release || {
  wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %> http://download.fedoraproject.org/pub/epel/5/i386/epel-release-5-4.noarch.rpm
  rpm -Uvh epel-release-5-4.noarch.rpm
 }

 [ -f /etc/yum.repos.d/aegis.rep ] || wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %>-O /etc/yum.repos.d/aegis.repo http://rpm.aegisco.com/aegisco/el5/aegisco.repo
 
 yum install -y gcc gcc-c++ automake autoconf make
fi

RBENV_BIN="$HOME/.rbenv/versions/$RBENV_VERSION/bin"
GEM_OPTS="--no-rdoc --no-ri"

gem update $GEM_OPTS --system
gem update $GEM_OPTS
[ -x $RBENV_BIN/ohai ] || gem install ohai $GEM_OPTS --verbose
[ -x $RBENV_BIN/chef-client ] || gem install chef $GEM_OPTS --verbose <%= bootstrap_version_string %>

mkdir -p /etc/chef

for x in chef-client chef-solo knife ohai shef; do
 [ -h /usr/bin/${x} ] && rm -f /usr/bin/${x}
 ln -s $RBENV_BIN/${x} /usr/bin/${x}
done

(
cat <<'EOP'
<%= validation_key %>
EOP
) > /tmp/validation.pem
awk NF /tmp/validation.pem > /etc/chef/validation.pem
rm /tmp/validation.pem

(
cat <<'EOP'
<%= config_content %>
EOP
) > /etc/chef/client.rb

(
cat <<'EOP'
<%= { "run_list" => @run_list }.to_json %>
EOP
) > /etc/chef/first-boot.json

<%= start_chef %>'