Change:
Following YAML file is accepted without error. Notice the field, it is an instead of , containing character. This can lead to an issue when resource driver generates structured parameters' in-tree object with being just without version. The DRA scheduler plugin will try to match the parameters object based on the reference here: In latest master the code appears to use an indexer, and the issue might be hidden, if applicable at all. I did not check the reproducibility in master yet. However, main question is whether the should allow value with character in general. An error is expected from the apiserver upon object creation request, reporting that APIGroup containes APIVersion. Maybe. Have any resource driver that supports structured parameters, , for instance, also puts (gpucrd.APIGroup) value into . v1.30.1 <details</details<details</details<details</details<details</details<detailsscheduler's dynamicresources plugin </details
/sig node /triage accepted
/assign

Discussion:
import ( apiequality "k8s.io/apimachinery/pkg/api/equality" apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation" <ins> pathvalidation "k8s.io/apimachinery/pkg/api/validation/path" </ins> "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" <ins> utilvalidation "k8s.io/apimachinery/pkg/util/validation" </ins> "k8s.io/apimachinery/pkg/util/validation/field" corevalidation "k8s.io/kubernetes/pkg/apis/core/validation" "k8s.io/kubernetes/pkg/apis/resource"

func validateResourceClaimParametersRef(ref *resource.ResourceClaimParametersReference, fldPath *field.Path) field.ErrorList { var allErrs field.ErrorList <del> if ref != nil { if ref.Kind == "" { allErrs = append(allErrs, field.Required(fldPath.Child("kind"), "")) </del> <ins> if ref == nil { return allErrs } // group is required but the Core group is the empty value, so it can not be enforced. if ref.APIGroup != "" { for _, msg := range utilvalidation.IsDNS1123Subdomain(ref.APIGroup) { allErrs = append(allErrs, field.Invalid(fldPath.Child("apiGroup"), ref.APIGroup, msg)) } } if ref.Kind == "" { allErrs = append(allErrs, field.Required(fldPath.Child("kind"), "")) } else { for _, msg := range pathvalidation.IsValidPathSegmentName(ref.Kind) { allErrs = append(allErrs, field.Invalid(fldPath.Child("kind"), ref.Kind, msg)) </ins> } <del> if ref.Name == "" { allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) </del> <ins> } if ref.Name == "" { allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) } else { for _, msg := range pathvalidation.IsValidPathSegmentName(ref.Name) { allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), ref.Name, msg)) </ins> } } return allErrs

func validateClassParameters(ref *resource.ResourceClassParametersReference, fldPath *field.Path) field.ErrorList { var allErrs field.ErrorList <del> if ref != nil { if ref.Kind == "" { allErrs = append(allErrs, field.Required(fldPath.Child("kind"), "")) </del> <ins> if ref == nil { return allErrs } // group is required but the Core group is the empty value, so it can not be enforced. if ref.APIGroup != "" { for _, msg := range utilvalidation.IsDNS1123Subdomain(ref.APIGroup) { allErrs = append(allErrs, field.Invalid(fldPath.Child("apiGroup"), ref.APIGroup, msg)) </ins> } <del> if ref.Name == "" { allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) </del> <ins> } if ref.Kind == "" { allErrs = append(allErrs, field.Required(fldPath.Child("kind"), "")) } else { for _, msg := range pathvalidation.IsValidPathSegmentName(ref.Kind) { allErrs = append(allErrs, field.Invalid(fldPath.Child("kind"), ref.Kind, msg)) </ins> } <del> if ref.Namespace != "" { for _, msg := range apimachineryvalidation.ValidateNamespaceName(ref.Namespace, false) { allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), ref.Namespace, msg)) } </del> <ins> } if ref.Name == "" { allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) } else { for _, msg := range pathvalidation.IsValidPathSegmentName(ref.Name) { allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), ref.Name, msg)) } } // namespace is optional. if ref.Namespace != "" { for _, msg := range apimachineryvalidation.ValidateNamespaceName(ref.Namespace, false) { allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), ref.Namespace, msg)) </ins> } } return allErrs

} now := metav1.Now() badValue := "spaces not allowed" <ins> badAPIGroup := "example.com/v1" goodAPIGroup := "example.com" </ins> scenarios := map[string]struct { claim        *resource.ResourceClaim

return claim }(), }, <ins> "good-parameters-apigroup": { claim: func() *resource.ResourceClaim { claim := testClaim(goodName, goodNS, goodClaimSpec) claim.Spec.ParametersRef = &resource.ResourceClaimParametersReference{ APIGroup: goodAPIGroup, Kind:     "foo", Name:     "bar", } return claim }(), }, "bad-parameters-apigroup": { wantFailures: field.ErrorList{field.Invalid(field.NewPath("spec", "parametersRef", "apiGroup"), badAPIGroup, "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')")}, claim: func() *resource.ResourceClaim { claim := testClaim(goodName, goodNS, goodClaimSpec) claim.Spec.ParametersRef = &resource.ResourceClaimParametersReference{ APIGroup: badAPIGroup, Kind:     "foo", Name:     "bar", } return claim }(), }, </ins> "missing-parameters-kind": { wantFailures: field.ErrorList{field.Required(field.NewPath("spec", "parametersRef", "kind"), "")}, claim: func() *resource.ResourceClaim {

} now := metav1.Now() badValue := "spaces not allowed" <ins> badAPIGroup := "example.com/v1" goodAPIGroup := "example.com" </ins> scenarios := map[string]struct { template     *resource.ResourceClaimTemplate

return template }(), }, <ins> "good-parameters-apigroup": { template: func() *resource.ResourceClaimTemplate { template := testClaimTemplate(goodName, goodNS, goodClaimSpec) template.Spec.Spec.ParametersRef = &resource.ResourceClaimParametersReference{ APIGroup: goodAPIGroup, Kind:     "foo", Name:     "bar", } return template }(), }, "bad-parameters-apigroup": { wantFailures: field.ErrorList{field.Invalid(field.NewPath("spec", "spec", "parametersRef", "apiGroup"), badAPIGroup, "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')")}, template: func() *resource.ResourceClaimTemplate { template := testClaimTemplate(goodName, goodNS, goodClaimSpec) template.Spec.Spec.ParametersRef = &resource.ResourceClaimParametersReference{ APIGroup: badAPIGroup, Kind:     "foo", Name:     "bar", } return template }(), }, </ins> "missing-parameters-kind": { wantFailures: field.ErrorList{field.Required(field.NewPath("spec", "spec", "parametersRef", "kind"), "")}, template: func() *resource.ResourceClaimTemplate {

} badName := "!@#$%^" badValue := "spaces not allowed" <ins> badAPIGroup := "example.com/v1" goodAPIGroup := "example.com" </ins> scenarios := map[string]struct { class        *resource.ResourceClass

return class }(), }, <ins> "good-parameters-apigroup": { class: func() *resource.ResourceClass { class := testClass(goodName, goodName) class.ParametersRef = goodParameters.DeepCopy() class.ParametersRef.APIGroup = goodAPIGroup return class }(), }, "bad-parameters-apigroup": { wantFailures: field.ErrorList{field.Invalid(field.NewPath("parametersRef", "apiGroup"), badAPIGroup, "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')")}, class: func() *resource.ResourceClass { class := testClass(goodName, goodName) class.ParametersRef = goodParameters.DeepCopy() class.ParametersRef.APIGroup = badAPIGroup return class }(), }, </ins> "missing-parameters-name": { wantFailures: field.ErrorList{field.Required(field.NewPath("parametersRef", "name"), "")}, class: func() *resource.ResourceClass {