github.com/giantswarm/apiextensions/v2@v2.6.2/pkg/apis/infrastructure/v1alpha2/common_cluster_status_funcs.go (about) 1 package v1alpha2 2 3 import ( 4 "sort" 5 "time" 6 7 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 8 ) 9 10 func (s CommonClusterStatus) GetCreatedCondition() CommonClusterStatusCondition { 11 return getCondition(s.Conditions, ClusterStatusConditionCreated) 12 } 13 14 func (s CommonClusterStatus) GetCreatingCondition() CommonClusterStatusCondition { 15 return getCondition(s.Conditions, ClusterStatusConditionCreating) 16 } 17 18 func (s CommonClusterStatus) GetDeletedCondition() CommonClusterStatusCondition { 19 return getCondition(s.Conditions, ClusterStatusConditionDeleted) 20 } 21 22 func (s CommonClusterStatus) GetDeletingCondition() CommonClusterStatusCondition { 23 return getCondition(s.Conditions, ClusterStatusConditionDeleting) 24 } 25 26 func (s CommonClusterStatus) GetUpdatedCondition() CommonClusterStatusCondition { 27 return getCondition(s.Conditions, ClusterStatusConditionUpdated) 28 } 29 30 func (s CommonClusterStatus) GetUpdatingCondition() CommonClusterStatusCondition { 31 return getCondition(s.Conditions, ClusterStatusConditionUpdating) 32 } 33 34 func (s CommonClusterStatus) HasCreatedCondition() bool { 35 return hasCondition(s.Conditions, ClusterStatusConditionCreated) 36 } 37 38 func (s CommonClusterStatus) HasCreatingCondition() bool { 39 return hasCondition(s.Conditions, ClusterStatusConditionCreating) 40 } 41 42 func (s CommonClusterStatus) HasDeletedCondition() bool { 43 return hasCondition(s.Conditions, ClusterStatusConditionDeleted) 44 } 45 46 func (s CommonClusterStatus) HasDeletingCondition() bool { 47 return hasCondition(s.Conditions, ClusterStatusConditionDeleting) 48 } 49 50 func (s CommonClusterStatus) HasUpdatedCondition() bool { 51 return hasCondition(s.Conditions, ClusterStatusConditionUpdated) 52 } 53 54 func (s CommonClusterStatus) HasUpdatingCondition() bool { 55 return hasCondition(s.Conditions, ClusterStatusConditionUpdating) 56 } 57 58 func (s CommonClusterStatus) HasVersion(semver string) bool { 59 return hasVersion(s.Versions, semver) 60 } 61 62 func (s CommonClusterStatus) LatestCondition() string { 63 if len(s.Conditions) == 0 { 64 return "" 65 } 66 67 sort.Sort(sort.Reverse(sortClusterStatusConditionsByDate(s.Conditions))) 68 69 return s.Conditions[0].Condition 70 } 71 72 func (s CommonClusterStatus) LatestVersion() string { 73 if len(s.Versions) == 0 { 74 return "" 75 } 76 77 sort.Sort(sort.Reverse(sortClusterStatusVersionsByDate(s.Versions))) 78 79 return s.Versions[0].Version 80 } 81 82 func (s CommonClusterStatus) WithCreatedCondition() []CommonClusterStatusCondition { 83 newCondition := CommonClusterStatusCondition{ 84 LastTransitionTime: metav1.Now(), 85 Condition: ClusterStatusConditionCreated, 86 } 87 88 return withCondition(s.Conditions, newCondition, ClusterConditionLimit) 89 } 90 91 func (s CommonClusterStatus) WithCreatingCondition() []CommonClusterStatusCondition { 92 newCondition := CommonClusterStatusCondition{ 93 LastTransitionTime: metav1.Now(), 94 Condition: ClusterStatusConditionCreating, 95 } 96 97 return withCondition(s.Conditions, newCondition, ClusterConditionLimit) 98 } 99 100 func (s CommonClusterStatus) WithDeletedCondition() []CommonClusterStatusCondition { 101 newCondition := CommonClusterStatusCondition{ 102 LastTransitionTime: metav1.Now(), 103 Condition: ClusterStatusConditionDeleted, 104 } 105 106 return withCondition(s.Conditions, newCondition, ClusterConditionLimit) 107 } 108 109 func (s CommonClusterStatus) WithDeletingCondition() []CommonClusterStatusCondition { 110 newCondition := CommonClusterStatusCondition{ 111 LastTransitionTime: metav1.Now(), 112 Condition: ClusterStatusConditionDeleting, 113 } 114 115 return withCondition(s.Conditions, newCondition, ClusterConditionLimit) 116 } 117 118 func (s CommonClusterStatus) WithNewVersion(version string) []CommonClusterStatusVersion { 119 newVersion := CommonClusterStatusVersion{ 120 LastTransitionTime: metav1.Now(), 121 Version: version, 122 } 123 124 return withVersion(s.Versions, newVersion, ClusterVersionLimit) 125 } 126 127 func (s CommonClusterStatus) WithUpdatedCondition() []CommonClusterStatusCondition { 128 newCondition := CommonClusterStatusCondition{ 129 LastTransitionTime: metav1.Now(), 130 Condition: ClusterStatusConditionUpdated, 131 } 132 133 return withCondition(s.Conditions, newCondition, ClusterConditionLimit) 134 } 135 136 func (s CommonClusterStatus) WithUpdatingCondition() []CommonClusterStatusCondition { 137 newCondition := CommonClusterStatusCondition{ 138 LastTransitionTime: metav1.Now(), 139 Condition: ClusterStatusConditionUpdating, 140 } 141 142 return withCondition(s.Conditions, newCondition, ClusterConditionLimit) 143 } 144 145 func getCondition(conditions []CommonClusterStatusCondition, condition string) CommonClusterStatusCondition { 146 for _, c := range conditions { 147 if c.Condition == condition { 148 return c 149 } 150 } 151 152 return CommonClusterStatusCondition{} 153 } 154 155 func getConditionForPair(a CommonClusterStatusCondition) string { 156 for _, p := range conditionPairs { 157 if p[0] == a.Condition { 158 return p[1] 159 } 160 if p[1] == a.Condition { 161 return p[0] 162 } 163 } 164 165 return "" 166 } 167 168 func hasCondition(conditions []CommonClusterStatusCondition, condition string) bool { 169 for _, c := range conditions { 170 if c.Condition == condition { 171 return true 172 } 173 } 174 175 return false 176 } 177 178 func hasVersion(versions []CommonClusterStatusVersion, search string) bool { 179 for _, v := range versions { 180 if v.Version == search { 181 return true 182 } 183 } 184 185 return false 186 } 187 188 func isConditionPair(a CommonClusterStatusCondition, b CommonClusterStatusCondition) bool { 189 for _, p := range conditionPairs { 190 if p[0] == a.Condition && p[1] == b.Condition { 191 return true 192 } 193 if p[1] == a.Condition && p[0] == b.Condition { 194 return true 195 } 196 } 197 198 return false 199 } 200 201 // withCondition takes a list of status conditions and manages the given list 202 // according to the condition to add on top and the given limit argument. The 203 // limit argument should always only be given by ClusterConditionLimit. Also see 204 // the godoc there. The limit is applied to condition pairs as defined by 205 // conditionPairs. Internally the given conditions list is copied so that the 206 // input arguments are not manipulated by accident. One specific functionality 207 // of withCondition is that incomplete condition pairs are completed 208 // automatically as this may happen due to unexpected behaviour in the callers 209 // environment. For more information on implementation details read the inline 210 // comments of the code. 211 func withCondition(conditions []CommonClusterStatusCondition, condition CommonClusterStatusCondition, limit int) []CommonClusterStatusCondition { 212 // We create a new list which acts like a copy so the input parameters are not 213 // manipulated. Here we also prepend the given condition and inject certain 214 // missing conditions in case the condition list gets out of sync 215 // unintendedly due to any eventual bugs. Test case 8 demonstrates that. 216 var newConditions []CommonClusterStatusCondition 217 { 218 if len(conditions) > 0 && conditions[0].Condition == condition.Condition { 219 injected := CommonClusterStatusCondition{ 220 // The implication of unintendedly untracked conditions is that the 221 // automatically added condition does not obtain a reasonable timestamp. 222 // Here we take the timestamp of the new condition we want to track and 223 // substract one nano second from it to keep the order intact. 224 LastTransitionTime: metav1.Time{Time: condition.LastTransitionTime.Add(-(1 * time.Nanosecond))}, 225 Condition: getConditionForPair(condition), 226 } 227 newConditions = append(newConditions, injected) 228 } 229 230 newConditions = append(newConditions, condition) 231 newConditions = append(newConditions, conditions...) 232 } 233 234 // The new list is sorted to have the first item being the oldest. This is to 235 // have an easier grouping mechanism below. When the first item of a new pair 236 // is added, it would throw of the grouping when the order would be kept as 237 // given. 238 sort.Sort(sortClusterStatusConditionsByDate(newConditions)) 239 240 // The conditions are grouped into their corresponding pairs of transitioning 241 // states. Associated Creating/Created, Updating/Updated and Deleting/Deleted 242 // conditions are put together. 243 var conditionGroups [][]CommonClusterStatusCondition 244 for len(newConditions) > 0 { 245 var g []CommonClusterStatusCondition 246 247 for _, c := range newConditions { 248 // If the list only contains one item anymore, we process it separately 249 // here and be done. Otherwhise the pruning of the list below panics due 250 // to the range calculations. 251 if len(newConditions) == 1 { 252 g = append(g, c) 253 newConditions = []CommonClusterStatusCondition{} 254 break 255 } 256 257 // Put the first item from the top of the list into the group and drop 258 // the grouped item from the list. 259 if len(g) == 0 { 260 g = append(g, c) 261 newConditions = newConditions[1:] 262 continue 263 } 264 265 // When we find the second item of the pair we are done for this group. 266 if len(g) == 1 { 267 if isConditionPair(g[0], c) { 268 g = append(g, c) 269 newConditions = newConditions[1:] 270 } 271 break 272 } 273 } 274 275 conditionGroups = append(conditionGroups, g) 276 } 277 278 // The pairs are now grouped. When there are only three group kinds for 279 // create/update/delete, conditionPairs has a length of 3. Each of the groups 280 // has then as many pairs as grouped together. Below these groups are limited. 281 var conditionPairs [][]CommonClusterStatusCondition 282 for len(conditionGroups) > 0 { 283 var p []CommonClusterStatusCondition 284 285 for _, g := range conditionGroups { 286 if len(p) == 0 { 287 p = append(p, g...) 288 conditionGroups = conditionGroups[1:] 289 continue 290 } 291 292 if len(g) >= 1 { 293 if isConditionPair(p[0], g[0]) || isConditionPair(p[1], g[0]) { 294 p = append(p, g...) 295 conditionGroups = conditionGroups[1:] 296 } 297 } 298 } 299 300 conditionPairs = append(conditionPairs, p) 301 } 302 303 // Here the list is finally flattened again and its pairs are limitted to the 304 // input parameter. 305 var limittedList []CommonClusterStatusCondition 306 for _, p := range conditionPairs { 307 // We compute the pair limit here for the total number of items. This is why 308 // we multiply by 2. When the limit is 5, we want to track for instance 5 309 // Updating/Updated pairs. Additionally when there is an item of a new pair 310 // and the list must be capped, the additional odd of the new item has to be 311 // considered when computing the limit. This results in an additional pair 312 // being dropped. Test case 6 demonstrates that. 313 l := (limit * 2) - (len(p) % 2) 314 if len(p) < l { 315 l = len(p) 316 } 317 318 limittedList = append(limittedList, p[len(p)-l:]...) 319 } 320 321 // We reverse the list order to have the item with the highest timestamp at 322 // the top again. 323 sort.Sort(sort.Reverse(sortClusterStatusConditionsByDate(limittedList))) 324 325 return limittedList 326 } 327 328 // withVersion computes a list of version history using the given list and new 329 // version structure to append. withVersion also limits the total amount of 330 // elements in the list by cutting off the tail with respect to the limit 331 // parameter. 332 func withVersion(versions []CommonClusterStatusVersion, version CommonClusterStatusVersion, limit int) []CommonClusterStatusVersion { 333 if hasVersion(versions, version.Version) { 334 return versions 335 } 336 337 // Create a copy to not manipulate the input list. 338 var newVersions []CommonClusterStatusVersion 339 newVersions = append(newVersions, versions...) 340 341 // Sort the versions in a way that the newest version, namely the one with the 342 // highest timestamp, is at the top of the list. 343 sort.Sort(sort.Reverse(sortClusterStatusVersionsByDate(newVersions))) 344 345 // Calculate the index for capping the list in the next step. 346 l := limit - 1 347 if len(newVersions) < l { 348 l = len(newVersions) 349 } 350 351 // Cap the list and prepend the new version. 352 newVersions = append([]CommonClusterStatusVersion{version}, newVersions[0:l]...) 353 354 return newVersions 355 }