istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/model/kstatus/helper.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package kstatus 16 17 import ( 18 "reflect" 19 20 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 22 "istio.io/istio/pkg/config" 23 "istio.io/istio/pkg/slices" 24 ) 25 26 const ( 27 StatusTrue = "True" 28 StatusFalse = "False" 29 ) 30 31 // InvertStatus returns the opposite of the provided status. If an invalid status is passed in, False is returned 32 func InvertStatus(status metav1.ConditionStatus) metav1.ConditionStatus { 33 switch status { 34 case StatusFalse: 35 return StatusTrue 36 default: 37 return StatusFalse 38 } 39 } 40 41 // WrappedStatus provides a wrapper around a status message that keeps track of whether or not any 42 // changes have been made. This allows users to declarative write status, without worrying about 43 // tracking changes. When read to commit (typically to Kubernetes), any messages with Dirty=false can 44 // be discarded. 45 type WrappedStatus struct { 46 // Status is the object that is wrapped. 47 config.Status 48 // Dirty indicates if this object has been modified at all. 49 // Note: only changes wrapped in Mutate are tracked. 50 Dirty bool 51 } 52 53 func Wrap(s config.Status) *WrappedStatus { 54 return &WrappedStatus{config.DeepCopy(s), false} 55 } 56 57 func (w *WrappedStatus) Mutate(f func(s config.Status) config.Status) { 58 if w.Status == nil { 59 return 60 } 61 old := config.DeepCopy(w.Status) 62 w.Status = f(w.Status) 63 // TODO: change this to be more efficient. Likely we allow modifications via WrappedStatus that 64 // modify specific things (ie conditions). 65 if !reflect.DeepEqual(old, w.Status) { 66 w.Dirty = true 67 } 68 } 69 70 func (w *WrappedStatus) Unwrap() config.Status { 71 return w.Status 72 } 73 74 var EmptyCondition = metav1.Condition{} 75 76 func GetCondition(conditions []metav1.Condition, condition string) metav1.Condition { 77 for _, cond := range conditions { 78 if cond.Type == condition { 79 return cond 80 } 81 } 82 return EmptyCondition 83 } 84 85 // UpdateConditionIfChanged updates a condition if it has been changed. 86 func UpdateConditionIfChanged(conditions []metav1.Condition, condition metav1.Condition) []metav1.Condition { 87 ret := slices.Clone(conditions) 88 existing := slices.FindFunc(ret, func(cond metav1.Condition) bool { 89 return cond.Type == condition.Type 90 }) 91 if existing == nil { 92 ret = append(ret, condition) 93 return ret 94 } 95 96 if existing.Status == condition.Status { 97 if existing.Message == condition.Message && 98 existing.ObservedGeneration == condition.ObservedGeneration { 99 // Skip update, no changes 100 return conditions 101 } 102 // retain LastTransitionTime if status is not changed 103 condition.LastTransitionTime = existing.LastTransitionTime 104 } 105 *existing = condition 106 107 return ret 108 } 109 110 // CreateCondition sets a condition only if it has not already been set 111 func CreateCondition(conditions []metav1.Condition, condition metav1.Condition, unsetReason string) []metav1.Condition { 112 ret := append([]metav1.Condition(nil), conditions...) 113 idx := -1 114 for i, cond := range ret { 115 if cond.Type == condition.Type { 116 idx = i 117 if cond.Reason == unsetReason { 118 // Condition is set, but its for unsetReason. This is needed because some conditions have defaults 119 ret[idx] = condition 120 return ret 121 } 122 break 123 } 124 } 125 126 if idx == -1 { 127 // Not found! We should set it 128 ret = append(ret, condition) 129 } 130 return ret 131 }