デプロイユーザーとしてファブリック経由でvirtualenvをアクティブ化


130

ローカルでファブリックスクリプトを実行し、サーバーにログインし、ユーザーをデプロイに切り替え、プロジェクトの.virtualenvをアクティブにします。これにより、dirがプロジェクトに変更され、git pullが発行されます。

def git_pull():
    sudo('su deploy')
    # here i need to switch to the virtualenv
    run('git pull')

私は通常、アクティブ化ファイルをソースするvirtualenvwrapperからworkonコマンドを使用します。postactivateファイルを使用すると、プロジェクトフォルダーに配置されます。この場合、ファブリックはシェル内から実行されるため、制御はファブリックに渡されるため、 '$ source〜/ .virtualenv / myvenv / bin / activate'に組み込みのbashのソースを使用できません。

誰かがこれをどのように行ったかの例と説明がありますか?


1
好奇心から、なぜあなたworkonprefix
ダニエルC.ソブラル2012年

回答:


96

今、あなたは私がすることをすることができます、それはkludgyですが完全にうまく機能します*(この使用法はあなたがvirtualenvwrapperを使用していることを前提としています-それはそうであるはずですが)あなたが言及したかなり長い「ソース」コールで簡単に置き換えることができます、ない場合):

def task():
    workon = 'workon myvenv && '
    run(workon + 'git pull')
    run(workon + 'do other stuff, etc')

バージョン1.0以降、Fabricにはこの手法を使用するprefixコンテキストマネージャがあり、たとえば次のことができます。

def task():
    with prefix('workon myvenv'):
        run('git pull')
        run('do other stuff, etc')

* 失敗した(実行されない)場合や、適切にエスケープされておらず、特殊なシェル文字が含まcommand1 && command2れている場合など、このアプローチを使用すると問題が発生する場合があります。command1command2command1


7
しかし、workonは不明shです。代わりにbashを使用するようにファブリックに指示するにはどうすればよいですか?
Pierre de LESPINAY 2013

18
私見あなたはちょうど使用する必要がありますsource venv/bin/activate。それはより簡単で、箱から出してすぐに動作します。workon追加の依存関係であり、インストールされている場合でも追加する必要があります.bashrc-ファブリックのデプロイには複雑すぎます。
Dave Halter 2013

@PierredeLESPINAY 問題の解決策については、stackoverflow.com / questions / 11272372 /…を参照してください。
デュークボディ2016年

137

bitprophetの予測の更新として:Fabric 1.0では、prefix()と独自のコンテキストマネージャーを利用できます。

from __future__ import with_statement
from fabric.api import *
from contextlib import contextmanager as _contextmanager

env.hosts = ['servername']
env.user = 'deploy'
env.keyfile = ['$HOME/.ssh/deploy_rsa']
env.directory = '/path/to/virtualenvs/project'
env.activate = 'source /path/to/virtualenvs/project/bin/activate'

@_contextmanager
def virtualenv():
    with cd(env.directory):
        with prefix(env.activate):
            yield

def deploy():
    with virtualenv():
        run('pip freeze')

@ simon、.bashrcを呼び出し、bashの-c引数内に接頭辞とコマンドの両方をラップする独自の接頭辞メソッドを記述することにより。以下
デイブ

5
しかし、sourceは不明shです。代わりにbashを使用するようにファブリックに指示するにはどうすればよいですか?
Pierre de LESPINAY 2013

2
@PierredeLESPINAYの.代わりに使用できますsource
katy lavallee 2013年

in cd()へのパスを完全に指定しているときに使用するのはなぜですか?activateprefix()
Nick T

@NickT prefix()そこにcdしていないようです- 同じことをするこれらのドキュメント参照してください。他のコマンド(この例では)を実行するcdときに、それらのコマンドがそのディレクトリに対して相対的になるようにしたいと考えています。yieldpip freeze
nh2 2013

18

run()の代わりに呼び出すことができる単純なラッパー関数virtualenv()を使用しています。cdコンテキストマネージャーを使用しないため、相対パスを使用できます。

def virtualenv(command):
    """
    Run a command in the virtualenv. This prefixes the command with the source
    command.
    Usage:
        virtualenv('pip install django')
    """
    source = 'source %(project_directory)s/bin/activate && ' % env
    run(source + command)

9

virtualenvwrapper これを少し簡単にすることができます

  1. NH2のアプローチ@使用(使用している場合、このアプローチにも動作しますlocalが、唯一のvirtualenvwrapperインストールのためworkonにある$PATH他の言葉で、 - Windowsの場合)

    from contextlib import contextmanager
    from fabric.api import prefix
    
    @contextmanager
    def virtualenv():
        with prefix("workon env1"):
            yield
    
    def deploy():
        with virtualenv():
            run("pip freeze > requirements.txt")
  2. または、fabファイルをデプロイしてローカルで実行します。この設定により、ローカルまたはリモートコマンドのvirtualenvをアクティブ化できます。この方法は、localを使用して.bashrcを実行できないことを回避するため、強力ですbash -l

    @contextmanager
    def local_prefix(shell, prefix):
        def local_call(command):
            return local("%(sh)s \"%(pre)s && %(cmd)s\"" % 
                {"sh": shell, "pre": prefix, "cmd": command})
        yield local_prefix
    
    def write_requirements(shell="/bin/bash -lic", env="env1"):
        with local_prefix(shell, "workon %s" % env) as local:
            local("pip freeze > requirements.txt")
    
    write_requirements()  # locally
    run("fab write_requirements")

nh2の答えを要約してくれてありがとう、virtualenv contextmanager宣言はPython 2.6以降では5行で行うことができますが、「workon」エイリアスが常に正しくインポートされることが保証されることはなく、「source ... / activate」を使用する方がはるかに信頼性が高くなります。コマンド
Alex Volkov

8

これは、virtualenvローカル展開で使用する私のアプローチです。

実行できるファブリックのpath()コンテキストマネージャを使用するpippython、virtualenvのバイナリを使用します。

from fabric.api import lcd, local, path

project_dir = '/www/my_project/sms/'
env_bin_dir = project_dir + '../env/bin/'

def deploy():
    with lcd(project_dir):
        local('git pull origin')
        local('git checkout -f')
        with path(env_bin_dir, behavior='prepend'):
            local('pip freeze')
            local('pip install -r requirements/staging.txt')
            local('./manage.py migrate') # Django related

            # Note: previous line is the same as:
            local('python manage.py migrate')

            # Using next line, you can make sure that python 
            # from virtualenv directory is used:
            local('which python')

私はこれがとても好きです-このアプローチに明らかな欠点はなく、とてもクリーンです。ありがとう:)
サイモン

まだここで最善かつ最も
明確

4

投稿されたすべての回答に感謝します。これにもう1つの選択肢を追加したいと思います。同じコードとして機能を提供できるモジュール、fabric-virtualenvがあります:

>>> from fabvenv import virtualenv
>>> with virtualenv('/home/me/venv/'):
...     run('python foo')

fabric-virtualenvはを利用しますfabric.context_managers.prefix。これは良い方法かもしれません:)


興味深いですが、SCM /課題追跡へのリンクがないという事実は好きではありません。ソースコードと課題追跡へのリンクなしでPYPIでのみ公開されているパッケージは、それほど信頼されていませんが、簡単に修正できます。
ソリン

2

パッケージを環境にインストールする場合、または環境内のパッケージに従ってコマンドを実行する場合、ファブリックの複雑な方法を記述したり、新しいOSパッケージをインストールしたりする代わりに、このハックが問題を解決することがわかりました。

/path/to/virtualenv/bin/python manage.py migrate/runserver/makemigrations  # for running commands under virtualenv

local("/home/user/env/bin/python manage.py migrate")    # fabric command


/path/to/virtualenv/bin/pip install -r requirements.txt   # installing/upgrading virtualenv

local("/home/user/env/bin/pip install -r requirements.txt")  #  fabric command

この方法では、環境をアクティブにする必要はないかもしれませんが、環境下でコマンドを実行できます。


1

以下は、run / sudo呼び出しに仮想環境を使用するデコレータのコードです。

# This is the bash code to update the $PATH as activate does
UPDATE_PYTHON_PATH = r'PATH="{}:$PATH"'.format(VIRTUAL_ENV_BIN_DIR)

def with_venv(func, *args, **kwargs):
  "Use Virtual Environment for the command"

  def wrapped(*args, **kwargs):
    with prefix(UPDATE_PYTHON_PATH):
      return func(*args, **kwargs)

  wrapped.__name__ = func.__name__
  wrapped.__doc__ = func.__doc__
  return wrapped

デコレータを使用するには、デコレータの順序が重要であることに注意してください。

@task
@with_venv
def which_python():
  "Gets which python is being used"
  run("which python")

1

このアプローチは私にとってうまくいきました、あなたもこれを適用することができます。

from fabric.api import run 
# ... other code...
def install_pip_requirements():
    run("/bin/bash -l -c 'source venv/bin/activate' "
        "&& pip install -r requirements.txt "
        "&& /bin/bash -l -c 'deactivate'")

venvあなたの仮想環境ディレクトリを想定し、適切な場所にこのメソッドを追加します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.