sigs.k8s.io/cluster-api@v1.7.1/util/conditions/getter.go (about) 1 /* 2 Copyright 2020 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 conditions 18 19 import ( 20 corev1 "k8s.io/api/core/v1" 21 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 22 "sigs.k8s.io/controller-runtime/pkg/client" 23 24 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 25 ) 26 27 // Getter interface defines methods that a Cluster API object should implement in order to 28 // use the conditions package for getting conditions. 29 type Getter interface { 30 client.Object 31 32 // GetConditions returns the list of conditions for a cluster API object. 33 GetConditions() clusterv1.Conditions 34 } 35 36 // Get returns the condition with the given type, if the condition does not exists, 37 // it returns nil. 38 func Get(from Getter, t clusterv1.ConditionType) *clusterv1.Condition { 39 conditions := from.GetConditions() 40 if conditions == nil { 41 return nil 42 } 43 44 for _, condition := range conditions { 45 if condition.Type == t { 46 return &condition 47 } 48 } 49 return nil 50 } 51 52 // Has returns true if a condition with the given type exists. 53 func Has(from Getter, t clusterv1.ConditionType) bool { 54 return Get(from, t) != nil 55 } 56 57 // IsTrue is true if the condition with the given type is True, otherwise it return false 58 // if the condition is not True or if the condition does not exist (is nil). 59 func IsTrue(from Getter, t clusterv1.ConditionType) bool { 60 if c := Get(from, t); c != nil { 61 return c.Status == corev1.ConditionTrue 62 } 63 return false 64 } 65 66 // IsFalse is true if the condition with the given type is False, otherwise it return false 67 // if the condition is not False or if the condition does not exist (is nil). 68 func IsFalse(from Getter, t clusterv1.ConditionType) bool { 69 if c := Get(from, t); c != nil { 70 return c.Status == corev1.ConditionFalse 71 } 72 return false 73 } 74 75 // IsUnknown is true if the condition with the given type is Unknown or if the condition 76 // does not exist (is nil). 77 func IsUnknown(from Getter, t clusterv1.ConditionType) bool { 78 if c := Get(from, t); c != nil { 79 return c.Status == corev1.ConditionUnknown 80 } 81 return true 82 } 83 84 // GetReason returns a nil safe string of Reason for the condition with the given type. 85 func GetReason(from Getter, t clusterv1.ConditionType) string { 86 if c := Get(from, t); c != nil { 87 return c.Reason 88 } 89 return "" 90 } 91 92 // GetMessage returns a nil safe string of Message. 93 func GetMessage(from Getter, t clusterv1.ConditionType) string { 94 if c := Get(from, t); c != nil { 95 return c.Message 96 } 97 return "" 98 } 99 100 // GetSeverity returns the condition Severity or nil if the condition 101 // does not exist (is nil). 102 func GetSeverity(from Getter, t clusterv1.ConditionType) *clusterv1.ConditionSeverity { 103 if c := Get(from, t); c != nil { 104 return &c.Severity 105 } 106 return nil 107 } 108 109 // GetLastTransitionTime returns the condition Severity or nil if the condition 110 // does not exist (is nil). 111 func GetLastTransitionTime(from Getter, t clusterv1.ConditionType) *metav1.Time { 112 if c := Get(from, t); c != nil { 113 return &c.LastTransitionTime 114 } 115 return nil 116 } 117 118 // summary returns a Ready condition with the summary of all the conditions existing 119 // on an object. If the object does not have other conditions, no summary condition is generated. 120 func summary(from Getter, options ...MergeOption) *clusterv1.Condition { 121 conditions := from.GetConditions() 122 123 mergeOpt := &mergeOptions{} 124 for _, o := range options { 125 o(mergeOpt) 126 } 127 128 // Identifies the conditions in scope for the Summary by taking all the existing conditions except Ready, 129 // or, if a list of conditions types is specified, only the conditions the condition in that list. 130 conditionsInScope := make([]localizedCondition, 0, len(conditions)) 131 for i := range conditions { 132 c := conditions[i] 133 if c.Type == clusterv1.ReadyCondition { 134 continue 135 } 136 137 if mergeOpt.conditionTypes != nil { 138 found := false 139 for _, t := range mergeOpt.conditionTypes { 140 if c.Type == t { 141 found = true 142 break 143 } 144 } 145 if !found { 146 continue 147 } 148 } 149 150 conditionsInScope = append(conditionsInScope, localizedCondition{ 151 Condition: &c, 152 Getter: from, 153 }) 154 } 155 156 // If it is required to add a step counter only if a subset of condition exists, check if the conditions 157 // in scope are included in this subset or not. 158 if mergeOpt.addStepCounterIfOnlyConditionTypes != nil { 159 for _, c := range conditionsInScope { 160 found := false 161 for _, t := range mergeOpt.addStepCounterIfOnlyConditionTypes { 162 if c.Type == t { 163 found = true 164 break 165 } 166 } 167 if !found { 168 mergeOpt.addStepCounter = false 169 break 170 } 171 } 172 } 173 174 // If it is required to add a step counter, determine the total number of conditions defaulting 175 // to the selected conditions or, if defined, to the total number of conditions type to be considered. 176 if mergeOpt.addStepCounter { 177 mergeOpt.stepCounter = len(conditionsInScope) 178 if mergeOpt.conditionTypes != nil { 179 mergeOpt.stepCounter = len(mergeOpt.conditionTypes) 180 } 181 if mergeOpt.addStepCounterIfOnlyConditionTypes != nil { 182 mergeOpt.stepCounter = len(mergeOpt.addStepCounterIfOnlyConditionTypes) 183 } 184 } 185 186 return merge(conditionsInScope, clusterv1.ReadyCondition, mergeOpt) 187 } 188 189 // mirrorOptions allows to set options for the mirror operation. 190 type mirrorOptions struct { 191 fallbackTo *bool 192 fallbackReason string 193 fallbackSeverity clusterv1.ConditionSeverity 194 fallbackMessage string 195 } 196 197 // MirrorOptions defines an option for mirroring conditions. 198 type MirrorOptions func(*mirrorOptions) 199 200 // WithFallbackValue specify a fallback value to use in case the mirrored condition does not exists; 201 // in case the fallbackValue is false, given values for reason, severity and message will be used. 202 func WithFallbackValue(fallbackValue bool, reason string, severity clusterv1.ConditionSeverity, message string) MirrorOptions { 203 return func(c *mirrorOptions) { 204 c.fallbackTo = &fallbackValue 205 c.fallbackReason = reason 206 c.fallbackSeverity = severity 207 c.fallbackMessage = message 208 } 209 } 210 211 // mirror mirrors the Ready condition from a dependent object into the target condition; 212 // if the Ready condition does not exists in the source object, no target conditions is generated. 213 func mirror(from Getter, targetCondition clusterv1.ConditionType, options ...MirrorOptions) *clusterv1.Condition { 214 mirrorOpt := &mirrorOptions{} 215 for _, o := range options { 216 o(mirrorOpt) 217 } 218 219 condition := Get(from, clusterv1.ReadyCondition) 220 221 if mirrorOpt.fallbackTo != nil && condition == nil { 222 switch *mirrorOpt.fallbackTo { 223 case true: 224 condition = TrueCondition(targetCondition) 225 case false: 226 condition = FalseCondition(targetCondition, mirrorOpt.fallbackReason, mirrorOpt.fallbackSeverity, mirrorOpt.fallbackMessage) 227 } 228 } 229 230 if condition != nil { 231 condition.Type = targetCondition 232 } 233 234 return condition 235 } 236 237 // Aggregates all the Ready condition from a list of dependent objects into the target object; 238 // if the Ready condition does not exists in one of the source object, the object is excluded from 239 // the aggregation; if none of the source object have ready condition, no target conditions is generated. 240 func aggregate(from []Getter, targetCondition clusterv1.ConditionType, options ...MergeOption) *clusterv1.Condition { 241 conditionsInScope := make([]localizedCondition, 0, len(from)) 242 for i := range from { 243 condition := Get(from[i], clusterv1.ReadyCondition) 244 245 conditionsInScope = append(conditionsInScope, localizedCondition{ 246 Condition: condition, 247 Getter: from[i], 248 }) 249 } 250 251 mergeOpt := &mergeOptions{ 252 addStepCounter: true, 253 stepCounter: len(from), 254 } 255 for _, o := range options { 256 o(mergeOpt) 257 } 258 return merge(conditionsInScope, targetCondition, mergeOpt) 259 }