How to use paswordless sudo with capistrano - ruby-on-rails

I have searched a half of internet and I still can't make this work.
Let's take redis for example, in order to start it, I use the following command
sudo /etc/init.d/redis-server start
and have the following capistrano task:
namespace :redis do
desc "Start the Redis server"
task :start do
on roles(:app) do
execute "/etc/init.d/redis-server start"
end
end
end
and I added the line in visudo
michael ALL=(ALL) NOPASSWD: /etc/init.d/redis-server
and I still can't run that damn task, it either complains that I dont have permission or if I prepend sudo, I get
sudo: no tty present and no askpass program specified
what the hell does it need? How to run the tasks that require sudo with capistrano 3?

Related

Upstart script using foreman export is using wrong ruby version

I have just recently deployed my application to production server, but it looks that that every process I have added to my .procfile (foreman) is not started at all. Details:
I am using Rails 4.0.12, foreman 0.78.0, sidekiq 3.4.2 and clockwork 1.2.0. I am using Capistrano and I have defined a task to export procfile as an upstart service on Ubuntu 14.02. But when I start the service, no background jobs are processed. When I take look at the log files of that upstart service, I just see the following:
Your ruby version is 1.9.3, but your Gemfile specified 2.1.2
Application is running, I can see on sidekiq dashboard that nothing is processed. Based on the error message, it looks like that I am executing my procfile somehow wrong. I have tried multiple execution scenarios, but nothing seems to work. My .procfile currently looks like this:
worker: rbenv sudo bundle exec sidekiq -C config/sidekiq.yml -e production
clock: rbenv sudo bundle exec clockwork config/clock.rb
One part of exported upstart script looks like this for example:
start on starting aaa-clock
stop on stopping aaa-clock
respawn
env PORT=5100
setuid da_admin
chdir /var/www/aaa/releases/20150728172635
exec rbenv sudo bundle exec clockwork config/clock.rb
If i try the last two commands alone in bash, it works, but when i start the service "sudo service aaa start" or "rbenv sudo service aaa start", it doesn't work.
Part of deploy.rb where I am exporting my upstart service:
namespace :foreman do
desc "Export the Procfile to Ubuntu's upstart scripts"
task :export do
on roles(:app) do
within release_path do
execute :rbenv, "sudo bundle exec foreman export upstart /etc/init -a #{fetch(:application)} -u #{fetch(:user)} -l #{current_path}/log -f #{release_path}/Procfile"
end
end
end
desc "Start the application services"
task :start do
on roles(:app) do
execute :rbenv, "sudo service #{fetch(:application)} start"
end
end
desc "Stop the application services"
task :stop do
on roles(:app) do
execute :rbenv, "sudo service #{fetch(:application)} stop"
end
end
desc "Restart the application services"
task :restart do
on roles(:app) do
execute :rbenv, "sudo service #{fetch(:application)} restart"
end
end
end
Does anybody has any idea what could be wrong? I suspect, that this will be some mistake in environment configuration. Thank you in advance for your time.
EDIT:
The problem was at the end in environment of the upstart script, similar problems which pointed me in the right direction were:
foreman issue
foreman another issue
I had to create .env file with configuration of various environment variables. Now it atleast starts (other bugs arised, but they are not related to this issue).
Example of the .env file in the root of project directory:
PATH=/home/user/.rbenv/versions/2.1.2/bin:/usr/bin
RAILS_ENV=production
HOME=/home/user

bundler: not executable: script/delayed_job

I'm trying to run the following command on my remote server (either via capistrano or ssh):
bundle exec RAILS_ENV=production script/delayed_job start
But I'm getting this error message: bundler: not executable: script/delayed_job
Never saw this before, and google had nothing for me. Any idea what might be the problem?
Maybe it does not have permissions to run? Try running this command
chmod +x script/delayed_job
and then executing the file again.
I am not sure if if it is a fundamental misunderstanding of the capistrano rbenv gem or some issue with the gem itself, but I had similar issue with delayed_job, where the bin/delayed_job file just would not get the executable permission when copied to the server by capistrano. So I wrote a task which I had run before invoking the delayed_job:restart task.
Note - Adding this answer because earlier one is from 2014, and also I wanted to show how to add the task, so the permission change can happen during deployment itself.
Created a task in lib/capistrano/tasks folder (in namespace delayed_job):
namespace :delayed_job do
desc 'Ensure that bin/delayed_job has the permission to be executable. Ideally, this should not have been needed.'
task :ensure_delayed_job_executable do
on roles(delayed_job_roles) do
within release_path do
execute :chmod, :'u+x', :'bin/delayed_job'
end
end
end
end
after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
task :restart do
invoke 'delayed_job:ensure_delayed_job_executable'
invoke 'delayed_job:restart'
end
end

Whenever - Cron not working? Permission denied

'I have set up a cron with wehenever, but its not working. I tried to run the command manually and i get the error /bin/bash: bin/rails: Permission denied.
Here what the command of the cron looks like:
/bin/bash -l -c 'cd /var/www/domain.net/main && bin/rails runner -e production '\''User.weekly_update'\'''
I also tried to run this command as root but i got the same message.
Try to make bin/rails executable:
chmod u+x bin/rails
This is, of course, assuming that bin/rails is owned by the crontab's user.
I found that use of RVM can complicate this. A worthy alternative is to make your whenever job into a rake job instead of a runner job:
every 7.days do
rake "user:weekly_update"
end
This does, of course, necessitate an extra bit of code in your lib/tasks directory:
namespace :user do
task :weekly_update=> :environment do
User.weekly_update
end
end
i had the same problem and solved this as follows:
(iam work with rvm and my */bin/rails has already +rx privileges)
As you can see in whenever-github you can change job_type within config/schedule.rb
job_type :runner, "cd :path && /other-path/path-x/bin/rails runner -e :environment ':task' :output"

Bluepill - installed in user RVM - project specific gemset - how to run with sudo without password?

I have Bluepill setup to monitor my delayed_job processes.
On my production server, I use RVM installed in the user's home folder (username is deploy). My app's gems are installed in its own project-specific gemset. So, the bluepill gem and its corresponding binary are installed within the ~/.rvm/.... folder.
When I deploy my app using capistrano, I want bluepill to be stopped and started, so my DJs get restarted. I am looking at the instructions for the capistrano recipe here.
I think my RVM-compliant bluepill tasks have to be like the following:
# Bluepill related tasks
after 'deploy:start', 'bluepill:start'
after 'deploy:stop', 'bluepill:quit'
after 'deploy:restart', 'bluepill:quit', 'bluepill:start'
namespace :bluepill do
desc 'Stop processes that bluepill is monitoring and quit bluepill'
task :quit, :roles => [:app] do
run "cd #{current_path}; sudo bluepill #{application}_#{rails_env} stop"
run "cd #{current_path}; sudo bluepill #{application}_#{rails_env} quit"
sleep 5
end
desc 'Load bluepill configuration and start it'
task :start, :roles => [:app] do
run "cd #{current_path}; sudo bluepill load #{current_path}/config/server/#{rails_env}/delayed_job.bluepill"
end
desc 'Prints bluepills monitored processes statuses'
task :status, :roles => [:app] do
run "cd #{current_path}; sudo bluepill #{application}_#{rails_env} status"
end
end
I haven't tested the above yet.
What I am wondering is: what should I put in my sudoers file to allow the deploy user run just these bluepill related commands as root without a password? On this page they have mentioned this:
deploy ALL=(ALL) NOPASSWD: /usr/local/bin/bluepill
But the path to the bluepill binary would be different in my case. And it would be different for different projects, because of project-specific gemsets. Should I be mentioning each of the binary paths or is there a better way of handling this?
use wrappers and aliases:
namespace :bluepill do
task :setup do
run "rvm alias create #{application} #{rvm_ruby_name_evaluated}"
run "rvm wrappers #{application} --no-links bluepill"
end
end
so after this task bluepill is available via #{rvm_path}/wrappers/#{application}/bluepill which will be always the same even if you change ruby version, so it can be added to sudoers for preserving path:
deploy ALL=(ALL) NOPASSWD: /home/my_user/.rvm/wrappers/my_app/bluepill
and then the tasks can use:
sudo #{rvm_path}/wrappers/#{application}/bluepill ...
it is important to note here that the wrapper takes care of loading rvm environment because it was lost by invocation of sudo ... but this is just a detail ;)

How to enter rails console on production via capistrano?

I want to enter the rails console on production server from my local machine via capistrano.
I found some gists, e.g. https://gist.github.com/813291 and when I enter console via
cap production console
I get the following result
192-168-0-100:foldername username $ cap console RAILS_ENV=production
* executing `console'
* executing "cd /var/www/myapp/current && rails console production"
servers: ["www.example.de"]
[www.example.de] executing command
[www.example.de] rvm_path=$HOME/.rvm/ $HOME/.rvm/bin/rvm-shell '1.9.3' -c 'cd /var/www/myapp/current && rails console production'
/var/www/myapp/releases/20120305102218/app/controllers/users_controller.rb:3: warning: already initialized constant VERIFY_PEER
Loading production environment (Rails 3.2.1)
Switch to inspect mode.
and thats it... Now I can enter some text, but nothing happens...
Has anybody an idea how to get that work or another solution for my problem?
I've added my own tasks for this kind of thing:
namespace :rails do
desc "Remote console"
task :console, :roles => :app do
run_interactively "bundle exec rails console #{rails_env}"
end
desc "Remote dbconsole"
task :dbconsole, :roles => :app do
run_interactively "bundle exec rails dbconsole #{rails_env}"
end
end
def run_interactively(command)
server ||= find_servers_for_task(current_task).first
exec %Q(ssh #{user}##{myproductionhost} -t '#{command}')
end
I now say cap rails:console and get a console.
For Capistrano 3 you can add these lines in your config/deploy:
namespace :rails do
desc 'Open a rails console `cap [staging] rails:console [server_index default: 0]`'
task :console do
server = roles(:app)[ARGV[2].to_i]
puts "Opening a console on: #{server.hostname}...."
cmd = "ssh #{server.user}##{server.hostname} -t 'cd #{fetch(:deploy_to)}/current && RAILS_ENV=#{fetch(:rails_env)} bundle exec rails console'"
puts cmd
exec cmd
end
end
To open the first server in the servers list:
cap [staging] rails:console
To open the second server in the servers list:
cap [staging] rails:console 1
Reference: Opening a Rails console with Capistrano 3
exec is needed to replace the current process, otherwise you will not be able to interact with the rails console.
A simple Capistrano 3 solution may be:
namespace :rails do
desc "Run the console on a remote server."
task :console do
on roles(:app) do |h|
execute_interactively "RAILS_ENV=#{fetch(:rails_env)} bundle exec rails console", h.user
end
end
def execute_interactively(command, user)
info "Connecting with #{user}##{host}"
cmd = "ssh #{user}##{host} -p 22 -t 'cd #{fetch(:deploy_to)}/current && #{command}'"
exec cmd
end
end
Then you can call it say, on staging, with: cap staging rails:console. Have fun!
For Capistrano > 3.5 and rbenv. Working in 2021
namespace :rails do
desc "Open the rails console on one of the remote servers"
task :console do |current_task|
on roles(:app) do |server|
server ||= find_servers_for_task(current_task).first
exec %Q[ssh -l #{server.user||fetch(:user)} #{server.hostname} -p #{server.port || 22} -t 'export PATH="$HOME/.rbenv/bin:$PATH"; eval "$(rbenv init -)"; cd #{release_path}; bin/rails console -e production']
end
end
end
I have fiddled with that approach as well, but then resorted to avoiding building my own interactive SSH shell client and just went with this snippet I found that simply uses good old SSH. This might not be suitable if you have some weird SSH gateway proxying going on, but for logging into a box and performing some operations, it works like a charm.
In my experience, capistrano isn't built to work very well with interactive terminals.
If you have to execute things in multiple terminals, I'd suggest iterm, which has a "send to all windows" function that works very well for me:
http://www.iterm2.com/#/section/home
I have a somewhat difficult environment, which is influx ... So bash -lc isn't really an option right now. My solution is similar to #Rocco, but it's a bit more refined.
# run a command in the `current` directory of `deploy_to`
def run_interactively(command)
# select a random server to run on
server = find_servers_for_task(current_task).sample
# cobble together a shell environment
app_env = fetch("default_environment", {}).map{|k,v| "#{k}=\"#{v}\""}.join(' ')
# Import the default environment, cd to the currently deployed app, run the command
command = %Q(ssh -tt -i #{ssh_options[:keys]} #{user}##{server} "env #{app_env} bash -c 'cd #{deploy_to}/current; #{command}'")
puts command
exec command
end
namespace :rails do
desc "rails console on a sidekiq worker"
task :console, role: :sidekiq_normal do
run_interactively "bundle exec rails console #{rails_env}"
end
end
For a Rails console in Capistrano 3 see this gist: https://gist.github.com/joost/9343156
I have just used capistrano-rails-console gem to open rails console and it is working fine.

Resources