diff --git a/controllers/vspherevm_controller.go b/controllers/vspherevm_controller.go index f78c765729..862c0dc1f4 100644 --- a/controllers/vspherevm_controller.go +++ b/controllers/vspherevm_controller.go @@ -27,6 +27,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" apitypes "k8s.io/apimachinery/pkg/types" kerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/tools/record" "k8s.io/klog/v2" "k8s.io/utils/ptr" @@ -41,6 +42,7 @@ import ( "sigs.k8s.io/cluster-api/util/predicates" ctrl "sigs.k8s.io/controller-runtime" ctrlbldr "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/client" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" ctrlutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -252,6 +254,7 @@ func (r vmReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.R defer func() { log.V(4).Info("VSphereVM.Status.TaskRef OnExit", "taskRef", vmContext.VSphereVM.Status.TaskRef) }() + originalTaskRef := vmContext.VSphereVM.Status.TaskRef // Always issue a patch when exiting this function so changes to the // resource are patched back to the API server. @@ -269,6 +272,25 @@ func (r vmReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.R if err := vmContext.Patch(ctx); err != nil { reterr = kerrors.NewAggregate([]error{reterr, err}) } + + // Wait until VSphereVM is updated in the cache if the `.Status.TaskRef` field changes. + // Note: We have to do this because otherwise using a cached client in current state could + // return a stale state of a VSphereVM we just patched (because the cache might be stale). + if vmContext.VSphereVM.Status.TaskRef != originalTaskRef { + err = wait.PollUntilContextTimeout(ctx, 5*time.Millisecond, 5*time.Second, true, func(ctx context.Context) (bool, error) { + key := client.ObjectKey{Namespace: vmContext.VSphereVM.GetNamespace(), Name: vmContext.VSphereVM.GetName()} + cachedMD := &infrav1.VSphereVM{} + if err := r.Client.Get(ctx, key, cachedMD); err != nil { + return false, err + } + return originalTaskRef != cachedMD.Status.TaskRef, nil + }) + if reterr != nil { + reterr = kerrors.NewAggregate([]error{reterr, err}) + } else { + reterr = err + } + } }() if vsphereVM.ObjectMeta.DeletionTimestamp.IsZero() {