Creating a symlink with sudo in Capistrano 3.x - ruby-on-rails

I am deploying my Rails app with Capistrano 3. I've struggled all the way through, but now when everything is almost done I cannot create a symlink through a Capistrano task.
With Capistrano 2.x I could easily do it with the following line:
sudo "ln -nfs #{current_path}/config/nginx.conf /etc/nginx/sites-enabled/#{application}"
Now Capistrano 3 has advocated passwordless sudo approach as described here.
I've added the following line to sudoers
deployer ALL=NOPASSWD:/etc/init.d/sites-enabled/application-name
and changed my command in Capistrano task to:
execute :sudo, :ln, "-nfs", "#{current_path}/nginx.conf /etc/nginx/sites-enabled/#{fetch(:application)}"
What am I missing? Is the line I added to sudoers correct?
Thank you!

Alex, when you edit sudoers, you should list commands you would like to execute (not the files you'd like to symlink).
Thus, the line in sudoers should be as follows:
deployer ALL=NOPASSWD:/bin/ln -nfs /current/path/config/nginx.conf /etc/nginx/sites-enabled/application-name
You can also make it more general:
deployer ALL=NOPASSWD:/bin/ln -nfs /current/path/* /etc/nginx/sites-enabled/*
but it will be less secure.

Related

Capistrano 3 recipe for dynamic_sitemaps

I'm trying to "translate" the Capistrano recipe to deploy dynamic_sitemaps to work with Capistrano 3.
The snippet suggested in the readme looks like this:
after "deploy:update_code", "sitemaps:create_symlink"
namespace :sitemaps do
task :create_symlink, roles: :app do
run "mkdir -p #{shared_path}/sitemaps"
run "rm -rf #{release_path}/public/sitemaps"
run "ln -s #{shared_path}/sitemaps #{release_path}/public/sitemaps"
end
end
But this doesn't work with Capistrano 3. I pasted this code into config/deploy.rb and the first error I got was: Don't know how to build task 'sitemaps:create_symlink'`.
I read somewhere that in Capistrano 3 the namespaces have to be defined before the calls so I reversed the order of the blocks, defining the namespace first and having the after call last. I got NoMethodError: undefined method `map' for :roles:Symbol`.
So I rewrote the namespace block to:
namespace :sitemaps do
task :create_symlink do
on roles(:web) do
run "mkdir -p #{shared_path}/sitemaps"
run "rm -rf #{release_path}/public/sitemaps"
run "ln -s #{shared_path}/sitemaps #{release_path}/public/sitemaps"
end
end
end
And now I'm getting Don't know how to build task 'deploy:update_code' and I'm at loss.
While I couldn't solve precisely the issue I posted above, the solution is actually very simple. If using Capistrano 3 just add public/sitemaps to your :linked_dirs setting as such:
set :linked_dirs, %w{bin log tmp vendor/bundle public/system public/sitemaps}
This will create a symbolic link between #{release_path}/public/sitemaps and #{shared_path}/public/sitemap creating the latter if needed.

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 ;)

Capistrano and Carrierwave

I'm deploying a Ruby on Rails and NodeJS application using Capistrano. The uploads folder gets removed on every deploy.
This popped up on several places but it doesn't seem to work:
# Keep File Uploads
task :symlink_uploads do
run "ln -nfs #{shared_path}/rails/uploads #{release_path}/rails/public/uploads"
end
after 'deploy:update_code', 'deploy:symlink_uploads'
the repo:
repo:
/node
/rails
Thanks!
There is another solution to this problem. You can add your uploads dir to Capistrano's shared_children and it will do all the magic automatically. You can find more details in this answer: https://stackoverflow.com/a/9710542/835935
Make sure you remove the existing public/uploads folder, passing -f to ln doesn't cover removing target directories (or at least hasn't done so portably for me)
My symlink directories tasks normally look like
task :symlink_uploads do
run "rm -rf #{release_path}/rails/public/uploads} && ln -nfs #{shared_path}/rails/uploads #{release_path}/rails/public/uploads"
end
Obviously make sure there is nothing in the checked in version of public/uploads that you need!
Did you try
after 'deploy:update_code', ':symlink_uploads'
Your :symlink_uploads task is not in a namespace, so rather do the above or put it in a namespace
namespace :deploy do
task :symlink_uploads do
# ...
end
end
I have similar problem with uploaded file with my RoR app. This is my capistrano tasks:
...
task :link_public_folder, :roles => [:app, :web] do
run "mv -u #{release_path}/public/* #{shared_path}/public"
run "rm -rf #{release_path}/public"
run "ln -s #{shared_path}/public #{release_path}/public"
end
after "deploy:update", "deploy:link_public_folder"
task :setup_config, :roles => :app do
sudo "ln -nfs #{current_path}/config/apache.conf /etc/apache2/sites-available/#{application}"
run "mkdir -p #{shared_path}/config"
run "mkdir -p #{shared_path}/public"
put File.read("config/database.yml"), "#{shared_path}/config/database.yml"
puts "Now edit the config files in #{shared_path}."
end
after "deploy:setup", "deploy:setup_config"
...
Maybe help you
Edit:
I use Carrierwave too.

rake db:migrate RAILS_ENV=development

Why we get an error on the command rake db:migrate
Rails Error: Unable to access log file. Please ensure that /home/mahaloo/mahaloo/releases/20120329200051/log/development.log exists and is chmod 0666. The log level has been raised to WARN and the output directed to STDERR until the problem is fixed.
rake aborted!
unable to open database file
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
Whats wrong there. I tryed to deploy via capistrano, i used this tutorial to setup capistrano http://teachmetocode.com/screencasts/basic-deployment-with-capistrano/
You're either missing the log directory or file. Have you run cap deploy:setup ?
Otherwise manually create the log file first.
This is likely because you're following the practice of not checking your database.yml into source control. If that is the case, you can make a copy of your database.yml in your deploy shared/config folder, and create a Capistrano task to symlink that back into your release folder. Something like this (in namespace deploy)
task :create_symlinks do
run "ln -nfs #{shared_path}/db/production.sqlite3 #{release_path}/db/production.sqlite3"
run " -nfs #{shared_path}/config/ldap.yml #{release_path}/config/ldap.yml"
run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
end
Then call this in a hook
after "deploy:finalize_update", "deploy:create_symlinks"
after "deploy:finalize_update", "deploy:migrate"
I think that would work, that's how we're step up on our project. This is similar to these questions:
database.yml deployment best practice
Capistrano - can't deploy my database.yml
How to manage Rails database.yml
Have you try with sudo if your enviroment its on linux, for example, i got that error trying to run the migration, rake db:migrate, so i used sudo rake db:migrate and that's work, maybe because the rake when its trying to consult development.log doesn't have the right permissions or something like that.

Prevent whenenver gem from running --clear-crontab before gems installed

I am using capistrano, and the whenever gem, on a fresh deploy to a server without the whenever gem installed, capistrano attempts to run
whenever --clear-crontab
BEFORE the rake gems:install command has been run, its clear (from this) that this command runs after deploy_code but so does my command that installs the gems (below)..
after "deploy:update_code", "deploy:symlink_config"
deploy.task :symlink_config, :roles => :app do
# create a symlink to the database.yml file located in the shared_path
run "ln -nsf #{shared_path}/config/database.yml #{current_release}/config"
# install any missing gems
run "cd #{current_release} && sudo rake gems:install --trace RAILS_ENV=#{rails_env}"
# migrate the database
run "cd #{current_release} && rake db:migrate --trace RAILS_ENV=#{rails_env}"
end
Is there a way to order these tasks, because on a cold deploy I always get whenever: not found and have to manually install the whenever gem on the remote server
What I ended up doing is removing the require "whenever/capistrano" from the config\deploy.rb to avoid the "automatic" deploy. Instead I have added a task that executes the --clear-crontab and --update-crontab. This works as it will execute in the sequence I set it to.
I have based it off this post, which deals with a slightly different problem but has the same solution - not to use the "automatic" integration with capistrano.

Resources