How to run ruby via sudo - ruby

Hi I am creating a new init script for monitoring a ruby program .
NAME=differ
FILE_PATH=/home/amer/Documents/ruby_projects/differ/
PIDFILE=/home/amer/pid/differ.pid
PID=$$
EXEC='/home/amer/.rvm/rubies/ruby-2.0.0-p247/bin/ruby main_scheduler.rb'
do_start(){
echo "started"
cd $FILE_PATH
pwd
$EXEC >> init_log/output.log &
echo $! > $PIDFILE
echo "---------"
echo `cat $PIDFILE`
echo "all are DONE "
}
do_stop(){
PID=`cat $PIDFILE`
echo $PID
if ps -p $PID ; then
kill -6 $PID
echo "it is over"
else
echo "its not running"
fi
}
case "$1" in
start)
echo $$
echo -n "Starting script differ "
do_start
;;
stop)
echo "stopping ...."
do_stop
;;
status)
PID=`cat $PIDFILE`
echo "STATUS $PID"
if ps -p $PID -f; then
echo running
else
echo not running
fi
;;
restart|reload|condrestart)
do_stop
do_start
;;
*)
echo "Usage: /etc/init.d/blah {start|stop}"
exit 1
;;
esac
exit 0
And my monit process is
check process differ with pidfile /home/amer/pid/differ.pid
if changed pid then exec "/etc/init.d/differ start"
start program = "/etc/init.d/differ start"
stop program = "/etc/init.d/differ stop"
if 5 restarts within 5 cycles then timeout
But when I execute start service in my monit the status was "Execution failed" and i checked the log file of monit it said
info : 'differ' start: /bin/bash
error : 'differ' failed to start
error : 'differ' process is not running
When I analyzed the root of the problem . the reason was monit is running as root and the script which executes ruby will be executing as sudo /etc/init.d/differ.sh start but ruby is installed only in user 'amer' . I have tried
sudo -u amer $EXEC >>init_log/output.log &
it displayed the error as
amer#amer-Inspiron-1525:~$ /home/amer/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/rubygems/core_ext/kernel_require.rb:45:in `require': cannot load such file -- bundler/setup (LoadError)
from /home/amer/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/rubygems/core_ext/kernel_require.rb:45:in `require'
from main_scheduler.rb:2:in `<main>'
Please help in this problem . I have two ruby versions.
/home/amer/.rvm/rubies/ruby-2.0.0-p247/bin/ruby
/home/amer/.rvm/bin/ruby

It looks like your environment is missing. Replace
sudo -u amer $EXEC >>init_log/output.log &
with
su -s /bin/bash - amer -c "$EXEC >> init_log/output.log 2>&1" &
This should setup your shell environment properly. If you ran sudo .. >> log before, the log file might be owned by root. Change that or it will fail. I also added the redirect of STDERR to STDOUT, since you are probably interested in error messages.

after a long struggle i found the solution for this problem .
Two things must be done
1) EXPORT your PATH,GEM_HOME,GEM_PATH in the script
export PATH="/home/amer/.rvm/gems/ruby-2.0.0-p247#rails329/bin:/home/amer/.rvm/gems/ruby-2.0.0-p247#global/bin:/home/amer/.rvm/rubies/ruby-2.0.0-p247/bin:/home/amer/.rvm/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"
export GEM_HOME=/home/amer/.rvm/gems/ruby-2.0.0-p247#rails329
export GEM_PATH=/home/amer/.rvm/gems/ruby-2.0.0-p247#rails329:/home/amer/.rvm/gems/ruby-2.0.0-p247#global
2) USE rvmsudo bundle exec ruby "filename" (use full path)
rvmsudo -u amer /home/amer/.rvm/gems/ruby-2.0.0-p247#rails329/bin/bundle exec /home/amer/.rvm/rubies/ruby-2.0.0-p247/bin/ruby main_scheduler.rb&
it worked for me . hope it does for everyone .

Here's what I do when I want to run ruby scripts in init:
I switch to super user and install rvm. This won't cause problems with your single user installation.
I put this in the init script:
/usr/local/rvm/bin/rvm-shell 'yourgemset' -c 'ruby pathtoyourscript/yourscript.rb'
Example:
/usr/local/rvm/bin/rvm-shell 'jruby-1.7.4' -c 'ruby /home/someone/service.rb'
Hint: all the necessary gems need to be installed in that gemset.
The proper way of doing all this is to create an rvm wrapper script (see example) but I find my method easier for a simple setup where there aren't many gemsets.

Related

How to keep the internal shell script running while the main shell script ends?

I am trying to create one script which check for a running process and start it if it is not running.
Here is test.sh
#!/bin/bash
if pgrep infiloop > /dev/null ;
then
echo "Process is running."
else
exec /u/team/infiloop.sh > /u/team/infiloopOutput.txt
echo "Process was not running."
fi
And infiloop.sh
#!/bin/sh
while true
do
echo "helllo"
sleep 2
done
Now when i run the 1st script , it starts the script but after it start it doesn't allow me to run another command.
Output:
[user#host ~]$ ./checkforRunningJob.sh
^C
I have to press Ctrl+C, Ctrl+Z, and once i do that my infinite script also stop.
Could you please check.
Thanks.
You can put the process in the background with &:
#!/bin/bash
if pgrep infiloop > /dev/null ;
then
echo "Process is running."
else
exec /u/team/infiloop.sh > /u/team/infiloopOutput.txt &
echo "Process was not running, started process $!"
fi

Require in Init.d script

I've done an init.d script in order to start a newrelic plugin as daemon. The problem is that when I run service rb_nr_agent start it has some errors related with "require". Output:
[root#device newrelic_rb_plugin]# /usr/local/rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- snmp (LoadError)
from /usr/local/rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /opt/newrelic_rb_plugin/newrelic_redborder_agent:5:in `<main>'
[root#device newrelic_rb_plugin]# ./rb_nr_agent start Starting rb_nr_agent:[ OK ]
It doesn't start properly. When I run the same script but in the root path of the project it doesn't have any error and it works fine. The init.d is a copy of that one. Here you have the start option of the script:
start() {
RESULT=`ps aux | grep $executable | grep -c -v grep`
if [ "${RESULT:-null}" -ge "1" ]; then
echo "$prog is currently running"
else
echo -n "Starting $prog: "
/opt/newrelic_rb_plugin/newrelic_redborder_agent > /dev/null &
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
echo_success
else
echo_failure; failure
RETVAL=1
fi
echo
fi
return $RETVAL }
Error text suggests that you're using RVM, but it is loaded only at user login and thus is not available in init-scripts by default.
Use rvm do to run a command with rvm enabled:
/usr/local/rvm/bin/rvm ruby-2.1.2 do /opt/newrelic_rb_plugin/newrelic_redborder_agent > /dev/null &
(you may need to correct for the exact installed ruby version and gemset name, if any is used)

Bash Start and Stop Scripts

I wrote a bash script that starts a number of different widgets (various Rails applications) and runs them in the background. I'm now trying to write a complimenting stop script that kills each of the processes started by that start script, but I'm not sure of the best way to approach it.
Following is my start script:
#!/bin/bash
widgets=( widget1 widget2 widget3 ) # Specifies, in order, which widgets to load
port=3000
basePath=$("pwd")
for dir in "${widgets[#]}"
do
cd ${basePath}/widgets/$dir
echo "Starting ${dir} widget."
rails s -p$port &
port=$((port+1))
done
If possible, I was trying to avoid saving the PIDs to a .pid file because they're horribly unreliable. Is there a better way to approach this?
One possibility is to use pkill with the -f switch that is described thus in the man page:
-f The pattern is normally only matched against the process name. When -f is set, the full command line is used.
Hence, if you want to kill rails s -p3002, you can proceed as follows:
pkill -f 'rails s -p3002'
To keep extra dependencies at a minimum and ensure I didn't shut down rails instances that don't belong to me, I ended up going with the following:
Start Script
#!/bin/bash
widgets=( widget1 widget2 widget3 ) # Specifies, in order, which widgets to load
port=3000
basePath=$("pwd")
pidFile="${basePath}/pids.pid"
if [ -f $pidFile ];
then
echo "$pidFile already exists. Stop the process before attempting to start."
else
echo -n "" > $pidFile
for dir in "${widgets[#]}"
do
cd ${basePath}/widgets/$dir
echo "Starting ${dir} widget."
rails s -p$port &
echo -n "$! " >> $pidFile
port=$((port+1))
done
fi
Stop Script
#!/bin/bash
pidFile='pids.pid'
if [ -f $pidFile ];
then
pids=`cat ${pidFile}`
for pid in "${pids[#]}"
do
kill $pid
done
rm $pidFile
else
echo "Process file wasn't found. Aborting..."
fi

rc.d start does not terminate?

So I wrote the Arch Linux rc.d script for mongod daemon (following an example), but when I do:
sudo rc.d start mongod
it just gets stuck on:
:: Starting /usr/bin/mongod [BUSY]
and never transitions to "DONE" phase. Any tips?
Here is my script:
#!/bin/bash
# import predefined functions
. /etc/rc.conf
. /etc/rc.d/functions
# Point to the binary
DAEMON=/usr/bin/mongod
# Get the ARGS from the conf
. /etc/conf.d/crond
# Function to get the process id
PID=$(get_pid $DAEMON)
case "$1" in
start)
stat_busy "Starting $DAEMON"
# Check the PID exists - and if it does (returns 0) - do no run
[ -z "$PID" ] && $DAEMON $ARGS &> /dev/null
if [ $? = 0 ]; then
add_daemon $DAEMON
stat_done
else
stat_fail
exit 1
fi
;;
stop)
stat_busy "Stopping $DAEMON"
kill -HUP $PID &>/dev/null
rm_daemon $DAEMON
stat_done
;;
restart)
$0 stop
sleep 1
$0 start
;;
*)
echo "usage: $0 {start|stop|restart}"
esac
I've looked at how apache does it, but I can't figure out what they are doing that's different. Here's a piece of their httpd script:
case "$1" in
start)
stat_busy "Starting Apache Web Server"
[ ! -d /var/run/httpd ] && install -d /var/run/httpd
if $APACHECTL start >/dev/null ; then
add_daemon $daemon_name
stat_done
else
stat_fail
exit 1
fi
;;
For one thing, you are passing an $ARGS variable that is never actually defined. You will probably want to either pass some configuration options, or the location of a mongodb.conf file using the -f or --config option, to inform the daemon of the location of your database, log file, IP bindings, etc.
The mongod defaults assume that you database location is /data/db/. If this does not exist, or the daemon does not have permissions to that location, then the init script will fail.
You should probably also run the daemon with a user account other than yourself or root (the default pacman package creates a user named mongodb), and give this user read/write access to the data path and log file.
[ -z "$PID" ] && /bin/su mongodb -c "/usr/bin/mongod --config /etc/mongodb.conf --fork" > /dev/null
I would suggest referring to the mongodb init script provided in the Arch Community package, and comparing that to what you have here. Or, install MongoDB using pacman, which sets all of this up for you.
If all else fails, add some 'echo' commands inside of your if and else blocks to track down exactly where the init script is hanging, check mongodb's logs, and report back to us.

Can't start service with sudo since root user has no access to Ruby

tl;dr
Trying to run a service which needs ruby to run. But, Ruby is installed with RVM where the root user can't seem to access it, producting the error /usr/bin/env: ruby: No such file or directory. rvmsudo doesn't work.
Background
I have an init.d script which is supposed to start a unicorn server. I keep the script in the config directory of my rails application and symlink to it from /etc/init.d/busables_unicorn.
$ ls -l /etc/init.d/busables_unicorn
-> lrwxrwxrwx 1 root root 62 2012-01-12 15:02 busables_unicorn -> /home/dtuite/dev/rails/busables/current/config/unicorn_init.sh
This script (which is appended to the bottom) essentially just runs the following command:
$APP_ROOT/bin/unicorn -D -c $APP_ROOT/config/unicorn.rb -E production
where $APP_ROOT is the path to the root of my rails application. Every time that command is executed in that init.d script, it is supposed to do so as the dtuite (my deploy) user. To accomplish that, I call su -c "$CMD" - dtuite rather than just $CMD.
/bin/unicorn is a "binscript" which was generated by Bundler and config/unicorn.rb contains some configuration options which are passed to it.
The unicorn binscript looks like this:
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'unicorn' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('unicorn', 'unicorn')
Now, I'm trying to start my unicorn service by running:
sudo service busables_unicorn start
That however produces the error:
/usr/bin/env: ruby: No such file or directory
I believe that this is happening because I'm running the service as the root user but RVM has installed ruby under the dtuite user's home directory and the root user has no access to it.
dtuite#localhost:$ which ruby
-> /home/dtuite/.rvm/rubies/ruby-1.9.3-p0/bin/ruby
dtuite#localhost:$ su
Password:
root#localhost:$ which ruby
root#localhost:$
Question
What do I need to do to make this work?
My Setup
- ubuntu 11.10
- ruby 1.9.3p0 (2011-10-30 revision 33570) [i686-linux]
- nginx: nginx version: nginx/1.0.5
What I've tried
rvmsudo
$ rvmsudo service busables_unicorn start
/usr/bin/env: ruby: No such file or directory
rvm-auto-ruby
$ sudo service cakes_unicorn start
-> [sudo] password for dtuite:
-> -su: /home/dtuite/dev/rails/cakes/current/bin/unicorn: rvm-auto-ruby: bad interpreter: No such file or directory
This other question may help but to be honest I don't really understand it.
Appendix
The busables_unicorn script in it's entirety.
# INFO: This file is based on the example found at
# https://github.com/defunkt/unicorn/blob/master/examples/init.sh
# Modifications are courtesy of Ryan Bate's Unicorn Railscast
# Install Instructions:
# sudo ln -s full-path-to-script /etc/init.d/APP_NAME_unicorn
# Once installed, an app's unicorn can be reloaded by running
# sudo service APP_NAME_unicorn restart
#!/bin/sh
set -e
# Example init script, this can be used with nginx, too,
# since nginx and unicorn accept the same signals
# Feel free to change any of the following variables for your app:
TIMEOUT=${TIMEOUT-60}
APP_ROOT=/home/dtuite/dev/rails/busables/current
PID=$APP_ROOT/tmp/pids/unicorn.pid
# in order to access this, we need to first run
# 'bundle install --binstubs'. THis will fill our
# app/bin directory with loads of stubs for executables
# this is the command that is run when we run this script
CMD="$APP_ROOT/bin/unicorn -D -c $APP_ROOT/config/unicorn.rb -E production"
# we don't need an init config because this file does it's job
action="$1"
set -u
old_pid="$PID.oldbin"
cd $APP_ROOT || exit 1
sig () {
test -s "$PID" && kill -$1 `cat $PID`
}
oldsig () {
test -s $old_pid && kill -$1 `cat $old_pid`
}
case $action in
start)
sig 0 && echo >&2 "Already running" && exit 0
# NOTE: We have to change all these lines.
# Otherwise, the app will run as the root user
su -c "$CMD" - dtuite
;;
stop)
sig QUIT && exit 0
echo >&2 "Not running"
;;
force-stop)
sig TERM && exit 0
echo >&2 "Not running"
;;
restart|reload)
sig HUP && echo reloaded OK && exit 0
echo >&2 "Couldn't reload, starting '$CMD' instead"
su -c "$CMD" - dtuite
;;
upgrade)
if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
then
n=$TIMEOUT
while test -s $old_pid && test $n -ge 0
do
printf '.' && sleep 1 && n=$(( $n - 1 ))
done
echo
if test $n -lt 0 && test -s $old_pid
then
echo >&2 "$old_pid still exists after $TIMEOUT seconds"
exit 1
fi
exit 0
fi
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
su -c "$CMD" - dtuite
;;
reopen-logs)
sig USR1
;;
*)
echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
exit 1
;;
esac
It sounds like su isn't spawning a shell that reads the profile files that normally setup the rvm environment.
I'd try changing the command you run to
source "/home/dtuite/.rvm/scripts/rvm" && $APP_ROOT/bin/unicorn...
Try adding your ruby path somewhere at the beginning of the start script, in an export statement like this:
export PATH=/home/dtuite/.rvm/rubies/ruby-1.9.3-p0/bin:$PATH

Resources