Skip to content

Commit 2fb7d9a

Browse files
committed
Ensure infrastructure is destroyed before deleting the node
If there were an edge case where we deleted an unreachable node and therefore removing any pod from etcd, but an stateful process were still running on the underlying host, we'll be immediately freeing up the pod name from the apiserver. "This would let the StatefulSet controller create a replacement Pod with that same identity; this can lead to the duplication of a still-running Pod, and if said Pod can still communicate with the other members of the StatefulSet, will violate the at most one semantics that StatefulSet is designed to guarantee." To mitigate this it'd be safer to delete the node only after the owned infraMachine is gone. This would give stronger guarantees that the underlying host is destroyed and so there's no chance of a stateful "leaked" process still running. kubernetes-sigs#2565
1 parent 88506f8 commit 2fb7d9a

File tree

1 file changed

+9
-7
lines changed

1 file changed

+9
-7
lines changed

controllers/machine_controller.go

+9-7
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,16 @@ func (r *MachineReconciler) reconcileDelete(ctx context.Context, cluster *cluste
281281
}
282282
r.recorder.Eventf(m, corev1.EventTypeNormal, "SuccessfulDrainNode", "success draining Machine's node %q", m.Status.NodeRef.Name)
283283
}
284-
logger.Info("Deleting node", "node", m.Status.NodeRef.Name)
285284

285+
// Verify infrastructure is destroyed before attempting to delete the node.
286+
// https://github.com/kubernetes-sigs/cluster-api/issues/2565
287+
if ok, err := r.reconcileDeleteExternal(ctx, m); !ok || err != nil {
288+
// Return early and don't remove the finalizer if we got an error or
289+
// the external reconciliation deletion isn't ready.
290+
return ctrl.Result{}, err
291+
}
292+
293+
logger.Info("Deleting node", "node", m.Status.NodeRef.Name)
286294
var deleteNodeErr error
287295
waitErr := wait.PollImmediate(2*time.Second, 10*time.Second, func() (bool, error) {
288296
if deleteNodeErr = r.deleteNode(ctx, cluster, m.Status.NodeRef.Name); deleteNodeErr != nil && !apierrors.IsNotFound(deleteNodeErr) {
@@ -296,12 +304,6 @@ func (r *MachineReconciler) reconcileDelete(ctx context.Context, cluster *cluste
296304
}
297305
}
298306

299-
if ok, err := r.reconcileDeleteExternal(ctx, m); !ok || err != nil {
300-
// Return early and don't remove the finalizer if we got an error or
301-
// the external reconciliation deletion isn't ready.
302-
return ctrl.Result{}, err
303-
}
304-
305307
controllerutil.RemoveFinalizer(m, clusterv1.MachineFinalizer)
306308
return ctrl.Result{}, nil
307309
}

0 commit comments

Comments
 (0)