So setzen Sie eine Aufgabe fort, wenn Fabric einen Fehler erhält

94

Wenn ich eine Aufgabe definiere, die auf mehreren Remoteservern ausgeführt werden soll, wenn Fabric auf Server 1 ausgeführt wird und mit einem Fehler beendet wird, stoppt Fabric die Aufgabe und bricht sie ab. Aber ich möchte, dass Fabric den Fehler ignoriert und die Aufgabe auf dem nächsten Server ausführt. Wie kann ich das schaffen?

Beispielsweise:

$ fab site1_service_gw
[site1rpt1] Executing task 'site1_service_gw'

[site1fep1] run: echo 'Nm123!@#' | sudo -S route
[site1fep1] err:
[site1fep1] err: We trust you have received the usual lecture from the local System
[site1fep1] err: Administrator. It usually boils down to these three things:
[site1fep1] err:
[site1fep1] err:     #1) Respect the privacy of others.
[site1fep1] err:     #2) Think before you type.
[site1fep1] err:     #3) With great power comes great responsibility.
[site1fep1] err: root's password:
[site1fep1] err: sudo: route: command not found

Fatal error: run() encountered an error (return code 1) while executing 'echo 'Nm123!@#' | sudo -S route '

Aborting.
Mingo
quelle

Antworten:

146

Aus den Dokumenten :

... Fabric verwendet standardmäßig ein "Fail-Fast" -Verhaltensmuster: Wenn etwas schief geht, z. B. ein Remote-Programm, das einen Rückgabewert ungleich Null zurückgibt, oder der Python-Code Ihrer Fabfile, bei dem eine Ausnahme auftritt, wird die Ausführung sofort angehalten.

Dies ist normalerweise das gewünschte Verhalten, es gibt jedoch viele Ausnahmen von der Regel, sodass Fabric env.warn_only bereitstellt, eine boolesche Einstellung. Der Standardwert ist False, was bedeutet, dass eine Fehlerbedingung dazu führt, dass das Programm sofort abgebrochen wird. Wenn jedoch env.warn_only zum Zeitpunkt des Fehlers auf True gesetzt ist - beispielsweise mit dem Einstellungskontextmanager -, gibt Fabric eine Warnmeldung aus, wird jedoch weiter ausgeführt.

Sieht aus wie Sie feinkörnige Kontrolle darüber , wo Fehler werden ignoriert , indem Sie die Übung können settingsKontext - Manager , so etwas wie so:

from fabric.api import settings

sudo('mkdir tmp') # can't fail
with settings(warn_only=True):
    sudo('touch tmp/test') # can fail
sudo('rm tmp') # can't fail
Will McCutchen
quelle
13
Vergessen Sie nicht zu importierenfrom fabric.api settings
Cevaris
31

Ab Fabric 1.5 gibt es einen ContextManager, der dies einfacher macht:

from fabric.api import sudo, warn_only

with warn_only():
    sudo('mkdir foo')

Update: Ich habe erneut bestätigt, dass dies in Ipython mit dem folgenden Code funktioniert.

from fabric.api import local, warn_only

#aborted with SystemExit after 'bad command'
local('bad command'); local('bad command 2')

#executes both commands, printing errors for each
with warn_only():
    local('bad command'); local('bad command 2')
Chris Marinos
quelle
Welche Stoffversion verwenden Sie? Ich habe gerade mit Fabric == 1.6.2 erneut getestet und es funktioniert gut.
Chris Marinos
Möglicherweise verwende ich Fabric == 1.9.0 und es funktioniert nicht für mich
Cevaris
Gerade auch auf 1.9.0 getestet. Was ist Ihre Ausgabe, wenn Sie den Beispielcode aus meinem aktualisierten Kommentar ausprobieren?
Chris Marinos
Wenn Sie nicht die Warnungen / Fehler drucken möchten, können Sie auch die Verwendung hide Kontext - Manager:with hide('everything'):
NP8
13

Sie können auch festlegen, dass die Einstellung warn_only des gesamten Skripts mit true übereinstimmt

def local():
    env.warn_only = True
Rawkcy
quelle
10

Sie sollten die einstellen abort_exception Umgebungsvariable und die Ausnahme abfangen.

Beispielsweise:

from fabric.api        import env
from fabric.operations import sudo

class FabricException(Exception):
    pass

env.abort_exception = FabricException
# ... set up the rest of the environment...

try:
    sudo('reboot')
except FabricException:
    pass  # This is expected, we can continue.

Sie können es auch in einen with-Block setzen. Siehe die Dokumentation hier .

ArtOfWarfare
quelle
Vielen Dank dafür, aber eine Frage: Ist es möglich, in der aktuellen Fabric-Umgebung zuzugreifen / zu übergeben, wie definiert, als die Ausnahme aufgetreten ist? (So ​​kann ich einige spezifische Einstellungen mit der Ausnahme drucken.)
Brian
@Brian: Könntest du nicht einfach das fabric.api.envin deinem exceptBlock überprüfen ?
ArtOfWarfare
@ArtOfWarefare Ahh, ich habe versucht zu vermeiden, alle meine Aufgaben in einen Versuch / außer zu packen, und stattdessen einfach das eingerichtet, env.abort_exception=MyExceptiondamit ich meinen eigenen Fehler ausführen kann. Es funktioniert irgendwie, wenn ich eine Funktion anstelle einer Klasse verwende (erfüllt die aufrufbare Anforderung für abort_exception), aber ich arbeite immer noch an einigen anderen Problemen mit diesem Ansatz.
Brian
@Brian: Also im Körper dieser Funktion überprüfen, was fabric.api.envist.
ArtOfWarfare
7

Zumindest in Fabric 1.3.2 können Sie die Ausnahme wiederherstellen, indem Sie die Ausnahme abfangen SystemExit. Dies ist hilfreich, wenn Sie mehr als einen Befehl in einem Stapel ausführen müssen (z. B. eine Bereitstellung) und bereinigen möchten, wenn einer von ihnen fehlschlägt.

zimbatm
quelle
+1: Getestet - dies funktioniert auch in Fabric 1.9.0. Nachdem Sie dies abgefangen haben, können Sie die SystemExitNachricht oder den Code des Codes auf weitere Details überprüfen .
ArtOfWarfare
Noch besser als das Fangen SystemExit, setzen Sie abort_exceptioneine andere Ausnahme, damit Sie nicht versehentlich Ausnahmen fangen, die nichts mit Fabric zu tun haben. Siehe meine Antwort für ein Beispiel: stackoverflow.com/a/27990242/901641
ArtOfWarfare
7

In Stoff 2.x Sie nur verwenden können invoke s‘ laufen mit dem warnen = True Argument. Auf jeden Fall ist invoke eine Abhängigkeit von Fabric 2.x :

from invoke import run
run('bad command', warn=True)

Aus einer Aufgabe heraus:

from invoke import task

@task
def my_task(c):
    c.run('bad command', warn=True)
Qlimax
quelle
-5

In meinem Fall auf Fabric> = 1.4 diese Antwort die richtige.

Sie können schlechte Hosts überspringen, indem Sie Folgendes hinzufügen:

env.skip_bad_hosts = True

Oder die --skip-bad-hostsFlagge übergeben /

Christian Vielma
quelle