in pkg/controller/direct/directbase/directbase_controller.go [243:360]
func (r *reconcileContext) doReconcile(ctx context.Context, u *unstructured.Unstructured) (requeue bool, err error) {
logger := log.FromContext(ctx)
cc, ccc, err := kccstate.FetchLiveKCCState(ctx, r.Reconciler.Client, r.NamespacedName)
if err != nil {
return true, err
}
am := resourceactuation.DecideActuationMode(cc, ccc)
switch am {
case v1beta1.Reconciling:
logger.V(2).Info("Actuating a resource as actuation mode is \"Reconciling\"", "resource", r.NamespacedName)
case v1beta1.Paused:
logger.Info("Skipping actuation of resource as actuation mode is \"Paused\"", "resource", r.NamespacedName)
// add finalizers for deletion defender to make sure we don't delete cloud provider resources when uninstalling
if u.GetDeletionTimestamp().IsZero() {
if err := r.ensureFinalizers(ctx, u); err != nil {
return false, nil
}
}
return false, nil
default:
return false, fmt.Errorf("unknown actuation mode %v", am)
}
adapter, err := r.Reconciler.model.AdapterForObject(ctx, r.Reconciler.Client, u)
if err != nil {
if unwrappedErr, ok := lifecyclehandler.CausedByUnresolvableDeps(err); ok {
logger.Info(unwrappedErr.Error(), "resource", k8s.GetNamespacedName(u))
return r.handleUnresolvableDeps(ctx, u, unwrappedErr)
}
return false, r.handleUpdateFailed(ctx, u, err)
}
// To create, update or delete the GCP object, we need to get the GCP object first.
// Because the object contains the cloud service information like `selfLink` `ID` required to validate
// the resource uniqueness before updating/deleting.
existsAlready, err := adapter.Find(ctx)
if err != nil {
if unwrappedErr, ok := lifecyclehandler.CausedByUnresolvableDeps(err); ok {
logger.Info(unwrappedErr.Error(), "resource", k8s.GetNamespacedName(u))
return r.handleUnresolvableDeps(ctx, u, unwrappedErr)
}
return false, r.handleUpdateFailed(ctx, u, err)
}
defer execution.RecoverWithInternalError(&err)
if !u.GetDeletionTimestamp().IsZero() {
if !k8s.HasFinalizer(u, k8s.ControllerFinalizerName) {
// Resource has no controller finalizer; no finalization necessary
return false, nil
}
if k8s.HasFinalizer(u, k8s.DeletionDefenderFinalizerName) {
// deletion defender has not yet finalized; requeuing
logger.Info("deletion defender has not yet finalized; requeuing", "resource", k8s.GetNamespacedName(u))
return true, nil
}
if !k8s.HasAbandonAnnotation(u) {
deleteOp := NewDeleteOperation(r.Reconciler.Client, u)
if _, err := adapter.Delete(ctx, deleteOp); err != nil {
if !errors.Is(err, k8s.ErrIAMNotFound) && !k8s.IsReferenceNotFoundError(err) {
if unwrappedErr, ok := lifecyclehandler.CausedByUnresolvableDeps(err); ok {
logger.Info(unwrappedErr.Error(), "resource", k8s.GetNamespacedName(u))
resource, err := toK8sResource(u)
if err != nil {
return false, fmt.Errorf("error converting k8s resource while handling unresolvable dependencies event: %w", err)
}
// Requeue resource for reconciliation with exponential backoff applied
return true, r.Reconciler.HandleUnresolvableDeps(ctx, resource, unwrappedErr)
}
return false, r.handleDeleteFailed(ctx, u, err)
}
}
}
return false, r.handleDeleted(ctx, u)
}
if err := r.ensureFinalizers(ctx, u); err != nil {
return false, err
}
// set the etag to an empty string, since IAMPolicy is the authoritative intent, KCC wants to overwrite the underlying policy regardless
//policy.Spec.Etag = ""
hasSetReadyCondition := false
requeueRequested := false
if !existsAlready {
createOp := NewCreateOperation(r.Reconciler.LifecycleHandler, r.Reconciler.Client, u)
if err := adapter.Create(ctx, createOp); err != nil {
if unwrappedErr, ok := lifecyclehandler.CausedByUnresolvableDeps(err); ok {
logger.Info(unwrappedErr.Error(), "resource", k8s.GetNamespacedName(u))
return r.handleUnresolvableDeps(ctx, u, unwrappedErr)
}
return false, r.handleUpdateFailed(ctx, u, fmt.Errorf("error creating: %w", err))
}
hasSetReadyCondition = createOp.HasSetReadyCondition
requeueRequested = createOp.RequeueRequested
} else {
updateOp := NewUpdateOperation(r.Reconciler.LifecycleHandler, r.Reconciler.Client, u)
if err := adapter.Update(ctx, updateOp); err != nil {
if unwrappedErr, ok := lifecyclehandler.CausedByUnresolvableDeps(err); ok {
logger.Info(unwrappedErr.Error(), "resource", k8s.GetNamespacedName(u))
return r.handleUnresolvableDeps(ctx, u, unwrappedErr)
}
return false, r.handleUpdateFailed(ctx, u, fmt.Errorf("error updating: %w", err))
}
hasSetReadyCondition = updateOp.HasSetReadyCondition
requeueRequested = updateOp.RequeueRequested
}
if !hasSetReadyCondition && isAPIServerUpdateRequired(u) {
return requeueRequested, r.handleUpToDate(ctx, u)
}
return requeueRequested, nil
}