Description
Edit from @negz: I'd like to drop the resource.ClientApplicator
. For *Unstructured
resources we've mostly already replaced it with SSA. For concrete types, I've found a few places where it's been easy to just replace it with Get
+ Update
. Using https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/controller/controllerutil#CreateOrUpdate would probably be fine too.
Original issue follows:
What happened?
Looking at the claim controller, updating the XR (cp
in the code), the following race with other actors in the system (controllers, user with kubectl) exists:
- reconciler gets latest XR state
cp
- reconciler updates in the
cp
whatever it wants to update - reconciler calls Apply with
cp
- applicator gets current state via client
- applicator sets RV
cp.RV = current.RV
- applicator calls update with cp
Assuming between 1 and 3a some client updates the XR out of band, e.g. some other controller, or kubectl. 3c will wipe out that change, won't it?
Above is just one example for that issue. The apply func is widely used in Crossplane.
How can we reproduce it?
This will likely show up as subtle bugs as this is some kind of time travel, or controllers fighting for their desired state of the world and racing with their informers.
What environment did it happen in?
Crossplane version: main