How can I switch user in a Capistrano task? - capistrano

I made a small test task below:
set :user, "user"
set :password, "password"
set :root_password, "root password"
set :use_sudo, false
role :srv, "exmaple.com"
task :show_info do
run "iptables -L", :shell => "su -" do |channel, stream, data|
channel.send_data("#{root_password}\n")
end
end
This server doesn't allow me to use sudo, so I have to login as a normal user then become root.
I have also tried to create surun from this article, though it doesn't help me... :(
Could someone please tell me the promising method to run command after switching to root in Capistrano?
Thanks in advance.
P.S. Added the output log:
$ cap show_info
* executing `show_info'
* executing "iptables -L"
servers: ["example.com"]
[example.com] executing command
command finished in 000ms
failed: "su - -c 'iptables -L'" on example.com

The point is default_run_options[:pty] = true
try this
def surun(command)
default_run_options[:pty] = true
password = fetch(:root_password, Capistrano::CLI.password_prompt("root password: "))
run("su - -c #{command}") do |channel, stream, output|
channel.send_data("#{password}\n")
end
end

Related

chef. how can I reliably test for, and store the result of, a postgres database existence check?

For each of the following 3 databases I want to check if the database exists.
"psql -d #{dbname} -c 'SELECT 1 as check_;'" on its own, works as expected and returns 0 if it exists and 2 if it doesn't.
But getting chef to do something with that test is difficult.
I can't use guard not_if because I really need to control a number of steps from that existence:
load the database
create user
grant user
etc...
So what I was really planning to do was to do a next and iterate to the next database in the loop if it existed, via next.
%w{ hcm91dmo ksysdb pgfin92}.each do |dbname|
begin
execute "check_exist_db" do
command "psql -d #{dbname} -c 'SELECT 1 as check_;'"
user "postgres"
ignore_failure true
dbexist2 = true
end
dbexist1 = true
Chef::Log.info("jlp:execute OK")
rescue
Chef::Log.info("jlp:execute rescue")
dbexist1 = false
dbexist2 = false
end
The rescue doesn't seem to matter much. And I still get errors despite the ignore_failure:
==> default: STDERR: psql: FATAL: database "pgfin92" does not exist
==> default: ---- End output of psql -d pgfin92 -c 'SELECT 1 as check_;' ----
==> default: Ran psql -d pgfin92 -c 'SELECT 1 as check_;' returned 2; ignore_failure is set, continuing
==> default:
==> default: ================================================================================
==> default: Error executing action `run` on resource 'execute[check_exist_db]'
==> default: ================================================================================
==> default:
==> default: Mixlib::ShellOut::ShellCommandFailed
==> default: ------------------------------------
==> default: Expected process to exit with [0], but received '2'
==> default: ---- Begin output of psql -d pgfin92 -c 'SELECT 1 as check_;' ----
==> default: STDOUT:
==> default: STDERR: psql: FATAL: database "pgfin92" does not exist
==> default: ---- End output of psql -d pgfin92 -c 'SELECT 1 as check_;' ----
==> default: Ran psql -d pgfin92 -c 'SELECT 1 as check_;' returned 2
For those who are curious, I am using Chef to gradually tweak a server to its desired state. A lot of time the code and configuration changes a bit, but without the databases needing any updates. In fact, since the databases get updated by user input, I want user changes to persist through Chef runs. So I don't want to drop and reload the databases without a good reason.
Solution, adapted from #coderanger 's answer:
#chef load: save list of databases that don't exist
dbtodo = []
%w{ hcm91dmo ksysdb pgfin92}.each do |dbname|
#note that you need to specify a user that works for postgres
if (shell_out("psql", "-d", dbname, "-c", "SELECT 1 as check_;",:user => "postgres").error?)
dbtodo.push(dbname)
end
end
#now, just loop thru databases that didn't exist
#I know I need to perform all the actions on each one of these.
dbtodo.each do |dbname|
#execute phase, no conditional needed because we're running off
#saved database list
postgresql_database dbname do
connection postgresql_connection_info
action :create
end
...
end
execute is a resource, which doesn't really help when you want to get some kind of result from running the command. What you want is to use the shell_out helper method:
shell_out("psql", "-d", dbname, "-c", "SELECT 1 as check_;").error?
or something similar to that. Unlike a resource which has the usual two-pass loading and execution process, shell_out (and shell_out!) are imperative Ruby code so when that line runs, it runs the command and gets you the result right then. Check out https://coderanger.net/two-pass/ for more info on the loading model and why your example doesn't work.

How can I solve Permission denied on deploying app?

I have setup an app to deploy to my site that is hosted on Digital Ocean CentOS 6 server and I am using Capistrano to deploy the app from my development machine. I have got a repo setup that I push to and that my Capistrano config references when I do cap development deploy.
The issue I am having is that it throws this error:
[a7406f5e] Command: ( GIT_ASKPASS=/bin/echo GIT_SSH=/tmp/PopupHub/git-ssh.sh /usr/bin/env git ls-remote git#repo-url-is-here/popup-hub.git )
DEBUG [a7406f5e] Permission denied (publickey).
DEBUG [a7406f5e] fatal: The remote end hung up unexpectedly
In capfile I have got this:
# 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
#
# require 'capistrano/rvm'
# require 'capistrano/rbenv'
# require 'capistrano/chruby'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano/sitemap_generator'
# Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }
In my config/deploy.rb I have:
lock '3.1.0'
server "0.0.0.0.0"
set :application, "NameOfApp"
set :scm, "git"
set :repo_url, "git#the-repo-url-is-here/popup-hub.git"
# set :scm_passphrase, ""
# set :user, "deploy"
# files we want symlinking to specific entries in shared.
set :linked_files, %w{config/database.yml}
# dirs we want symlinking to shared
set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
SSHKit.config.command_map[:rake] = "bundle exec rake" #8
SSHKit.config.command_map[:rails] = "bundle exec rails"
set :branch, ENV["REVISION"] || ENV["BRANCH_NAME"] || "master"
set :keep_releases, 20
namespace :deploy do
desc 'Restart passenger without service interruption (keep requests in a queue while restarting)'
task :restart do
on roles(:app) do
execute :touch, release_path.join('tmp/restart.txt')
unless execute :curl, '-s -k --location localhost | grep "Pop" > /dev/null'
exit 1
end
end
end
after :finishing, "deploy:cleanup"
after :finishing, "deploy:sitemap:refresh"
end
after "deploy", "deploy:migrate"
after 'deploy:publishing', 'deploy:restart'
# deploy:sitemap:create #Create sitemaps without pinging search engines
# deploy:sitemap:refresh #Create sitemaps and ping search engines
# deploy:sitemap:clean #Clean up sitemaps in the sitemap path
# start new deploy.rb stuff for the beanstalk repo
Then in my config/development.rb I have got:
set :stage, :development
set :ssh_options, {
forward_agent: true,
password: 'thepassword',
user: 'deployer',
}
server "0.0.0.0", user: "deployer", roles: %w{web app db}
set :deploy_to, "/home/deployer/development"
set :rails_env, 'development' # If the environment differs from the stage name
set :branch, ENV["REVISION"] || ENV["BRANCH_NAME"] || "master"
When I push in bash cap development deploy the error further up happens.
Can anyone tell me why this is happening? I have carried out everything fine up to now and I have this setup on another Digital Ocean droplet.
Thanks,
I think you have not ssh access to your remote server using you local system's ssh keys.
If you don't have ssh keys on local system, generate:
ssh-keygen -t rsa
Upload your local keys to remote server:
cat ~/.ssh/id_rsa.pub | ssh user#hostname 'cat >> .ssh/authorized_keys'
Source: HowToGeek.com
You need to set up your SSH key in Digital Ocean

how to run a script on rails server using capistrano?

I have written a script named mailman_server using gem "mailman" placed in 'script/mailman_server'
#!/usr/bin/env ruby
require "rubygems"
require "bundler/setup"
require "mailman"
#Mailman.config.logger = Logger.new("log/mailman.log")
Mailman.config.poll_interval = 3
Mailman.config.pop3 = {
server: 'server', port: 110,
username: "loginid",
password: "password"
}
Mailman::Application.run do
default do
p "Found a new message"
# 'perform some action here'
end
end
It fetches all the emails from my account and then i do processing on them.
I have my deploy.rb file as
set :stages, %w(production) #various environments
load "deploy/assets" #precompile all the css, js and images... before deployment..
require "bundler/capistrano" # install all the new missing plugins...
require 'delayed/recipes' # load this for delayed job..
require 'capistrano/ext/multistage' # deploy on all the servers..
require "rvm/capistrano" # if you are using rvm on your server..
require './config/boot'
require 'airbrake/capistrano' # using airbrake in your application for crash notifications..
set :delayed_job_args, "-n 2" # number of delayed job workers
before "deploy:assets:symlink", "deploy:copy_database_file"
before "deploy:update_code", "delayed_job:stop" # stop the previous deployed job workers...
after "deploy:start", "delayed_job:start" #start the delayed job
after "deploy:restart", "delayed_job:restart" # restart it..
after "deploy:update", "deploy:cleanup" #clean up temp files etc.
set :rvm_ruby_string, '1.9.3' # ruby version you are using...
set :rvm_type, :user
server "my_server_ip", :app, :web, :db, :primary => true
set(:application) { "my_application_name" }
set (:deploy_to) { "/home/user/#{application}/#{stage}" }
set :user, 'user'
set :keep_releases, 3
set :repository, "git#bitbucket.org:my_random_git_repo_url"
set :use_sudo, false
set :scm, :git
default_run_options[:pty] = true
ssh_options[:forward_agent] = true
set :deploy_via, :remote_cache
set :git_shallow_clone, 1
set :git_enable_submodules, 1
namespace :deploy do
task :start do ; end
task :stop do ; end
task :restart, :roles => :app, :except => { :no_release => true } do
run "#{try_sudo} touch #{File.join(current_path,'tmp','restart.txt')}"
end
task :copy_database_file do
run "ln -sf #{shared_path}/database.yml #{release_path}/config/database.yml"
end
end
I want to execute this script every time I deploy to the server. Also I need to stop this script whenever I am deploying the code.
I am unable to figure out how can we start or stop this script using capistrano on server.
You could try to save pid of process on start with something like this
run "cd #{deploy_to}/current; ./script/mailman_server &; echo &! > /var/run/mailman_server.pid" #untested
and stop it with
run "kill `cat /var/run/mailman_server.pid`; rm /var/run/mailman_server.pid"
But I think you should check out Foreman, it provides handy way to run jobs in development and supports exporting your jobs to upstart or inid.d scripts for production, so you will need just to start or stop corresponding service with
run "sudo /etc/init.d/mailman_server start"
run "sudo /etc/init.d/mailman_server stop"

Capifony & Symfony 2 error: php bin/vendors install --reinstall

I have a big problem.
I had a configuration which worked properly till today.
I don't know why I have now this error
*** [err :: server.com] Could not open input file: bin/vendors
command finished in 312ms
*** [deploy:update_code] rolling back
* executing "rm -rf /home/server/deploy/releases/20120301143822; true"
servers: ["server.com"]
[server.com] executing command
command finished in 208ms
failed: "sh -c 'cd /home/server/deploy/releases/20120301143822 && php bin/vendors install --reinstall'" on server.com
I precise that I deploy my local work to production
here is my deploy file
set :application, "MyApp"
set :deploy_to, "/home/server/deploy"
set :serverName, "myServer.com" # The server's hostname
set :domain, "server.com"
set :scm, :git
set :repository, "file:///Applications/MAMP/htdocs/localWorkDev"
set :deploy_via, :rsync_with_remote_cache
role :web, domain
role :app, domain
role :db, domain, :primary => true
set :use_sudo, false
set :keep_releases, 3
set :user, "root"
set :shared_files, ["app/config/parameters.ini"]
set :shared_children, [app_path + "/logs", web_path + "/uploads", "vendor"]
set :update_vendors, true
Please help me
Thanks
Sam
ALL is right now. I have just done a
php bin/vendors install --reinstall
and now it works.
In my case, it was very important to add --reinstall command.
Hope it would be usefull
Sam

Capistrano remote authentication problem

I'm trying to deploy to a slicehost slice using this config/deploy/production.rb file. I'm clueless & haven't used capistrano before now. Here are the steps I followed. Sorry but I'm completely new to capistrano. It keeps asking for my password (have set up passwordless SSH), and throwing this error:
(SocketError: getaddrinfo: Name or service not known)
connection failed for: ---------.com (Net::SSH::AuthenticationFailed: -----)
First, it's a 'bort' app http://github.com/fudgestudios/bort/tree/master
Second, I used the ubuntu-machine gem, detailed here:
http://suitmymind.github.com/ubuntu-machine/#screencast
config/deploy/production.rb
#############################################################
# Application
#############################################################
set :application, "---------------"
set :deploy_to, "/var/www/#{application}"
#############################################################
# Settings
#############################################################
default_run_options[:pty] = true
ssh_options[:forward_agent] = true
set :use_sudo, true
set :scm_verbose, true
set :rails_env, "production"
#############################################################
# Servers
#############################################################
set :user, "----------"
set :domain, "--------------------------"
server domain, :app, :web
role :db, domain, :primary => true
#############################################################
# Git
#############################################################
set :scm, :git
set :branch, "master"
set :scm_user, '---------'
set :scm_passphrase, "----------"
set :repository, "git#github.com:--------/----------.git"
set :deploy_via, :remote_cache
#############################################################
# Passenger
#############################################################
namespace :deploy do
desc "Create the database yaml file"
task :after_update_code do
db_config = <<-EOF
production:
adapter: mysql
encoding: utf8
username: root
password: ------------
database: ------------_production
host: localhost
EOF
put db_config, "#{release_path}/config/database.yml"
#########################################################
# Uncomment the following to symlink an uploads directory.
# Just change the paths to whatever you need.
#########################################################
desc "Symlink the assets directories"
task :before_symlink do
run "mkdir -p #{shared_path}/assets"
run "ln -nfs #{shared_path}/assets #{release_path}/public/assets"
end
end
# Restart passenger on deploy
desc "Restarting mod_rails with restart.txt"
task :restart, :roles => :app, :except => { :no_release => true } do
run "touch #{current_path}/tmp/restart.txt"
end
[:start, :stop].each do |t|
desc "#{t} task is a no-op with mod_rails"
task t, :roles => :app do ; end
end
end
I think the problem would be either
It can't resolve your hostname
You typo wrong domain value
Just in case, have you tried to set the domain value to be your server's IP address instead?
"SocketError: getaddrinfo: Name or service not known" implies some sort of problem resolving or connecting to the remote host. Have you checked that you can connect manually?
One way to start debugging cap scripts is to perform each step of the process yourself. You can copy the statements directly from the verbose cap output. That should help isolate the problem, in this case, where the connection problem is (slicehost?, github?, both?).