Skip to content

Commit

Permalink
Migrate controllers to v1beta1 APIs
Browse files Browse the repository at this point in the history
Change-Id: If389945ad5833d8b869823afa1816772af22663c
  • Loading branch information
alculquicondor committed Mar 8, 2023
1 parent 6136eed commit cfaf110
Show file tree
Hide file tree
Showing 76 changed files with 3,028 additions and 3,400 deletions.
1 change: 0 additions & 1 deletion apis/kueue/v1alpha2/clusterqueue_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,6 @@ type ClusterQueuePreemption struct {
//+kubebuilder:printcolumn:name="Strategy",JSONPath=".spec.queueingStrategy",type=string,description="The queueing strategy used to prioritize workloads",priority=1
//+kubebuilder:printcolumn:name="Pending Workloads",JSONPath=".status.pendingWorkloads",type=integer,description="Number of pending workloads"
//+kubebuilder:printcolumn:name="Admitted Workloads",JSONPath=".status.admittedWorkloads",type=integer,description="Number of admitted workloads that haven't finished yet",priority=1
//+kubebuilder:storageversion

// ClusterQueue is the Schema for the clusterQueue API.
type ClusterQueue struct {
Expand Down
1 change: 0 additions & 1 deletion apis/kueue/v1alpha2/localqueue_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ type LocalQueueStatus struct {
//+kubebuilder:printcolumn:name="Pending Workloads",JSONPath=".status.pendingWorkloads",type=integer,description="Number of pending workloads"
//+kubebuilder:printcolumn:name="Admitted Workloads",JSONPath=".status.admittedWorkloads",type=integer,description="Number of admitted workloads that haven't finished yet."
//+kubebuilder:resource:shortName={queue,queues}
//+kubebuilder:storageversion

// LocalQueue is the Schema for the localQueues API
type LocalQueue struct {
Expand Down
1 change: 0 additions & 1 deletion apis/kueue/v1alpha2/resourceflavor_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (

//+kubebuilder:object:root=true
//+kubebuilder:resource:scope=Cluster,shortName={flavor,flavors}
//+kubebuilder:storageversion

// ResourceFlavor is the Schema for the resourceflavors API.
type ResourceFlavor struct {
Expand Down
2 changes: 0 additions & 2 deletions apis/kueue/v1alpha2/workload_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,7 @@ const (
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Queue",JSONPath=".spec.queueName",type=string,description="Name of the queue this workload was submitted to"
// +kubebuilder:printcolumn:name="Admitted by",JSONPath=".spec.admission.clusterQueue",type=string,description="Name of the ClusterQueue that admitted this workload"
// +kubebuilder:printcolumn:name="Age",JSONPath=".metadata.creationTimestamp",type=date,description="Time this workload was created"
// +kubebuilder:storageversion

// Workload is the Schema for the workloads API
type Workload struct {
Expand Down
1 change: 1 addition & 0 deletions apis/kueue/v1beta1/clusterqueue_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ type ClusterQueuePreemption struct {
}

//+kubebuilder:object:root=true
//+kubebuilder:storageversion
//+kubebuilder:resource:scope=Cluster
//+kubebuilder:subresource:status
//+kubebuilder:printcolumn:name="Cohort",JSONPath=".spec.cohort",type=string,description="Cohort that this ClusterQueue belongs to"
Expand Down
1 change: 1 addition & 0 deletions apis/kueue/v1beta1/localqueue_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type LocalQueueStatus struct {
}

//+kubebuilder:object:root=true
//+kubebuilder:storageversion
//+kubebuilder:subresource:status
//+kubebuilder:printcolumn:name="ClusterQueue",JSONPath=".spec.clusterQueue",type=string,description="Backing ClusterQueue"
//+kubebuilder:printcolumn:name="Pending Workloads",JSONPath=".status.pendingWorkloads",type=integer,description="Number of pending workloads"
Expand Down
1 change: 1 addition & 0 deletions apis/kueue/v1beta1/resourceflavor_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
)

//+kubebuilder:object:root=true
//+kubebuilder:storageversion
//+kubebuilder:resource:scope=Cluster,shortName={flavor,flavors}

// ResourceFlavor is the Schema for the resourceflavors API.
Expand Down
3 changes: 2 additions & 1 deletion apis/kueue/v1beta1/workload_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,10 @@ const (
)

// +kubebuilder:object:root=true
// +kubebuilder:storageversion
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Queue",JSONPath=".spec.queueName",type=string,description="Name of the queue this workload was submitted to"
// +kubebuilder:printcolumn:name="Admitted by",JSONPath=".spec.admission.clusterQueue",type=string,description="Name of the ClusterQueue that admitted this workload"
// +kubebuilder:printcolumn:name="Admitted by",JSONPath=".status.admission.clusterQueue",type=string,description="Name of the ClusterQueue that admitted this workload"
// +kubebuilder:printcolumn:name="Age",JSONPath=".metadata.creationTimestamp",type=date,description="Time this workload was created"
// +kubebuilder:resource:shortName={wl}

Expand Down
77 changes: 37 additions & 40 deletions apis/kueue/webhooks/clusterqueue_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ package webhooks

import (
"context"
"fmt"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
apivalidation "k8s.io/apimachinery/pkg/api/validation"
"k8s.io/apimachinery/pkg/apis/meta/v1/validation"
Expand All @@ -31,7 +31,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/webhook"

kueue "sigs.k8s.io/kueue/apis/kueue/v1alpha2"
kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1"
)

const (
Expand All @@ -48,7 +48,7 @@ func setupWebhookForClusterQueue(mgr ctrl.Manager) error {
Complete()
}

// +kubebuilder:webhook:path=/mutate-kueue-x-k8s-io-v1alpha2-clusterqueue,mutating=true,failurePolicy=fail,sideEffects=None,groups=kueue.x-k8s.io,resources=clusterqueues,verbs=create,versions=v1alpha2,name=mclusterqueue.kb.io,admissionReviewVersions=v1
// +kubebuilder:webhook:path=/mutate-kueue-x-k8s-io-v1beta1-clusterqueue,mutating=true,failurePolicy=fail,sideEffects=None,groups=kueue.x-k8s.io,resources=clusterqueues,verbs=create,versions=v1beta1,name=mclusterqueue.kb.io,admissionReviewVersions=v1

var _ webhook.CustomDefaulter = &ClusterQueueWebhook{}

Expand All @@ -69,7 +69,7 @@ func (w *ClusterQueueWebhook) Default(ctx context.Context, obj runtime.Object) e
return nil
}

// +kubebuilder:webhook:path=/validate-kueue-x-k8s-io-v1alpha2-clusterqueue,mutating=false,failurePolicy=fail,sideEffects=None,groups=kueue.x-k8s.io,resources=clusterqueues,verbs=create;update,versions=v1alpha2,name=vclusterqueue.kb.io,admissionReviewVersions=v1
// +kubebuilder:webhook:path=/validate-kueue-x-k8s-io-v1beta1-clusterqueue,mutating=false,failurePolicy=fail,sideEffects=None,groups=kueue.x-k8s.io,resources=clusterqueues,verbs=create;update,versions=v1beta1,name=vclusterqueue.kb.io,admissionReviewVersions=v1

var _ webhook.CustomValidator = &ClusterQueueWebhook{}

Expand Down Expand Up @@ -105,7 +105,7 @@ func ValidateClusterQueue(cq *kueue.ClusterQueue) field.ErrorList {
if len(cq.Spec.Cohort) != 0 {
allErrs = append(allErrs, validateNameReference(cq.Spec.Cohort, path.Child("cohort"))...)
}
allErrs = append(allErrs, validateResources(cq.Spec.Resources, path.Child("resources"))...)
allErrs = append(allErrs, validateResourceGroups(cq.Spec.ResourceGroups, path.Child("resourceGroups"))...)
allErrs = append(allErrs,
validation.ValidateLabelSelector(cq.Spec.NamespaceSelector, validation.LabelSelectorValidationOptions{}, path.Child("namespaceSelector"))...)

Expand All @@ -123,55 +123,52 @@ func ValidateClusterQueueUpdate(newObj, oldObj *kueue.ClusterQueue) field.ErrorL
return allErrs
}

func validateResources(resources []kueue.Resource, path *field.Path) field.ErrorList {
func validateResourceGroups(resourceGroups []kueue.ResourceGroup, path *field.Path) field.ErrorList {
var allErrs field.ErrorList
flavorsPerRes := make([]sets.Set[string], len(resources))
seenResources := sets.New[corev1.ResourceName]()
seenFlavors := sets.New[kueue.ResourceFlavorReference]()

for i, resource := range resources {
for i, rg := range resourceGroups {
path := path.Index(i)
allErrs = append(allErrs, validateResourceName(resource.Name, path.Child("name"))...)

flavorsPerRes[i] = make(sets.Set[string], len(resource.Flavors))
for j, flavor := range resource.Flavors {
path := path.Child("flavors").Index(j)
allErrs = append(allErrs, validateNameReference(string(flavor.Name), path.Child("name"))...)
allErrs = append(allErrs, validateFlavorQuota(flavor, path.Child("quota"))...)
flavorsPerRes[i].Insert(string(flavor.Name))
for j, name := range rg.CoveredResources {
path := path.Child("coveredResources").Index(j)
allErrs = append(allErrs, validateResourceName(name, path)...)
if seenResources.Has(name) {
allErrs = append(allErrs, field.Duplicate(path, name))
} else {
seenResources.Insert(name)
}
}
for j := 0; j < i; j++ {
if !flavorsPerRes[i].HasAny(flavorsPerRes[j].UnsortedList()...) || matchesFlavorsInOrder(resource.Flavors, resources[j].Flavors) {
continue
for j, fqs := range rg.Flavors {
path := path.Child("flavors").Index(j)
allErrs = append(allErrs, validateFlavorQuotas(fqs, rg.CoveredResources, path)...)
if seenFlavors.Has(fqs.Name) {
allErrs = append(allErrs, field.Duplicate(path.Child("name"), fqs.Name))
} else {
seenFlavors.Insert(fqs.Name)
}
err := field.Invalid(path.Child("flavors"), resource.Flavors, fmt.Sprintf("has flavors present in resource %s; all flavors must be different or they all must be present in the same order", resources[j].Name))
allErrs = append(allErrs, err)
}
}
return allErrs
}

func validateFlavorQuota(flavor kueue.Flavor, path *field.Path) field.ErrorList {
var allErrs field.ErrorList
allErrs = append(allErrs, validateResourceQuantity(flavor.Quota.Min, path.Child("min"))...)

if flavor.Quota.Max != nil {
allErrs = append(allErrs, validateResourceQuantity(*flavor.Quota.Max, path.Child("max"))...)
if flavor.Quota.Min.Cmp(*flavor.Quota.Max) > 0 {
allErrs = append(allErrs, field.Invalid(path.Child("min"), flavor.Quota.Min.String(), fmt.Sprintf("must be less than or equal to %s max", flavor.Name)))
}
func validateFlavorQuotas(flavorQuotas kueue.FlavorQuotas, coveredResources []corev1.ResourceName, path *field.Path) field.ErrorList {
allErrs := validateNameReference(string(flavorQuotas.Name), path.Child("name"))
if len(flavorQuotas.Resources) != len(coveredResources) {
allErrs = append(allErrs, field.Invalid(path.Child("resources"), field.OmitValueType{}, "must have the same number of resources as the coveredResources"))
}
return allErrs
}

func matchesFlavorsInOrder(f1, f2 []kueue.Flavor) bool {
if len(f1) != len(f2) {
return false
}
for i := range f1 {
if f1[i].Name != f2[i].Name {
return false
for i, rq := range flavorQuotas.Resources {
path := path.Child("resources").Index(i)
if rq.Name != coveredResources[i] {
allErrs = append(allErrs, field.Invalid(path.Child("name"), rq.Name, "must match the name in coveredResources"))
}
allErrs = append(allErrs, validateResourceQuantity(rq.NominalQuota, path.Child("nominalQuota"))...)
if rq.BorrowingLimit != nil {
allErrs = append(allErrs, validateResourceQuantity(*rq.BorrowingLimit, path.Child("borrowingLimit"))...)
}
}
return true
return allErrs
}

// validateResourceQuantity enforces that specified quantity is valid for specified resource
Expand Down
Loading

0 comments on commit cfaf110

Please sign in to comment.