func()

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
}