Ir para o conteúdo

Documentação

Fluxos e automação

Um fluxo é um desenho que corre. Colocam-se nós numa tela, traçam-se fios entre eles, e a plataforma percorre esse desenho sempre que chega o momento escolhido. Esta página diz o que um fluxo consegue fazer, o que significa cada nó e onde estão exatamente os seus limites.

O que é um fluxo

Um fluxo é um grafo orientado: nós ligados por fios, percorridos a partir de um único ponto de partida. Não é, de propósito, um guião com um ciclo. Quatro regras fixam a forma, e o editor recusa publicar um desenho que quebre alguma delas, apontando o nó errado.

  • Exatamente um disparador. O nó disparador é a única entrada, e é ele que decide que variáveis existem no resto do desenho.
  • Sem ciclos. Um fio que volta a um nó de onde saiu é recusado, porque um fluxo não sabe esperar: um ciclo simplesmente nunca terminaria.
  • Todos os nós têm de ser alcançáveis a partir do disparador. Um nó solto é um erro que uma captura de ecrã não mostra, por isso é um erro no momento de publicar.
  • Os ramos são percorridos um a seguir ao outro, nunca lado a lado. Dois ramos ao mesmo tempo escreveriam em state no mesmo instante, e o resultado dependeria do acaso do relógio.
Um desenho aceita no máximo 80 nós e 160 fios, dos quais no máximo 25 fazem realmente alguma coisa. Este último número é o mesmo que as antigas listas de passos tinham; desenhar em vez de enumerar não o aumenta.

A tela

O editor é uma tela, e não há uma segunda. Um fluxo novo abre logo nela, e um fluxo que era uma lista direita de passos abre como uma cadeia direita de nós.

  • A paleta contém os doze tipos de nó. Basta clicar num deles para o pousar na tela, ou arrastá-lo para o sítio pretendido.
  • Um nó move-se arrastando-o pelo seu cabeçalho. Tudo o resto no nó é um controlo e portanto não inicia um arrasto.
  • Um fio vai de um ponto de saída para um ponto de entrada. Arrasta-se de um para o outro, ou clica-se primeiro na saída e depois na entrada. As duas coisas fazem o mesmo, e a segunda é o caminho pelo teclado.
  • Largar um fio no vazio não faz nada. Para remover um, seleciona-se e carrega-se em Delete, ou usa-se a cruz que está em cima dele.
  • O zoom vai de 50 a 200 por cento, Ajustar mostra o desenho inteiro, e arrastar o fundo desloca a vista. Não há minimapa.
A vista em lista é o mesmo grafo em texto, com o mesmo painel de propriedades ao lado. É uma alternativa completa e não um resumo: cada nó, cada fio e cada definição são alcançáveis ali sem rato.

Os nós

Doze tipos, e a lista é curta de propósito. Cada tipo é um painel, nove traduções, um ramo no executor e uma linha na tabela de verdade, por isso um tipo que ganha o seu lugar vale mais do que um que quase o ganha.

Tipos de nó, as suas saídas e os seus limites
NóSaídasO que faz e onde para
triggeroutA única entrada. O seu evento decide que variáveis existem. Um disparador manual leva ainda o JSON que se injeta: no máximo 2048 caracteres, 40 chaves e 512 caracteres por valor.
scriptok · errorCompõe um modelo de script contra um destino. Sai por ok, ou por error quando a composição falha. Marcando continuar após um erro, uma falha segue mesmo assim.
switchrule-0 … · otherwiseOlha para um valor e toma a primeira regra que serve; tudo o resto sai por otherwise. No máximo doze regras, e um valor comparado de no máximo 512 caracteres.
iftrue · falseUma condição, duas saídas. Os mesmos operadores e a mesma avaliação de uma regra de switch, desenhados como o sim ou não que realmente são.
setoutEscreve em state, de onde um nó posterior ou um guião o volta a ler. No máximo doze atribuições por nó e 4096 caracteres por valor. Os nomes são escolhidos por quem desenha; http está reservado.
httpok · errorChama um URL e põe a resposta em state.http. GET ou POST, no máximo oito cabeçalhos, um tempo limite entre 0,5 e 10 segundos, e um teto de resposta entre 256 bytes e 256 KiB, 64 KiB por omissão. No máximo três redirecionamentos, cada um filtrado de novo.
notifyoutEscreve um aviso no painel desta conta, ao nível informação ou alerta. Título de no máximo 120 caracteres, texto de no máximo 1000. Marcando Enviar também por e-mail, sai também por correio para todas as pessoas com acesso aos scripts que não tenham desativado Notificações de fluxos em Notificações por e-mail. Uma execução de teste nunca envia correio.
actionok · errorArranca, para, desliga, suspende ou retoma o servidor desta execução, e espera até 300 segundos pelo fim do comando. Zero significa não esperar: aceite não é o mesmo que a funcionar.
delayoutColoca a execução em pausa. Até 30 segundos dentro do pedido que a iniciou; mais do que isso e a execução fica de lado e é retomada mais tarde, no máximo 30 dias.
approvalapproved · rejectedPara a execução até que uma pessoa aprove ou rejeite, com um prazo e um resultado escolhido se ninguém responder.
foreachloop · donePercorre a saída do ciclo uma vez por elemento de uma lista, lida como JSON, um por linha ou separados por vírgulas.
repeatloop · donePercorre a saída do ciclo enquanto uma condição for verdadeira e lê essa condição de novo antes de cada volta.
break—Sai do ciclo em que está; a execução continua na saída Concluído desse ciclo.
subflowok · errorExecuta outro fluxo desta conta e aguarda o resultado. O filho recebe a sua entrada como input.*.
logoutEscreve uma linha na execução, tal como o nó de depuração faz no Node-RED. O campo aceita 1000 caracteres; na execução ficam os primeiros 200.
note—Texto sobre a tela. Não tem portas e nunca é percorrido, por isso também nunca aparece numa execução.
end—Termina este ramo e diz como acabou a execução: com êxito, com falha, ou ignorada para um servidor a que este fluxo não se dirigia. Acompanha-o uma mensagem de no máximo 280 caracteres.
Um nó action e um nó http têm saída de erro pela mesma razão: tratam de outra parte, um agente ou o servidor de terceiros, e só quem desenhou o fluxo sabe se uma falha ali é grave.

Disparadores

Cinco momentos, e o que se escolhe não é só quando o fluxo corre. É também que variáveis existem, quais o seletor oferece e quais a plataforma recusa guardar. Um caminho que não pode existir nesse momento é um erro ao guardar, e não um texto vazio a meio de uma execução.

Os cinco disparadores e aquilo de que cada um dispõe
DisparadorQuando correO que há e o que não há
server.provisionedUma vez, logo depois de uma encomenda ter produzido a máquina.Tudo. É o único momento em que existe cada grupo.
server.reinstalledDepois de a reinstalação de uma máquina existente ter corrido bem.A mesma máquina, outra imagem. O endereço não muda e a data de criação continua a ser a original. Hoje só dispara para contentores; a reinstalação de uma máquina virtual é rematada por uma peça que não sabe compor.
server.deletedAssim que uma eliminação é aceite, enquanto a linha ainda se consegue ler.Tudo menos a imagem. Já não resta nada de onde ler uma imagem, e a plataforma não a inventa: os fica portanto simplesmente ausente.
manualNunca por si próprio. Lança-se a partir do editor com Inject.Uma máquina existente que se indica, mais o próprio JSON como input. Aqui também não há imagem: o que está instalado numa máquina não é algo que a plataforma consiga consultar depois.
webhookAssim que um terceiro envia um pedido para um URL só dele.Máquina nenhuma, portanto nem plano, nem endereço, nem ligação, nem agente. Ficam a conta, o fluxo, o corpo enviado como input e o próprio pedido como webhook.
Um plano pendura no máximo um fluxo em cada um dos três momentos de servidor, por isso provisioned, reinstalled e deleted levam um cada e nunca uma lista. Um fluxo manual ou de webhook não pode sequer ser pendurado num plano: nenhum dos dois é arrancado por uma encomenda, e é precisamente para isso que esses dois servem.

Variáveis

Todos os valores que um fluxo pode ler vêm de um destes grupos. O seletor do editor mostra os grupos que existem para o disparador escolhido, e mais nada. Ler um caminho desconhecido é um erro e nunca um valor vazio: um pressuposto errado tem de fazer barulho.

Os grupos de variáveis, quando existem e o que contêm
GrupoExiste comO que contém
org.*Qualquer disparadorA conta: id, nome e nome curto.
user.*Os quatro de servidorA pessoa por quem a execução age: id, nome e endereço de correio.
flow.*Qualquer disparadorEste fluxo e esta execução: nome, id de execução, número e total de passos, disparador e hora de início.
server.*Os quatro de servidorA máquina: nome, nome de anfitrião, tipo, estado, id externo, nó, núcleos, memória, disco e data de criação.
server.compute.*Os quatro de servidorQue género de hóspede é e o que esse género consegue mesmo fazer: género, modelo, unprivileged, armazenamento, pontos de montagem, capabilities e unsupported. Os sete são facultativos, e faltar significa não apurado e não que seja não.
plan.*Os quatro de servidorO plano por trás da encomenda: nome, núcleos, memória, disco e ponte.
os.*Criada e reinstaladaA imagem: nome, nome curto e categoria. Não há família nem versão, porque o catálogo não tem essas colunas e adivinhá-las escolhe o gestor de pacotes errado.
ip.*Os quatro de servidorO endereço atribuído, e se é da versão 4 ou 6.
network.*Os quatro de servidorTudo o que rodeia esse endereço: cidr, gateway, máscara, rede, difusão e os resolvedores.
prefix.*Os quatro de servidorO lote de endereços de onde veio, com o seu intervalo e o seu pai.
integration.*Os quatro de servidorA ligação que sustenta a máquina: nome, tipo, nó, armazenamento, ponte e o intervalo de vmid.
agent.*Os quatro de servidorO agente que fez o trabalho: nome, estado, versão, nome de anfitrião, sistema operativo, núcleo e núcleos de processamento.
input.*Manual e webhookO que se injetou, ou o que o webhook enviou. As chaves são próprias, e o seletor segue-as.
webhook.*Só webhookO próprio pedido: que ponto de entrada, quando chegou e de que endereço.
state.*Depois de um nó setAquilo que um nó set deste fluxo escreveu. Os nomes são próprios, e só existem abaixo do nó que os escreve.
state.http.<node>.*Depois de um nó httpPor cada nó http: status, ok, body, json, error e url. Os seis existem sempre, no caminho bom e no mau.
device.*Ainda em nenhumPensado para equipamento de rede. Não há nenhum fornecedor que o consiga preencher, por isso hoje nenhum fluxo o pode usar.
Um valor em falta e um valor vazio não são a mesma coisa. Os grupos que não existem para o disparador escolhido são removidos em vez de esvaziados, e um campo facultativo pede uma verificação à volta antes de ser lido.

Expressões

Um nó set escreve em state. O seu valor é texto literal, a não ser que se marque a caixa de expressão; aí é lido como um modelo, com as variáveis desta execução já preenchidas.

  • Essa caixa é uma decisão deliberada. Um valor que por acaso tem duas chavetas, um pedaço de Ansible ou um fragmento de Helm, continua a significar o que dizia. Nada muda de sentido por causa de uma alteração que ninguém pediu.
  • A linguagem é só saída. Duas chavetas e um caminho, e mais nada: sem assign, sem capture, sem ciclo, sem include. O que está na tela é o que sai, com os valores preenchidos.
  • Há 46 filtros: texto, números, datas, os poucos filtros de lista que produzem texto, e os próprios quote, ini e ipoctet. O seletor do editor enumera-os. Faltam duas famílias de propósito, as que tiram à sorte e as que devolvem um objeto onde se queria uma palavra.
  • Os segredos não estão disponíveis aqui, nem os fragmentos reutilizáveis. O que um nó set escreve acaba no relato da execução, e um segredo não tem nada que fazer ali.
O título e o texto de um nó notify são sempre lidos como modelo, sem caixa. São prosa, e pôr lá um nome é todo o sentido que têm.

Aprovações e ciclos

Um fluxo pode parar e esperar por uma pessoa, e pode percorrer os mesmos nós mais do que uma vez. Nenhuma das duas coisas era possível enquanto uma execução não pudesse ser estacionada e acordada depois; essa fila já existe.

  • Um nó de aprovação para a execução, cria um pedido e avisa a conta. Responder exige um direito separado, para que quem escreveu o fluxo não seja automaticamente quem o assina.
  • Cada pedido leva um prazo e o que acontece sem resposta: continuar como aprovado, continuar como rejeitado ou terminar a execução como não aplicável. Não há uma quarta opção, porque uma execução que espera para sempre é uma execução de que ninguém volta a saber.
  • Para cada percorre a sua saída de ciclo uma vez por elemento de uma lista. Dentro do ciclo, state.loop contém o elemento atual, a sua posição e o total.
  • Nada de fora de um ciclo pode ligar-se aos nós que estão dentro. Esses nós correm de novo em cada volta, e um aviso ligado a ambos escreveria uma mensagem por volta.
  • Um passo de aprovação também pode enviar e-mail. Esse e-mail chega apenas aos membros que podem decidir sobre aprovações, não a todos os que veem fluxos, e a notificação do painel é escrita de qualquer forma.
Cada ciclo leva um limite rígido de voltas, e uma execução um de passos. Acima do limite a execução para com um erro em vez de fazer parte do trabalho em silêncio: um fluxo que percorreu cem de mil elementos e nada disse é pior do que um que falhou.

Esperar, e fluxos que chamam fluxos

Uma execução parada não é uma execução falhada. Três coisas podem pô-la de lado, e as três usam a mesma fila: uma aprovação, uma pausa longa e um subfluxo cujo filho também espera.

  • Uma pausa de meio minuto ou menos espera dentro do pedido que a iniciou, que é o que se pretende ao dar um momento a um agente. Tudo o que demore mais põe a execução de lado, para que a encomenda que a iniciou termine já e o resto do fluxo venha depois.
  • Um subfluxo executa outro fluxo desta conta como um único passo. O resultado decide a saída: um filho bem-sucedido, ou que nada encontrou para fazer, segue por OK; um filho falhado segue por Erro. O estado, a execução e o nome do fluxo ficam em state.subflow.
  • Um fluxo nunca pode alcançar-se a si próprio, nem diretamente nem através de outro fluxo. Isso é verificado ao publicar, e a mensagem nomeia a cadeia encontrada.
  • Os fluxos podem chamar-se no máximo três níveis de profundidade. Como cada fluxo é editado por si, esse limite é verificado duas vezes: ao publicar e enquanto a execução avança de facto.
Um filho que pára numa aprovação pára também o pai, e a página de execução de cada um remete para a outra. Nada se perde enquanto uma execução espera: o percurso a meio fica guardado e continua exatamente com o grafo com que começou.

Webhooks

Um ponto de entrada de webhook dá a um sistema exterior um URL só dele. Esse sistema envia JSON, o fluxo por trás do URL corre, e a resposta é um código de estado nu. Os pontos de entrada vivem em Scripts, no separador Webhooks, e são objetos próprios: o mesmo ponto de entrada pode apontar para outro fluxo sem que o remetente dê por isso.

  1. Criar o ponto de entrada e dar-lhe um nome que se reconheça mais tarde. O URL é gerado e não se pode escolher: 32 caracteres aleatórios, ou seja 160 bits, com o que adivinhar não é uma estratégia.
  2. Escolher como o remetente se identifica, e copiar o segredo. É mostrado uma só vez e nunca mais; se se perder, regenera-se, e então também muda o URL.
  3. Apontar o ponto de entrada para um fluxo cujo disparador seja um webhook. O ponto de entrada pode existir antes do fluxo, e até lá um pedido é aceite e recebe um 202 que não arranca nada. É a ordem pela qual as pessoas constroem isto de verdade, por isso não é tratado como um erro.
As três maneiras de um remetente se identificar
EsquemaO que faz
noneNenhuma prova: quem conhecer o URL pode lançar o fluxo. Defensável com uma lista de endereços ao lado, difícil de defender sem ela.
hmac_sha256O remetente assina o corpo em bruto juntamente com uma marca temporal. É esta a escolha a fazer: prende o pedido ao seu próprio corpo, pelo que um pedido intercetado não se consegue editar e reenviar.
bearerO remetente põe a senha partilhada no cabeçalho Authorization. Simples, e não diz nada sobre o corpo que vinha com ela.

A assinatura é a palavra sha256, um sinal de igual e o HMAC-SHA256 sobre exatamente os bytes da marca temporal, de um ponto e do corpo, em hexadecimal minúsculo. Vai em X-Provibr-Signature, e a própria marca temporal vai em X-Provibr-Timestamp, em segundos inteiros desde a época.

Um pedido cuja marca temporal tenha mais de 300 segundos, ou esteja no futuro, é recusado com um 401. Essa janela é uma regra a sério e não um adorno, porque a marca temporal está dentro do material assinado: um pedido intercetado não se consegue reenviar amanhã colando-lhe por cima uma marca nova.

Assinar um pedido é uma linha de openssl. Este exemplo envia um objeto pequeno; o texto para o terminal fica em inglês de propósito, para coincidir com aquilo que o terminal mostra.

shell
# Sign the raw body together with the timestamp, then post it.
SECRET="$PROVIBR_WEBHOOK_SECRET"
BODY='{"reason":"maintenance","attempt":1}'
TS=$(date +%s)
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -r | cut -d' ' -f1)

curl -sS -X POST 'https://app.provibr.com/api/hooks/flows/<your-slug>' \
  -H 'Content-Type: application/json' \
  -H "X-Provibr-Timestamp: $TS" \
  -H "X-Provibr-Signature: sha256=$SIG" \
  --data "$BODY"
O que um ponto de entrada aceita
LimitePormenores
body64 KiB por omissão, ajustável entre 1 KiB e 256 KiB. Um pedido maior é cortado enquanto ainda está a chegar, e não lido por inteiro para depois ser recusado.
rate60 pedidos por minuto por omissão, ajustável entre 1 e 600. A contagem é por ponto de entrada e não por remetente, porque uma fonte a sério tem um endereço e um atacante tem mil.
payloadUm objeto JSON de um só nível. Cada chave passa a ser input seguido dessa chave; um objeto encaixado é recusado em vez de ser achatado.
allowlistNo máximo 20 endereços ou intervalos, em v4 ou v6. Vazio significa nenhuma restrição.
endpointsNo máximo 50 pontos de entrada por conta.
O que significa cada resposta
CódigoSignificado
202Aceite. Ou arrancou uma execução, ou não havia nada para arrancar: ainda sem fluxo ligado, o fluxo está desligado, ou a própria execução caiu. Nos quatro casos o remetente não fez nada de errado, e um recibo diz qual dos quatro foi.
401A assinatura ou a senha falta ou não bate certo, ou a assinatura bate certo e a sua marca temporal cai fora da janela.
403O ponto de entrada está desligado, ou o endereço de origem não está na lista.
404Não existe nenhum ponto de entrada com este identificador.
410O ponto de entrada foi revogado. O identificador fica ocupado para sempre, e esta resposta diz a uma fonte honesta que precisa de um URL novo, coisa que um 404 não faria.
413O corpo é maior do que este ponto de entrada aceita.
422O corpo não é um objeto JSON de um só nível.
429Acima do caudal permitido para este ponto de entrada.

Cada pedido deixa um recibo, aceite ou não: o desfecho, o estado devolvido, o endereço de origem por inteiro e quantos bytes foram mesmo lidos. O corpo nunca é guardado. Os recibos desaparecem ao fim de 90 dias, mais cedo do que as próprias execuções, porque um endereço de origem é um dado pessoal de alguém que não é nosso cliente.

Desligar um ponto de entrada não é o mesmo que revogá-lo. Desligado responde 403 e pode voltar a ser ligado; revogado responde 410 para sempre, e o URL nunca mais é atribuído.

Revisões e execuções

Duas perguntas parecidas têm aqui duas respostas diferentes. Quem mudou o quê, e quando, é uma revisão. O que esta execução em concreto percorreu de facto é uma cópia guardada na própria execução. Uma fotografia não consegue responder à primeira pergunta e uma revisão não consegue responder à segunda, por isso existem ambas.

  • Cada publicação escreve uma revisão, mesmo uma publicação que não mudou nada. O número sobe por fluxo e nunca é reutilizado.
  • A diferença entre duas revisões é uma lista legível e não JSON em bruto: um nó acrescentado, removido ou alterado com os campos nomeados, um fio acrescentado ou removido. Onde está um nó na tela não é uma alteração.
  • Repor não rebobina. Escreve o desenho antigo como uma revisão nova por cima da história, com uma nota a dizer de onde veio.
  • Cada execução guarda o desenho que percorreu. Editar um fluxo depois nunca reescreve o que uma execução mais antiga fez.
  • Uma execução tem uma linha por cada nó visitado, com o desfecho e a saída por onde passou, e uma linha por cada nó não visitado com o motivo. Não visitado é um facto que vale a pena anotar, não uma ausência.
  • A lista de execuções filtra por disparador, estado e revisão, e exporta-se para CSV. A exportação para às 5000 linhas e di-lo dentro do próprio ficheiro em vez de acabar em silêncio.

Os modelos de script mantêm ao lado uma história própria: cada versão guardada do conteúdo, e uma diferença linha a linha entre duas quaisquer delas.

Uma execução que chega a uma aprovação é estacionada: o percurso é guardado, a execução passa a Em espera e um worker continua-a assim que alguém decide ou o prazo termina. O resto continua a ser percorrido dentro do pedido que a iniciou, e por isso uma pausa vai até cinco minutos.