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

94

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 s'arrêtera et abandonnera la tâche. Mais je veux que Fabric ignore l'erreur et exécute la tâche sur le serveur suivant. Comment puis-je faire cela?

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.
Mingo
la source

Réponses:

146

À partir de la documentation :

... Fabric utilise par défaut un modèle de comportement «fail-fast»: si quelque chose ne va pas, comme un programme distant renvoyant une valeur de retour différente de zéro ou le code Python de votre fabfile rencontrant une exception, l'exécution s'arrêtera immédiatement.

C'est généralement le 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'arrêt 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.

On dirait que vous pouvez exercer un contrôle précis sur les endroits où les erreurs sont ignorées en utilisant le settingsgestionnaire de contexte , 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
Will McCutchen
la source
13
N'oubliez pas d'importerfrom fabric.api settings
cevaris
31

À partir de 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 dans 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')
Chris Marinos
la source
Quelle version de tissu utilisez-vous? Je viens de tester à nouveau avec Fabric == 1.6.2, et cela fonctionne très bien.
Chris Marinos
Peut-être, j'utilise Fabric == 1.9.0 et cela ne fonctionne pas pour moi
cevaris
Juste testé sur 1.9.0 aussi. Quelle est votre sortie lorsque vous essayez l'exemple de code de mon commentaire mis à jour?
Chris Marinos
Si vous ne souhaitez pas imprimer les avertissements / erreurs, vous pouvez également utiliser le gestionnaire de contexte de masquage :with hide('everything'):
np8
13

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

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

Vous devez définir la abort_exceptionvariable 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. Consultez la documentation ici .

ArtOfWarfare
la source
Merci pour cela, mais une question - est-il possible d'accéder / passer dans le dict d'environnement de tissu actuel tel que défini lorsque l'exception s'est produite? (Je peux donc imprimer certains paramètres spécifiques à l'exception.)
Brian
@Brian: Ne pourriez-vous pas simplement vérifier fabric.api.envdans votre exceptbloc?
ArtOfWarfare
@ArtOfWarefare Ahh idiot, j'essayais d'éviter d'encapsuler toutes mes tâches dans un essai / sauf et à la place de configurer simplement le env.abort_exception=MyExceptionpour que je puisse exécuter mon propre échec. Cela fonctionne en quelque sorte si j'utilise une fonction au lieu d'une classe (satisfait la demande appelable pour abort_exception) mais je travaille toujours sur d'autres problèmes avec cette approche.
Brian
@Brian: Donc, dans le corps de cette fonction, vérifiez ce que fabric.api.envc'est.
ArtOfWarfare
7

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

zimbatm
la source
+1: Testé - cela fonctionne également dans Fabric 1.9.0. Après avoir attrapé cela, vous pouvez vérifier le SystemExitmessage ou le code du s pour plus de détails.
ArtOfWarfare
Encore mieux que la capture SystemExit, définie abort_exceptionsur une exception différente, afin de ne pas intercepter accidentellement des exceptions qui n'ont rien à voir avec Fabric. Voir ma réponse pour un exemple: stackoverflow.com/a/27990242/901641
ArtOfWarfare
7

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

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

À partir d'une tâche:

from invoke import task

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

Dans mon cas, sur Fabric> = 1.4 cette réponse était la bonne.

Vous pouvez ignorer les mauvais hôtes en ajoutant ceci:

env.skip_bad_hosts = True

Ou passer le --skip-bad-hostsdrapeau /

Christian Vielma
la source