diff --git a/pkg/controller/machine/controller.go b/pkg/controller/machine/controller.go index 840853f0c1..67ddb4eff2 100644 --- a/pkg/controller/machine/controller.go +++ b/pkg/controller/machine/controller.go @@ -83,6 +83,8 @@ const ( // Machine has a deletion timestamp phaseDeleting = "Deleting" + + skipWaitForDeleteTimeoutSeconds = 60 * 5 ) var DefaultActuator Actuator @@ -344,6 +346,10 @@ func (r *ReconcileMachine) drainNode(machine *machinev1.Machine) error { DryRun: false, } + if nodeIsUnreachable(node) { + drainer.SkipWaitForDeleteTimeoutSeconds = skipWaitForDeleteTimeoutSeconds + } + if err := drain.RunCordonOrUncordon(drainer, node, true); err != nil { // Can't cordon a node klog.Warningf("cordon failed for node %q: %v", node.Name, err) @@ -429,6 +435,16 @@ func machineIsFailed(machine *machinev1.Machine) bool { return false } +func nodeIsUnreachable(node *corev1.Node) bool { + for _, condition := range node.Status.Conditions { + if condition.Type == corev1.NodeReady && condition.Status == corev1.ConditionUnknown { + return true + } + } + + return false +} + // writer implements io.Writer interface as a pass-through for klog. type writer struct { logFunc func(args ...interface{}) diff --git a/pkg/controller/machine/controller_test.go b/pkg/controller/machine/controller_test.go index 2c99555213..97dffe159d 100644 --- a/pkg/controller/machine/controller_test.go +++ b/pkg/controller/machine/controller_test.go @@ -497,3 +497,56 @@ func TestMachineIsFailed(t *testing.T) { } } } + +func TestNodeIsUnreachable(t *testing.T) { + testCases := []struct { + name string + node *corev1.Node + expected bool + }{ + { + name: "Node should be unreachable", + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Node", + Namespace: "test", + }, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{ + corev1.NodeCondition{ + Type: corev1.NodeReady, + Status: corev1.ConditionUnknown, + }, + }, + }, + }, + expected: true, + }, + { + name: "Node should not be unreachable", + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Node", + Namespace: "test", + }, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{ + corev1.NodeCondition{ + Type: corev1.NodeReady, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + expected: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if actual := nodeIsUnreachable(tc.node); actual != tc.expected { + t.Errorf("Expected: %v, got: %v", actual, tc.expected) + } + }) + } +}