func()

in internal/controllers/liveness/namespace.go [53:124]


func (c *namespaceController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
	logger := logr.FromContextOrDiscard(ctx)

	ns := &corev1.Namespace{}
	ns.Name = req.Name
	err := c.client.Get(ctx, req.NamespacedName, ns)
	if client.IgnoreNotFound(err) != nil {
		logger.Error(err, "failed to get namespace")
		return ctrl.Result{}, err
	}

	const annoKey = "eno.azure.io/recreation-reason"
	const annoValue = "OrphanedResources"

	// Delete the recreated namespace immediately.
	// Its finalizers will keep it around until we've had time to remove our finalizers.
	logger = logger.WithValues("resourceNamespace", ns.Name)
	if ns.Annotations != nil && ns.Annotations[annoKey] == annoValue {
		if ns.DeletionTimestamp != nil {
			return ctrl.Result{}, c.cleanup(ctx, req.Name)
		}
		err := c.client.Delete(ctx, ns)
		if err != nil {
			logger.Error(err, "failed to delete namespace")
			return ctrl.Result{}, err
		}
		logger.V(0).Info("deleting recreated namespace")
		return ctrl.Result{}, nil
	}
	if err == nil {
		// Successful GETs mean the namespace still exists - nothing for us to do
		return ctrl.Result{}, nil
	}

	// Avoid recreating the namespace when it doesn't have any orphaned resources
	for i := 1; true; i++ {
		var foundOrphans bool
		for _, kind := range orphanableKinds {
			hasOrphans, res, err := c.findOrphans(ctx, ns.Name, kind)
			if err != nil {
				logger.Error(err, "failed to find orphaned resources", "resourceKind", kind)
				return ctrl.Result{}, err
			}
			if res != nil {
				return *res, nil
			}
			if hasOrphans {
				foundOrphans = true
			}
		}
		if !foundOrphans {
			return ctrl.Result{}, nil
		}
		if i >= c.orphanCheckIterations {
			break
		}

		// Sleep a bit before the next check to let informers catch up.
		time.Sleep(time.Second / 2)
	}

	// Recreate the namespace briefly so we can remove the finalizers.
	// Any updates (including finalizer updates) will fail if the namespace doesn't exist.
	ns.Annotations = map[string]string{annoKey: annoValue}
	err = c.client.Create(ctx, ns)
	if err != nil {
		logger.Error(err, "failed to create namespace")
		return ctrl.Result{}, err
	}
	logger.V(0).Info("recreated missing namespace to free orphaned resources")
	return ctrl.Result{}, nil
}