Cómo continuar una tarea cuando Fabric recibe un error.

Cuando defino una tarea para ejecutar en varios servidores remotos, si la tarea se ejecuta en el servidor uno y sale con un error, Fabric se detendrá y abortará la tarea. Pero quiero hacer que Fabric ignore el error y ejecute la tarea en el siguiente servidor. ¿Cómo puedo hacer que haga esto?

Por ejemplo:

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

De los documentos :

… De manera predeterminada, la tela tiene un patrón de comportamiento “a prueba de fallas”: si algo sale mal, como un progtwig remoto que devuelve un valor de retorno distinto de cero o el código Python de su archivo fabiano encuentra una excepción, la ejecución se detendrá de inmediato.

Este es típicamente el comportamiento deseado, pero hay muchas excepciones a la regla, por lo que Fabric proporciona env.warn_only, una configuración booleana. El valor predeterminado es False, lo que significa que una condición de error hará que el progtwig se cancele de inmediato. Sin embargo, si env.warn_only se establece en Verdadero en el momento de la falla, por ejemplo, con el administrador de contexto de configuración, Fabric emitirá un mensaje de advertencia pero continuará ejecutándose.

Parece que puede ejercer un control preciso sobre dónde se ignoran los errores mediante el administrador de contexto de settings , algo así:

 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 

A partir de Fabric 1.5, hay un ContextManager que lo hace más fácil:

 from fabric.api import sudo, warn_only with warn_only(): sudo('mkdir foo') 

Actualización: Re-confirmé que esto funciona en ipython usando el siguiente código.

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

También puede establecer que la configuración warn_only de todo el script sea verdadera con

 def local(): env.warn_only = True 

Debe establecer la variable de entorno abort_exception y capturar la excepción.

Por ejemplo:

 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. 

También puedes configurarlo en un bloque with. Vea la documentación aquí .

Al menos en Fabric 1.3.2, puede recuperar la excepción capturando la excepción SystemExit . Eso es útil si tiene más de un comando para ejecutar en un lote (como un despliegue) y desea limpiar si uno de ellos falla.

En Fabric 2.x puedes usar la ejecución de invoke con el argumento warn = True . De todos modos, invocar es una dependencia de Fabric 2.x :

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

Desde dentro de una tarea:

 from invoke import task @task def my_task(c): c.run('bad command', warn=True) 

En mi caso, en Fabric> = 1.4 esta respuesta fue la correcta.

Puede omitir malos hosts agregando esto:

 env.skip_bad_hosts = True 

O pasando la bandera --skip-bad-hosts /