sigs.k8s.io/kueue@v0.6.2/pkg/workload/admissionchecks.go (about) 1 /* 2 Copyright 2023 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 workload 18 19 import ( 20 "time" 21 22 apimeta "k8s.io/apimachinery/pkg/api/meta" 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 "k8s.io/apimachinery/pkg/util/sets" 25 26 kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1" 27 ) 28 29 // SyncAdmittedCondition sync the state of the Admitted condition 30 // with the state of QuotaReserved and AdmissionChecks. 31 // Return true if any change was done. 32 func SyncAdmittedCondition(w *kueue.Workload) bool { 33 hasReservation := HasQuotaReservation(w) 34 hasAllChecksReady := HasAllChecksReady(w) 35 isAdmitted := IsAdmitted(w) 36 37 if isAdmitted == (hasReservation && hasAllChecksReady) { 38 return false 39 } 40 newCondition := metav1.Condition{ 41 Type: kueue.WorkloadAdmitted, 42 Status: metav1.ConditionTrue, 43 Reason: "Admitted", 44 Message: "The workload is admitted", 45 } 46 switch { 47 case !hasReservation && !hasAllChecksReady: 48 newCondition.Status = metav1.ConditionFalse 49 newCondition.Reason = "NoReservationNoChecks" 50 newCondition.Message = "The workload has no reservation and not all checks ready" 51 case !hasReservation: 52 newCondition.Status = metav1.ConditionFalse 53 newCondition.Reason = "NoReservation" 54 newCondition.Message = "The workload has no reservation" 55 case !hasAllChecksReady: 56 newCondition.Status = metav1.ConditionFalse 57 newCondition.Reason = "NoChecks" 58 newCondition.Message = "The workload has not all checks ready" 59 } 60 61 return apimeta.SetStatusCondition(&w.Status.Conditions, newCondition) 62 } 63 64 // FindAdmissionCheck - returns a pointer to the check identified by checkName if found in checks. 65 func FindAdmissionCheck(checks []kueue.AdmissionCheckState, checkName string) *kueue.AdmissionCheckState { 66 for i := range checks { 67 if checks[i].Name == checkName { 68 return &checks[i] 69 } 70 } 71 72 return nil 73 } 74 75 // SetAdmissionCheckState - adds or updates newCheck in the provided checks list. 76 func SetAdmissionCheckState(checks *[]kueue.AdmissionCheckState, newCheck kueue.AdmissionCheckState) { 77 if checks == nil { 78 return 79 } 80 existingCondition := FindAdmissionCheck(*checks, newCheck.Name) 81 if existingCondition == nil { 82 if newCheck.LastTransitionTime.IsZero() { 83 newCheck.LastTransitionTime = metav1.NewTime(time.Now()) 84 } 85 *checks = append(*checks, newCheck) 86 return 87 } 88 89 if existingCondition.State != newCheck.State { 90 existingCondition.State = newCheck.State 91 if !newCheck.LastTransitionTime.IsZero() { 92 existingCondition.LastTransitionTime = newCheck.LastTransitionTime 93 } else { 94 existingCondition.LastTransitionTime = metav1.NewTime(time.Now()) 95 } 96 } 97 existingCondition.Message = newCheck.Message 98 existingCondition.PodSetUpdates = newCheck.PodSetUpdates 99 } 100 101 // GetRejectedChecks returns the list of Rejected admission checks 102 func GetRejectedChecks(wl *kueue.Workload) []string { 103 rejectedChecks := make([]string, 0, len(wl.Status.AdmissionChecks)) 104 for i := range wl.Status.AdmissionChecks { 105 ac := wl.Status.AdmissionChecks[i] 106 if ac.State == kueue.CheckStateRejected { 107 rejectedChecks = append(rejectedChecks, ac.Name) 108 } 109 } 110 return rejectedChecks 111 } 112 113 // HasAllChecksReady returns true if all the checks of the workload are ready. 114 func HasAllChecksReady(wl *kueue.Workload) bool { 115 for i := range wl.Status.AdmissionChecks { 116 if wl.Status.AdmissionChecks[i].State != kueue.CheckStateReady { 117 return false 118 } 119 } 120 return true 121 } 122 123 // HasAllChecks returns true if all the mustHaveChecks are present in the workload. 124 func HasAllChecks(wl *kueue.Workload, mustHaveChecks sets.Set[string]) bool { 125 if mustHaveChecks.Len() == 0 { 126 return true 127 } 128 129 if mustHaveChecks.Len() > len(wl.Status.AdmissionChecks) { 130 return false 131 } 132 133 mustHaveChecks = mustHaveChecks.Clone() 134 for i := range wl.Status.AdmissionChecks { 135 mustHaveChecks.Delete(wl.Status.AdmissionChecks[i].Name) 136 } 137 return mustHaveChecks.Len() == 0 138 } 139 140 // HasRetryOrRejectedChecks returns true if any of the workloads checks are Retry or Rejected 141 func HasRetryOrRejectedChecks(wl *kueue.Workload) bool { 142 for i := range wl.Status.AdmissionChecks { 143 state := wl.Status.AdmissionChecks[i].State 144 if state == kueue.CheckStateRetry || state == kueue.CheckStateRejected { 145 return true 146 } 147 } 148 return false 149 }