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
}