Switching user in Fabric

fabric, python

Solution

First of all, you should use `sudo` when executing commands under another user. Second, `workon` sets environment variables for current shell. Since fabric invokes new shell for every command, you should run `workon rhino_env` in every command, where you need virtualenv (i.e. as prefix). With this edits yor code should look like this:

env.user = 'root'

@roles('web')
def deploy():
    dev_path = '/srv/web/prod'
    app_path = '/srv/web/prod/rhino'
    workon = 'workon rhino_env; '
    with settings(warn_only=True):
        run('kill -9 `cat /srv/web/run/rhino/rhino.pid`')
        puts('Stopped rhino...')
    with cd(app_path):
        sudo('git reset --hard HEAD', user='web')
        puts('Discarded all untracked and modified files')
        sudo('git checkout master', user='web')
        sudo('git pull origin master', user='web')
        users = run('users')
        puts('Output from `users` command: %s' % users)

        with prefix(workon):
            sudo('build_assets -m build', user='web')
    with cd(dev_path):
        run('chown -R web:ebalu rhino')

    with cd(app_path):
        sudo('./run', user='web')

    pid = run('cat /srv/web/run/rhino/rhino.pid')
    puts('Rhino started again with pid: %s.' % pid)

Problem

I have a problem when using Fabric to mimic my SSH workflow to deploy my web application. Here's my usual flow of commands when I SSH to a server: - SSH using root user. ssh root@1.2.3.4 - Switch to web user: su - web - Change directory: cd /srv/web/prod/abc_project - Start virtualenv: workon abc_env - Perform git pull: git pull origin master - Run a script: build_stuff -m build - Run another script: ./run I tried to write this as a deploy script in Fabric and I get a shell output when su - web is entered. I have to hit Ctrl-D to continue the script. I am also unable to activate my virtualenv....because: su - web successfully switches the user to `web` but because of the Ctrl-d (so that I can continue the Fabric script), it logs out of that user and back to root. Here's my script: ``` env.user = 'root' @roles('web') def deploy(): dev_path = '/srv/web/prod' app_path = '/srv/web/prod/rhino' workon = 'workon rhino_env' with prefix('su - web'): puts('Switched to `web` user') with settings(warn_only=True): run('kill -9 `cat /srv/web/run/rhino/rhino.pid`') puts('Stopped rhino...') with cd(app_path): run('git reset --hard HEAD') puts('Discarded all untracked and modified files') run('git checkout master') run('git pull origin master') users = run('users') puts('Output from `users` command: %s' % users) run(workon) run('build_assets -m build') run('cd %(dev_path)s; chown -R web:ebalu rhino' % {'dev_path': dev_path}) run('cd %(app_path)s; ./run' % {'app_path': app_path}) pid = run('cat /srv/web/run/rhino/rhino.pid') puts('Rhino started again with pid: %s.' % pid) ``` ...there's one more thing: No, I can't login as web initially, I have to login as root. It is the web user that has the virtualenv not the root user.

Original source