sigs.k8s.io/cluster-api@v1.7.1/internal/controllers/machineset/machineset_delete_policy.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package machineset 18 19 import ( 20 "math" 21 "sort" 22 23 "github.com/pkg/errors" 24 corev1 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 27 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 28 "sigs.k8s.io/cluster-api/util/conditions" 29 ) 30 31 type ( 32 deletePriority float64 33 deletePriorityFunc func(machine *clusterv1.Machine) deletePriority 34 ) 35 36 const ( 37 mustDelete deletePriority = 100.0 38 shouldDelete deletePriority = 75.0 39 betterDelete deletePriority = 50.0 40 couldDelete deletePriority = 20.0 41 mustNotDelete deletePriority = 0.0 42 43 secondsPerTenDays float64 = 864000 44 ) 45 46 // maps the creation timestamp onto the 0-100 priority range. 47 func oldestDeletePriority(machine *clusterv1.Machine) deletePriority { 48 if !machine.DeletionTimestamp.IsZero() { 49 return mustDelete 50 } 51 if _, ok := machine.ObjectMeta.Annotations[clusterv1.DeleteMachineAnnotation]; ok { 52 return shouldDelete 53 } 54 if !isMachineHealthy(machine) { 55 return betterDelete 56 } 57 if machine.ObjectMeta.CreationTimestamp.Time.IsZero() { 58 return mustNotDelete 59 } 60 d := metav1.Now().Sub(machine.ObjectMeta.CreationTimestamp.Time) 61 if d.Seconds() < 0 { 62 return mustNotDelete 63 } 64 return deletePriority(float64(betterDelete) * (1.0 - math.Exp(-d.Seconds()/secondsPerTenDays))) 65 } 66 67 func newestDeletePriority(machine *clusterv1.Machine) deletePriority { 68 if !machine.DeletionTimestamp.IsZero() { 69 return mustDelete 70 } 71 if _, ok := machine.ObjectMeta.Annotations[clusterv1.DeleteMachineAnnotation]; ok { 72 return shouldDelete 73 } 74 if !isMachineHealthy(machine) { 75 return betterDelete 76 } 77 return betterDelete - oldestDeletePriority(machine) 78 } 79 80 func randomDeletePolicy(machine *clusterv1.Machine) deletePriority { 81 if !machine.DeletionTimestamp.IsZero() { 82 return mustDelete 83 } 84 if _, ok := machine.ObjectMeta.Annotations[clusterv1.DeleteMachineAnnotation]; ok { 85 return betterDelete 86 } 87 if !isMachineHealthy(machine) { 88 return betterDelete 89 } 90 return couldDelete 91 } 92 93 type sortableMachines struct { 94 machines []*clusterv1.Machine 95 priority deletePriorityFunc 96 } 97 98 func (m sortableMachines) Len() int { return len(m.machines) } 99 func (m sortableMachines) Swap(i, j int) { m.machines[i], m.machines[j] = m.machines[j], m.machines[i] } 100 func (m sortableMachines) Less(i, j int) bool { 101 priorityI, priorityJ := m.priority(m.machines[i]), m.priority(m.machines[j]) 102 if priorityI == priorityJ { 103 // In cases where the priority is identical, it should be ensured that the same machine order is returned each time. 104 // Ordering by name is a simple way to do this. 105 return m.machines[i].Name < m.machines[j].Name 106 } 107 return priorityJ < priorityI // high to low 108 } 109 110 func getMachinesToDeletePrioritized(filteredMachines []*clusterv1.Machine, diff int, fun deletePriorityFunc) []*clusterv1.Machine { 111 if diff >= len(filteredMachines) { 112 return filteredMachines 113 } else if diff <= 0 { 114 return []*clusterv1.Machine{} 115 } 116 117 sortable := sortableMachines{ 118 machines: filteredMachines, 119 priority: fun, 120 } 121 sort.Sort(sortable) 122 123 return sortable.machines[:diff] 124 } 125 126 func getDeletePriorityFunc(ms *clusterv1.MachineSet) (deletePriorityFunc, error) { 127 // Map the Spec.DeletePolicy value to the appropriate delete priority function 128 switch msdp := clusterv1.MachineSetDeletePolicy(ms.Spec.DeletePolicy); msdp { 129 case clusterv1.RandomMachineSetDeletePolicy: 130 return randomDeletePolicy, nil 131 case clusterv1.NewestMachineSetDeletePolicy: 132 return newestDeletePriority, nil 133 case clusterv1.OldestMachineSetDeletePolicy: 134 return oldestDeletePriority, nil 135 case "": 136 return randomDeletePolicy, nil 137 default: 138 return nil, errors.Errorf("Unsupported delete policy %s. Must be one of 'Random', 'Newest', or 'Oldest'", msdp) 139 } 140 } 141 142 func isMachineHealthy(machine *clusterv1.Machine) bool { 143 if machine.Status.NodeRef == nil { 144 return false 145 } 146 if machine.Status.FailureReason != nil || machine.Status.FailureMessage != nil { 147 return false 148 } 149 nodeHealthyCondition := conditions.Get(machine, clusterv1.MachineNodeHealthyCondition) 150 if nodeHealthyCondition != nil && nodeHealthyCondition.Status != corev1.ConditionTrue { 151 return false 152 } 153 return true 154 }