Por favor, certifique-se de ler esta postagem do blog e todos os seus links primeiro!: http://bitprophet.org/blog/2017/04/17/fabric-2-alpha-beta
Este é o local para deixar comentários sobre problemas não cobertos por nenhum dos tickets existentes; por favor, procure os lugares abaixo primeiro!!
Não encontra nada relevante? Deixe um comentário abaixo! Estou procurando feedback _semelhante, mas não limitado a_:
Pequeno erro na URL, deveria ser http://bitprophet.org/blog/2017/04/17/fabric-2-alpha-beta/
Vai mostrar o quão bem eu me lembro do meu próprio site, hein? Obrigado! Eu até fiz um verificador de links no meu post, mas... não contra este ticket ;)
Eu tenho uma proposta de como o sistema roledefs do fabric 1 pode ser implementado de uma forma que acredito estar de acordo com a filosofia do fabric 2. Cada Collection
de tarefas também pode ter funções decoradas @group
no mesmo namespace que retornam objetos Group
preenchidos nos quais as tarefas podem ser executadas. Namespaces seriam importantes, então se fabfile.py
contivesse um Collection
chamado deploy
que tivesse @group
s chamados web
e db
, pode-se usar deploy.web.execute(mytask)
ou fab -G deploy.web mytask
para executar mytask
em cada host no grupo web
. Essas funções decoradas seriam chamadas preguiçosamente e memorizadas para evitar chamadas de API desnecessárias, caso uma pesquisa na lista de hosts fosse uma operação lenta conforme implementada pelo usuário.
Isso está de acordo com a filosofia de design do tecido 2? Eu adoraria dar uma olhada na implementação, se assim for.
Essa é uma ideia legal, @RedKrieg! Eu tenho adiado meu próprio brainstorm sobre como "melhor" gerar objetos de grupo e/ou como se referir a eles na CLI, mas de improviso isso parece um caminho razoável a seguir. Acabei de descartar muitas palavras em #1594 e incluí sua ideia lá (+ um link). Vamos continuar a discussão lá, mas tl;dr sim, eu adoraria ver um PoC PR.
Qual é a melhor abordagem para executar um comando localmente, apesar do argumento -H
estar presente, por exemplo, se eu quiser combinar compilação local e rsync para host remoto em uma única tarefa?
Objetos de conexão @max-arnold têm um atributo .local
que age como .run
na máquina local: http://docs.fabfile.org/en/v2/api/connection.html#fabric .connection.Connection.local
Ok, eu acho que um exemplo é melhor do que palavras:
<strong i="6">@task</strong>
def build(ctx):
# should always run locally
ctx.local('uname -a')
<strong i="7">@task</strong>
def deploy(ctx):
build(ctx)
# this one should run on remote host
ctx.run('uname -a')
A tarefa combinada funciona bem:
fab -H host deploy
A tarefa local sozinha falha com AttributeError: Nenhum atributo ou chave de configuração encontrada para 'local':
fab build
Basicamente eu quero ter uma tarefa que faça algo localmente, não importa como ela foi invocada (com ou sem -H
).
Por outro lado, alguns comandos destinam-se apenas a serem executados remotamente. Se nenhum host estiver presente, ctx.run
tentará executá-los localmente, o que pode levar a consequências inesperadas.
| O usuário executa a tarefa | O autor do comando/tarefa deseja que seja executado | Como deve se comportar? |
|----------|--------------------------- ---|----------------|
| localmente | localmente | comportamento run() é bom (mas irá violar a intenção do autor se executado remotamente) |
| localmente | remotamente | Ele deve falhar (ou solicitar a string do host como o tecido antigo fez) |
|localmente | localmente ou remotamente | comportamento run() é bom |
| remotamente | localmente | Ele deve sempre ser executado localmente, mas Context não tem o método local() para garantir |
| remotamente | remotamente | comportamento run() é bom (mas são esperados problemas durante a chamada local) |
| remotamente | localmente ou remotamente | comportamento run() é bom |
@max-arnold é exatamente o nº 98! que eu ainda não resolvi totalmente. Colocando alguns pensamentos modernos lá como um comentário ... edit: este
Eu notei o que parece ser inconsistência com o sudo.
Onde connection
é um servidor remoto, autenticado como root.
Tentando expandir o til como outro usuário que não seja o root:
c.sudo("echo bar > ~/foo", user="builder")
Isso é bem-sucedido, mas em vez de escrever /home/builder/foo, ele escreveu /root/foo.
Por outro lado, se eu apenas tentar ls:
c.sudo("ls", user="builder")
Eu recebo Permission denied
.
Algo parece errado.
Meu palpite quando Dustin relatou o fora de banda acima, foi que esta é uma ruga específica de sudo
(o comando, não o método), desde a última vez que olhei, estamos usando -H
e aparentemente não se comporta 100% como esperamos.
Olá Jeff,
como já estou trabalhando em python 3, agora estou usando fabric3
(a portabilidade do fabric 1.x).
Fiquei tentado a tentar a migração para o fabric 2, mas imediatamente bati em uma rolha. Eu faço uso extensivo das funções fabric.contrib
, mas o documento de migração diz que não existe mais.
Com certeza eu não quero inchar o código revertendo para o equivalente do shell, e como, a julgar pelo número de problemas em contrib.*
do fabric 1.x, parece que é muito usado, acho que é a falta pode ser um sério obstáculo para a migração de muitos outros.
Encontrei um projeto de patchwork que aparentemente contém o equivalente a fabric.contrib
, mas seu código não é atualizado há anos.
Você tem algum plano para portar fabric.contrib
para o tecido 2?
Obrigado,
Gabriel
@garu57 Sim, o plano agora é usar patchwork
como basicamente "contribuição de 2.0". No momento, é baseado no Fabric 1, mas isso mudará depois que o Fabric 2.0.0 for lançado. Espero que os bits de contribuição mais usados sejam transferidos rapidamente.
Olá a todos,
Às vezes, meu programa executa um comando remoto, por exemplo
source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./00-update-kernel.sh'
Eu vejo que os scripts são executados assim:
033[0;32m[DONE]\033[0m'
+ return 0
+ alt_test_done_msg 'Prepare evironment'
+ echo -e '* Prepare evironment \033[0;32m[DONE]\033[0m'
+ exit 0
e devo ver também minha saída de depuração "?" de acordo com meu código:
class GenericFabric(object):
def __init__(self, host, user, key_filename=None, port=22):
connection_string = "{u}@{h}:{p}".format(u=user, h=host, p=port)
self.connection = Connection(connection_string)
self.key_filename = key_filename
#<strong i="13">@with_settings</strong>
def generic_cmd(self, command_str, timeout, fabric_timeout, **kwargs):
"""
Creating remote container from template
<strong i="14">@type</strong> command_str: str
<strong i="15">@param</strong> command_str: command for execute with VM
<strong i="16">@type</strong> timeout int or float
<strong i="17">@param</strong> timeout number of seconds for pause
<strong i="18">@type</strong> fabric_timeout int or float
<strong i="19">@param</strong> fabric_timeout number of seconds for timeout fabric run
<strong i="20">@rtype</strong>: FabricResponse
<strong i="21">@return</strong>: Return remote status of operation VM
"""
if fabric_timeout > 0:
command = self.connection.run(command_str.format(**kwargs),
timeout=fabric_timeout,
warn=True, echo=True)
else:
command = self.connection.run(command_str.format(**kwargs),
warn=True, echo=True)
print("?")
if timeout > 0:
sleep(timeout)
return FabricResponse(command)
def simple_generic_cmd(self, command_str, **kwargs):
"""
<strong i="22">@type</strong> command_str: str
<strong i="23">@param</strong> command_str: command for execute with VM
<strong i="24">@rtype</strong>: FabricResponse
<strong i="25">@return</strong>: Return remote status of operation VM
"""
return self.generic_cmd(command_str, 0.1, 0, **kwargs)
Mas não há ninguém "?". Então, sugiro que houvesse travamento no run().
Na verdade, meu programa é enorme e há programação multi-processo. Para travar estou executando comandos remotos com o seguinte código:
class TestingSystemVM(GenericFabric):
#######
<strong i="7">@signal_alarm_down</strong>
def run_rpm_test(self, command_test, package, type_of_test="base"):
"""
"""
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(self.__timeout)
returned_value = Queue()
start_time = datetime.utcnow()
directory, command_test = os.path.split(command_test)
try:
if command_test.endswith(".yml"):
directory = directory.replace("/opt/QA", self.ansible.git_qa_repo)
output = self.ansible.play_ansible(command_test,
package,
directory)
else:
vm_instance = (self.host,
self.user,
self.key_filename,
self.os_name,
self.platform,
self.arch)
running_test = Process(target=separate_process_running_test,
args=(vm_instance,
returned_value,
directory,
command_test,
package,
type_of_test))
running_test.start()
running_test.join(self.__timeout)
if running_test.is_alive():
running_test.terminate()
command_test_res = "FAIL: Timeout\n"
return command_test_res, work_time(start_time), 1
elif returned_value.empty():
command_test_res = "FAIL: Problem while getting result\n"
return command_test_res, work_time(start_time), 1
else:
output = returned_value.get()
except TimeOut:
command_test_res = "FAIL: Timeout\n"
return command_test_res, work_time(start_time), 1
if output.failed or (package.name in ("lve-utils", "lve-stats") and
"FAIL" in output.stdout):
res_output = "FAIL: " + output.stdout
else:
res_output = output.stdout
return res_output, work_time(start_time), 0 if output.succeeded else 1
def separate_process_running_test(vm_instance, return_value_queue,
directory, command_test, package,
type_of_test="base"):
"""
"""
sleep(0.5)
signal.signal(signal.SIGTERM, kill_fabric_runner)
signal.signal(signal.SIGINT, kill_fabric_runner)
(host,
user,
key_filename,
os_name,
platform,
arch) = vm_instance
child_vm_instance = TestingSystemVM(host,
user,
key_filename,
os_name,
platform,
arch,
FakeAnsible())
if command_test.endswith(".bats"):
command_test = "/usr/bin/bats --tap " + command_test
else:
command_test = os.path.join("./", command_test)
output = child_vm_instance.simple_generic_cmd(child_vm_instance._c_run_test,
envvars=child_vm_instance.env_vars,
exec_test=command_test,
dir=directory,
package=package.name,
pver=package.version,
prel=package.release,
type_test=type_of_test)
print("!")
return_value_queue.put(output)
Quando uso o fabric2, alguns comandos iniciados a partir de processos filho ficam suspensos de tempos em tempos.
Atualizado Na verdade, foi meu erro no código. Então, fabric2 não contém hang
Olá pessoal,
Fiz alguns experimentos de lançamento e posso compartilhar minha experiência.
Em primeiro lugar, executei o comando do meu console
ssh [email protected] -t "source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'"
e isso terminou perfeitamente e rápido com exit=0:
###
+ echo -e '* Prepare evironment \033[0;32m[DONE]\033[0m'
* Prepare evironment [DONE]
+ exit 0
Connection to 192.168.0.34 closed.
Boa.
Então executei outro comando:
ssh [email protected] "source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'"
Isso foi concluído tão rápido com exit=0 também:
###
+ echo -e '* Prepare evironment \033[0;32m[DONE]\033[0m'
+ exit 0
Mas não há "Conexão com 192.168.0.36 fechada". Não sei se é importante ou não.
Depois disso, recriei VMs e lancei o comando pelo fabric2 (do IPython):
In [1]: from fabric import Connection
In [2]: Connection('[email protected]').run("source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'", pty=True)
....
+ echo -e '* Prepare evironment \033[0;32m[DONE]\033[0m'
* Prepare evironment [DONE]
+ exit 0
Out[2]: <Result cmd="source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'" exited=0>
Além disso, eu corri com pty=False:
In [1]: from fabric import Connection
In [2]: Connection('[email protected]').run("source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'", pty=False)
+ echo -e '* Prepare evironment \033[0;32m[DONE]\033[0m'
+ exit 0
Out[2]: <Result cmd="source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'" exited=0>
Não havia "Conexão com
Em segundo lugar, decidi que não é um bom ambiente para o meu estande, pois preciso lançar do processo filho. Então, recriei as VMs novamente e executei o script com o próximo código:
In [1]: import subprocess
In [2]: t = subprocess.Popen(""" ssh [email protected] -t "source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'" """, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True); r = t.communicate()
Na saída desta execução havia "Conexão com 192.168.0.34 fechada".
Por outro lado
In [1]: import subprocess
In [2]: t = subprocess.Popen(""" ssh [email protected] "source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'" """, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True); r = t.communicate()
Ambos não foram enforcados.
Hoje à noite vou lançar meus scripts com fabric2 no processo que foi bifurcado e escreverei.
Atualizado Na verdade, foi meu erro no código. Portanto, fabric2 não contém enforcamento.
Seria bom obter suporte de $ use_sudo
para Transfer.put
.
Eu acho que a solução mais simples por enquanto é apenas fazer um put
em algum lugar que eu tenha permissões, então um sudo mv
?
@ned2 isso é tudo que use_sudo
pode realmente fazer em get
/ put
de qualquer maneira, por exemplo, é como v1 faz isso. Na verdade, não é possível fazer upload de um arquivo "com sudo", tanto quanto sei! (Não sem conectar como root, o que é uma má ideia e, idealmente, nem é permitido.)
Dada a tentativa de ter uma API um pouco mais limpa na v2, é quase mais provável que eu implemente um wrapper em vez de agrupar esse comportamento dentro get
/ put
. Talvez apenas algo como Transfer.sudo_put
(que chamaria self.put
). Dessa forma, o put
"puro" é mantido no mínimo.
@bitprophet Gostaria de começar agradecendo por alguns softwares bastante estáveis e úteis com o Fabric1 e sua abordagem para lançar o Fabric2.
Comecei a brincar com a v2, mas tive um problema com o Connection. Estou usando minha configuração SSH do Fabric 1, o Fabric 1 me solicitaria uma senha ao tentar me conectar. O Fabric 2 não está fazendo isso e falha informando que a autenticação falhou. Não consigo ver em nenhum lugar nos documentos da v2 que menciona o mecanismo de autenticação para conexão. Há uma menção de senhas com sudo, mas pelo que posso perceber isso é depois que a conexão foi bem-sucedida de qualquer maneira.
Minha pergunta é se eu perdi alguma coisa nos documentos ou se esse é um recurso ausente ou um problema.
O código:
<strong i="10">@task</strong>
def testing(c):
with Connection('MyHostname') as cxn:
print("Connected")
cxn.run('ls -l')
O erro:
File /lib/python3.4/site-packages/paramiko/auth_handler.py", line 223, in wait_for_response
raise e
paramiko.ssh_exception.AuthenticationException: Authentication failed.
Minha configuração SSH (valores substituídos para postar aqui):
Host MyHostname
HostName replacedhostname.co.uk
Port 22
IdentityFile ~/.ssh/id_rsa
User replaceduser
Estou na versão v2 mais recente: https://github.com/fabric/fabric/commit/fec3a22ee89900500ae731913fd33f9b56e89f46
Espero que resolver isso ajude alguém com o mesmo problema.
Obrigado pelo seu tempo.
@ Aiky30 Provavelmente não é você, o material de autenticação ainda precisa de trabalho (em grande parte devido à necessidade de algum trabalho em andamento do Paramiko, para que as exceções de autenticação não sejam horrivelmente difíceis de interpretar corretamente.) Acho que neste caso pode ser simplesmente que Fab 2 não está interpretando IdentityFile
- pegamos host, usuário, porta e várias outras configurações, mas IdentityFile ainda é um TODO.
Isso ocorre em parte porque também não lidamos com senhas no momento (veja acima - queremos evitar um grande truque do Fabric 1, onde temos que fazer suposições selvagens se uma determinada falha de autenticação significar que é necessária senha ou senha). Então você provavelmente faria a transição para um erro "Não consigo desbloquear este arquivo" depois disso. E ambos são porque eu uso um agente ssh na maioria das vezes - o que seria minha primeira sugestão para uma solução imediata.
Dito isso, acho que provavelmente vale a pena invadir o suporte de configuração de senha do IdentityFile e explícito, porque as chaves não-agentes são provavelmente a configuração de autenticação mais comum número 1, então falta provavelmente significa que a maioria dos usuários alfa/beta são deixados na mão . Vou ver se consigo fazer isso hoje.
Tomou 2.0a para dar uma volta.
1) Também estou um pouco perdido sobre como definir e usar hosts. Eu posso correr:
fab -H user<strong i="7">@host</strong>:22 some-task
Mas se eu não quiser passar detalhes do host (usuário, host, porta) toda vez, não tenho certeza de como configurar hosts em fabfile.py
( Connection
s ou Group
) e, em seguida, apenas consulte-os. Se eu entendi https://github.com/fabric/fabric/issues/1591#issuecomment -296343613 corretamente, ele não é suportado no momento (e rastreado em https://github.com/fabric/fabric/issues/1594 )?
2) Além disso, bati o problema em que criptografei a chave SSH (em ~/.ssh/id_rsa
) e tenho ssh-add
para ssh-agent
. Ele aparece se eu listar as chaves via ssh-add -l
. Quando executo alguma tarefa, fornecendo o nome de usuário adequado:
fab -H musttu<strong i="20">@host</strong> sometask
As coisas funcionam bem. Mas se eu usar usuário incorreto, por exemplo, fab -H bad_user<strong i="23">@host</strong> sometask
, recebo:
Traceback (most recent call last):
...
File "/home/maximus/.virtualenvs/testenv/lib/python3.6/site-packages/paramiko/pkey.py", line 326, in _read_private_key
raise PasswordRequiredException('Private key file is encrypted')
paramiko.ssh_exception.PasswordRequiredException: Private key file is encrypted
Mas presumo que se enquadre em https://github.com/paramiko/paramiko/issues/387 e não seja realmente específico para o fabric 2.0. Mas sim, parece estranho receber o erro PasswordRequiredException: Private key file is encrypted
, quando o agente ssh já tem a chave descriptografada. Se entendi corretamente, após o login inválido, paramiko
voltará a usar a chave diretamente e, sem a senha fornecida, lançará esse erro.
3) Seria bom permitir funções de tarefa de anotação de tipo (para melhor preenchimento automático no IDE). Você teve tempo para considerar https://github.com/pyinvoke/invoke/pull/458 ?
4) Gosto da ideia da biblioteca de retalhos. Para fabric 1.x, há https://github.com/sebastien/cuisine (que parece bem morto) que contém muitas funções extras (eu mesmo não usei). A ideia com patchwork é construir algo semelhante (portanto, funções declarativas no estilo Chef/Ansible/SaltStack, embora com escopo reduzido)? Eu sempre odiei a abordagem YAML/DSL de vários diretórios/vários arquivos que outras ferramentas seguem e gostaria de permanecer em python, para obter mais flexibilidade, sintaxe menos detalhada, preenchimento automático de IDE, depuração fácil etc.
5) Basta soltar o suporte py 2.6 e 3.2-3.3 para fabric 2.0. As pessoas não deveriam simplesmente seguir em frente?
@tuukkamustonen - obrigado pelo feedback! Respostas:
As funções são realmente cobertas em # 1594 - e acho que há outro ticket para a questão relacionada de apenas ter dados de configuração por host, além de como o suporte ssh_config
o faz em seu próprio nível.
Decidir como exatamente reconciliar a configuração em nível de malha com ssh_config
e também com qualquer coisa do Grupo ou dados de tempo de execução... não é trivial. Embora definitivamente precise acontecer em breve; Eu só quero ter uma solução meio pensada em vez de um primeiro rascunho.
Novamente, sim, este é o ticket da Paramiko que você mencionou, e seu palpite é preciso, a situação do nome de usuário incorreto sempre falhará e, como a Paramiko rastreia apenas o último erro encontrado, acontece que a última coisa que tentou foi a cópia criptografada em disco da chave. (Se você moveu essa chave para outro lugar, por exemplo, o último erro seria outra coisa.)
Acabei de comentar sobre esse ticket, ele pode (ou não) duplicar tickets existentes para o mesmo recurso geral. Eu comentei sobre os mais antigos e o IIRC é um "sim, acho que seria bom, desde que não estrague o Python 2". No entanto, não é tão alta prioridade quanto a maioria dos recursos ausentes maiores, por isso cai no bucket "precisa de um ótimo, todas as caixas marcadas PR que eu posso apenas mesclar" :)
Sim, veja o nº 461, que é muito antigo, mas ainda está em minha mente. Atualmente, a grande questão é como tal lib seria escrita para abranger tanto o Invoke quanto o Fabric; em muitos/na maioria dos casos, pode-se simplesmente escrever tarefas Invoke genéricas que não "conhecem" quaisquer contextos locais/remotos divididos, que podem receber um contexto de conexão Fabric quando se deseja executá-las em um sistema remoto.
Tais tarefas "agnósticas de contexto" gostariam de viver na biblioteca de 'invocações' (ou alguma outra lib ainda específica do Invoke); mas alguns (por exemplo, qualquer coisa que envolva transferência de arquivos e não apenas comandos de shell) precisariam ser "conscientes do tecido". Descobrir como preencher essa lacuna é o problema.
Poderia seguir o caminho de "essa lib requer apenas invocar, não requer muito tecido, _mas_ um subconjunto de tarefas reclamará se você não instalar o tecido e entregar a eles um contexto de conexão". Poderia se dividir em duas libs (com a orientada a Fabric exigindo a mais genérica Invoke.) Etc.
Recentemente, isso está definitivamente nos cartões, veja paramiko/paramiko#1070 e/ou pyinvoke/invoke#364. Invoke 1.0, Fabric 2.0 e Paramiko 3.0 (ou, _talvez_, um 2.4/2.5/whatever) serão todos Python 2.7/3.4 e superior.
Sobre (1):
Tenho certeza que você já sabe disso, mas você pode querer pegar algumas ideias dos inventários do Ansible . Ou talvez não :).
Sobre (4):
Acho que https://github.com/pyinvoke/invocations é muito opinativo para isso. As invocações fornecem _conventions_ e podem ser construídas em cima do pacote patchwork/cozinha, mas eu não misturaria convenções (como liberar ou doctest) com utilitários (como copiar arquivos ou alterar permissões).
Não vejo problema em colocar utils para operações somente locais, somente remotas e locais + remotas na mesma biblioteca (patchwork). Qual operação suporta qual modo pode ser abordado como documentação (como docstring, gerado automaticamente a partir de anotação, etc.).
Isso é melhor do que dividir a lógica em mais de 2 pacotes. Porque e se você primeiro adicionar uma operação ao seu pacote "somente invocação" (e pode haver até operações "somente remotas") e depois adicionar suporte para que ele funcione também em servidores remotos? Você moveria, copiaria ou estenderia o código? Em ambos os casos, é mais trabalho, e o usuário precisa de importação diferente, etc., então soa um pouco complicado.
O que posso fazer para que isso seja polido o suficiente para ir no PyPi?
@haydenflinner Vai acontecer na próxima semana ou duas!! (O objetivo é lançar antes de eu pegar meu avião para o PyCon, que é 10 de maio.)
Por exemplo, consulte os documentos de atualização recentemente atualizados nos quais eu estava trabalhando esta semana: http://docs.fabfile.org/en/v2/upgrading.html
Na verdade, eu posso fechar este ticket agora, já que estarei aceitando reais reais para 2.0.0 e acima em breve 👍
Observem, vocês ainda podem comentar aqui se quiserem. Observe que espero realizar pelo menos algumas partes do trabalho de recursos antes do lançamento, juntamente com toda a preparação do gerenciamento de projetos.
Eu olhei para o tecido v2 hoje e me desculpe, eu simplesmente não consigo usá-lo.
As tarefas aceitam argumentos, mas a sintaxe mudou. Consulte http://docs.pyinvoke.org/en/1.1/concepts/invoking-tasks.html#task -command-line-arguments
@dgarstang Você pode considerar adotar um tom mais neutro ou empático com pessoas que lhe dão seu trabalho gratuito! Só dizendo 😉
@task(hosts=xxx)
.(re: 3: Em termos de dar --hosts
e amigos como se fossem argumentos por tarefa, isso é algo que eu poderia adicionar em algum momento, foi dividido se vale a pena. Semelhante a --help
por tarefa
Comentários muito úteis
@haydenflinner Vai acontecer na próxima semana ou duas!! (O objetivo é lançar antes de eu pegar meu avião para o PyCon, que é 10 de maio.)
Por exemplo, consulte os documentos de atualização recentemente atualizados nos quais eu estava trabalhando esta semana: http://docs.fabfile.org/en/v2/upgrading.html
Na verdade, eu posso fechar este ticket agora, já que estarei aceitando reais reais para 2.0.0 e acima em breve 👍