0

I'm using Capistrano 2(.15.4) to deploy rails applications (i know, trying to get to 3 but not quite there yet). We have a new server environment being set up, with IT preferring access through our own user and sudo'ing to the user to deploy as.

I've been testing using:

set :use_sudo, true
set :sudo, "sudo -u <user>"

It looks to me like sudo is working for manually-defined tasks that use the sudo command:

cap deploy:restart

...
triggering load callbacks
  * 2014-09-01 11:34:28 executing `deploy:restart'
  * executing "sudo -u <user> touch /path/to/deploy/current/tmp/restart.txt"
servers: ["hostname.com"]
...

Note that the deploy:restart functionality is manually defined as:

cmd = "touch #{current_path}/tmp/restart.txt"
sudo cmd

but it does NOT look like sudo kicks in for the automatic update_code task when deploying:

cap deploy

...
triggering load callbacks
  * 2014-09-01 10:14:32 executing `deploy'
  * 2014-09-01 10:14:32 executing `deploy:update'
 ** transaction: start
  * 2014-09-01 10:14:32 executing `deploy:update_code'
    updating the cached checkout on all servers
...
copying the cached version to /path/to/deploy/20140901171450
  * executing "cp -RPp /path/to/deploy/shared/cached-copy /path/to/deploy/releases/20140901171450 && (echo 690 > /path/to/deploy/releases/20140901171450/REVISION)"
servers: ["hostname.com"]
[hostname.com] executing command
 ** [out :: hostname] cp: cannot create directory `/path/to/deploy/releases/20140901171450': Permission denied
command finished in 918ms
*** [deploy:update_code] rolling back
  * executing "rm -rf /path/to/deploy/releases/20140901171450; true"
servers: ["hostname.com"]
[hostname.com] executing command
command finished in 922ms
...

Any guidance on why sudo isn't applied to the update_code task would be much appreciated, thanks!

ilasno
  • 236
  • 1
  • 3
  • 16

2 Answers2

1

try defining your sudo remote commands as recommended in the latest 2.x documentation or exactly 2.14.5 version

pay attention especially to the part which describes the syntax of invoking sudo as another user:
#{sudo :as => 'bob'} + invoking the run instead of cmd

Dig deeper in ruby sources to understand how sudo is invoked: https://github.com/capistrano/capistrano/blob/legacy-v2/lib/capistrano/shell.rb

A blunt copy paste from the documentation follows:

Definition

sudo(options={}) sudo(command, options={}, &block)

Module

Capistrano::Configuration::Actions::Invocation
The sudo action is used to execute commands via [http://en.wikipedia.org/wiki/Sudo sudo]. It can be used in either of two ways (although one is deprecated). Although you could use sudo directly in your run() invocations, this helper makes it possible for Capistrano to prompt you for the sudo password when the remote server(s) prompt for it.

sudo(options={})

This use of sudo does not actually execute anything. Instead, it returns a string containing the sudo command to execute. This lets you embed it in commands invoked via run, which in turn lets you build arbitrarily complex commands that use sudo.

run "#{sudo} apachectl restart" run "#{sudo :as => 'bob'} crontab -l" run "cd /u/apps/social && #{sudo} script/restart" run "if [ ! -d /u/apps ]; then #{sudo} mkdir -p /u/apps; fi" Arguments

Options

:as

Specify the user to sudo as. This defaults to nil, which is typically the same as specifying "root" as the user.

Variables

:sudo

Specify the path to sudo on the servers. This defaults to just "sudo", but if sudo on your servers is either in a non-standard location or is named something other than "sudo", you can set this variable accordingly.

:sudo_password

Specify the password ''prompt'' (not the password itself!) that sudo should use when asking for a password. You shouldn't ever need to change this (the default is "sudo password: "), since this is only needed so that Capistrano can recognize the sudo prompt and pass the prompt on to the user. Setting the value of this variable to the empty string will cause Capistrano to not request any specific password prompt.

sudo(command, options={}, &block)

This use of sudo is deprecated and is included only for backwards compatibility with some Capistrano recipes. It is essentially identical to run(), except that it will prefix the command with sudo (see the first use of the sudo()).

sudo "apachectl restart" sudo "crontab -l", :as => "bob"

Note that this syntax does not allow complicated shell script commands, or chaining commands together in a single invocation. See the first syntax for that.

Costin Gușă
  • 293
  • 2
  • 13
  • I really appreciate your time and answer, but i don't think that it really addresses my question. As the first part of the question says, using sudo functionality looks like it's working ok for *manually-defined* tasks/commands. My hope/assumption was that, if sudo is configured (with :use_sudo=true), that this would carry through to the automatic/default tasks like *update_code*. But what it's looking like is that i'll need to manually override those, specifying the commands myself to use sudo..? – ilasno Sep 09 '14 at 17:36
  • as far as I understand from the docs, the ":as" sudo option is the recommended way to run sudo as a different user. can you try that way? – Costin Gușă Sep 09 '14 at 18:09
  • I appreciate your time and effort, so i'm awarding you the bounty. I don't think that you really answer my question, though, so i'm not marking it correct. – ilasno Sep 11 '14 at 00:28
  • thanks for the bounty :). what I am wondering is that _maybe_ there is some bug in your capistrano version that somehow messes the invocation of sudo in the way it is used (manually vs automatic). that's why I was suggesting to try using it with the :as option instead – Costin Gușă Sep 16 '14 at 22:45
1

Capistrano is not implemented to support the use case you describe. You can try setting the git variable to include sudo (set :git, 'sudo git'), however you will then likely run into the issue of your forwarded authentication key not being available to the sudo'ed git command.

Perhaps a more fruitful strategy involves adding your user to the group of the owner of the folder that cap is trying to check out into, and then setting the group writable permission on that folder.

shulmang
  • 126
  • 2