2010-10-06 9 views
85

Kiedy definiuję zadanie uruchamiane na kilku serwerach zdalnych, jeśli zadanie zostanie uruchomione na serwerze pierwszym i zakończy się z błędem, Fabric zatrzyma się i przerwie zadanie. Ale chcę, aby tkanina ignorowała błąd i uruchamiała zadanie na następnym serwerze. Jak mogę to zrobić?Jak kontynuować zadanie, gdy Fabric otrzyma błąd

Na przykład:

$ fab site1_service_gw 
[site1rpt1] Executing task 'site1_service_gw' 

[site1fep1] run: echo '[email protected]#' | 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 '[email protected]#' | sudo -S route ' 

Aborting. 

Odpowiedz

137

Od the docs:

... domyślnie tkaniny do wzorca „fail-fast” Zachowanie: jeśli coś pójdzie nie tak, jak zdalna Program Zwracanie niezerowa wartość zwracana lub kod pythona twojego fabfile napotyka wyjątek, wykonanie zostanie natychmiast zatrzymane.

Zazwyczaj jest to pożądane zachowanie, ale istnieje wiele wyjątków od reguły, więc Fabric udostępnia env.warn_only, ustawienie typu Boolean. Domyślnie jest to False, co oznacza, że ​​błąd spowoduje natychmiastowe przerwanie programu. Jeśli jednak w momencie niepowodzenia ustawiono wartość env.warn_only na wartość True - z, powiedzmy, menedżerem kontekstu ustawień - Fabric wyśle ​​komunikat ostrzegawczy, ale kontynuuje wykonywanie.

Wygląda można wykonywać precyzyjną kontrolę nad tym, gdzie błędy są ignorowane przy użyciu settings context manager, coś tak:

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 
+13

Nie zapomnij importować 'z fabric.api Settings' – cevaris

+0

to nie działa. – Cerin

13

Można również ustawić warn_only ustawienie całego skryptu aby mogło być prawdziwe z

7

Co najmniej w wersji 1.3.2 można odzyskać wyjątek, przechwytując wyjątek SystemExit. Jest to przydatne, jeśli masz więcej niż jedno polecenie do uruchomienia w pakiecie (jak na przykład wdrożenie) i chcesz je wyczyścić, jeśli jedno z nich zawiedzie.

+0

+1: Testowany - działa to również w Fabric 1.9.0. Po przechwyceniu tego, możesz sprawdzić komunikat lub kod 'SystemExit', aby uzyskać więcej szczegółów. – ArtOfWarfare

+0

Nawet lepiej niż przechwytując 'SystemExit', ustaw' abort_exception' na inny wyjątek, aby nie przypadkowo wychwycić wyjątki, które nie mają nic wspólnego z Fabric. Zobacz moją odpowiedź na przykład: http://stackoverflow.com/a/27990242/901641 – ArtOfWarfare

26

Jak tkaniny 1.5, istnieje ContextManager sprawia, że ​​to łatwiejsze:

from fabric.api import sudo, warn_only 

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

Aktualizacja: I ponownie potwierdziła, że ​​pracuje w ipython używając następującego kodu.

+0

To nie działa dla mnie. – cevaris

+0

Z której wersji tkaniny korzystasz? Właśnie powtórzyłem test z Fabric == 1.6.2 i działa dobrze. –

+0

Prawdopodobnie używam Fabric == 1.9.0 i to nie działa dla mnie – cevaris

8

Powinieneś ustawić zmienną środowiskową abort_exception i wychwycić wyjątek.

Na przykład:

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. 

Można również ustawić go w sposób z bloku. Zobacz dokumentację here.

+0

Dziękuję za to, ale jedno pytanie - czy jest możliwy dostęp/przekazanie w bieżącej env dict tkaniny, jak zdefiniowano, kiedy wystąpił wyjątek? (Mogę wydrukować określone ustawienia z wyjątkiem). – Brian

+0

@Brian: Czy nie możesz po prostu sprawdzić 'fabric.api.env' w swoim bloku' except'? – ArtOfWarfare

+0

@ArtOfWarefare Ahh głupi mnie Próbowałem uniknąć zawijania wszystkich moich zadań w próbie/except i zamiast tego po prostu skonfigurowałem 'env.abort_exception = MyException', dzięki czemu mogłem uruchomić swój własny błąd. To "działa", jeśli używam funkcji zamiast klasy (spełnia wymagania wywołania dla 'abort_exception'), ale wciąż pracuję nad innymi problemami z tym podejściem. – Brian

-2

W moim przypadku na Fabric> = 1.4 this answer było prawidłowe.

Można pominąć złych gospodarzy, dodając w ten sposób:

env.skip_bad_hosts = True 

Albo mijając --skip-bad-hosts flagi/

Powiązane problemy