Atualização de 2018: este é um tíquete muito antigo e está pronto para ser implementado agora que 2.0 está disponível para desenvolver recursos.
O tl; dr é que os usuários precisam de maneiras de armazenar dados valiosos sobre seus hosts de destino (e, geralmente, grupos ou "funções"), primeiro, e depois precisam de uma maneira de endereçar essas informações ao fazer coisas em nível de API ou CLI, em segundo lugar.
O Fabric 2 é construído em Invoke, que possui um sistema de configuração poderoso, que é então exposto a tarefas por meio de um objeto de 'contexto'. Parece provável que iremos construir este recurso sobre eles, algo como (mas não necessariamente limitado a):
Por exemplo (novamente: apenas um _exemplo_do manguito_!) Talvez possamos configurá-lo de forma que os dados do host obtenham seu próprio arquivo de estilo de configuração que fica ao lado dos arquivos de configuração regulares - digamos, $PROJECT/hosts.(yml|json|py|etc)
:
web1:
host: web1
# Implicit local user, as with Connection
web2:
host: web2
user: admin2
port: 2223
db:
# Implicit dict-key-is-the-host-value, i.e. implicit "host: db"
user: dbadmin
Então, talvez haja algo assim (usando tarefas de estilo Invoke puras por enquanto, embora certamente isso desejasse a capacidade de usar -H
ou decoradores para selecionar hosts de destino para 'embrulhar' a tarefa, como em v1):
<strong i="27">@task</strong>
def deploy_webs(c):
# Assuming auto-creation of Connection objects...
for cxn in [c.find_host('web1'), c.find_host('web2')]:
cxn.run("hostname")
Há muitas maneiras diferentes de dividir e dividir isso, e várias direções nas quais ele pode ser estendido; a ênfase deve ser dar aos usuários tanto poder e controle quanto razoavelmente possível e, então, sair do caminho deles. Idealmente, tudo o que faremos é padronizar em alguma maneira muito básica de inserir dados em objetos Connection e adicionar suporte à estrutura executiva CLI principal para chegar a algo semelhante ao Fabric 1 em relação à seleção de alvos de execução.
Ao mesmo tempo, expor esses mecanismos publicamente para que usuários avançados possam resolver o problema por conta própria - mais uma vez, espero que qualquer pessoa além dos casos de uso mais básicos tenha grande probabilidade de recorrer a "tarefas regulares do estilo Invoke + fazer as chamadas API necessárias dentro dessas tarefas corpos "abordagem.
No momento, um "host" está limitado exclusivamente ao usuário / nome do host / porta. Seria bom, mesmo apenas para arquivos de fábrica do usuário, armazenar informações adicionais, como sistema operacional, configurações por host como env.shell e assim por diante.
Observe que este pode (ou não) ser um bom momento para reconsiderar a alteração do valor padrão de shell
para /bin/sh
.
Enviado originalmente por Jeff Forcier ( bitprophet ) em 20/07/2009 às 17h02 EDT
Silas Sewell ( silas ) postou:
Com relação ao shell padrão, mesmo se você não mudar para /bin/sh
, pode ser bom usar /usr/bin/env bash
para consertar situações em que o usuário instalou o bash.
Patch de exemplo: http://github.com/silas/fabric/commit/6f7d33c1a3180fbba21c89447bb9a32b84e839ba
PS Eu postei aqui porque "Suporte # 43" foi marcado como uma duplicata.
em 09-11-2009 às 23:13 EST
Erich Heine ( sophacles ) postou:
Eu descobri uma maneira de fazer esses metadados de host que funciona muito bem para os casos simples. Os bits de código relevantes estão aqui http://paste.pocoo.org/show/173964/ no entanto, existem algumas ideias que ainda não tive tempo de implementar - nomeadamente, que este tipo de interface para hospedar metadados pode ser melhor definido como um 'protocolo'. Com isso, quero dizer, ter uma interface definida em uma extremidade, de modo que vários back-ends possam ser implementados, por exemplo, um cliente ldap e um cliente redis, e assim por diante. Isso permitiria que as pessoas se integrassem melhor com as ferramentas existentes (por exemplo, buildbot).
em 04/02/2010 às 15:33 EST
Isso está fortemente relacionado a algumas coisas que eu estava experimentando no # 563, onde ter um objeto Host real ajudaria muito com host_string BS, e também pavimentaria o caminho para esse tipo de sobreposição de configurações por host.
Isso foi reduzido para 2.x, então este também é.
Atualmente, armazenamos metadados adicionais sobre o host remoto em env.server
, que extraímos de um inventário de configurações de servidor salvas em disco como JSON. Mas isso só funciona quando estamos executando tarefas em um único servidor ou quando todas as tarefas que devem ser executadas com vários servidores contêm código para atualizar env.server
base no valor de env.host_string
.
Uma coisa que tornaria isso mais fácil para nós é se o tecido fornecesse um gancho para quando env.host_string
fosse trocado. Então poderíamos ter apenas um pedaço de código que se conecta a isso e atualiza env.server
com o contexto adicional sempre que env.host_string
é alterado.
Isso poderia ser implementado facilmente, sem a necessidade de refatorar host_string
em um objeto Host
completo?
Copiando comentários relevantes de # 1748, @peteruhnak comentou:
"" "
Oi! É possível especificar hosts em um arquivo de configuração ou no próprio fabfile?
Eu sei que posso fornecê-los via CLI (-H), mas se o fabfile for projetado para se comunicar com um servidor específico, ele apenas força o usuário a fazer coisas extras sem um bom motivo.
A "melhor" solução que consegui descobrir foi criar a conexão manualmente, por exemplo
@tarefa
def my_ls (c):
conn = Conexão ('myhost')
conn.run ('ls')
mas isso parece muito sujo, pois preciso (1) duplicá-lo em todos os lugares e (2) tornar o argumento do contexto sem sentido.
"" "
E eu segui com:
"" "
Concordo com tudo acima. Eu realmente sinto falta da velha configuração env.hosts. Foi lindamente simples.
-1 sobre a necessidade de outro arquivo de configuração como invoke.yaml ou outros enfeites. Eu preferiria muito mais o monkey-patch ou algum tipo de gancho de importação que me permitisse declarar os hosts.
Também demorei um pouco para descobrir que ctx.local não está presente se nenhum host for especificado :(
"" "
Eu entendo que o Invoke fornece suporte de configuração avançada. Eu espero que isso inclua a configuração dos arquivos fab do Python.
Em fabric1, adicionei a capacidade de carregar listas de hosts com --set list = somelistfile.txt. No fabfile, eu analisaria o arquivo e modificaria env.hosts e env.passwords com as configurações desse arquivo. Isso me permitiu fazer, por exemplo, fab task --set list=datacenter1.txt
. Em seguida, tive dezenas de tarefas de uso geral que poderia executar em listas predefinidas, em alguns casos uma lista por datacenter ou lista por função lógica. Sei que isso pode ser meio problemático, mas me serviu bem por muitos anos em minha carreira profissional.
Não encontrei uma maneira de fazer isso no fab2, pois os hosts são carregados dentro do executor. Eu gostaria muito de fazer algo semelhante no fab2. No entanto, parece que o paradigma em fab2 exige que eu especifique os hosts nas tarefas. Isso torna impossível ter minhas tarefas de propósito geral e usá-las em uma ampla variedade de servidores (sem usar fab2 -H).
Ter algum tipo de arquivo de configuração de host avançado e ser capaz de especificá-lo na linha de comando seria uma ótima adição ao fabric2.
como @grantjenks mencionou, há suporte de configuração avançada em invoke: http://docs.pyinvoke.org/en/1.1/concepts/configuration.html - portanto, precisaríamos apenas construir um arquivo yaml e pronto. isso seria / poderia ser estendido (manualmente, cada um por sua conta por enquanto), para suportar algo como o conceito env
, como no tecido um. Se alguém não gosta de yaml, isso pode ser feito completamente em código python, pelo que entendi.
@benzkji Absolutamente verdadeiro; os usuários podem, agora mesmo, colocar dados arbitrários em seus arquivos de configuração (py, yml, json, eventualmente outros) e extrair esses dados de suas tarefas para construir conexões e grupos e outros enfeites. Isso é intencional; nunca queremos que haja apenas uma maneira de lidar com esse tipo de configuração, e é por isso que os objetos são todos públicos e tal.
Veja também o topo do tíquete; Eu editei a descrição com uma visão moderna de como esse recurso pode se parecer na v2, em termos de alguns auxiliares básicos comuns "para usuários não opinativos". Na verdade, estou mexendo nisso em um repositório privado (cliente do tecido, não bifurcação) hoje em dia para ver quais padrões emergem.
Olá!
Depois de muita leitura, ainda não entendo como isso realmente funciona. Por exemplo, se eu tiver um arquivo de configuração hosts.yml como este:
hosts.yml:
server1:
host: serverip
user: username
Como devo usar isso para criar uma conexão? Tive que renomear o hosts.yml para fabric.yml para obter acesso a esses dados, por meio da variável de contexto, por exemplo:
<strong i="11">@task</strong>
def do(ctx):
ctx['server1']
E vai me devolver um DataProxy, que não posso usar para criar conexão, ou simplesmente não encontrei na documentação
Meu outro problema: como é possível especificar esses hosts declarados no arquivo hosts.yml com a alternância -H? Só funciona se eu criar um alias no arquivo _ ~ / .ssh / config_ que não é nada bom.
Fora do tópico: o prompt foi removido da api? Não encontrei um método correspondente.
Olá!
Depois de muita leitura, ainda não entendo como isso realmente funciona. Por exemplo, se eu tiver um arquivo de configuração hosts.yml como este:
hosts.yml:
server1: host: serverip user: username
Como devo usar isso para criar uma conexão? Tive que renomear o hosts.yml para fabric.yml para obter acesso a esses dados, por meio da variável de contexto, por exemplo:
<strong i="12">@task</strong> def do(ctx): ctx['server1']
E vai me devolver um DataProxy, que não posso usar para criar conexão, ou simplesmente não encontrei na documentação
Meu outro problema: como é possível especificar esses hosts declarados no arquivo hosts.yml com a alternância -H? Só funciona se eu criar um alias no arquivo _ ~ / .ssh / config_ que não é nada bom.
Fora do tópico: o prompt foi removido da api? Não encontrei um método correspondente.
Eu tenho a mesma pergunta. Não encontrei um único exemplo ou tutorial sobre como criar e usar arquivos de configuração. A documentação da API é muito deficiente a esse respeito.
O fabric 2 é ótimo, mas da minha perspectiva de usuário final, é muito mais difícil colocá-lo em funcionamento (em comparação com o fabric 1), por exemplo, como uma ferramenta de implantação simples para webapps Django (no meu caso).
Há alguma notícia sobre este assunto? Eu acho que um pacote pypi "django / qualquer implantação" opinado faria sentido, para mexer com as coisas básicas que seriam necessárias, de modo que a integração possa ser muito mais fácil. Existe algo assim conhecido / em andamento?
Em qualquer caso, vou precisar mexer no tecido 2 e compartilhar algumas idéias aqui, se valem a pena ;-)
Qual é a maneira apropriada de armazenar vários hosts / tipos de hosts? Ou seja:
gpu_workers:
- [email protected]
cpu_workers:
- [email protected]
fab --FLAG gpu_workers do_some_task
Podemos criar um decorador task
que substitui o argumento de contexto:
import fabric
from functools import wraps
def task(f, *args, **kwargs):
@wraps(f)
def wrapper(c, *args, **kwargs):
c = fabric.Connection('host')
f(c, *args, **kwargs)
return fabric.task(wrapper, *args, **kwargs)
<strong i="7">@task</strong>
def deploy(c):
with c.forward_remote(9418):
c.run('git pull http://localhost/app')
ou colocá-lo em um módulo externo
fabutil.py
import inspect
import fabric
from functools import wraps
class Connection(fabric.Connection):
# add helper methods
def exists(self, path):
return not self.run(f'test -e "{path}").failed
def task(f, *args, **kwargs):
caller = inspect.getmodule(inspect.currentframe().f_back)
host = caller.HOST
user = caller.USER
@wraps(f)
def wrapper(c, *args, **kwargs):
c = Connection(host, user=user, connect_kwargs={'key_filename': os.path.expanduser('~/.ssh/id_rsa.pub')})
f(c, *args, **kwargs)
return fabric.task(wrapper, *args, **kwargs)
fabfile.py
from fabutil import task
HOST = 'host'
USER = 'user'
<strong i="17">@task</strong>
def deploy(c):
with c.forward_remote(9418):
c.run('git pull http://localhost/app')
Comentários muito úteis
Eu tenho a mesma pergunta. Não encontrei um único exemplo ou tutorial sobre como criar e usar arquivos de configuração. A documentação da API é muito deficiente a esse respeito.