Recentemente, estive trabalhando em um projeto que requer muito gerenciamento de host remoto. É baseado em Django e usa Celery e Fabric para gerenciamento de tarefas e conexão SSH, respectivamente. Existem, no entanto, alguns gottchas que são aplicáveis tanto na minha situação quanto em qualquer outra situação em que você queira usar o Fabric como uma API.
Hosts Dinâmicos
O primeiro grande passo foi ser capaz de oferecer suporte a hosts dinâmicos. A solução para isso é simples. Dentro de qualquer método no qual estamos obtendo informações do host e queremos nos conectar a esse host via SSH por meio do Fabric, definimos um método interno com o decorador @hosts da API do fabric.
from fabric.api import hosts
from celery import task
@task()
def my_celery_task():
username, host = grab_my_host_info()
host_string = "%s@%s" % (username, host)
@hosts(host_string)
def my_fab_task():
run("ls")
execute(my_fab_task)
Manipulação de exceção
Isso exigiu um pouco mais de pesquisa, mas acabou não sendo tão ruim quanto eu pensava. O Fabric tem uma política de execução rápida contra falhas. Portanto, se absolutamente alguma coisa acontecer, ele será abortado por meio de abort ().
Esse é um grande problema com o aipo, pois o que ele acaba matando seu trabalhador. A solução para isso é dupla, e ambas são configurações que habilitamos na variável global fabric.api.env do Fabric.
Essas configurações são skip_bad_hosts e warn_only . Ambos permitem o tratamento de erros personalizado pelo programador. Observe que, em ambos os casos, você precisará observar o valor de retorno de qualquer chamada para o erro. Embora a maioria das chamadas de malha como run (), cd () e get () retornem com um atributo * .failed, execute não.
Execute retornará um dicionário cujas chaves são as diferentes cadeias de caracteres do host nas quais a tarefa deveria ser executada, junto com uma exceção como o valor, caso ocorresse. O tratamento de erros pode ser parecido com isto, modificando nosso exemplo anterior.
from fabric.api import hosts, env
from celery import task
env.skip_bad_hosts = True
env.warn_only = True
@task()
def my_celery_task():
username, host = grab_my_host_info()
host_string = "%s@%s" % (username, host)
@hosts(host_string)
def my_fab_task():
run("ls")
try:
result = execute(my_fab_task)
if isinstance(result.get(host_string, None), BaseException):
raise result.get(host_string)
except Exception as e:
print "my_celery_task -- %s" % e.message
Substituindo a declaração de impressão pelo seu logger favorito, é claro.
Gestão de Contexto Env
Agora, pode não ser a melhor coisa do mundo ir e especificar valores de variáveis env rígidas no script dessa forma. Você também pode usar o gerenciador de contexto de configurações, decorando a tarefa de tecido ou usando uma instrução with.
Links legais
Aqui estão alguns links que me ajudaram a descobrir tudo isso.
http://awaseroot.wordpress.com/2012/06/05/fabric-wrappers-and-more-error-handling/