web-dev-qa-db-fra.com

Comment continuer une tâche lorsque Fabric reçoit une erreur

Lorsque je définis une tâche à exécuter sur plusieurs serveurs distants, si la tâche s'exécute sur le serveur un et se termine avec une erreur, Fabric arrête et abandonne la tâche. Mais je veux que le tissu ignore l'erreur et exécute la tâche sur le serveur suivant. Comment puis-je le faire?

Par exemple:

$ 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.
92
Mingo

De les docs :

... Fabric adopte par défaut un modèle de comportement "fail-fast": si quelque chose se passe mal, comme un programme distant renvoyant une valeur de retour non nulle ou le code Python de Python rencontrant une exception, l'exécution sera exécutée). arrêtez immédiatement.

Il s'agit généralement du comportement souhaité, mais il existe de nombreuses exceptions à la règle, donc Fabric fournit env.warn_only, un paramètre booléen. La valeur par défaut est False, ce qui signifie qu'une condition d'erreur entraînera l'abandon immédiat du programme. Cependant, si env.warn_only est défini sur True au moment de l'échec - avec, par exemple, le gestionnaire de contexte des paramètres - Fabric émettra un message d'avertissement mais continuera à s'exécuter.

Il semble que vous puissiez exercer un contrôle précis sur les endroits où les erreurs sont ignorées en utilisant le settings context manager , quelque chose comme ceci:

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
144
Will McCutchen

Depuis Fabric 1.5, il existe un ContextManager qui facilite les choses:

from fabric.api import Sudo, warn_only

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

Mise à jour: j'ai reconfirmé que cela fonctionne en ipython en utilisant le code suivant.

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')
30
Chris Marinos

Vous pouvez également définir le paramètre warn_only du script sur true avec

def local():
    env.warn_only = True
13
Rawkcy

Vous devez définir le abort_exception variable d'environnement et intercepter l'exception.

Par exemple:

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.

Vous pouvez également le définir dans un bloc with. Voir la documentation ici .

10
ArtOfWarfare

Dans Fabric 1.3.2 au moins, vous pouvez récupérer l'exception en interceptant l'exception SystemExit. Cela est utile si vous avez plusieurs commandes à exécuter dans un lot (comme un déploiement) et que vous souhaitez nettoyer si l'une d'entre elles échoue.

7
zimbatm

Dans Fabric 2.x , vous pouvez simplement utiliser invokerun avec warn = True argument. Quoi qu'il en soit, invoquer est une dépendance de Fabric 2.x :

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

De l'intérieur d'une tâche:

from invoke import task

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