Problem deploying Ruby+RVM and daemontools - ruby

I am using daemontools in production to keep the services alive and want to run a Ruby server, not Rails, and without RVM it works well but with RVM I have some issues.
My goal is to start a process by root, make it drop root rights to get another user rights and then spawn a Ruby process with RVM and a specified Ruby version.
Here is the run script I was using until now:
#!/bin/sh
exec 2>&1
cd /app/src
. /usr/local/rvm/scripts/rvm
rvm use 1.9.1-p378
exec setuidgid app_user ruby main.rb
This script works but setuidgid has a major problem: the application will be run by user <x> and group <x> and only this group. If the user is in other groups the process will not have their rights.
So it led me to another approach:
#!/bin/sh
exec 2>&1
cd /app
exec sudo -u app_user rvm 1.9.1-p378 exec ruby main.rb
This one works fine except it is the RVM process which is spawned by daemontools and it does not react when it receives a SIGTERM which is not really nice. Basically it means the service cannot be restarted by hand, which is not good.

I found the answer but looking at the rvmsudo script installed with rvm, here is a working run script:
#!/bin/sh
# redirect stderr to stdout
exec 2>&1
cd /app
# load rvm
. /usr/local/rvm/scripts/rvm
# select ruby version for this application
rvm use 1.9.1
# # depending on your configuration you may need to provide the absolute path to rvm, like that:
# /usr/local/bin/rvm use 1.9.1
# build the exec command line preserving the rvm environment
command="exec sudo -u app_user /usr/bin/env PATH='$PATH'"
[[ -n "${GEM_HOME:-}" ]] && command="${command} GEM_HOME='$GEM_HOME' "
[[ -n "${GEM_PATH:-}" ]] && command="${command} GEM_PATH='$GEM_PATH' "
# this is where your real command line goes
command="${command} ruby main.rb"
# run the application
eval "${command}"

Related

Understanding rubygems 'require' in sudo vs rvmsudo

I'm using Ubuntu 12.04.4 TLS
I wrote a simple shell script in /home/abdo/sample_serv.sh that executes a Ruby file:
#!/bin/bash
/home/abdo/.rvm/rubies/ruby-2.1.0/bin/ruby /home/abdo/sample_serv.rb
and /home/abdo/sample_serv.rb containing the code below:
puts $:
require 'sinatra'
set :port, 8084
get '/' do
%{ <html><body>Hello from Abdo</body></html> }
end
Executing rvmsudo ./home/abdo/sample_serv.sh works just fine but I would like to get sudo ./home/abdo/sample_serv.sh to work by passing the necessary environment variables because I am having issues with upstart.
The issue arises in my /etc/init/foo.conf
description "webserver test"
start on runlevel [23]
stop on shutdown
pre-start script
exec >> /var/log/unicorn_test.log 2>&1
echo starting
end script
script
exec >> /var/log/unicorn_test.log 2>&1
/bin/bash /home/abdo/.rvm/bin/rvmsudo /home/abdo/sample_serv.sh
echo started
end script
When the line /bin/bash /home/abdo/.rvm/bin/rvmsudo /home/abdo/sample_serv.sh is reached, I get
/home/abdo/.rvm/rubies/ruby-2.1.0/lib/ruby/site_ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in
`require': cannot load such file -- sinatra (LoadError)
I was able to get the same ruby -v as that of my user but it looks like the GEM_PATH (even if I set it inside the upstart config file), is not helping.
Basically, if I can understand how (and where -- gem env is not helping since gem is not a command when I do sudo) rubygems looks for a file being required, I should be able to move forward.
When you run under sudo you run in a different environment, where gem is not installed, the $PATH is different, so things may not run smoothly.
You may want to try this:
Changing sudo's strict defaults
There are 3 things needed to mitigate this situation if you encounter
it:
the user that is invoking sudo must have export rvmsudo_secure_path=0 set on his shell environment (think .bashrc,
.bash_profile or .zshrc)
comment out Defaults secure_path=... on /etc/sudoers
add Defaults env_keep +="rvm_bin_path GEM_HOME IRBRC MY_RUBY_HOME rvm_path rvm_prefix rvm_version GEM_PATH rvmsudo_secure_path
RUBY_VERSION rvm_ruby_string rvm_delete_flag" to /etc/sudoers in
rare cases it is required to add more variables - they should be
reported by first run of rvmsudo.
After these changes, you should be able to use rvmsudo preserving
the same password/no-password directives as "normal" sudo calls.
Edit
If you don't want to change the defaults, you can try to synchronize the values of the environment values stated above (rvm_bin_path GEM_HOME IRBRC MY_RUBY_HOME rvm_path rvm_prefix rvm_version GEM_PATH rvmsudo_secure_path RUBY_VERSION rvm_ruby_string rvm_delete_flag) to your root user.
If that doesn't work, you can try installing rvm as root, and using that environment (instead of /home/abdo/.rvm/bin/rvm) to run your code.

Ruby RVM under another user from Bash script

What is the best way to launch ruby script under another user via su command and from another script?
I have a bash script with the following command for launching unicorn:
sudo -u unicornuser sh -l -c "bundle exec unicorn_rails -E production -D"
This script is an init.d script and it being execute when system starts and manually also.
The problem is the default ruby on system is 1.8, other rubyes (1.9) is working under RVM. I need to modify above script that it can execute ruby with RVM (non system wide)
Now I've migrated for this notation:
su -l -c "rvm use ruby-1.9.3-p125 && bundle exec unicorn_rails -E production -D" unicornuser
this worked for me, but I guess there must be a better way to do this.
You should use wrappers:
rvm wrapper ruby-1.9.3-p125 ext_1.9.3 bundle
This will create $rvm_path/bin/ext_1.9.3_bundle, so now you can use:
/full/path/to/rvm/bin/ext_1.9.3_bundle exec unicorn_rails -E production -D
replace /full/path/to/rvm with output from echo $rvm_path

Why does ruby script stop when trying to start unicorn_rails as daemon?

I'm trying to start unicorn_rails in a ruby script, and after executing many commands in the script, when the script gets to the following line
%x[bash -ic "bash <(. ~/.bashrc); cd /home/www-data/rails_app; bundle exec unicorn_rails -p 8000 -E production -c /home/www-data/rails_app/config/unicorn.rb -D"]
the script stops, generating the following output
[1]+ Stopped ./setup_rails.rb
and returns to the Linux prompt. If I type "fg", the script finishes running, the line where the script had stopped gets executed and unicorn gets started as a daemon.
If I run the line in a separate script, the script completes without stopping.
UPDATE_1 -
I source .bashrc because earlier in the script I install rvm and to get it to run with the correct environment I have the following:
%x[echo "[[ -s \"$HOME/.rvm/scripts/rvm\" ]] && source \"$HOME/.rvm/scripts/rvm\"" >> .bashrc]
%x[bash -ic "bash <(. ~/.bashrc); rvm install ruby-1.9.2-p290; rvm 1.9.2-p290 --default;"]
So if I want to run correct version of rvm, ruby and bundle I need to source .bashrc
end UPDATE_1
Does anyone have any idea what could cause a ruby script to halt as if control-Z was pressed?
Not sure why it's stopping, but my general rule of thumb is to never source my .bashrc in a script -- that might be the source of your problem right there, but I can't be sure without seeing what's in it. You should be able to change your script to something like:
$ vi setup_rails.sh
#!/usr/bin/bash
# EDIT from comments below
# expanding from a one liner to a better script...
$RVM_PATH=$HOME/.rvm/scripts
# install 1.9.2-p290 unless it's installed
$RVM_PATH/rvm info 1.9.2-p290 2&>1 >/dev/null || $RVM_SH install 1.9.2-p290
# run startup command inside rvm shell
$RVM_PATH/rvm-shell 1.9.2-p290 -c "cd /home/www-data/rails_app && bundle exec unicorn_rails -p 8000 -E production -c /home/www-data/rails_app/config/unicorn.rb -D"
This should give you the same result.

Run a gem from rvm with runit

I need to create a runit service that runs a gem's binary that was installed with rvm, the problem is that a non-login bash shell, which is how runit runs its services does not have the correct path's for rvm. Is there any automatic way of doing this?
I use following script:
#!/bin/sh
exec 2>&1
DIR=/var/www/apps/mega_app/current
export rvm_path=/usr/local/rvm
export rvm_ignore_rvmrc=1
cd $DIR
exec chpst -u user:group /usr/local/rvm/bin/rvm ree exec bundle exec ${DIR}/daemons/mega_daemon.rb
Does su - USERNAME -c '/path/to/script' work? It should preserve the $PATH variables.

RVM is not working over SSH

RVM is not working over SSH.
At the command-line:
leifg#host:~$ which ruby
/usr/local/rvm/rubies/ruby-1.9.2-p290/bin/ruby
Connected over SSH:
local:~$ ssh leifg#server 'which ruby'
/usr/bin/ruby
I'm using Ubuntu 11.04.
How do I get SSH to use the same Ruby as it is on the system?
I already verified some prequisites:
Ruby was already installed using apt-get install ruby. Does that make any difference?
sshd_config has the option "PermitUserEnvironment yes", and I restarted the daemon.
The .bashrc on the server contains these lines, but I see the same behavior when I remove them:
if [ -s "$HOME/.rvm/scripts/rvm" ] ; then
. "$HOME/.rvm/scripts/rvm"
elif [ -s "/usr/local/rvm/scripts/rvm" ] ; then
. "/usr/local/rvm/scripts/rvm"
fi
Actually, your ~/.bashrc will be executed. The problem is usually that one adds the
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" # Load RVM into a shell session *as a function*
... snippet at the bottom of the file. However, the default .bashrc on ubuntu systems includes the following near the top
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
That call will stop executing the rest of the script and will therefore not set the proper paths. So you can either put the rvm call at the top of the file or remove the return call.
From the ssh man page:
If command is specified, it is executed on the remote host instead of
a login shell.
This should mean that your .bashrc won't get sourced, so RVM doesn't get set up.
Solution
This did the trick in the end:
ssh <host> bash --login -c <command>
Start bash as a login shell through SSH and then start the RVM installed Ruby via SSH's -c option.
Actually there's totally another, more safe and lightweight option.
You add "PermitUserEnvironment yes" somewhere to your sshd_config in /etc/(open)ssh
Now you are allowed to specify user environment in /home/user/.ssh/environment. So what do you put there ?
Just something like :
user# env | grep rvm > ~/.ssh/environment
so it looks like below :
user#app3:~$ cat ~/.ssh/environment
rvm_bin_path=/usr/local/rvm/bin
GEM_HOME=/usr/local/rvm/gems/ree-1.8.7-2012.02
IRBRC=/usr/local/rvm/rubies/ree-1.8.7-2012.02/.irbrc
MY_RUBY_HOME=/usr/local/rvm/rubies/ree-1.8.7-2012.02
rvm_path=/usr/local/rvm
rvm_prefix=/usr/local
PATH=/usr/local/rvm/gems/ree-1.8.7-2012.02/bin:/usr/local/rvm/gems/ree-1.8.7-2012.02#global/bin:/usr/local/rvm/rubies/ree-1.8.7-2012.02/bin:/usr/local/rvm/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
rvm_version=1.14.5 (stable)
GEM_PATH=/usr/local/rvm/gems/ree-1.8.7-2012.02:/usr/local/rvm/gems/ree-1.8.7-2012.02#global
Note: this also works work user-install RVM (not only for the system wide)
Now your are able to use ruby in ssh non interactive sessions :
ssh user#app3 'ruby --version'
ruby 1.8.7 (2012-02-08 MBARI 8/0x6770 on patchlevel 358) [x86_64-linux], MBARI 0x6770, Ruby Enterprise Edition 2012.02
Voila!
“rvm” has two invocation bugs: the default installation drops the file /etc/profile.d/rvm.sh and believes any bash trick is now globally available. – This assumption is wrong.
Files in /etc/profile.d/ are “sourced” on login, but maybe not from bash, maybe not even from a shell. So the cd hook it installs is not there after the shell which runs these files exits. Actually, because of the buggy way “rvm” installs this hook, it is already gone once you run naked bash in a login-shell!
I don’t know if “rvm” supports an explicit invocation for virtual environments, without relying on cding into some directory (that I consider the second bug).
There is one sane workaround:
Make your shell source /etc/profile.d/rvm.sh from e.g. ~/.bashrc. .bashrc is executed from any non-login bash, and login-bash is usually setup to source .bashrc from those login-shell files like ~/.profile
For your ssh problem: should a proper ssh-shell not be login-shell anyway?
I've just added at the top of ~/.bashrc (for git user) this string:
[[ -s "/usr/local/rvm/scripts/rvm" ]] && source "/usr/local/rvm/scripts/rvm"
Mentioned solutions work certainly fine, but mine was to run
source /usr/local/rvm/environments/<ruby version>#<gemset version>
at the start of the remote ssh call. Something like:
ssh -l <remote username> <server ip> "source /usr/local/rvm/environments/<ruby version>#<gemset version> ; <rest of the remote script>"
(if using Capistrano) Don't use rvm1/capistrano3 or rvm/capistrano; don't set :pty.
Change ~/.rvmrc for the runner user, on the server, to this — note that it has to come before the line where it kills itself when not running interactively:
# get rvm for non-interactive shells (eg capistrano) too
source /etc/profile.d/rvm.sh
export BASH_ENV=$HOME/.bashrc
export rvm_is_not_a_shell_function=0
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
I had the same problem. I realized, that I accidentally installed RVM for multiple users, too. After deleting the directory /usr/local/rvm and edit ~/.bashrc like zoonmix suggested, the problem was solved.
Make sure that on the server you have done something like rvm --default 1.9.2 to set RVM's Ruby to be the default. Otherwise, it will always use the default system Ruby.
zoomix's is the best solution. But when you change with "ruby rvm use system" in terminal or what else you get an error :
Warning! PATH is not properly set up, is not at first place.... To solve that put the snippet just before the return instead of at the top of the .bashrc file (Debian Jessie here)
case $- in
*i*) ;;
*)
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" # Load RVM into a shell session *as a function*
return;; esac

Resources