Săriți la conținut

Documentație

Fluxuri și automatizare

Un flux este un desen care rulează. Se pun noduri pe o pânză, se trag fire între ele, iar platforma parcurge acel desen ori de câte ori vine momentul ales. Această pagină spune ce poate face un flux, ce înseamnă fiecare nod și unde se află exact limitele lui.

Ce este un flux

Un flux este un graf orientat: noduri legate prin fire, parcurse dintr-un singur punct de pornire. Nu este, în mod deliberat, un script cu o buclă. Patru reguli îi fixează forma, iar editorul refuză să publice un desen care încalcă una dintre ele, numind nodul greșit.

  • Exact un declanșator. Nodul declanșator este singura intrare și el hotărăște ce variabile există în restul desenului.
  • Fără cicluri. Un fir care duce înapoi la un nod din care a plecat este refuzat, pentru că un flux nu știe să aștepte: o buclă pur și simplu nu s-ar termina niciodată.
  • Fiecare nod trebuie să fie accesibil dinspre declanșator. Un nod rămas atârnat este o greșeală pe care o captură de ecran nu o arată, deci este o greșeală în momentul publicării.
  • Ramurile sunt parcurse una după alta, niciodată alături. Două ramuri simultane ar scrie în state în același moment, iar rezultatul ar depinde de hazardul ceasului.
Un desen acceptă cel mult 80 de noduri și 160 de fire, dintre care cel mult 25 fac într-adevăr ceva. Acest ultim număr este același pe care îl aveau vechile liste de pași; a desena în loc de a enumera nu îl ridică.

Pânza

Editorul este o pânză și nu există o a doua. Un flux nou se deschide direct pe ea, iar un flux care era o listă dreaptă de pași se deschide ca un lanț drept de noduri.

  • Paleta conține cele douăsprezece tipuri de nod. Un clic pune unul pe pânză, sau se trage la locul dorit.
  • Un nod se mută trăgându-l de antetul lui. Tot restul nodului este un control și deci nu pornește o tragere.
  • Un fir merge de la un punct de ieșire la un punct de intrare. Se trage de la unul la celălalt, sau se dă clic întâi pe ieșire și apoi pe intrare. Ambele fac același lucru, iar a doua este calea de la tastatură.
  • Lăsarea unui fir în gol nu face nimic. Pentru a scoate unul se selectează și se apasă Delete, sau se folosește crucea așezată pe el.
  • Mărirea merge de la 50 la 200 la sută, Încadrare arată întregul desen, iar tragerea fundalului mută vederea. Nu există o hartă în miniatură.
Vederea ca listă este același graf sub formă de text, cu același panou de proprietăți alături. Este o variantă completă și nu un rezumat: fiecare nod, fiecare fir și fiecare setare sunt accesibile acolo fără maus.

Nodurile

Douăsprezece tipuri, iar lista este scurtă în mod intenționat. Fiecare tip este un panou, nouă traduceri, o ramură în executor și un rând în tabelul de adevăr, deci un tip care își merită locul valorează mai mult decât unul care aproape și-l merită.

Tipurile de nod, ieșirile și limitele lor
NodIeșiriCe face și unde se oprește
triggeroutSingura intrare. Evenimentul lui hotărăște ce variabile există. Un declanșator manual poartă în plus JSON-ul pe care îl injectați: cel mult 2048 de caractere, 40 de chei și 512 caractere pentru fiecare valoare.
scriptok · errorRedă un șablon de script către o țintă. Iese prin ok, sau prin error atunci când redarea eșuează. Bifând continuarea după o eroare, un eșec merge mai departe oricum.
switchrule-0 … · otherwiseSe uită la o valoare și ia prima regulă care se potrivește; tot restul iese prin otherwise. Cel mult douăsprezece reguli și o valoare comparată de cel mult 512 caractere.
iftrue · falseO condiție, două ieșiri. Aceiași operatori și aceeași evaluare ca o regulă de switch, desenate ca alegerea de da sau nu care sunt de fapt.
setoutScrie în state, de unde un nod ulterior sau un script îl citește înapoi. Cel mult douăsprezece atribuiri pe nod și 4096 de caractere pentru fiecare valoare. Numele sunt alese de cel care desenează; http este rezervat.
httpok · errorApelează un URL și pune răspunsul în state.http. GET sau POST, cel mult opt antete, o limită de timp între 0,5 și 10 secunde și un plafon de răspuns între 256 de octeți și 256 KiB, 64 KiB implicit. Cel mult trei redirecționări, fiecare filtrată din nou.
notifyoutScrie o notificare în panoul acestui cont, la nivelul informare sau avertisment. Titlu de cel mult 120 de caractere, text de cel mult 1000. Bifând Trimite și prin e-mail, aceasta pleacă și prin poștă electronică către toate persoanele cu acces la scripturi care nu au dezactivat Notificări din fluxuri în Notificări prin e-mail. O rulare de test nu trimite niciodată mesaje.
actionok · errorPornește, oprește, închide, suspendă sau reia serverul acestei rulări și așteaptă până la 300 de secunde încheierea comenzii. Zero înseamnă a nu aștepta: acceptată nu este același lucru cu în funcțiune.
delayoutPune execuția în pauză. Până la 30 de secunde în cadrul cererii care a pornit-o; mai mult, iar execuția este pusă deoparte și reluată mai târziu, cel mult 30 de zile.
approvalapproved · rejectedOprește execuția până când o persoană aprobă sau respinge, cu un termen și un rezultat ales dacă nu răspunde nimeni.
foreachloop · doneParcurge ieșirea buclei o dată pentru fiecare element al unei liste, citită ca JSON, unul pe linie sau separate prin virgule.
repeatloop · doneParcurge ieșirea buclei cât timp o condiție este adevărată și recitește acea condiție înainte de fiecare rundă.
break—Iese din bucla în care se află; execuția continuă la ieșirea Gata a acelei bucle.
subflowok · errorExecută un alt flux al acestui cont și așteaptă rezultatul. Copilul primește intrarea sa ca input.*.
logoutScrie o linie în rulare, așa cum face nodul de depanare în Node-RED. Câmpul acceptă 1000 de caractere; în rulare ajung primele 200.
note—Text pe pânză. Nu are porturi și nu este parcurs niciodată, deci nici nu apare vreodată într-o rulare.
end—Încheie această ramură și spune cum s-a terminat rularea: reușită, eșuată, sau omisă pentru un server căruia acest flux nu i se adresa. Îl însoțește un mesaj de cel mult 280 de caractere.
Un nod action și un nod http au o ieșire de eroare din același motiv: privesc pe altcineva, un agent sau serverul unui terț, iar numai cel care a desenat fluxul știe dacă un eșec acolo este grav.

Declanșatoare

Cinci momente, iar cel ales nu spune doar când rulează fluxul. Spune și ce variabile există, pe care le oferă selectorul și pe care platforma refuză să le salveze. O cale care nu poate exista în acel moment este o eroare la salvare și nu un text gol în mijlocul unei rulări.

Cele cinci declanșatoare și de ce dispune fiecare
DeclanșatorCând ruleazăCe există și ce nu
server.provisionedO dată, imediat după ce o comandă a produs mașina.Totul. Este singurul moment în care există fiecare grup.
server.reinstalledDupă ce reinstalarea unei mașini existente a reușit.Aceeași mașină, altă imagine. Adresa rămâne neschimbată, iar data creării este tot cea originală. Astăzi se declanșează numai pentru containere; reinstalarea unei mașini virtuale este încheiată de o piesă care nu știe să redea.
server.deletedImediat ce o ștergere este acceptată, cât timp rândul se mai poate citi.Totul în afară de imagine. Nu mai rămâne nimic din care să se citească o imagine, iar platforma nu inventează una: os pur și simplu lipsește.
manualNiciodată de la sine. Se pornește din editor cu Inject.O mașină existentă pe care o alegeți, plus propriul JSON ca input. Nici aici nu există imagine: ce anume este instalat pe o mașină nu poate fi aflat ulterior de platformă.
webhookImediat ce un străin trimite o cerere către un URL numai al lui.Nicio mașină, deci niciun plan, nicio adresă, nicio legătură și niciun agent. Rămân contul, fluxul, corpul trimis ca input și cererea însăși ca webhook.
Un plan atârnă de fiecare dintre cele trei momente de server cel mult un flux, așa că provisioned, reinstalled și deleted poartă câte unul și niciodată o listă. Un flux manual sau de webhook nu poate fi atârnat deloc de un plan: niciunul dintre cele două nu este pornit de o comandă, iar tocmai pentru asta există acele două.

Variabile

Fiecare valoare pe care un flux o poate citi vine din unul dintre aceste grupuri. Selectorul din editor arată grupurile care există la declanșatorul ales și nimic altceva. A citi o cale necunoscută este o eroare și niciodată o valoare goală: o presupunere greșită trebuie să facă zgomot.

Grupurile de variabile, când există și ce conțin
GrupExistă laCe conține
org.*Orice declanșatorContul: id, nume și nume scurt.
user.*Cele patru de serverPersoana pentru care acționează rularea: id, nume și adresă electronică.
flow.*Orice declanșatorAcest flux și această rulare: nume, id de rulare, numărul și totalul pașilor, declanșator și ora de început.
server.*Cele patru de serverMașina: nume, nume de gazdă, tip, stare, id extern, nod, nuclee, memorie, disc și data creării.
server.compute.*Cele patru de serverCe fel de oaspete este și ce poate face cu adevărat acel fel: fel, șablon, unprivileged, stocare, puncte de montare, capabilities și unsupported. Toate șapte sunt opționale, iar lipsa înseamnă neconstatat și nu un nu.
plan.*Cele patru de serverPlanul din spatele comenzii: nume, nuclee, memorie, disc și punte.
os.*Creată și reinstalatăImaginea: nume, nume scurt și categorie. Nu există familie și nici versiune, pentru că în catalog nu sunt acele coloane, iar ghicirea lor alege gestionarul de pachete greșit.
ip.*Cele patru de serverAdresa dată și dacă este de versiunea 4 sau 6.
network.*Cele patru de serverTot ce înconjoară acea adresă: cidr, poartă, mască, rețea, difuzare și rezolvatoarele.
prefix.*Cele patru de serverLotul de adrese din care provine, cu intervalul și părintele lui.
integration.*Cele patru de serverLegătura care poartă mașina: nume, tip, nod, stocare, punte și intervalul de vmid.
agent.*Cele patru de serverAgentul care a făcut treaba: nume, stare, versiune, nume de gazdă, sistem de operare, nucleu și nuclee de procesare.
input.*Manual și webhookCe ați injectat, sau ce a trimis webhookul. Cheile vă aparțin, iar selectorul le urmează.
webhook.*Numai webhookCererea însăși: care punct de intrare, când a sosit și de la ce adresă.
state.*După un nod setCeea ce a scris un nod set din acest flux. Numele vă aparțin și există numai sub nodul care le scrie.
state.http.<node>.*După un nod httpPentru fiecare nod http: status, ok, body, json, error și url. Toate șase există întotdeauna, atât pe drumul bun, cât și pe cel rău.
device.*Încă la niciunulGândit pentru echipamente de rețea. Nu există niciun furnizor care să îl poată umple, deci astăzi niciun flux nu îl poate folosi.
O valoare care lipsește și o valoare goală nu sunt același lucru. Grupurile care nu există la declanșatorul ales sunt înlăturate în loc să fie golite, iar un câmp opțional cere o verificare în jurul lui înainte de a fi citit.

Expresii

Un nod set scrie în state. Valoarea lui este text literal, în afară de cazul în care bifați căsuța de expresie; atunci este citită ca un șablon, cu variabilele acestei rulări deja completate.

  • Acea bifă este o alegere deliberată. O valoare care conține din întâmplare două acolade, o bucată de Ansible sau un fragment de Helm, înseamnă în continuare ceea ce spunea. Nimic nu își schimbă sensul din cauza unei modificări pe care nu a cerut-o nimeni.
  • Limbajul este numai ieșire. Două acolade și o cale, și nimic altceva: fără assign, fără capture, fără buclă, fără include. Ce scrie pe pânză este ce iese, cu valorile completate.
  • Există 46 de filtre: text, numere, date, puținele filtre de listă care produc text și proprii quote, ini și ipoctet. Selectorul din editor le enumeră. Două familii lipsesc intenționat, cele care dau cu zarul și cele care întorc un obiect acolo unde se dorea un cuvânt.
  • Secretele nu sunt disponibile aici, nici fragmentele reutilizabile. Ceea ce scrie un nod set ajunge în consemnarea rulării, iar un secret nu are ce căuta acolo.
Titlul și textul unui nod notify sunt citite întotdeauna ca șablon, fără bifă. Sunt proză, iar introducerea unui nume în ele este întregul lor rost.

Aprobări și bucle

Un flux se poate opri și poate aștepta o persoană și poate parcurge aceleași noduri de mai multe ori. Niciuna nu era posibilă cât timp o execuție nu putea fi pusă în așteptare și trezită mai târziu; acea coadă există acum.

  • Un nod de aprobare oprește execuția, creează o cerere și anunță contul. Răspunsul necesită un drept separat, astfel încât cine a scris fluxul să nu fie automat cel care îl semnează.
  • Fiecare cerere poartă un termen și ce se întâmplă fără răspuns: continuă ca aprobat, continuă ca respins sau încheie execuția ca neaplicabilă. Nu există o a patra opțiune, pentru că o execuție care așteaptă la nesfârșit este una despre care nimeni nu mai aude.
  • Pentru fiecare parcurge ieșirea buclei o dată pentru fiecare element al unei liste. În buclă, state.loop conține elementul curent, poziția lui și totalul.
  • Nimic din afara unei bucle nu se poate lega de nodurile din interiorul ei. Acele noduri rulează din nou la fiecare rundă, iar o notificare legată de ambele ar scrie un mesaj pe rundă.
  • Un pas de aprobare poate trimite și e-mail. Acesta ajunge doar la membrii care pot decide asupra aprobărilor, nu la toți cei care văd fluxuri, iar notificarea din panou este scrisă oricum.
Fiecare buclă poartă o limită strictă a numărului de runde, iar o execuție una a numărului de pași. Peste limită, execuția se oprește cu o eroare în loc să facă în tăcere o parte din muncă: un flux care a parcurs o sută din o mie de elemente și nu a spus nimic este mai rău decât unul care a eșuat.

Așteptarea și fluxurile care apelează fluxuri

O execuție oprită nu este o execuție eșuată. Trei lucruri o pot pune deoparte, iar toate trei folosesc aceeași coadă: o aprobare, o pauză lungă și un subflux al cărui copil așteaptă la rândul lui.

  • O pauză de o jumătate de minut sau mai scurtă așteaptă pur și simplu în cadrul cererii care a pornit-o, exact ce doriți când lăsați un agent să își revină. Tot ce durează mai mult pune execuția deoparte, astfel încât comanda care a pornit-o se încheie imediat, iar restul fluxului urmează mai târziu.
  • Un subflux execută un alt flux al acestui cont ca un singur pas. Rezultatul lui decide ieșirea: un copil reușit sau care nu a găsit nimic de făcut continuă pe OK, iar unul eșuat pe Eroare. Starea, execuția și numele fluxului se află în state.subflow.
  • Un flux nu trebuie să se atingă niciodată pe sine, nici direct, nici prin alt flux. Acest lucru este verificat la publicare, iar mesajul numește lanțul găsit.
  • Fluxurile se pot apela pe cel mult trei niveluri. Deoarece fluxurile se editează separat, această limită este verificată de două ori: la publicare și în timp ce execuția chiar avansează.
Un copil care se oprește la o aprobare își oprește și părintele, iar pagina fiecărei execuții trimite către cealaltă. Nimic nu se pierde cât timp o execuție așteaptă: parcursul pe jumătate este păstrat și continuă exact cu graful cu care a început.

Webhookuri

Un punct de intrare de webhook îi dă unui sistem din afară un URL numai al lui. Acel sistem trimite JSON, fluxul din spatele URL-ului rulează, iar răspunsul este un cod de stare gol. Punctele de intrare stau la Scripturi, în fila Webhookuri, și sunt obiecte de sine stătătoare: același punct de intrare poate arăta către alt flux fără ca expeditorul să observe ceva.

  1. Creați punctul de intrare și dați-i un nume pe care îl veți recunoaște mai târziu. URL-ul este generat și nu se poate alege: 32 de caractere aleatorii, adică 160 de biți, așa că ghicirea nu este o strategie.
  2. Alegeți cum se legitimează expeditorul și copiați secretul. Este arătat o singură dată și niciodată după aceea; dacă se pierde, îl regenerați, iar atunci primiți și un URL nou.
  3. Îndreptați punctul de intrare către un flux al cărui declanșator este un webhook. Punctul de intrare poate exista înaintea fluxului, iar până atunci o cerere este acceptată și primește un 202 care nu pornește nimic. Aceasta este ordinea în care oamenii construiesc asta în realitate, deci nu este tratată ca o greșeală.
Cele trei feluri în care un expeditor se poate legitima
SchemăCe face
noneNicio dovadă: cine cunoaște URL-ul poate porni fluxul. De apărat cu o listă de adrese alături și greu de apărat fără ea.
hmac_sha256Expeditorul semnează corpul brut împreună cu o marcă de timp. Aceasta este alegerea de făcut: leagă cererea de propriul corp, așa că o cerere interceptată nu poate fi modificată și trimisă mai departe.
bearerExpeditorul pune jetonul comun în antetul Authorization. Simplu, și nu spune nimic despre corpul care venea cu el.

Semnătura este cuvântul sha256, un semn egal și HMAC-SHA256 peste exact octeții mărcii de timp, ai unui punct și ai corpului, în hexazecimal cu litere mici. Merge în X-Provibr-Signature, iar marca de timp merge în X-Provibr-Timestamp, în secunde întregi de la epocă.

O cerere a cărei marcă de timp are peste 300 de secunde, sau se află în viitor, este refuzată cu un 401. Acea fereastră este o regulă adevărată și nu un ornament, pentru că marca de timp se află în materialul semnat: o cerere interceptată nu poate fi retrimisă mâine lipind peste ea o marcă proaspătă.

Semnarea unei cereri înseamnă o linie de openssl. Acest exemplu trimite un obiect mic; textul pentru terminal rămâne în engleză în mod intenționat, ca să corespundă cu ceea ce arată terminalul.

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"
Ce acceptă un punct de intrare
LimităAmănunte
body64 KiB implicit, reglabil între 1 KiB și 256 KiB. O cerere mai mare este tăiată în timp ce încă sosește, nu citită în întregime și apoi refuzată.
rate60 de cereri pe minut implicit, reglabile între 1 și 600. Numărătoarea este pe punct de intrare și nu pe expeditor, pentru că o sursă adevărată are o adresă, iar un atacator are o mie.
payloadUn obiect JSON de un singur nivel. Fiecare cheie devine input urmat de acea cheie; un obiect imbricat este refuzat în loc să fie aplatizat.
allowlistCel mult 20 de adrese sau intervale, în v4 sau v6. Gol înseamnă nicio restricție.
endpointsCel mult 50 de puncte de intrare pentru fiecare cont.
Ce înseamnă fiecare răspuns
CodÎnțeles
202Acceptată. Fie a pornit o rulare, fie nu era nimic de pornit: încă niciun flux legat, fluxul este oprit, sau rularea însăși a căzut. În toate cele patru cazuri expeditorul nu a greșit cu nimic, iar o chitanță spune care dintre cele patru a fost.
401Semnătura sau jetonul lipsește ori nu se potrivește, sau semnătura se potrivește, iar marca ei de timp cade în afara ferestrei.
403Punctul de intrare este oprit, sau adresa sursă nu se află în listă.
404Nu există niciun punct de intrare cu acest identificator.
410Punctul de intrare a fost revocat. Identificatorul rămâne ocupat pentru totdeauna, iar acest răspuns îi spune unei surse oneste că are nevoie de un URL nou, ceea ce un 404 nu ar face.
413Corpul este mai mare decât acceptă acest punct de intrare.
422Corpul nu este un obiect JSON de un singur nivel.
429Peste debitul îngăduit pentru acest punct de intrare.

Fiecare cerere lasă o chitanță, acceptată sau nu: rezultatul, starea întoarsă, adresa sursă în întregime și câți octeți au fost citiți cu adevărat. Corpul nu este păstrat niciodată. Chitanțele dispar după 90 de zile, mai devreme decât rulările însele, pentru că o adresă sursă este o dată cu caracter personal a cuiva care nu este clientul nostru.

A opri un punct de intrare nu este același lucru cu a-l revoca. Oprit răspunde 403 și poate fi pornit din nou; revocat răspunde 410 pentru totdeauna, iar URL-ul nu mai este dat niciodată.

Revizii și rulări

Două întrebări care seamănă au aici două răspunsuri diferite. Cine a schimbat ce și când este o revizie. Ce a parcurs cu adevărat această rulare anume este o copie păstrată pe rularea însăși. O fotografie nu poate răspunde la prima întrebare, iar o revizie nu poate răspunde la a doua, deci există amândouă.

  • Fiecare publicare scrie o revizie, chiar și o publicare care nu a schimbat nimic. Numărul urcă pe flux și nu este niciodată refolosit.
  • Diferența dintre două revizii este o listă lizibilă și nu JSON brut: un nod adăugat, scos sau modificat cu câmpurile numite, un fir adăugat sau scos. Unde se află un nod pe pânză nu este o modificare.
  • Restaurarea nu derulează înapoi. Scrie desenul vechi ca o revizie nouă peste istorie, cu o notă despre locul din care a venit.
  • Fiecare rulare păstrează desenul pe care l-a parcurs. Modificarea ulterioară a unui flux nu rescrie niciodată ce a făcut o rulare mai veche.
  • O rulare are un rând pentru fiecare nod vizitat, cu rezultatul și ieșirea prin care a plecat, și un rând pentru fiecare nod nevizitat, cu motivul. Nevizitat este un fapt care merită notat, nu o absență.
  • Lista rulărilor filtrează după declanșator, stare și revizie și se exportă în CSV. Exportul se oprește la 5000 de rânduri și o spune chiar în fișier, în loc să se termine în tăcere.

Șabloanele de script țin alături o istorie proprie: fiecare versiune salvată a conținutului și o diferență linie cu linie între oricare două dintre ele.

O execuție care ajunge la o aprobare este pusă în așteptare: parcurgerea este salvată, execuția trece în așteptare, iar un worker o continuă imediat ce cineva decide sau expiră termenul. Restul este parcurs în continuare în cererea care a pornit-o, și de aceea o pauză merge până la cinci minute.