Crossplane Provider Mechanics
The way a provider has to be implemented is still (as of Crossplane v1.19) rather not obvious.
Crossplane does have a simple provider development guide.
Basically, one has to implement 2 interfaces in Go: managed.ExternalConnecter
and managed.ExternalClient
.
There is some more boilerplate required to set it up correctly, but not relevant in this page. |
The managed.ExternalConnecter
interface is meant as an entrypoint for every reconciliation.
It’s the step where the runtime fetches some credentials to connect to an external cloud API.
The return value of ExternalConnector.Connect()
is an instance of managed.ExternalClient
itself.
managed.ExternalClient
features the 4 basic CRUD methods: Create()
, Observe()
, Update()
, Delete()
.
By implementing Connect
and these 4 CRUD methods everything should be in place to get started for a managed CRD.
What is not comprehensibly explained is how the reconciliation actually works and that can have a significant impact to the implementation. From the GoDocs it’s not clear how these methods actually have to be implemented and how they’re used (how often, in what order).
So this is the basic order of the reconciliation performed by crossplane-runtime
:
-
Controller attempts to reconcile the resource (
Reconcile()
fromcontroller-runtime
library) -
Controller calls
Connect()
from themanaged.ExternalConnecter
interface. Implementers are expected to create some client to interact with the external cloud API. -
Controller calls Observe() from the
managed.ExternalClient
interface. The result determines the next call:-
If resource doesn’t exist,
Create()
is called. -
If resource does exist but doesn’t match desired state,
Update()
is called. -
If resource does exist and matches desired state, no method is called anymore.
-
-
Controller does another reconciliation (start from top) even if
Create()
orUpdate()
returned no error.
For deletions, the order is slightly different:
-
Controller attempts to reconcile the resource (
Reconcile()
fromcontroller-runtime
library) This is possible thanks to the finalizer that the crossplane runtime manages. -
Controller calls
Connect()
from themanaged.ExternalConnecter
interface. -
Controller calls Observe() from the
managed.ExternalClient
interface. The result determines the next call:-
If resource still exists,
Delete()
is called. -
If resource doesn’t exist, no method is called anymore.
-
-
Controller does another reconciliation (start from top) even if
Delete()
returned no error.
After |
Status updates are only allowed from within the |