No momento em que este artigo foi escrito, o branch v2 tinha uma classe Group
que deveria ser capaz de servir como unidades anteriormente conhecidas como 'funções', também conhecidas como "um monte de hosts para fazer coisas com / em".
No entanto, ainda não há uma maneira específica de organizar ou rotular Group
objetos; está "pronto" o suficiente para o caso de uso de API puro de usuários avançados que desejam implementar sua própria maneira específica de criá-los, mas não tem nada para usuários orientados a CLI ou pessoas intermediárias que querem algo em estrutura para construir.
Colocando de outra forma, a menos que você esteja rolando puramente com a API, ter objetos Group espalhados em algum lugar é inútil se a CLI ou os bits de chamada de tarefa não tiverem como localizá-los!
Na v1, as funções eram efetivamente um único namespace plano mapeando rótulos de string simples para o que seriam Grupos na v2, e eles podiam ser selecionados na CLI em tempo de execução ( fab --roles=web,db
) e / ou registrados como alvos padrão para tarefas ( @task('db') \n def migrate():
), bem como hosts.
Os usuários os definiram em env.roledefs
, um dicionário simples; qualquer funcionalidade intermediária a avançada girava em torno de modificá-la, geralmente em tempo de execução (via pré-tarefa ou sub-rotina), às vezes no tempo de carregamento do módulo.
Group
s e / ou Connection
s.Lexicon
vez de dict
.db
, web
, lb
, mas então um nome de 2ª camada chamado prod
que é sempre a união dos outros três. Eu esqueci se eu adicionei isso a Lexicon
ainda. É possível que haja outras subclasses de mapa por aí que também fazem isso.if cxn in group
funcionaria mesmo se cxn
fosse um objeto distinto do membro igual dentro de group
.db
"@group
como @task
, e as funções não são unidades de trabalho executáveis, mas, em vez disso, geram objetos Group.Da lista de correio:
Implementamos nossa própria API REST interna, que preenche env.roledefs dinamicamente, dependendo do projeto que está sendo implementado, e depende fortemente de não incorporar strings de host no fabfile do projeto ou especificá-las na CLI.
Nossos casos de uso são:
EnvironmentDatabaseAPIClient(
'https://rest.api.url/schema/',
env.service_name,
).apply_env()
Número de ambientes de servidor - vários ambientes de teste (alguns deles são privados, alguns públicos) e vários ambientes de produção (para clientes diferentes). Cada ambiente consiste em um ou mais hosts e é mapeado para a função de malha.
Cada serviço ( env.service_name
no exemplo acima) possui um conjunto diferente de ambientes.
Também temos meta-papéis (grupos de papéis). Eles são prefixados com group-
: group-production
, group-test
, group-external
, group-internal
, group-all
. Isso nos permite implantar em várias funções de servidor sem especificá-las uma por uma, por exemplo group-all
implanta em todas as funções, tanto de produção quanto de teste.
Temos tarefas de malha especiais para imprimir informações sobre grupos de funções, funções e hosts.
Também contamos muito com o mapeamento reverso das strings de host de volta aos nomes de funções (as strings de hosts são exclusivas por service_name). Isso é usado para registro e notificações de implantação. Basicamente, registramos as implantações de serviço em cada host e enviamos uma notificação do Slack quando o serviço foi implantado em todos os hosts em uma função. O servidor EnvironmentDatabaseAPI é responsável por isso (ele mantém os logs e o estado de implantação). Isso é feito decorando as tarefas de tecido com um decorador que envia env.host
, env.port
e env.service_name
(mais informações de confirmação) de volta ao servidor API.
Planejamos adicionar autenticação de implantação no futuro, também muito provavelmente para extrair mais env
variáveis do servidor para disponibilizá-las no contexto da tarefa.
Obrigado @ max-arnold! Eu reconheço muitos deles em meus próprios casos de uso no passado também. O bit de mapeamento reverso em particular, lembro-me de aparecer na v1 algumas vezes, então o adicionei à lista.
Para que o Fabric v2 se torne útil para mim, eu precisaria de uma maneira de dizer a fab
qual conjunto de hosts executar uma tarefa.
Anteriormente, defini funções e executei fab -R ...
. (Na verdade, as funções foram definidas programaticamente usando um intervalo de endereços IP, mas isso não é um requisito e uma lista estática dentro de um arquivo YAML seria suficiente.)
Não consegui encontrar um equivalente no Fabric v2 e também não consegui emular esse recurso usando:
fabric.yaml
contendoactive_hostset: null
hostsets:
myhostset:
- ...
active_hostset = config["hostsets"][config["active_hostset"]]
em fabfile.py
env INVOKE_ACTIVE_HOSTSET=myhostset fab ...
Em vez da lista esperada de hosts, recebo KeyError: 'active_hostset'
.
Mapeamos diferentes conjuntos de hosts para cada função de cada um de nossos ambientes no fabric v1 e o ambiente é definido executando uma tarefa role.environment:staging
para especificá-lo. Portanto, essa tarefa influencia os hosts usados pelas tarefas a seguir.
Na v2, tentamos usar uma tarefa personalizada, mas o problema é que Executor.expand_calls
é executado antes de nossa tarefa role.environment
executada e, portanto, nenhuma das tarefas a seguir conhece o ambiente para construir dinamicamente suas listas de hosts.
Tornar Executor.expand_calls
um gerador permite que a execução de tarefas influencie a execução de tarefas posteriores. Portanto, meu exemplo acima funciona, onde temos um Task
que precisa saber seu ambiente para expandir adequadamente as funções para hosts. por exemplo, fab role.environment dev deploy.app
- a tarefa role.environment
agora é executada antes de deploy.app
ser expandido, e assim deploy.app
conhece o ambiente e pode configurar seus hosts e então é expandido para o conjunto correto de tarefas.
Eu fiz um protótipo disso em meus garfos:
https://github.com/pyinvoke/invoke/compare/master...rectalogic : expand-generator
https://github.com/fabric/fabric/compare/master...rectalogic : expand-generator
Olá, não sei o que aconteceu com este software depois de muitos anos, mas realmente senti falta do conceito de "funções" em [email protected] , especialmente ao executar $ fab -R dev
Também usamos funções para representar o mesmo conjunto de operações em ambientes diferentes. Talvez separar o conceito de uma função nomeada e um ambiente nomeado seja útil? Como em, a função da web no ambiente de desenvolvimento.
Comentários muito úteis
Olá, não sei o que aconteceu com este software depois de muitos anos, mas realmente senti falta do conceito de "funções" em [email protected] , especialmente ao executar
$ fab -R dev