func()

in controllers/crds/cninode_controller.go [111:237]


func (r *CNINodeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
	cniNode := &v1alpha1.CNINode{}
	if err := r.Client.Get(ctx, req.NamespacedName, cniNode); err != nil {
		// Ignore not found error
		return ctrl.Result{}, client.IgnoreNotFound(err)
	}

	nodeFound := true
	node := &v1.Node{}
	if err := r.Client.Get(ctx, req.NamespacedName, node); err != nil {
		if errors.IsNotFound(err) {
			nodeFound = false
		} else {
			r.log.Error(err, "failed to get the node object in CNINode reconciliation, will retry")
			// Requeue request so it can be retried
			return ctrl.Result{}, err
		}
	}

	if cniNode.GetDeletionTimestamp().IsZero() {
		shouldPatch := false
		cniNodeCopy := cniNode.DeepCopy()
		// Add cluster name tag if it does not exist
		val, ok := cniNode.Spec.Tags[config.VPCCNIClusterNameKey]
		if !ok || val != r.clusterName {
			if len(cniNodeCopy.Spec.Tags) != 0 {
				cniNodeCopy.Spec.Tags[config.VPCCNIClusterNameKey] = r.clusterName
			} else {
				cniNodeCopy.Spec.Tags = map[string]string{
					config.VPCCNIClusterNameKey: r.clusterName,
				}
			}
			shouldPatch = true
		}
		// if node exists, get & add OS label if it does not exist on CNINode
		if nodeFound {
			nodeLabelOS := node.ObjectMeta.Labels[config.NodeLabelOS]
			val, ok = cniNode.ObjectMeta.Labels[config.NodeLabelOS]
			if !ok || val != nodeLabelOS {
				if len(cniNodeCopy.ObjectMeta.Labels) != 0 {
					cniNodeCopy.ObjectMeta.Labels[config.NodeLabelOS] = nodeLabelOS
				} else {
					cniNodeCopy.ObjectMeta.Labels = map[string]string{
						config.NodeLabelOS: nodeLabelOS,
					}
				}
				shouldPatch = true
			}
		}

		if shouldPatch {
			r.log.Info("patching CNINode to add required fields Tags and Labels", "cninode", cniNode.Name)
			return ctrl.Result{}, r.Client.Patch(ctx, cniNodeCopy, client.MergeFromWithOptions(cniNode, client.MergeFromWithOptimisticLock{}))
		}

		// Add finalizer if it does not exist
		if err := r.finalizerManager.AddFinalizers(ctx, cniNode, config.NodeTerminationFinalizer); err != nil {
			r.log.Error(err, "failed to add finalizer on CNINode, will retry", "cniNode", cniNode.Name, "finalizer", config.NodeTerminationFinalizer)
			return ctrl.Result{}, err
		}
		return ctrl.Result{}, nil

	} else { // CNINode is marked for deletion
		if !nodeFound {
			//  node is also deleted, proceed with running the cleanup routine and remove the finalizer

			// run cleanup for Linux nodes only
			if val, ok := cniNode.ObjectMeta.Labels[config.NodeLabelOS]; ok && val == config.OSLinux {
				r.log.Info("running the finalizer routine on cniNode", "cniNode", cniNode.Name)
				// run cleanup when node id is present
				if nodeID, ok := cniNode.Spec.Tags[config.NetworkInterfaceNodeIDKey]; ok && nodeID != "" {
					if err := r.newResourceCleaner(nodeID, r.eC2Wrapper, r.vpcId).DeleteLeakedResources(); err != nil {
						r.log.Error(err, "failed to cleanup resources during node termination")
						ec2API.NodeTerminationENICleanupFailure.Inc()
					}
				}
			}

			if err := r.finalizerManager.RemoveFinalizers(ctx, cniNode, config.NodeTerminationFinalizer); err != nil {
				r.log.Error(err, "failed to remove finalizer on CNINode, will retry", "cniNode", cniNode.Name, "finalizer", config.NodeTerminationFinalizer)
				return ctrl.Result{}, err
			}
			return ctrl.Result{}, nil
		} else {
			// node exists, do not run the cleanup routine(periodic cleanup routine will delete leaked ENIs), remove the finalizer,
			// delete old CNINode and recreate CNINode from the object

			// Create a copy to recreate CNINode object
			newCNINode := &v1alpha1.CNINode{
				ObjectMeta: metav1.ObjectMeta{
					Name:            cniNode.Name,
					Namespace:       "",
					OwnerReferences: cniNode.OwnerReferences,
					// TODO: should we include finalizers at object creation or let controller patch it on Create/Update event?
					Finalizers: cniNode.Finalizers,
				},
				Spec: cniNode.Spec,
			}

			if err := r.finalizerManager.RemoveFinalizers(ctx, cniNode, config.NodeTerminationFinalizer); err != nil {
				r.log.Error(err, "failed to remove finalizer on CNINode, will retry")
				return ctrl.Result{}, err
			}
			// wait till CNINode is deleted before recreation as the new object will be created with same name to avoid "object already exists" error
			if err := r.waitTillCNINodeDeleted(client.ObjectKeyFromObject(newCNINode)); err != nil {
				// raise event if CNINode was not deleted after removing the finalizer
				r.k8sAPI.BroadcastEvent(cniNode, utils.CNINodeDeleteFailed, "CNINode delete failed, will be retried",
					v1.EventTypeWarning)
				// requeue to retry CNINode deletion if node exists
				return ctrl.Result{}, err
			}

			r.log.Info("creating CNINode after it has been deleted as node still exists", "cniNode", newCNINode.Name)
			recreateCNINodeCallCount.Inc()
			if err := r.createCNINodeFromObj(ctx, newCNINode); err != nil {
				recreateCNINodeErrCount.Inc()
				// raise event on if CNINode is deleted and could not be recreated by controller
				utils.SendNodeEventWithNodeName(r.k8sAPI, node.Name, utils.CNINodeCreateFailed,
					"CNINode was deleted and failed to be recreated by the vpc-resource-controller", v1.EventTypeWarning, r.log)
				// return nil as object is deleted and we cannot recreate the object now
				return ctrl.Result{}, nil
			}
			r.log.Info("successfully recreated CNINode", "cniNode", newCNINode.Name)
		}
	}
	return ctrl.Result{}, nil
}