Foundry koppelt acht verschillende systemen aan elkaar, ondersteunt meer dan zestig acties en genereert automatisch API-endpoints, CLI-commando’s en formulieren voor de grafische interface. Dat allemaal in tien minuten uitleggen bleek nogal ambitieus. We moesten de presentatie dan ook voortijdig afbreken.
Gelukkig hebben we bij het schrijven van een artikel geen tijdslimiet. Voor wie bij LaraFest aanwezig was, onze presentatie heeft gemist of benieuwd is wat je buiten traditionele webapplicaties nog meer met Laravel kunt bouwen: hierbij de uitgebreide uitleg.
Waarom we Foundry meenamen naar LaraFest
Laravel kennen de meeste developers als framework voor webapplicaties. Bij Cyberfusion gebruiken we het óók om de infrastructuur te beheren waarop die applicaties draaien.
Daarvoor hebben we Foundry ontwikkeld: onze eigen workflow-engine, die infrastructuurhandelingen automatiseert over acht verschillende systemen. Denk aan Proxmox, NetBox en PowerDNS.
Het aanmaken van een virtuele machine is bijvoorbeeld een stuk ingewikkelder dan Proxmox opdracht geven om er eentje te starten. Er moeten IP-adressen worden toegewezen, DNS-records worden aangemaakt, monitoring worden ingesteld en back-ups worden geconfigureerd. Al die stappen moeten in de juiste volgorde plaatsvinden, en als ergens iets misgaat, moet dat netjes worden afgehandeld.
Veel organisaties gebruiken hiervoor werkinstructies. Engineers volgen dan handmatig een reeks stappen in verschillende systemen.
Wij hebben wel wat beters te doen: Foundry neemt die handelingen volledig over.
We hebben Foundry om drie redenen gebouwd:
- Voorspelbaar infrastructuurbeheer. Iedere handeling volgt een vastgelegde workflow. Daarmee verkleinen we de kans op menselijke fouten.
- Volledige automatisering. Ons managed-hostingplatform Cyberfusion Core moet infrastructuur kunnen aanmaken en beheren via API’s.
- Schaalbaarheid. Naarmate onze infrastructuur groeit, worden ook de bijbehorende processen ingewikkelder. Door die processen nu goed vast te leggen, houden we ze beheersbaar.
Voor LaraFest was vooral interessant hoe we hiervoor Laravel gebruiken. We combineren bestaande onderdelen van het framework met flink wat zelfontwikkelde functionaliteit.
Wat is Foundry precies?
Foundry is een workflow-engine. Een gebruiker, of een ander systeem, start een actie zoals ‘create VM’ en geeft de benodigde parameters mee.
Foundry maakt vervolgens een workflow aan met een vooraf bepaalde reeks taken. Iedere taak voert een afzonderlijke handeling uit, zoals het aanmaken van de virtuele machine in Proxmox of het registreren ervan in NetBox.
Gaat er iets mis? Dan stopt de workflow. Een engineer kan de fout onderzoeken, oplossen en de workflow opnieuw proberen, zonder alle eerder geslaagde taken opnieuw uit te voeren.
Zo ziet onze workflow voor het aanmaken van een virtuele machine eruit:
Foundry kent vier basisbegrippen:
- Domains: groepen bij elkaar horende handelingen, zoals ‘VM’.
- Actions: handelingen die je kunt starten, zoals ‘create VM’.
- Workflows: afzonderlijke uitvoeringen van een actie, bijvoorbeeld ‘create VM example.com’.
- Tasks: de individuele stappen binnen een workflow, zoals ‘create VM in NetBox’.
Ten tijde van LaraFest ondersteunde Foundry 63 acties. Daaronder vielen het aanmaken van virtuele machines, het configureren van FHRP-groepen voor VRRP, het registreren van back-upclients en monitoringgebruikers en het aanmaken van VLAN’s.
Laravel onder de motorkap
Een van de redenen om Foundry voor een LarAward aan te melden, was de manier waarop we bestaande Laravel-componenten gebruiken voor iets waar het framework niet specifiek voor is ontwikkeld: volledige automatisering van infrastructuur.
Neem bijvoorbeeld de actie ‘create VM’ binnen het domein ‘VM’:
De actie ontvangt een VmCreateRequest, die Laravel’s FormRequest uitbreidt voor de basisvalidatie van invoer.
Na validatie levert de request een Data Transfer Object (DTO) op, waarin alle gegevens staan die nodig zijn om de actie uit te voeren.
Die opzet is belangrijk, omdat we iedere actie op drie manieren beschikbaar willen maken: via de grafische interface, de CLI en de API.
Automatisering automatiseren
Aanvankelijk wilden we per actie bepalen via welke interface die beschikbaar moest zijn. Sommige handelingen zouden uitsluitend via de API worden uitgevoerd, terwijl andere alleen voor engineers in de GUI beschikbaar zouden zijn.
Al snel kwamen we tot de conclusie dat dit onnodig ingewikkeld, foutgevoelig en repetitief was. Met ruim zestig acties wilden we dezelfde bedrijfslogica zeker niet drie keer implementeren.
Daarom bouwden we een systeem waarmee acties zichzelf automatisch registreren.
Voor iedere actie genereert Foundry:
- Een GUI-formulier op basis van de bijbehorende request.
- Een API-endpoint, inclusief OpenAPI-specificatie.
- Een CLI-commando.
Alle drie gebruiken dezelfde validatie en achterliggende logica.
De GUI
Formulieren worden volledig automatisch gegenereerd op basis van de acties en hun requests.
Sommige formuliervelden zijn afhankelijk van externe gegevens. De beschikbare tenants worden bijvoorbeeld rechtstreeks uit NetBox opgehaald.
Daarvoor ontwikkelden we een systeem met datasets. Een dataset haalt gegevens uit een willekeurige bron op en kan die vervolgens verwerken, bijvoorbeeld door waarden te filteren op basis van gebruikersrechten.
Dankzij Livewire worden datasets automatisch opnieuw geladen wanneer relevante formuliervelden veranderen. De resultaten worden gecachet voor specifieke combinaties van argumenten.
Selecteert een engineer bijvoorbeeld een tenant bij het aanmaken van een VM? Dan toont het dropdownmenu voor IP-adressen automatisch alleen de adressen die bij die tenant horen.
De API
Ook API-endpoints en hun OpenAPI-specificaties worden dynamisch gegenereerd.
Endpoints volgen in principe het formaat /api/{domain}/{action}. Voor ‘create’- en ‘delete’-acties maken we een uitzondering. Het aanmaken van een VM verloopt bijvoorbeeld via POST /vm, zonder /create aan het einde.
De CLI
De CLI gebruikt dezelfde acties als de GUI en API. Ook hiervoor hoeven we dus geen afzonderlijke implementaties te onderhouden.
Het resultaat: voegen we één nieuwe actie toe, dan is die automatisch via alle drie de interfaces beschikbaar.
Betrouwbare workflows bouwen met Laravel
Het automatisch genereren van interfaces scheelt een hoop werk, maar het belangrijkste onderdeel van Foundry is het betrouwbaar uitvoeren van ingewikkelde infrastructuurhandelingen.
Een actie maakt een workflow aan, en iedere workflow bestaat uit een reeks taken.
In de eenvoudigste vorm ziet de workflow voor het aanmaken van een VM er zo uit:
Voordat Foundry taken uitvoert, kan het eerst afhankelijkheden (dependencies) controleren.
Met dependencies voeren we ingewikkeldere controles uit dan met de reguliere validatie van een FormRequest. Ze kunnen bovendien waarden teruggeven die volgende dependencies of taken weer gebruiken.
Oorspronkelijk gebruikten we hiervoor aangepaste validatieregels. Naarmate Foundry groeide, werd dat steeds lastiger te onderhouden. Iedere actie had net andere voorwaarden, en gegevens die tijdens één controle werden opgehaald, waren vaak ook nodig voor andere controles.
Met dependencies konden we die logica beter structureren en gegevens hergebruiken.
Zodra alle controles zijn geslaagd, voert Foundry de taken in de vastgelegde volgorde uit:
Taken kunnen teruggegeven waarden van eerdere taken ontvangen, evenals workflow-dependencies en services die via Laravel’s servicecontainer worden geïnjecteerd.
Voor de uitvoering gebruiken we Laravel’s ingebouwde queuesysteem.
Wanneer een workflow wordt gestart, plaatst Foundry de taken in de queue, inclusief de benodigde waarden uit dependencies. Vervolgens wordt de workflow asynchroon uitgevoerd.
De aanroeper ontvangt direct een UUID waarmee de status van de workflow via de GUI, API of CLI kan worden opgevraagd.
Iedere taak kan vier statussen hebben:
- Successful: de taak is geslaagd en kan waarden teruggeven aan volgende taken.
- Skipped: de taak is overgeslagen, inclusief een leesbare toelichting waarom.
- Failed: de taak is mislukt. De workflow stopt en volgende taken worden overgeslagen.
- Terminated: de uitvoering is expliciet beëindigd. Ook dan stopt de workflow.
Acht systemen, één workflow-engine
Tijdens LaraFest lieten we ook zien hoe Foundry verschillende systemen samenbrengt die anders afzonderlijk moeten worden beheerd.
Ten tijde van de presentatie integreerde Foundry met acht systemen:
| Systeem | Functie |
|---|---|
| Infscape | Back-ups |
| LibreNMS | Monitoring via SNMP |
| NetBox | Datacenterbeheer en IP-adresbeheer (DCIM/IPAM) |
| Interne API’s | Interne infrastructuurdiensten |
| PowerDNS | Forward en reverse DNS |
| Proxmox VE | Virtualisatie |
| Sensu | Realtime monitoring |
Een enkele infrastructuurhandeling kan meerdere van deze systemen aanspreken. En ieder systeem heeft zijn eigen API, validatieregels en mogelijke foutmeldingen.
Tijdelijke storingen komen voor. API’s gedragen zich soms anders dan verwacht. En niet iedere API is even goed gedocumenteerd.
Daar moet Foundry mee kunnen omgaan.
Wat gebeurt er als een workflow mislukt?
In de GUI zien engineers direct welke workflow is mislukt en welke exception de fout heeft veroorzaakt.
Vervolgens kunnen ze bekijken bij welke taak het misging:
En de volledige traceback van de exception raadplegen:
Zodra het onderliggende probleem is opgelost, kan de engineer de workflow opnieuw proberen.
Foundry maakt daarvoor een nieuwe poging (attempt) aan:
Taken die tijdens de vorige poging al zijn geslaagd, krijgen de status ‘Cached’ en worden niet opnieuw uitgevoerd.
Foundry bewaart de volledige uitvoeringsgeschiedenis, inclusief eerdere pogingen. Dat is belangrijk voor debugging en auditing.
Zo kunnen engineers een mislukte infrastructuurhandeling hervatten zonder handmatig uit te zoeken welke stappen al zijn uitgevoerd en welke nog niet.
Geplande infrastructuurautomatisering
Een ander onderdeel dat we tijdens LaraFest bespraken, was het automatisch uitvoeren van periodieke taken.
Foundry controleert bijvoorbeeld iedere dag of virtuele machines binnen Proxmox-pools voldoende over verschillende fysieke hypervisors zijn verdeeld.
Voor iedere Proxmox-pool wordt een afzonderlijke workflow gestart. Een geplande taak kan daarom meerdere workflows teruggeven in plaats van slechts één.
In de GUI kunnen engineers de laatste zeven uitvoeringen van iedere geplande taak zien:
Daarmee zien ze snel welke controles zijn mislukt, wanneer dat gebeurde en wat de oorzaak was.
Na LaraFest: hoe verder met Foundry?
Toen we Foundry tijdens LaraFest 2024 presenteerden, draaide het platform al ruim een jaar in productie.
We werkten op dat moment aan verschillende uitbreidingen, waaronder licentiebeheer, uitgebreidere Ansible-integraties en ondersteuning voor aanvullende 802.1Q-modi.
Foundry laat zien dat Laravel voor veel meer geschikt is dan het bouwen van traditionele webapplicaties. Met bestaande onderdelen zoals queues, validatie en dependency-injection hebben we een robuuste en uitbreidbare basis voor een systeem dat onze volledige infrastructuur aanstuurt. Daarbovenop hebben we onze eigen workflow-engine ontwikkeld voor de specifieke eisen van infrastructuurbeheer.
Het was leuk om Foundry tijdens LaraFest te mogen presenteren. De nominatie voor een LarAward maakt dat natuurlijk extra bijzonder.