sigs.k8s.io/kueue@v0.6.2/pkg/controller/jobframework/validation.go (about)

     1  /*
     2  Copyright 2023 The Kubernetes Authors.
     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      http://www.apache.org/licenses/LICENSE-2.0
     7  Unless required by applicable law or agreed to in writing, software
     8  distributed under the License is distributed on an "AS IS" BASIS,
     9  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    10  See the License for the specific language governing permissions and
    11  limitations under the License.
    12  */
    13  
    14  package jobframework
    15  
    16  import (
    17  	"fmt"
    18  	"strings"
    19  
    20  	batchv1 "k8s.io/api/batch/v1"
    21  	apivalidation "k8s.io/apimachinery/pkg/api/validation"
    22  	"k8s.io/apimachinery/pkg/util/sets"
    23  	"k8s.io/apimachinery/pkg/util/validation"
    24  	"k8s.io/apimachinery/pkg/util/validation/field"
    25  	jobset "sigs.k8s.io/jobset/api/jobset/v1alpha2"
    26  
    27  	"sigs.k8s.io/kueue/pkg/controller/constants"
    28  )
    29  
    30  var (
    31  	annotationsPath               = field.NewPath("metadata", "annotations")
    32  	labelsPath                    = field.NewPath("metadata", "labels")
    33  	parentWorkloadKeyPath         = annotationsPath.Key(constants.ParentWorkloadAnnotation)
    34  	queueNameLabelPath            = labelsPath.Key(constants.QueueLabel)
    35  	workloadPriorityClassNamePath = labelsPath.Key(constants.WorkloadPriorityClassLabel)
    36  	supportedPrebuiltWlJobGVKs    = sets.New(batchv1.SchemeGroupVersion.WithKind("Job").String(),
    37  		jobset.SchemeGroupVersion.WithKind("JobSet").String())
    38  )
    39  
    40  func ValidateCreateForQueueName(job GenericJob) field.ErrorList {
    41  	var allErrs field.ErrorList
    42  	allErrs = append(allErrs, ValidateLabelAsCRDName(job, constants.QueueLabel)...)
    43  	allErrs = append(allErrs, ValidateLabelAsCRDName(job, constants.PrebuiltWorkloadLabel)...)
    44  	allErrs = append(allErrs, ValidateAnnotationAsCRDName(job, constants.QueueAnnotation)...)
    45  
    46  	// this rule should be relaxed when its confirmed that running wit a prebuilt wl is fully supported by each integration
    47  	if _, hasPrebuilt := job.Object().GetLabels()[constants.PrebuiltWorkloadLabel]; hasPrebuilt {
    48  		gvk := job.GVK().String()
    49  		if !supportedPrebuiltWlJobGVKs.Has(gvk) {
    50  			allErrs = append(allErrs, field.Forbidden(labelsPath.Key(constants.PrebuiltWorkloadLabel), fmt.Sprintf("Is not supported for %q", gvk)))
    51  		}
    52  	}
    53  	return allErrs
    54  }
    55  
    56  func ValidateAnnotationAsCRDName(job GenericJob, crdNameAnnotation string) field.ErrorList {
    57  	var allErrs field.ErrorList
    58  	if value, exists := job.Object().GetAnnotations()[crdNameAnnotation]; exists {
    59  		if errs := validation.IsDNS1123Subdomain(value); len(errs) > 0 {
    60  			allErrs = append(allErrs, field.Invalid(annotationsPath.Key(crdNameAnnotation), value, strings.Join(errs, ",")))
    61  		}
    62  	}
    63  	return allErrs
    64  }
    65  
    66  func ValidateLabelAsCRDName(job GenericJob, crdNameLabel string) field.ErrorList {
    67  	var allErrs field.ErrorList
    68  	if value, exists := job.Object().GetLabels()[crdNameLabel]; exists {
    69  		if errs := validation.IsDNS1123Subdomain(value); len(errs) > 0 {
    70  			allErrs = append(allErrs, field.Invalid(labelsPath.Key(crdNameLabel), value, strings.Join(errs, ",")))
    71  		}
    72  	}
    73  	return allErrs
    74  }
    75  
    76  func ValidateCreateForParentWorkload(job GenericJob) field.ErrorList {
    77  	var allErrs field.ErrorList
    78  	if _, exists := job.Object().GetAnnotations()[constants.ParentWorkloadAnnotation]; exists {
    79  		if job.Object().GetOwnerReferences() == nil {
    80  			allErrs = append(allErrs, field.Forbidden(parentWorkloadKeyPath, "must not add a parent workload annotation to job without OwnerReference"))
    81  		}
    82  	}
    83  	return allErrs
    84  }
    85  
    86  func ValidateUpdateForQueueName(oldJob, newJob GenericJob) field.ErrorList {
    87  	var allErrs field.ErrorList
    88  	if !newJob.IsSuspended() {
    89  		allErrs = append(allErrs, apivalidation.ValidateImmutableField(QueueName(oldJob), QueueName(newJob), queueNameLabelPath)...)
    90  	}
    91  
    92  	oldWlName, _ := PrebuiltWorkloadFor(oldJob)
    93  	newWlName, _ := PrebuiltWorkloadFor(newJob)
    94  	allErrs = append(allErrs, apivalidation.ValidateImmutableField(oldWlName, newWlName, labelsPath.Key(constants.PrebuiltWorkloadLabel))...)
    95  	return allErrs
    96  }
    97  
    98  func ValidateUpdateForParentWorkload(oldJob, newJob GenericJob) field.ErrorList {
    99  	allErrs := apivalidation.ValidateImmutableField(ParentWorkloadName(newJob), ParentWorkloadName(oldJob), parentWorkloadKeyPath)
   100  	return allErrs
   101  }
   102  
   103  func ValidateUpdateForWorkloadPriorityClassName(oldJob, newJob GenericJob) field.ErrorList {
   104  	allErrs := apivalidation.ValidateImmutableField(workloadPriorityClassName(oldJob), workloadPriorityClassName(newJob), workloadPriorityClassNamePath)
   105  	return allErrs
   106  }