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.
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ă.
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ă.
| Nod | Ieșiri | Ce face și unde se oprește |
|---|---|---|
trigger | out | Singura 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. |
script | ok · error | Redă 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. |
switch | rule-0 … · otherwise | Se 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. |
if | true · false | O 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. |
set | out | Scrie î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. |
http | ok · error | Apelează 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. |
notify | out | Scrie 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. |
action | ok · error | Porneș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. |
delay | out | Pune 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. |
approval | approved · rejected | Oprește execuția până când o persoană aprobă sau respinge, cu un termen și un rezultat ales dacă nu răspunde nimeni. |
foreach | loop · done | Parcurge ieșirea buclei o dată pentru fiecare element al unei liste, citită ca JSON, unul pe linie sau separate prin virgule. |
repeat | loop · done | Parcurge 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. |
subflow | ok · error | Execută un alt flux al acestui cont și așteaptă rezultatul. Copilul primește intrarea sa ca input.*. |
log | out | Scrie 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. |
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.
| Declanșator | Când rulează | Ce există și ce nu |
|---|---|---|
server.provisioned | O dată, imediat după ce o comandă a produs mașina. | Totul. Este singurul moment în care există fiecare grup. |
server.reinstalled | După 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.deleted | Imediat 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. |
manual | Niciodată 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ă. |
webhook | Imediat 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. |
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.
| Grup | Există la | Ce conține |
|---|---|---|
org.* | Orice declanșator | Contul: id, nume și nume scurt. |
user.* | Cele patru de server | Persoana pentru care acționează rularea: id, nume și adresă electronică. |
flow.* | Orice declanșator | Acest flux și această rulare: nume, id de rulare, numărul și totalul pașilor, declanșator și ora de început. |
server.* | Cele patru de server | Mașina: nume, nume de gazdă, tip, stare, id extern, nod, nuclee, memorie, disc și data creării. |
server.compute.* | Cele patru de server | Ce 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 server | Planul 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 server | Adresa dată și dacă este de versiunea 4 sau 6. |
network.* | Cele patru de server | Tot ce înconjoară acea adresă: cidr, poartă, mască, rețea, difuzare și rezolvatoarele. |
prefix.* | Cele patru de server | Lotul de adrese din care provine, cu intervalul și părintele lui. |
integration.* | Cele patru de server | Legătura care poartă mașina: nume, tip, nod, stocare, punte și intervalul de vmid. |
agent.* | Cele patru de server | Agentul care a făcut treaba: nume, stare, versiune, nume de gazdă, sistem de operare, nucleu și nuclee de procesare. |
input.* | Manual și webhook | Ce ați injectat, sau ce a trimis webhookul. Cheile vă aparțin, iar selectorul le urmează. |
webhook.* | Numai webhook | Cererea însăși: care punct de intrare, când a sosit și de la ce adresă. |
state.* | După un nod set | Ceea 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 http | Pentru 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 niciunul | Gândit pentru echipamente de rețea. Nu există niciun furnizor care să îl poată umple, deci astăzi niciun flux nu îl poate folosi. |
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.
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.
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ă.
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.
- 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.
- 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.
- Î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ă.
| Schemă | Ce face |
|---|---|
none | Nicio 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_sha256 | Expeditorul 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. |
bearer | Expeditorul 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.
# 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"| Limită | Amănunte |
|---|---|
body | 64 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ă. |
rate | 60 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. |
payload | Un obiect JSON de un singur nivel. Fiecare cheie devine input urmat de acea cheie; un obiect imbricat este refuzat în loc să fie aplatizat. |
allowlist | Cel mult 20 de adrese sau intervale, în v4 sau v6. Gol înseamnă nicio restricție. |
endpoints | Cel mult 50 de puncte de intrare pentru fiecare cont. |
| Cod | Înțeles |
|---|---|
202 | Acceptată. 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. |
401 | Semnă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. |
403 | Punctul de intrare este oprit, sau adresa sursă nu se află în listă. |
404 | Nu există niciun punct de intrare cu acest identificator. |
410 | Punctul 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. |
413 | Corpul este mai mare decât acceptă acest punct de intrare. |
422 | Corpul nu este un obiect JSON de un singur nivel. |
429 | Peste 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.
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.