Aktivieren Sie eine virtuelle Umgebung über Fabric als Bereitstellungsbenutzer

130

Ich möchte mein Fabric-Skript lokal ausführen, das sich wiederum bei meinem Server anmeldet, den Benutzer zum Bereitstellen wechselt, die Projekte .virtualenv aktiviert, wodurch das Verzeichnis zum Projekt geändert und ein Git-Pull ausgegeben wird.

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

Normalerweise verwende ich den Befehl workon von virtualenvwrapper, der die Aktivierungsdatei als Quelle verwendet, und die Postaktivierungsdatei legt mich im Projektordner ab. In diesem Fall scheint es so zu sein, dass die Kontrolle dem Fabric übertragen wird, da Fabric von der Shell aus ausgeführt wird. Daher kann ich die in '$ source ~ / .virtualenv / myvenv / bin / enabled' integrierte Bash-Quelle nicht verwenden.

Hat jemand ein Beispiel und eine Erklärung, wie sie das gemacht haben?

Thomas Schreiber
quelle
1
Warum benutzt du aus Neugier nicht workonals prefix?
Daniel C. Sobral

Antworten:

96

Im Moment können Sie das tun, was ich tue, was klobig ist, aber einwandfrei funktioniert * (diese Verwendung setzt voraus, dass Sie virtualenvwrapper verwenden - was Sie auch sein sollten -, aber Sie können den von Ihnen erwähnten längeren Quellruf einfach ersetzen , wenn nicht):

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

Seit Version 1.0 verfügt Fabric über einen prefixKontextmanager, der diese Technik verwendet, sodass Sie beispielsweise Folgendes tun können:

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

* Es kann Fälle geben, in denen die Verwendung des command1 && command2Ansatzes Sie in die Luft jagt, z. B. wenn ein command1Fehler auftritt ( command2niemals ausgeführt wird) oder wenn er command1nicht ordnungsgemäß maskiert wird und spezielle Shell-Zeichen enthält, und so weiter.

Bitprophet
quelle
7
Ist workonaber unbekannt durch sh. Wie können wir Stoff anweisen, stattdessen Bash zu verwenden?
Pierre de LESPINAY
18
IMHO sollten Sie nur verwenden source venv/bin/activate. Es ist einfacher und funktioniert sofort. workonist eine zusätzliche Abhängigkeit, und selbst wenn sie installiert ist, müssen Sie sie hinzufügen .bashrc- zu kompliziert für Fabric-Bereitstellungen.
Dave Halter
@PierredeLESPINAY Eine Lösung für Ihr Problem finden Sie unter stackoverflow.com/questions/11272372/… .
Herzog am
137

Als Aktualisierung der Prognose von bitprophet: Mit Fabric 1.0 können Sie prefix () und Ihre eigenen Kontextmanager verwenden.

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')
nh2
quelle
@simon, indem Sie Ihre eigene Präfixmethode schreiben, die .bashrc aufruft und sowohl das Präfix als auch den Befehl in das Argument -c für bash einschließt. Siehe unten
Dave
5
Ist sourceaber unbekannt durch sh. Wie können wir Stoff anweisen, stattdessen Bash zu verwenden?
Pierre de LESPINAY
2
@PierredeLESPINAY können Sie .anstelle vonsource
katy lavallee
Warum verwenden Sie, cd()wenn Sie den Pfad zu activatein vollständig angeben prefix()?
Nick T
@NickT Weil prefix()es dort keine CD zu geben scheint - siehe diese Dokumente , die dasselbe tun. Wir möchten cddort, damit diese yieldBefehle , wenn wir andere Befehle ausführen ( pip freezein meinem Beispiel), relativ zu diesem Verzeichnis sein können.
nh2
18

Ich verwende nur eine einfache Wrapper-Funktion virtualenv (), die anstelle von run () aufgerufen werden kann. Der CD-Kontext-Manager wird nicht verwendet, daher können relative Pfade verwendet werden.

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)
ehc
quelle
9

virtualenvwrapper kann dies etwas einfacher machen

  1. Verwenden des Ansatzes von @ nh2 (dieser Ansatz funktioniert auch bei Verwendung local, jedoch nur für Virtualenvwrapper-Installationen, in denen workonsich $PATHWindows befindet).

    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. Oder stellen Sie Ihre Fab-Datei bereit und führen Sie diese lokal aus. Mit diesem Setup können Sie die virtuelle Umgebung für lokale oder Remote-Befehle aktivieren. Dieser Ansatz ist leistungsstark, da er die localUnfähigkeit umgeht, .bashrc mit bash -lfolgenden Funktionen auszuführen :

    @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")
Dave
quelle
Dank der Zusammenfassung der Antwort von nh2 kann die Deklaration von virtualenv contextmanager in Python 2.6+ in 5 Zeilen erfolgen. Es kann jedoch nie garantiert werden, dass der Alias ​​'workon' immer korrekt importiert wird, und es ist viel zuverlässiger, `source ... / activate 'zu verwenden. Befehl
Alex Volkov
8

Dies ist mein Ansatz zur Verwendung virtualenvmit lokalen Bereitstellungen.

Mit dem Pfad () -Kontextmanager von Fabric können Sie pipoder pythonmit Binärdateien von virtualenv ausführen.

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')
Darklow
quelle
Ich mag das sehr - ich sehe keine offensichtlichen Nachteile für diesen Ansatz und er ist sehr sauber. Danke :)
Simon
immer noch die beste und sauberste Antwort hier
n1_
4

Vielen Dank an alle Antworten und ich möchte noch eine Alternative dazu hinzufügen. Es gibt ein Modul, Fabric-Virtualenv , das die Funktion als denselben Code bereitstellen kann:

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

Fabric-Virtualenv nutzt fabric.context_managers.prefix, was ein guter Weg sein könnte :)

Drake Guan
quelle
Interessant, aber ich mag die Tatsache nicht, dass es keinen Link zu SCM / Issue Tracker gibt. Ein Paket, das nur auf PYPI ohne Link zum Quellcode und zum Issue Tracker veröffentlicht wird, schafft nicht viel Vertrauen ... ist aber einfach zu reparieren.
Sorin
2

Wenn Sie die Pakete in der Umgebung installieren oder Befehle gemäß den Paketen ausführen möchten, die Sie in der Umgebung haben, habe ich diesen Hack gefunden, um mein Problem zu lösen, anstatt komplexe Fabric-Methoden zu schreiben oder neue Betriebssystempakete zu installieren:

/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

Auf diese Weise müssen Sie möglicherweise die Umgebung nicht aktivieren, können jedoch Befehle unter der Umgebung ausführen.

vikas0713
quelle
1

Hier ist der Code für einen Dekorateur, der zur Verwendung der virtuellen Umgebung für alle Run- / Sudo-Aufrufe führt:

# 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

Um den Dekorateur zu verwenden, ist die Reihenfolge der Dekorateure wichtig:

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

Dieser Ansatz hat bei mir funktioniert, Sie können ihn auch anwenden.

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'")

Angenommen, es venvhandelt sich um Ihr virtuelles env-Verzeichnis, und fügen Sie diese Methode gegebenenfalls hinzu.

Manikanta
quelle