Switching users during a capistrano deploy
We have a complicated deployment on my current project which includes running several commands as a different user from the main deployment user. Normally, this wouldn’t be a problem since the sudo method provides an option called ‘as’:
task :run_command_as_another_user do
sudo "whoami", :as => "another_user"
end
Unfortunately, we do not have sudo access to our servers. Instead of using sudo, we wrote a new method called with_user which will execute a block as a different user:
task :try_another_user do
with_user("another_user", "another_password") do
run "whoami"
end
end
The with_user method will set the user and password back to the original values once the block is complete. For example:
task :whoami do
set :user, 'original'
set :password, 'original'
run 'whoami'
with_user("someone_else", 'password') do
run "whoami"
end
run 'whoami'
end
The output of the previous task (stripped down) is:
** [out :: 127.0.0.1] original
** [out :: 127.0.0.1] someone_else
** [out :: 127.0.0.1] original
The implementation of with_user is:
def with_user(new_user, new_pass, &block)
old_user, old_pass = user, password
set :user, new_user
set :password, new_pass
close_sessions
yield
set :user, old_user
set :password, old_pass
close_sessions
end
def close_sessions
sessions.values.each { |session| session.close }
sessions.clear
end
It saves the old user and password and then sets the new values. Then, it disconnects from all of the servers, which forces a reconnect on the next command with the new user and password. When the block is complete, it resets the user and password and disconnects again.
The repeated reconnecting is not the most efficient solution, but it is simple and works for us.