github.com/kubewharf/katalyst-core@v0.5.3/pkg/controller/vpa/util/api.go (about) 1 /* 2 Copyright 2022 The Katalyst 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 util 18 19 import ( 20 "context" 21 "fmt" 22 "reflect" 23 "time" 24 25 core "k8s.io/api/core/v1" 26 apiequality "k8s.io/apimachinery/pkg/api/equality" 27 "k8s.io/apimachinery/pkg/api/meta" 28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 "k8s.io/apimachinery/pkg/runtime" 30 31 apis "github.com/kubewharf/katalyst-api/pkg/apis/autoscaling/v1alpha1" 32 "github.com/kubewharf/katalyst-core/pkg/client/control" 33 ) 34 35 const ( 36 VPARecConditionReasonUpdated = "Updated" 37 VPARecConditionReasonIllegal = "Illegal" 38 ) 39 40 const ( 41 VPAConditionReasonUpdated = "Updated" 42 VPAConditionReasonCalculatedIllegal = "Illegal" 43 VPAConditionReasonPodSpecUpdated = "PodSpecUpdated" 44 VPAConditionReasonPodSpecNoUpdate = "PodSpecNoUpdate" 45 ) 46 47 // SetVPAConditions is used to set conditions for vpa in local vpa 48 func SetVPAConditions( 49 vpa *apis.KatalystVerticalPodAutoscaler, 50 conditionType apis.VerticalPodAutoscalerConditionType, 51 conditionStatus core.ConditionStatus, 52 reason, message string, 53 ) error { 54 if vpa == nil { 55 return fmt.Errorf("can't update condition of a nil vpa") 56 } 57 conditions := vpa.Status.Conditions 58 59 var conditionIndex int 60 for conditionIndex = 0; conditionIndex < len(conditions); conditionIndex++ { 61 if conditions[conditionIndex].Type == conditionType { 62 break 63 } 64 } 65 if conditionIndex == len(conditions) { 66 conditions = append(conditions, apis.VerticalPodAutoscalerCondition{ 67 Type: conditionType, 68 }) 69 } 70 71 condition := &conditions[conditionIndex] 72 if condition.Status != conditionStatus || condition.Message != message || 73 condition.Reason != reason { 74 condition.LastTransitionTime = metav1.NewTime(time.Now()) 75 } 76 77 condition.Status = conditionStatus 78 condition.Reason = reason 79 condition.Message = message 80 vpa.Status.Conditions = conditions 81 return nil 82 } 83 84 // SetVPARecConditions is used to set conditions for vpaRec in local vpa 85 func SetVPARecConditions( 86 vpaRec *apis.VerticalPodAutoscalerRecommendation, 87 conditionType apis.VerticalPodAutoscalerRecommendationConditionType, 88 conditionStatus core.ConditionStatus, 89 reason, message string, 90 ) error { 91 if vpaRec == nil { 92 return fmt.Errorf("can't update condition of a nil vpa") 93 } 94 conditions := vpaRec.Status.Conditions 95 96 var conditionIndex int 97 for conditionIndex = 0; conditionIndex < len(conditions); conditionIndex++ { 98 if conditions[conditionIndex].Type == conditionType { 99 break 100 } 101 } 102 if conditionIndex == len(conditions) { 103 conditions = append(conditions, apis.VerticalPodAutoscalerRecommendationCondition{ 104 Type: conditionType, 105 }) 106 } 107 108 condition := &conditions[conditionIndex] 109 if condition.Status != conditionStatus || condition.Message != message || 110 condition.Reason != reason { 111 condition.LastTransitionTime = metav1.NewTime(time.Now()) 112 } 113 114 condition.Status = conditionStatus 115 condition.Reason = reason 116 condition.Message = message 117 vpaRec.Status.Conditions = conditions 118 return nil 119 } 120 121 // PatchVPAConditions is used to update conditions for vpa to APIServer 122 func PatchVPAConditions( 123 ctx context.Context, 124 vpaUpdater control.VPAUpdater, 125 vpa *apis.KatalystVerticalPodAutoscaler, 126 conditionType apis.VerticalPodAutoscalerConditionType, 127 conditionStatus core.ConditionStatus, 128 reason, 129 message string, 130 ) error { 131 vpaNew := vpa.DeepCopy() 132 if err := SetVPAConditions(vpaNew, conditionType, conditionStatus, reason, message); err != nil { 133 return err 134 } 135 136 if apiequality.Semantic.DeepEqual(vpa.Status, vpaNew.Status) { 137 return nil 138 } 139 140 if _, err := vpaUpdater.PatchVPAStatus(ctx, vpa, vpaNew); err != nil { 141 return err 142 } 143 144 return nil 145 } 146 147 func UpdateVPAConditions( 148 ctx context.Context, 149 vpaUpdater control.VPAUpdater, 150 vpa *apis.KatalystVerticalPodAutoscaler, 151 conditionType apis.VerticalPodAutoscalerConditionType, 152 conditionStatus core.ConditionStatus, 153 reason, 154 message string, 155 ) error { 156 vpaNew := vpa.DeepCopy() 157 if err := SetVPAConditions(vpaNew, conditionType, conditionStatus, reason, message); err != nil { 158 return err 159 } 160 161 if apiequality.Semantic.DeepEqual(vpa.Status, vpaNew.Status) { 162 return nil 163 } 164 165 if _, err := vpaUpdater.UpdateVPAStatus(ctx, vpaNew, metav1.UpdateOptions{}); err != nil { 166 return err 167 } 168 169 return nil 170 } 171 172 // PatchVPARecConditions is used to update conditions for vpaRec to APIServer 173 func PatchVPARecConditions( 174 ctx context.Context, 175 vpaRecUpdater control.VPARecommendationUpdater, 176 vpaRec *apis.VerticalPodAutoscalerRecommendation, 177 conditionType apis.VerticalPodAutoscalerRecommendationConditionType, 178 conditionStatus core.ConditionStatus, 179 reason, 180 message string, 181 ) error { 182 vpaRecCopy := vpaRec.DeepCopy() 183 if err := SetVPARecConditions(vpaRecCopy, conditionType, conditionStatus, reason, message); err != nil { 184 return err 185 } 186 if apiequality.Semantic.DeepEqual(vpaRec.Status, vpaRecCopy.Status) { 187 return nil 188 } 189 190 return vpaRecUpdater.PatchVPARecommendationStatus(ctx, vpaRec, vpaRecCopy) 191 } 192 193 // SetOwnerReferencesForVPA is used to parse from workload list, and set the 194 // runtime information into OwnerReference fields for vpa CR 195 func SetOwnerReferencesForVPA(vpa *apis.KatalystVerticalPodAutoscaler, workload runtime.Object) error { 196 metadata, err := meta.Accessor(workload) 197 if err != nil { 198 return err 199 } 200 201 ownerRef := metav1.OwnerReference{ 202 Name: metadata.GetName(), 203 Kind: workload.GetObjectKind().GroupVersionKind().Kind, 204 APIVersion: workload.GetObjectKind().GroupVersionKind().GroupVersion().String(), 205 UID: metadata.GetUID(), 206 } 207 for _, ow := range vpa.GetOwnerReferences() { 208 if reflect.DeepEqual(ow, ownerRef) { 209 return nil 210 } 211 } 212 213 vpa.OwnerReferences = append(vpa.OwnerReferences, ownerRef) 214 return nil 215 } 216 217 // DeleteOwnerReferencesForVPA is used to parse from workload list, and clean up the 218 // runtime information from OwnerReference fields for vpa CR 219 func DeleteOwnerReferencesForVPA(vpa *apis.KatalystVerticalPodAutoscaler, workload runtime.Object) error { 220 metadata, err := meta.Accessor(workload) 221 if err != nil { 222 return err 223 } 224 225 ownerRef := metav1.OwnerReference{ 226 Name: metadata.GetName(), 227 Kind: workload.GetObjectKind().GroupVersionKind().Kind, 228 APIVersion: workload.GetObjectKind().GroupVersionKind().GroupVersion().String(), 229 UID: metadata.GetUID(), 230 } 231 232 for i, ow := range vpa.GetOwnerReferences() { 233 if reflect.DeepEqual(ow, ownerRef) { 234 vpa.OwnerReferences = append(vpa.OwnerReferences[:i], vpa.OwnerReferences[i+1:]...) 235 return nil 236 } 237 } 238 239 return nil 240 }