generic set

This commit is contained in:
AxeZhan 2023-10-26 12:46:28 +08:00
parent 92c4b3254f
commit 070e7a38cb
13 changed files with 408 additions and 364 deletions

View File

@ -390,19 +390,19 @@ func TestValidateStatefulSet(t *testing.T) {
name: "invalid restart policy 1", name: "invalid restart policy 1",
set: mkStatefulSet(&validPodTemplate, tweakTemplateRestartPolicy(api.RestartPolicyOnFailure)), set: mkStatefulSet(&validPodTemplate, tweakTemplateRestartPolicy(api.RestartPolicyOnFailure)),
errs: field.ErrorList{ errs: field.ErrorList{
field.NotSupported(field.NewPath("spec", "template", "spec", "restartPolicy"), nil, nil), field.NotSupported[string](field.NewPath("spec", "template", "spec", "restartPolicy"), nil, nil),
}, },
}, { }, {
name: "invalid restart policy 2", name: "invalid restart policy 2",
set: mkStatefulSet(&validPodTemplate, tweakTemplateRestartPolicy(api.RestartPolicyNever)), set: mkStatefulSet(&validPodTemplate, tweakTemplateRestartPolicy(api.RestartPolicyNever)),
errs: field.ErrorList{ errs: field.ErrorList{
field.NotSupported(field.NewPath("spec", "template", "spec", "restartPolicy"), nil, nil), field.NotSupported[string](field.NewPath("spec", "template", "spec", "restartPolicy"), nil, nil),
}, },
}, { }, {
name: "empty restart policy", name: "empty restart policy",
set: mkStatefulSet(&validPodTemplate, tweakTemplateRestartPolicy("")), set: mkStatefulSet(&validPodTemplate, tweakTemplateRestartPolicy("")),
errs: field.ErrorList{ errs: field.ErrorList{
field.NotSupported(field.NewPath("spec", "template", "spec", "restartPolicy"), nil, nil), field.NotSupported[string](field.NewPath("spec", "template", "spec", "restartPolicy"), nil, nil),
}, },
}, { }, {
name: "invalid update strategy", name: "invalid update strategy",
@ -468,8 +468,8 @@ func TestValidateStatefulSet(t *testing.T) {
tweakPVCPolicy(mkPVCPolicy()), tweakPVCPolicy(mkPVCPolicy()),
), ),
errs: field.ErrorList{ errs: field.ErrorList{
field.NotSupported(field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenDeleted"), nil, nil), field.NotSupported[string](field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenDeleted"), nil, nil),
field.NotSupported(field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenScaled"), nil, nil), field.NotSupported[string](field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenScaled"), nil, nil),
}, },
}, { }, {
name: "invalid PersistentVolumeClaimRetentionPolicy " + enableStatefulSetAutoDeletePVC, name: "invalid PersistentVolumeClaimRetentionPolicy " + enableStatefulSetAutoDeletePVC,
@ -480,8 +480,8 @@ func TestValidateStatefulSet(t *testing.T) {
)), )),
), ),
errs: field.ErrorList{ errs: field.ErrorList{
field.NotSupported(field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenDeleted"), nil, nil), field.NotSupported[string](field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenDeleted"), nil, nil),
field.NotSupported(field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenScaled"), nil, nil), field.NotSupported[string](field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenScaled"), nil, nil),
}, },
}, { }, {
name: "zero maxUnavailable", name: "zero maxUnavailable",

View File

@ -18,6 +18,7 @@ package validation
import ( import (
"fmt" "fmt"
apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation" apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
pathvalidation "k8s.io/apimachinery/pkg/api/validation/path" pathvalidation "k8s.io/apimachinery/pkg/api/validation/path"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
@ -387,7 +388,7 @@ func validateContainerResourceSource(src *autoscaling.ContainerResourceMetricSou
if len(src.Name) == 0 { if len(src.Name) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("name"), "must specify a resource name")) allErrs = append(allErrs, field.Required(fldPath.Child("name"), "must specify a resource name"))
} else { } else {
allErrs = append(allErrs, corevalidation.ValidateContainerResourceName(string(src.Name), fldPath.Child("name"))...) allErrs = append(allErrs, corevalidation.ValidateContainerResourceName(src.Name, fldPath.Child("name"))...)
} }
if len(src.Container) == 0 { if len(src.Container) == 0 {

View File

@ -919,7 +919,7 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
}}, }},
}, },
}, },
msg: "Invalid value: \"InvalidResource\": must be a standard resource type or fully qualified", msg: "Invalid value: InvalidResource: must be a standard resource type or fully qualified",
}, { }, {
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},

View File

@ -113,34 +113,34 @@ var Semantic = conversion.EqualitiesOrDie(
}, },
) )
var standardResourceQuotaScopes = sets.NewString( var standardResourceQuotaScopes = sets.New(
string(core.ResourceQuotaScopeTerminating), core.ResourceQuotaScopeTerminating,
string(core.ResourceQuotaScopeNotTerminating), core.ResourceQuotaScopeNotTerminating,
string(core.ResourceQuotaScopeBestEffort), core.ResourceQuotaScopeBestEffort,
string(core.ResourceQuotaScopeNotBestEffort), core.ResourceQuotaScopeNotBestEffort,
string(core.ResourceQuotaScopePriorityClass), core.ResourceQuotaScopePriorityClass,
) )
// IsStandardResourceQuotaScope returns true if the scope is a standard value // IsStandardResourceQuotaScope returns true if the scope is a standard value
func IsStandardResourceQuotaScope(str string) bool { func IsStandardResourceQuotaScope(scope core.ResourceQuotaScope) bool {
return standardResourceQuotaScopes.Has(str) || str == string(core.ResourceQuotaScopeCrossNamespacePodAffinity) return standardResourceQuotaScopes.Has(scope) || scope == core.ResourceQuotaScopeCrossNamespacePodAffinity
} }
var podObjectCountQuotaResources = sets.NewString( var podObjectCountQuotaResources = sets.New(
string(core.ResourcePods), core.ResourcePods,
) )
var podComputeQuotaResources = sets.NewString( var podComputeQuotaResources = sets.New(
string(core.ResourceCPU), core.ResourceCPU,
string(core.ResourceMemory), core.ResourceMemory,
string(core.ResourceLimitsCPU), core.ResourceLimitsCPU,
string(core.ResourceLimitsMemory), core.ResourceLimitsMemory,
string(core.ResourceRequestsCPU), core.ResourceRequestsCPU,
string(core.ResourceRequestsMemory), core.ResourceRequestsMemory,
) )
// IsResourceQuotaScopeValidForResource returns true if the resource applies to the specified scope // IsResourceQuotaScopeValidForResource returns true if the resource applies to the specified scope
func IsResourceQuotaScopeValidForResource(scope core.ResourceQuotaScope, resource string) bool { func IsResourceQuotaScopeValidForResource(scope core.ResourceQuotaScope, resource core.ResourceName) bool {
switch scope { switch scope {
case core.ResourceQuotaScopeTerminating, core.ResourceQuotaScopeNotTerminating, core.ResourceQuotaScopeNotBestEffort, case core.ResourceQuotaScopeTerminating, core.ResourceQuotaScopeNotTerminating, core.ResourceQuotaScopeNotBestEffort,
core.ResourceQuotaScopePriorityClass, core.ResourceQuotaScopeCrossNamespacePodAffinity: core.ResourceQuotaScopePriorityClass, core.ResourceQuotaScopeCrossNamespacePodAffinity:
@ -152,16 +152,16 @@ func IsResourceQuotaScopeValidForResource(scope core.ResourceQuotaScope, resourc
} }
} }
var standardContainerResources = sets.NewString( var standardContainerResources = sets.New(
string(core.ResourceCPU), core.ResourceCPU,
string(core.ResourceMemory), core.ResourceMemory,
string(core.ResourceEphemeralStorage), core.ResourceEphemeralStorage,
) )
// IsStandardContainerResourceName returns true if the container can make a resource request // IsStandardContainerResourceName returns true if the container can make a resource request
// for the specified resource // for the specified resource
func IsStandardContainerResourceName(str string) bool { func IsStandardContainerResourceName(name core.ResourceName) bool {
return standardContainerResources.Has(str) || IsHugePageResourceName(core.ResourceName(str)) return standardContainerResources.Has(name) || IsHugePageResourceName(name)
} }
// IsExtendedResourceName returns true if: // IsExtendedResourceName returns true if:
@ -196,88 +196,88 @@ func IsOvercommitAllowed(name core.ResourceName) bool {
!IsHugePageResourceName(name) !IsHugePageResourceName(name)
} }
var standardLimitRangeTypes = sets.NewString( var standardLimitRangeTypes = sets.New(
string(core.LimitTypePod), core.LimitTypePod,
string(core.LimitTypeContainer), core.LimitTypeContainer,
string(core.LimitTypePersistentVolumeClaim), core.LimitTypePersistentVolumeClaim,
) )
// IsStandardLimitRangeType returns true if the type is Pod or Container // IsStandardLimitRangeType returns true if the type is Pod or Container
func IsStandardLimitRangeType(str string) bool { func IsStandardLimitRangeType(value core.LimitType) bool {
return standardLimitRangeTypes.Has(str) return standardLimitRangeTypes.Has(value)
} }
var standardQuotaResources = sets.NewString( var standardQuotaResources = sets.New(
string(core.ResourceCPU), core.ResourceCPU,
string(core.ResourceMemory), core.ResourceMemory,
string(core.ResourceEphemeralStorage), core.ResourceEphemeralStorage,
string(core.ResourceRequestsCPU), core.ResourceRequestsCPU,
string(core.ResourceRequestsMemory), core.ResourceRequestsMemory,
string(core.ResourceRequestsStorage), core.ResourceRequestsStorage,
string(core.ResourceRequestsEphemeralStorage), core.ResourceRequestsEphemeralStorage,
string(core.ResourceLimitsCPU), core.ResourceLimitsCPU,
string(core.ResourceLimitsMemory), core.ResourceLimitsMemory,
string(core.ResourceLimitsEphemeralStorage), core.ResourceLimitsEphemeralStorage,
string(core.ResourcePods), core.ResourcePods,
string(core.ResourceQuotas), core.ResourceQuotas,
string(core.ResourceServices), core.ResourceServices,
string(core.ResourceReplicationControllers), core.ResourceReplicationControllers,
string(core.ResourceSecrets), core.ResourceSecrets,
string(core.ResourcePersistentVolumeClaims), core.ResourcePersistentVolumeClaims,
string(core.ResourceConfigMaps), core.ResourceConfigMaps,
string(core.ResourceServicesNodePorts), core.ResourceServicesNodePorts,
string(core.ResourceServicesLoadBalancers), core.ResourceServicesLoadBalancers,
) )
// IsStandardQuotaResourceName returns true if the resource is known to // IsStandardQuotaResourceName returns true if the resource is known to
// the quota tracking system // the quota tracking system
func IsStandardQuotaResourceName(str string) bool { func IsStandardQuotaResourceName(name core.ResourceName) bool {
return standardQuotaResources.Has(str) || IsQuotaHugePageResourceName(core.ResourceName(str)) return standardQuotaResources.Has(name) || IsQuotaHugePageResourceName(name)
} }
var standardResources = sets.NewString( var standardResources = sets.New(
string(core.ResourceCPU), core.ResourceCPU,
string(core.ResourceMemory), core.ResourceMemory,
string(core.ResourceEphemeralStorage), core.ResourceEphemeralStorage,
string(core.ResourceRequestsCPU), core.ResourceRequestsCPU,
string(core.ResourceRequestsMemory), core.ResourceRequestsMemory,
string(core.ResourceRequestsEphemeralStorage), core.ResourceRequestsEphemeralStorage,
string(core.ResourceLimitsCPU), core.ResourceLimitsCPU,
string(core.ResourceLimitsMemory), core.ResourceLimitsMemory,
string(core.ResourceLimitsEphemeralStorage), core.ResourceLimitsEphemeralStorage,
string(core.ResourcePods), core.ResourcePods,
string(core.ResourceQuotas), core.ResourceQuotas,
string(core.ResourceServices), core.ResourceServices,
string(core.ResourceReplicationControllers), core.ResourceReplicationControllers,
string(core.ResourceSecrets), core.ResourceSecrets,
string(core.ResourceConfigMaps), core.ResourceConfigMaps,
string(core.ResourcePersistentVolumeClaims), core.ResourcePersistentVolumeClaims,
string(core.ResourceStorage), core.ResourceStorage,
string(core.ResourceRequestsStorage), core.ResourceRequestsStorage,
string(core.ResourceServicesNodePorts), core.ResourceServicesNodePorts,
string(core.ResourceServicesLoadBalancers), core.ResourceServicesLoadBalancers,
) )
// IsStandardResourceName returns true if the resource is known to the system // IsStandardResourceName returns true if the resource is known to the system
func IsStandardResourceName(str string) bool { func IsStandardResourceName(name core.ResourceName) bool {
return standardResources.Has(str) || IsQuotaHugePageResourceName(core.ResourceName(str)) return standardResources.Has(name) || IsQuotaHugePageResourceName(name)
} }
var integerResources = sets.NewString( var integerResources = sets.New(
string(core.ResourcePods), core.ResourcePods,
string(core.ResourceQuotas), core.ResourceQuotas,
string(core.ResourceServices), core.ResourceServices,
string(core.ResourceReplicationControllers), core.ResourceReplicationControllers,
string(core.ResourceSecrets), core.ResourceSecrets,
string(core.ResourceConfigMaps), core.ResourceConfigMaps,
string(core.ResourcePersistentVolumeClaims), core.ResourcePersistentVolumeClaims,
string(core.ResourceServicesNodePorts), core.ResourceServicesNodePorts,
string(core.ResourceServicesLoadBalancers), core.ResourceServicesLoadBalancers,
) )
// IsIntegerResourceName returns true if the resource is measured in integer values // IsIntegerResourceName returns true if the resource is measured in integer values
func IsIntegerResourceName(str string) bool { func IsIntegerResourceName(name core.ResourceName) bool {
return integerResources.Has(str) || IsExtendedResourceName(core.ResourceName(str)) return integerResources.Has(name) || IsExtendedResourceName(name)
} }
// IsServiceIPSet aims to check if the service's ClusterIP is set or not // IsServiceIPSet aims to check if the service's ClusterIP is set or not
@ -289,7 +289,7 @@ func IsServiceIPSet(service *core.Service) bool {
service.Spec.ClusterIP != core.ClusterIPNone service.Spec.ClusterIP != core.ClusterIPNone
} }
var standardFinalizers = sets.NewString( var standardFinalizers = sets.New(
string(core.FinalizerKubernetes), string(core.FinalizerKubernetes),
metav1.FinalizerOrphanDependents, metav1.FinalizerOrphanDependents,
metav1.FinalizerDeleteDependents, metav1.FinalizerDeleteDependents,

View File

@ -60,7 +60,7 @@ func TestIsStandardResource(t *testing.T) {
{"requests.hugepages-2Mi", true}, {"requests.hugepages-2Mi", true},
} }
for i, tc := range testCases { for i, tc := range testCases {
if IsStandardResourceName(tc.input) != tc.output { if IsStandardResourceName(core.ResourceName(tc.input)) != tc.output {
t.Errorf("case[%d], input: %s, expected: %t, got: %t", i, tc.input, tc.output, !tc.output) t.Errorf("case[%d], input: %s, expected: %t, got: %t", i, tc.input, tc.output, !tc.output)
} }
} }
@ -77,7 +77,7 @@ func TestIsStandardContainerResource(t *testing.T) {
{"hugepages-2Mi", true}, {"hugepages-2Mi", true},
} }
for i, tc := range testCases { for i, tc := range testCases {
if IsStandardContainerResourceName(tc.input) != tc.output { if IsStandardContainerResourceName(core.ResourceName(tc.input)) != tc.output {
t.Errorf("case[%d], input: %s, expected: %t, got: %t", i, tc.input, tc.output, !tc.output) t.Errorf("case[%d], input: %s, expected: %t, got: %t", i, tc.input, tc.output, !tc.output)
} }
} }

View File

@ -24,6 +24,7 @@ import (
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/helper" "k8s.io/kubernetes/pkg/apis/core/helper"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
apivalidation "k8s.io/kubernetes/pkg/apis/core/validation" apivalidation "k8s.io/kubernetes/pkg/apis/core/validation"
@ -42,18 +43,18 @@ func ValidateResourceRequirements(requirements *v1.ResourceRequirements, fldPath
for resourceName, quantity := range requirements.Limits { for resourceName, quantity := range requirements.Limits {
fldPath := limPath.Key(string(resourceName)) fldPath := limPath.Key(string(resourceName))
// Validate resource name. // Validate resource name.
allErrs = append(allErrs, ValidateContainerResourceName(string(resourceName), fldPath)...) allErrs = append(allErrs, ValidateContainerResourceName(core.ResourceName(resourceName), fldPath)...)
// Validate resource quantity. // Validate resource quantity.
allErrs = append(allErrs, ValidateResourceQuantityValue(string(resourceName), quantity, fldPath)...) allErrs = append(allErrs, ValidateResourceQuantityValue(core.ResourceName(resourceName), quantity, fldPath)...)
} }
for resourceName, quantity := range requirements.Requests { for resourceName, quantity := range requirements.Requests {
fldPath := reqPath.Key(string(resourceName)) fldPath := reqPath.Key(string(resourceName))
// Validate resource name. // Validate resource name.
allErrs = append(allErrs, ValidateContainerResourceName(string(resourceName), fldPath)...) allErrs = append(allErrs, ValidateContainerResourceName(core.ResourceName(resourceName), fldPath)...)
// Validate resource quantity. // Validate resource quantity.
allErrs = append(allErrs, ValidateResourceQuantityValue(string(resourceName), quantity, fldPath)...) allErrs = append(allErrs, ValidateResourceQuantityValue(core.ResourceName(resourceName), quantity, fldPath)...)
// Check that request <= limit. // Check that request <= limit.
limitQuantity, exists := requirements.Limits[resourceName] limitQuantity, exists := requirements.Limits[resourceName]
@ -71,9 +72,9 @@ func ValidateResourceRequirements(requirements *v1.ResourceRequirements, fldPath
} }
// ValidateContainerResourceName checks the name of resource specified for a container // ValidateContainerResourceName checks the name of resource specified for a container
func ValidateContainerResourceName(value string, fldPath *field.Path) field.ErrorList { func ValidateContainerResourceName(value core.ResourceName, fldPath *field.Path) field.ErrorList {
allErrs := validateResourceName(value, fldPath) allErrs := validateResourceName(value, fldPath)
if len(strings.Split(value, "/")) == 1 { if len(strings.Split(string(value), "/")) == 1 {
if !helper.IsStandardContainerResourceName(value) { if !helper.IsStandardContainerResourceName(value) {
return append(allErrs, field.Invalid(fldPath, value, "must be a standard resource for containers")) return append(allErrs, field.Invalid(fldPath, value, "must be a standard resource for containers"))
} }
@ -86,7 +87,7 @@ func ValidateContainerResourceName(value string, fldPath *field.Path) field.Erro
} }
// ValidateResourceQuantityValue enforces that specified quantity is valid for specified resource // ValidateResourceQuantityValue enforces that specified quantity is valid for specified resource
func ValidateResourceQuantityValue(resource string, value resource.Quantity, fldPath *field.Path) field.ErrorList { func ValidateResourceQuantityValue(resource core.ResourceName, value resource.Quantity, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateNonnegativeQuantity(value, fldPath)...) allErrs = append(allErrs, ValidateNonnegativeQuantity(value, fldPath)...)
if helper.IsIntegerResourceName(resource) { if helper.IsIntegerResourceName(resource) {
@ -108,13 +109,13 @@ func ValidateNonnegativeQuantity(value resource.Quantity, fldPath *field.Path) f
// Validate compute resource typename. // Validate compute resource typename.
// Refer to docs/design/resources.md for more details. // Refer to docs/design/resources.md for more details.
func validateResourceName(value string, fldPath *field.Path) field.ErrorList { func validateResourceName(value core.ResourceName, fldPath *field.Path) field.ErrorList {
allErrs := apivalidation.ValidateQualifiedName(value, fldPath) allErrs := apivalidation.ValidateQualifiedName(string(value), fldPath)
if len(allErrs) != 0 { if len(allErrs) != 0 {
return allErrs return allErrs
} }
if len(strings.Split(value, "/")) == 1 { if len(strings.Split(string(value), "/")) == 1 {
if !helper.IsStandardResourceName(value) { if !helper.IsStandardResourceName(value) {
return append(allErrs, field.Invalid(fldPath, value, "must be a standard resource type or fully qualified")) return append(allErrs, field.Invalid(fldPath, value, "must be a standard resource type or fully qualified"))
} }

View File

@ -25,6 +25,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/apis/core"
) )
func TestValidateResourceRequirements(t *testing.T) { func TestValidateResourceRequirements(t *testing.T) {
@ -158,7 +159,7 @@ func validateNamesAndValuesInDescription(t *testing.T, r v1.ResourceList, errs f
func TestValidateContainerResourceName(t *testing.T) { func TestValidateContainerResourceName(t *testing.T) {
successCase := []struct { successCase := []struct {
name string name string
ResourceName string ResourceName core.ResourceName
}{{ }{{
name: "CPU resource", name: "CPU resource",
ResourceName: "cpu", ResourceName: "cpu",
@ -177,7 +178,7 @@ func TestValidateContainerResourceName(t *testing.T) {
}} }}
for _, tc := range successCase { for _, tc := range successCase {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
if errs := ValidateContainerResourceName(tc.ResourceName, field.NewPath(tc.ResourceName)); len(errs) != 0 { if errs := ValidateContainerResourceName(tc.ResourceName, field.NewPath(string(tc.ResourceName))); len(errs) != 0 {
t.Errorf("unexpected error: %v", errs) t.Errorf("unexpected error: %v", errs)
} }
}) })
@ -185,7 +186,7 @@ func TestValidateContainerResourceName(t *testing.T) {
errorCase := []struct { errorCase := []struct {
name string name string
ResourceName string ResourceName core.ResourceName
}{{ }{{
name: "Invalid standard resource", name: "Invalid standard resource",
ResourceName: "cpu-core", ResourceName: "cpu-core",
@ -198,7 +199,7 @@ func TestValidateContainerResourceName(t *testing.T) {
}} }}
for _, tc := range errorCase { for _, tc := range errorCase {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
if errs := ValidateContainerResourceName(tc.ResourceName, field.NewPath(tc.ResourceName)); len(errs) == 0 { if errs := ValidateContainerResourceName(tc.ResourceName, field.NewPath(string(tc.ResourceName))); len(errs) == 0 {
t.Errorf("expected error") t.Errorf("expected error")
} }
}) })

File diff suppressed because it is too large Load Diff

View File

@ -7526,8 +7526,7 @@ func TestValidateContainers(t *testing.T) {
}, },
} }
var PodRestartPolicy core.RestartPolicy var PodRestartPolicy core.RestartPolicy = "Always"
PodRestartPolicy = "Always"
if errs := validateContainers(successCase, volumeDevices, nil, defaultGracePeriod, field.NewPath("field"), PodValidationOptions{}, &PodRestartPolicy); len(errs) != 0 { if errs := validateContainers(successCase, volumeDevices, nil, defaultGracePeriod, field.NewPath("field"), PodValidationOptions{}, &PodRestartPolicy); len(errs) != 0 {
t.Errorf("expected success: %v", errs) t.Errorf("expected success: %v", errs)
} }
@ -8230,8 +8229,7 @@ func TestValidateInitContainers(t *testing.T) {
}, },
}, },
} }
var PodRestartPolicy core.RestartPolicy var PodRestartPolicy core.RestartPolicy = "Never"
PodRestartPolicy = "Never"
if errs := validateInitContainers(successCase, containers, volumeDevices, nil, defaultGracePeriod, field.NewPath("field"), PodValidationOptions{}, &PodRestartPolicy); len(errs) != 0 { if errs := validateInitContainers(successCase, containers, volumeDevices, nil, defaultGracePeriod, field.NewPath("field"), PodValidationOptions{}, &PodRestartPolicy); len(errs) != 0 {
t.Errorf("expected success: %v", errs) t.Errorf("expected success: %v", errs)
} }
@ -18811,7 +18809,7 @@ func TestValidateServiceUpdate(t *testing.T) {
func TestValidateResourceNames(t *testing.T) { func TestValidateResourceNames(t *testing.T) {
table := []struct { table := []struct {
input string input core.ResourceName
success bool success bool
expect string expect string
}{ }{
@ -18832,8 +18830,8 @@ func TestValidateResourceNames(t *testing.T) {
{"my.favorite.app.co/_12345", false, ""}, {"my.favorite.app.co/_12345", false, ""},
{"my.favorite.app.co/12345_", false, ""}, {"my.favorite.app.co/12345_", false, ""},
{"kubernetes.io/..", false, ""}, {"kubernetes.io/..", false, ""},
{"kubernetes.io/" + strings.Repeat("a", 63), true, ""}, {core.ResourceName("kubernetes.io/" + strings.Repeat("a", 63)), true, ""},
{"kubernetes.io/" + strings.Repeat("a", 64), false, ""}, {core.ResourceName("kubernetes.io/" + strings.Repeat("a", 64)), false, ""},
{"kubernetes.io//", false, ""}, {"kubernetes.io//", false, ""},
{"kubernetes.io", false, ""}, {"kubernetes.io", false, ""},
{"kubernetes.io/will/not/work/", false, ""}, {"kubernetes.io/will/not/work/", false, ""},
@ -22211,13 +22209,13 @@ func TestValidateTopologySpreadConstraints(t *testing.T) {
constraints: []core.TopologySpreadConstraint{ constraints: []core.TopologySpreadConstraint{
{MaxSkew: 1, TopologyKey: "k8s.io/zone"}, {MaxSkew: 1, TopologyKey: "k8s.io/zone"},
}, },
wantFieldErrors: []*field.Error{field.NotSupported(fieldPathWhenUnsatisfiable, core.UnsatisfiableConstraintAction(""), supportedScheduleActions.List())}, wantFieldErrors: []*field.Error{field.NotSupported(fieldPathWhenUnsatisfiable, core.UnsatisfiableConstraintAction(""), sets.List(supportedScheduleActions))},
}, { }, {
name: "unsupported scheduling mode", name: "unsupported scheduling mode",
constraints: []core.TopologySpreadConstraint{ constraints: []core.TopologySpreadConstraint{
{MaxSkew: 1, TopologyKey: "k8s.io/zone", WhenUnsatisfiable: core.UnsatisfiableConstraintAction("N/A")}, {MaxSkew: 1, TopologyKey: "k8s.io/zone", WhenUnsatisfiable: core.UnsatisfiableConstraintAction("N/A")},
}, },
wantFieldErrors: []*field.Error{field.NotSupported(fieldPathWhenUnsatisfiable, core.UnsatisfiableConstraintAction("N/A"), supportedScheduleActions.List())}, wantFieldErrors: []*field.Error{field.NotSupported(fieldPathWhenUnsatisfiable, core.UnsatisfiableConstraintAction("N/A"), sets.List(supportedScheduleActions))},
}, { }, {
name: "multiple constraints ok with all required fields", name: "multiple constraints ok with all required fields",
constraints: []core.TopologySpreadConstraint{ constraints: []core.TopologySpreadConstraint{
@ -22261,7 +22259,7 @@ func TestValidateTopologySpreadConstraints(t *testing.T) {
NodeTaintsPolicy: &ignore, NodeTaintsPolicy: &ignore,
}}, }},
wantFieldErrors: []*field.Error{ wantFieldErrors: []*field.Error{
field.NotSupported(nodeAffinityField, &unknown, supportedPodTopologySpreadNodePolicies.List()), field.NotSupported(nodeAffinityField, &unknown, sets.List(supportedPodTopologySpreadNodePolicies)),
}, },
}, { }, {
name: "unsupported policy name set on NodeTaintsPolicy", name: "unsupported policy name set on NodeTaintsPolicy",
@ -22273,7 +22271,7 @@ func TestValidateTopologySpreadConstraints(t *testing.T) {
NodeTaintsPolicy: &unknown, NodeTaintsPolicy: &unknown,
}}, }},
wantFieldErrors: []*field.Error{ wantFieldErrors: []*field.Error{
field.NotSupported(nodeTaintsField, &unknown, supportedPodTopologySpreadNodePolicies.List()), field.NotSupported(nodeTaintsField, &unknown, sets.List(supportedPodTopologySpreadNodePolicies)),
}, },
}, { }, {
name: "key in MatchLabelKeys isn't correctly defined", name: "key in MatchLabelKeys isn't correctly defined",

View File

@ -270,7 +270,7 @@ func validateAllowedTopologies(topologies []api.TopologySelectorTerm, fldPath *f
return allErrs return allErrs
} }
rawTopologies := make([]map[string]sets.String, len(topologies)) rawTopologies := make([]map[string]sets.Set[string], len(topologies))
for i, term := range topologies { for i, term := range topologies {
idxPath := fldPath.Index(i) idxPath := fldPath.Index(i)
exprMap, termErrs := apivalidation.ValidateTopologySelectorTerm(term, fldPath.Index(i)) exprMap, termErrs := apivalidation.ValidateTopologySelectorTerm(term, fldPath.Index(i))

View File

@ -164,7 +164,7 @@ func TestNewInvalid(t *testing.T) {
`Kind "name" is invalid: field[0].name: Not found: "bar"`, `Kind "name" is invalid: field[0].name: Not found: "bar"`,
}, },
{ {
field.NotSupported(field.NewPath("field[0].name"), "bar", nil), field.NotSupported[string](field.NewPath("field[0].name"), "bar", nil),
&metav1.StatusDetails{ &metav1.StatusDetails{
Kind: "Kind", Kind: "Kind",
Name: "name", Name: "name",

View File

@ -200,12 +200,12 @@ func Invalid(field *Path, value interface{}, detail string) *Error {
// NotSupported returns a *Error indicating "unsupported value". // NotSupported returns a *Error indicating "unsupported value".
// This is used to report unknown values for enumerated fields (e.g. a list of // This is used to report unknown values for enumerated fields (e.g. a list of
// valid values). // valid values).
func NotSupported(field *Path, value interface{}, validValues []string) *Error { func NotSupported[T ~string](field *Path, value interface{}, validValues []T) *Error {
detail := "" detail := ""
if len(validValues) > 0 { if len(validValues) > 0 {
quotedValues := make([]string, len(validValues)) quotedValues := make([]string, len(validValues))
for i, v := range validValues { for i, v := range validValues {
quotedValues[i] = strconv.Quote(v) quotedValues[i] = strconv.Quote(fmt.Sprint(v))
} }
detail = "supported values: " + strings.Join(quotedValues, ", ") detail = "supported values: " + strings.Join(quotedValues, ", ")
} }

View File

@ -32,7 +32,7 @@ func TestMakeFuncs(t *testing.T) {
ErrorTypeInvalid, ErrorTypeInvalid,
}, },
{ {
func() *Error { return NotSupported(NewPath("f"), "v", nil) }, func() *Error { return NotSupported[string](NewPath("f"), "v", nil) },
ErrorTypeNotSupported, ErrorTypeNotSupported,
}, },
{ {