Как продолжить задачу, когда Fabric получает сообщение об ошибке

Когда я определяю задачу для запуска на нескольких удаленных серверах, если задача выполняется на одном сервере и выходит с ошибкой, Fabric остановит и прервет задачу. Но я хочу, чтобы ткань игнорировала ошибку и запускала задачу на следующем сервере. Как я могу заставить это сделать это?

Например:

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

Ответ 1

Из документов:

... Fabric по умолчанию использует шаблон поведения "fast-fast": если что-то пойдет не так, как, например, удаленная программа, возвращающая ненулевое возвращаемое значение, или ваш код Python fabfiles, обнаруживший исключение, выполнение будет немедленно остановлено.

Это обычно желаемое поведение, но есть много исключений из правила, поэтому Fabric предоставляет логический параметр env.warn_only. По умолчанию используется значение False, означающее, что условие ошибки приведет к немедленному прерыванию работы программы. Однако, если для env.warn_only задано значение True во время сбоя - например, с помощью диспетчера контекста настроек - Fabric выдаст предупреждающее сообщение, но продолжит выполнение.

Похоже, вы можете осуществлять детальный контроль над тем, где ошибки игнорируются, используя менеджер контекста settings, что-то вроде этого:

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

Ответ 2

Как и в случае с Fabric 1.5, существует ContextManager, который делает это проще:

from fabric.api import sudo, warn_only

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

Обновление: я повторно подтвердил, что это работает в ipython, используя следующий код.

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

Ответ 3

Вы также можете установить для всего параметра script warn_only значение true с помощью

def local():
    env.warn_only = True

Ответ 4

Вы должны установить переменную среды abort_exception и уловить исключение.

Например:

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.

Вы также можете установить его в блоке с блоком. См. Документацию здесь.

Ответ 5

В Fabric 1.3.2 по крайней мере вы можете восстановить исключение, перехватив исключение SystemExit. Это полезно, если у вас есть несколько команд для запуска в пакете (например, для развертывания) и хотите очистить, если один из них не работает.

Ответ 6

В Fabric 2.x вы можете просто использовать invoke run с аргументом warn = True. В любом случае, invoke является зависимостью Fabric 2.x:

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

Изнутри задачи:

from invoke import task

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

Ответ 7

В моем случае, на Fabric >= 1.4 этот ответ был правильным.

Вы можете пропустить неудачные хосты, добавив следующее:

env.skip_bad_hosts = True

Или передать флаг --skip-bad-hosts/