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-workflow voor het aanmaken van een VM

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’:

Create-actie binnen het VM-domein

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

Grafische interface van Foundry

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.

Dataset voor dynamische dropdowns

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

Automatisch gegenereerde API van Foundry

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

CLI van Foundry

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:

Eenvoudige create-VM-workflow

Voordat Foundry taken uitvoert, kan het eerst afhankelijkheden (dependencies) controleren.

Dependencies van de create-VM-workflow

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:

Volgorde van taken binnen de create-VM-workflow

Taken kunnen teruggegeven waarden van eerdere taken ontvangen, evenals workflow-dependencies en services die via Laravel’s servicecontainer worden geïnjecteerd.

Taak binnen de create-VM-workflow

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:

SysteemFunctie
InfscapeBack-ups
LibreNMSMonitoring via SNMP
NetBoxDatacenterbeheer en IP-adresbeheer (DCIM/IPAM)
Interne API’sInterne infrastructuurdiensten
PowerDNSForward en reverse DNS
Proxmox VEVirtualisatie
SensuRealtime 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.

Mislukte workflow in Foundry

Vervolgens kunnen ze bekijken bij welke taak het misging:

Mislukte taak in Foundry

En de volledige traceback van de exception raadplegen:

Exception en traceback van een taak

Zodra het onderliggende probleem is opgelost, kan de engineer de workflow opnieuw proberen.

Workflow opnieuw uitvoeren

Foundry maakt daarvoor een nieuwe poging (attempt) aan:

Tweede poging van een workflow

Taken die tijdens de vorige poging al zijn geslaagd, krijgen de status ‘Cached’ en worden niet opnieuw uitgevoerd.

Gecachete taken tijdens de tweede poging

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.

Geplande taak in Foundry

In de GUI kunnen engineers de laatste zeven uitvoeringen van iedere geplande taak zien:

Overzicht van geplande taken

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.