diff --git a/api/v1alpha3/machine_types.go b/api/v1alpha3/machine_types.go index 32fe0dc431df..97bd17378a2d 100644 --- a/api/v1alpha3/machine_types.go +++ b/api/v1alpha3/machine_types.go @@ -37,6 +37,18 @@ const ( // MachineDeploymentLabelName is the label set on machines if they're controlled by MachineDeployment MachineDeploymentLabelName = "cluster.x-k8s.io/deployment-name" + + // PreDrainDeleteHookAnnotationPrefix annotation specifies the prefix we + // search each annotation for during the pre-drain.delete lifecycle hook + // to pause reconciliation of deletion. These hooks will prevent removal of + // draining the associated node until all are removed. + PreDrainDeleteHookAnnotationPrefix = "pre-drain.delete.hook.machine.cluster.x-k8s.io" + + // PreTerminateDeleteHookAnnotationPrefix annotation specifies the prefix we + // search each annotation for during the pre-terminate.delete lifecycle hook + // to pause reconciliation of deletion. These hooks will prevent removal of + // an instance from an infrastructure provider until all are removed. + PreTerminateDeleteHookAnnotationPrefix = "pre-terminate.delete.hook.machine.cluster.x-k8s.io" ) // ANCHOR: MachineSpec diff --git a/controllers/machine_controller.go b/controllers/machine_controller.go index 1fc09f3db1b5..771b566010f9 100644 --- a/controllers/machine_controller.go +++ b/controllers/machine_controller.go @@ -19,6 +19,7 @@ package controllers import ( "context" "fmt" + "strings" "time" "github.com/go-logr/logr" @@ -290,6 +291,11 @@ func (r *MachineReconciler) reconcileDelete(ctx context.Context, cluster *cluste } if isDeleteNodeAllowed { + // pre-drain.delete lifecycle hook + // Return early without error, will requeue if/when the Hook is removed. + if waitForHook(clusterv1.PreDrainDeleteHookAnnotationPrefix, m.ObjectMeta.Annotations) { + return ctrl.Result{}, nil + } // Drain node before deletion. if _, exists := m.ObjectMeta.Annotations[clusterv1.ExcludeNodeDrainingAnnotation]; !exists { logger.Info("Draining node", "node", m.Status.NodeRef.Name) @@ -301,6 +307,12 @@ func (r *MachineReconciler) reconcileDelete(ctx context.Context, cluster *cluste } } + // pre-term.delete lifecycle hook + // Return early without error, will requeue if/when the Hook is removed. + if waitForHook(clusterv1.PreTerminateDeleteHookAnnotationPrefix, m.ObjectMeta.Annotations) { + return ctrl.Result{}, nil + } + if ok, err := r.reconcileDeleteExternal(ctx, m); !ok || err != nil { // Return early and don't remove the finalizer if we got an error or // the external reconciliation deletion isn't ready. @@ -491,6 +503,15 @@ func (r *MachineReconciler) shouldAdopt(m *clusterv1.Machine) bool { return metav1.GetControllerOf(m) == nil && !util.HasOwner(m.OwnerReferences, clusterv1.GroupVersion.String(), []string{"Cluster"}) } +func waitForHook(hookName string, annotations map[string]string) bool { + for key := range annotations { + if strings.HasPrefix(key, hookName) { + return true + } + } + return false +} + // writer implements io.Writer interface as a pass-through for klog. type writer struct { logFunc func(args ...interface{})