Capistrano executes a command with sudo although it is turned off - ruby-on-rails

I have the following deploy.rb with my capistrano-enabled project:
# config valid only for Capistrano 3.1
lock '3.1.0'
# Default value for :pty is false
# forward password prompts
set :pty, true
set :use_sudo, false
namespace :setup do
desc 'installs required libraries'
task :libraries do
on roles(:app), in: :sequence do
execute :sudo, 'whoami'
execute :sudo, "apt-get install mplayer"
end
end
end
I might not really grasp the concept of :use_sudo and the execute :sudo, 'command' part but curiously the whoami returns root, even though :use_sudo is turned off.
The Documentation of v.2 states this too:
set :use_sudo, false. By default, Capistrano will try to use sudo to do certain operations (setting up your servers, restarting your application, etc.). If you are on a shared host, sudo might be unavailable to you, or maybe you just want to avoid using sudo.
So what is the :use_sudo flag for if sudo is executed anyways.

You're explicitly running a command in sudo: execute :sudo, 'whoami', why are you surprised that it uses sudo?
As explained in the documentation that you quoted, setting the :use_sudo option to false will tell Capistrano not to use sudo when doing certain operations. If you execute sudo whoami though it's not going to modify your command.

Related

Cron job not being updated by whenever gem

Having a series of rake tasks that should be translated by the whenever gem into the cron file, I was wondering why the takes shows were pointing to an old release.
It cannot be asserted that whenever is active somehow, even though it is listed in the gem file (and associated lock file) and deployment refers to whenever in the deployment as follows:
tar: DEBUG [1f7d4e56] bin/whenever: time stamp 2016-01-08 15:01:20 is 88.787104175 s in the future
update Checking bundle exec whenever -v returns the proper version. Need bundle exec there...
Capfile includes require "whenever/capistrano" after calls to bundler and rails.
require 'capistrano/bundler'
require 'capistrano/rails'
require 'whenever/capistrano'
Note: this is being tested in development mode.
Functional answer. The instructions are misleading If you don't need different jobs running on different servers in your capistrano deployment, then you can safely stop reading now and everything should just work the same way it always has. Keep on reading.
The nugget is nested after this statement. Roles default to [:db]. Thus two sources of error are possible:
different job_roles on different machines are not specified in schedule.rb
Check your environment file. If "db" is not listed, whenever will not fire.
I had the same issues with using Capistrano whenever plugin, I solved it by making custom deploy shell scripts, cap production deploy being one command of many, and then inclding cap production cron:regen; inside this script I called deploy.sh, with the command inside the deploy.rb being:
namespace :cron do
desc "restart cron"
task :regen do
on roles(:app) do |host|
rails_env = fetch(:stage)
execute_interactively "crontab -r;bundle exec whenever --update-crontab;crontab -l;"
end
end
end
def execute_interactively(command)
port = fetch(:port) || 22
exec "ssh root##{fetch(:ip)} -t 'cd SERVER_PATH_OF_YOUR_APP && #{command}'"
end
I use these functions for all types of different commands, since Capistrano still gives me problems with a lot of native plugins it uses.
If you're not happy with the whenever/capistrano, you can create yourself a simple Capistrano task to update the cron jobs:
namespace :deploy do
desc "Update crontab with whenever"
task :update_cron do
on roles(:app) do
within current_path do
execute :bundle, :exec, "whenever --update-crontab #{fetch(:application)}"
end
end
end
after :finishing, 'deploy:update_cron'
end
The task will be called when the code deployment is finished.

How to use paswordless sudo with capistrano

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?

cap v3 rails 4 passenger deploy Web application could not be started because Gemfile not found

When we deploy to our server, everything deploys fine, however we get the error "Gemfile not found" right after. At first I thought this was nginx not starting, but if I restart the box, the error goes away and the application works perfectly. We are trying to determine why this is occurring and how to fix it. As of right now, I am not sure where to begin and nothing I seem to research on the "google" has turned up answers.
The breakdown of the server setup and deployment:
rails 4
rbenv
ruby 2.1.0
capistrano v3
passenger
server build with chef
The Capfile:
require 'pry'
# Load DSL and Setup Up Stages
require 'capistrano/setup'
# Includes default deployment tasks
require 'capistrano/deploy'
# Includes tasks from other gems included in your Gemfile
#
# For documentation on these, see for example:
#
# https://github.com/capistrano/rvm
# https://github.com/capistrano/rbenv
# https://github.com/capistrano/chruby
# https://github.com/capistrano/bundler
# https://github.com/capistrano/rails/tree/master/assets
# https://github.com/capistrano/rails/tree/master/migrations
#
# require 'capistrano/rvm'
require 'capistrano/rbenv'
# require 'capistrano/chruby'
require 'capistrano/bundler'
# require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
# Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }
The deploy.rb:
set :application, 'api'
set :scm, :git
set :repo_url, 'git#github.com:PlacewiseMedia/API.git'
set :branch, 'develop'
set :deploy_to, '/home/apps/api'
set :deploy_via, :remote_cache
set :keep_releases, 10
set :user, 'deploy'
set :use_sudo, false
set :rbenv_type, :system
set :rbenv_ruby, '2.1.0'
set :rbenv_path, '/opt/rbenv'
namespace :deploy do
desc 'Restart application'
task :restart_application do
on roles(:app), in: :sequence, wait: 5 do
spacer("Setting up restart file")
execute "mkdir -p #{release_path}/tmp ; touch #{release_path}/tmp/restart.txt"
spacer("Restarting the nginx service")
execute "sudo service nginx restart"
spacer()
end
end
desc 'Run Migrations'
task :update_database do
on roles(:app), in: :sequence, wait: 5 do
within(release_path) do
with rails_env: fetch(:rails_env) do
spacer("Updating the database")
execute :rake, "db:migrate", "--trace"
spacer()
end
end
end
end
desc 'Create application symlinks'
task :shared_links do
on roles(:app), in: :sequence, wait: 5 do
spacer("Creating application symlinks")
execute "rm #{release_path}/config/database.yml"
execute "ln -s #{shared_path}/config/database.yml #{release_path}/config/database.yml"
execute "ln -s #{shared_path}/config/secrets.yml #{release_path}/config/secrets.yml"
execute "ln -s #{shared_path}/bin/passenger #{release_path}/bin/passenger"
spacer()
end
end
after 'deploy:updated', 'deploy:shared_links'
after :finishing, 'deploy:update_database'
after :finishing, 'deploy:restart_application'
after :finishing, 'deploy:cleanup'
end
namespace :setup do
desc 'Copy the secrets.yml and database.yml files'
task config: ['config/secrets.yml', 'config/database.yml'] do |t|
on roles(:all) do
execute "mkdir -p #{shared_path}/config"
t.prerequisites.each do |file|
upload! file, "#{shared_path}/config"
end
end
end
end
def spacer(desc = nil)
puts "-----------------------------------------------------------------------------"
if desc
puts desc
puts "-----------------------------------------------------------------------------"
end
end
The error:
UPDATE 09/25 : 02:10pm PST
After working with https://hackhands.com/ we discovered that multiple instances of nginx are running as shown:
I can work to kill the services and restart it but it seems like something may not be configured correctly on the server via chef or our cap deployment. If I restart the box things work as stated, but we also tried killing the nginx services. We discovered that works as well. Our dev ops team is working on this, but we are still perplexed how this has occurred or how to repair it.
UPDATE 09/26 : 11:06am PST
I found where the config comes from on the passenger spinup, if you
look in /etc/service/ you will see the folders for the apps that are
on the server. Look at the run file in the folder you're interested
in and you'll see the passenger config. That fires off a ruby .bin/passenger start process, which then fires off the /tmp nginx
process which is hanging on app restart. I've tried restarting all in
different combos, the one that seems to work is killing the nginx
process, then running sudo killall ruby to respawn the new app...
not ideal
So the update our DevOps team did to address this issue revolves around the way passenger spawns nginx. The config that it was using was the older spawn-lv2 from previous versions, and I changed it to spawn for the current version 4. What this seems to do is to stop creating new directories in /tmp that were referenced by the runit script but would fail because the old version was still running. Now it looks like the updates are done in the current /tmp directory instead, so it doesn't matter if the process is still running.
This update was done to the rackbox default attribute in chef: default["rackbox"]["default_config"]["passenger_runit"]["spawn_method"] = "smart"

Capistrano 3 sudo task

I want to write a recipe with Capistrano 3 executing a task on the remote server with sudo.
With Capistrano 2 this could be done for example:
default_run_options[:pty] = true
task :hello do
run "#{sudo} cp ~/something /something"
end
With Capistrano 3 I found:
set :pty, true
But I could not get to execute a task running with sudo.
How can I run a task with sudo?
The Capistrano 3 guide recommends the use of passwordless sudo. This allows your less-priveleged user execute the sudo command without having to enter a password via the PTY.
You can use the task that Kentaro wrote above, and add something like the following to your /etc/sudoers file:
deploy ALL=NOPASSWD:/bin/cp ~/something /something
http://www.capistranorb.com/documentation/getting-started/authentication-and-authorisation/#toc_8
I usually write like this:
task :hello do
on roles(:all) do |host|
execute :sudo, :cp, '~/something', '/something'
end
end
Edit
Capistrano 3 does not support sudo with password.
However, I created a small gem, which enables you to use sudo with password in Capistrano 3 task.
Add sshkit-sudo to your application's Gemfile:
# Gemfile
gem 'sshkit-sudo'
And require 'sshkit/sudo' in you Capfile:
# Capfile
require 'sshkit/sudo'
Now, you can execute a command with sudo as follows:
task :hello do
on roles(:all) do
sudo :cp, '~/something', '/something'
end
end
To resolve this issue I needed to add set :pty, true to my deploy.rb file.
I can now run the following:
# config valid only for Capistrano 3.1
lock '3.1.0'
set :application, 'APP_NAME'
set :pty, true
set :ssh_options, {:forward_agent => true}
namespace :deploy do
desc 'Restart NGINX'
task :restart do
on roles(:app), in: :sequence, wait: 1 do
execute :sudo, "./restart.sh"
end
end
end
This task basically runs a shell script called restart.sh that has a command within sudo service nginx restart.
you want "as user do end", like
as "root" do
execute :something
end
If you really need to use sudo you can always map the command like SSHKit.config.command_map[:rm] = 'sudo rm' which will make execute :rm into the proper rm command invoked with sudo. If your deploy user is in the sudoers things will work as expected.

Passenger standalone fails to start with capistano

I'm a bit of a newbie when it comes to deploying and related things, so please be lenient.
I'm building a staging server for a bunch of hobby projects, and to do that, I'll need to
Support multiple Ruby versions
Support multiple running rails/other applications
Support multiple databases and related software
I also want the deploy script to allow deploying to production, if the day ever comes.
This background necessitates the use of RVM, Capistrano-multistage and Passenger Standalone (the other option being Mongrel, but as I wish to use Passenger in production, I figured it'd be safer to use Passenger in staging too). All of this makes deployment a little hairy.
I've gotten things cobbled together quite nicely, and everything else seems to work, but for some reason Passenger fails to start when commanded to do so from Capistrano. If I SSH into the box and type the command in myself it works nicely. What's wrong?
To aid you in your efforts to help me, here is a copy of my config/deploy.rb
set :application, "Appname"
set :repository, "path-to-git-repo-over-ssh"
set :scm, :git
default_run_options[:pty] = true
set :rvm_ruby_string, ENV['GEM_HOME'].gsub(/.*\//,"")
set :rvm_install_ruby_params, '--1.9' # for jruby/rbx default to 1.9 mode
set :rvm_install_pkgs, %w[libyaml openssl] # package list from https://rvm.io/packages
set :rvm_install_ruby_params, '--with-opt-dir=/usr/local/rvm/usr' # package support
set :use_sudo, false
before 'deploy:setup', 'rvm:install_rvm' # install RVM
before 'deploy:setup', 'rvm:install_ruby' # install Ruby and create gemset
require "rvm/capistrano"
require "bundler/capistrano"
require 'sidekiq/capistrano'
set :deploy_via, :remote_cache
set :stages, %w(staging production)
set :default_stage, "staging"
require 'capistrano/ext/multistage'
set :rails_env, lambda { stage }
set :startcmd, lambda { "cd #{current_path} && bundle exec passenger start -d -p #{passenger_port} -e #{rails_env} --pid-file=#{current_path}/tmp/pids/passenger.#{passenger_port}.pid #{current_path}" }
namespace :deploy do
task :stop do
run("cd #{current_path} && bundle exec passenger stop -p #{passenger_port}")
end
task :restart do
run("cd #{current_path} && touch tmp/restart.txt")
end
task :start do
run("#{startcmd}")
end
end
after "deploy:update_code" do
run "(echo \"#reboot /bin/bash -l -c '#{startcmd}' >>log/boot.out 2>>log/boot.err # from capistrano \" && cat #{release_path}/crontab.#{stage}) | crontab -"
end
And here is config/deploy/staging.rb
set :deploy_to, "/var/www/appname"
set :user, 'app-specific-user'
set :password, 'super-secret-password'
set :domain, '1.2.3.4'
server domain, :app, :web
role :db, domain, :primary => true
set :passenger_port, 1234
Well bloody hell.
On complete hunch, I removed the
default_run_options[:pty] = true
Setting from the file, and like magic it started working. Now if only someone would tell me why.

Resources