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",
set: mkStatefulSet(&validPodTemplate, tweakTemplateRestartPolicy(api.RestartPolicyOnFailure)),
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",
set: mkStatefulSet(&validPodTemplate, tweakTemplateRestartPolicy(api.RestartPolicyNever)),
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",
set: mkStatefulSet(&validPodTemplate, tweakTemplateRestartPolicy("")),
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",
@ -468,8 +468,8 @@ func TestValidateStatefulSet(t *testing.T) {
tweakPVCPolicy(mkPVCPolicy()),
),
errs: field.ErrorList{
field.NotSupported(field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenDeleted"), nil, nil),
field.NotSupported(field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenScaled"), nil, nil),
field.NotSupported[string](field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenDeleted"), nil, nil),
field.NotSupported[string](field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenScaled"), nil, nil),
},
}, {
name: "invalid PersistentVolumeClaimRetentionPolicy " + enableStatefulSetAutoDeletePVC,
@ -480,8 +480,8 @@ func TestValidateStatefulSet(t *testing.T) {
)),
),
errs: field.ErrorList{
field.NotSupported(field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenDeleted"), nil, nil),
field.NotSupported(field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenScaled"), nil, nil),
field.NotSupported[string](field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenDeleted"), nil, nil),
field.NotSupported[string](field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenScaled"), nil, nil),
},
}, {
name: "zero maxUnavailable",

View File

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

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{
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},

View File

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

View File

@ -60,7 +60,7 @@ func TestIsStandardResource(t *testing.T) {
{"requests.hugepages-2Mi", true},
}
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)
}
}
@ -77,7 +77,7 @@ func TestIsStandardContainerResource(t *testing.T) {
{"hugepages-2Mi", true},
}
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)
}
}

View File

@ -24,6 +24,7 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/helper"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
apivalidation "k8s.io/kubernetes/pkg/apis/core/validation"
@ -42,18 +43,18 @@ func ValidateResourceRequirements(requirements *v1.ResourceRequirements, fldPath
for resourceName, quantity := range requirements.Limits {
fldPath := limPath.Key(string(resourceName))
// Validate resource name.
allErrs = append(allErrs, ValidateContainerResourceName(string(resourceName), fldPath)...)
allErrs = append(allErrs, ValidateContainerResourceName(core.ResourceName(resourceName), fldPath)...)
// 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 {
fldPath := reqPath.Key(string(resourceName))
// Validate resource name.
allErrs = append(allErrs, ValidateContainerResourceName(string(resourceName), fldPath)...)
allErrs = append(allErrs, ValidateContainerResourceName(core.ResourceName(resourceName), fldPath)...)
// Validate resource quantity.
allErrs = append(allErrs, ValidateResourceQuantityValue(string(resourceName), quantity, fldPath)...)
allErrs = append(allErrs, ValidateResourceQuantityValue(core.ResourceName(resourceName), quantity, fldPath)...)
// Check that request <= limit.
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
func ValidateContainerResourceName(value string, fldPath *field.Path) field.ErrorList {
func ValidateContainerResourceName(value core.ResourceName, fldPath *field.Path) field.ErrorList {
allErrs := validateResourceName(value, fldPath)
if len(strings.Split(value, "/")) == 1 {
if len(strings.Split(string(value), "/")) == 1 {
if !helper.IsStandardContainerResourceName(value) {
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
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 = append(allErrs, ValidateNonnegativeQuantity(value, fldPath)...)
if helper.IsIntegerResourceName(resource) {
@ -108,13 +109,13 @@ func ValidateNonnegativeQuantity(value resource.Quantity, fldPath *field.Path) f
// Validate compute resource typename.
// Refer to docs/design/resources.md for more details.
func validateResourceName(value string, fldPath *field.Path) field.ErrorList {
allErrs := apivalidation.ValidateQualifiedName(value, fldPath)
func validateResourceName(value core.ResourceName, fldPath *field.Path) field.ErrorList {
allErrs := apivalidation.ValidateQualifiedName(string(value), fldPath)
if len(allErrs) != 0 {
return allErrs
}
if len(strings.Split(value, "/")) == 1 {
if len(strings.Split(string(value), "/")) == 1 {
if !helper.IsStandardResourceName(value) {
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"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/apis/core"
)
func TestValidateResourceRequirements(t *testing.T) {
@ -158,7 +159,7 @@ func validateNamesAndValuesInDescription(t *testing.T, r v1.ResourceList, errs f
func TestValidateContainerResourceName(t *testing.T) {
successCase := []struct {
name string
ResourceName string
ResourceName core.ResourceName
}{{
name: "CPU resource",
ResourceName: "cpu",
@ -177,7 +178,7 @@ func TestValidateContainerResourceName(t *testing.T) {
}}
for _, tc := range successCase {
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)
}
})
@ -185,7 +186,7 @@ func TestValidateContainerResourceName(t *testing.T) {
errorCase := []struct {
name string
ResourceName string
ResourceName core.ResourceName
}{{
name: "Invalid standard resource",
ResourceName: "cpu-core",
@ -198,7 +199,7 @@ func TestValidateContainerResourceName(t *testing.T) {
}}
for _, tc := range errorCase {
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")
}
})

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

View File

@ -270,7 +270,7 @@ func validateAllowedTopologies(topologies []api.TopologySelectorTerm, fldPath *f
return allErrs
}
rawTopologies := make([]map[string]sets.String, len(topologies))
rawTopologies := make([]map[string]sets.Set[string], len(topologies))
for i, term := range topologies {
idxPath := 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"`,
},
{
field.NotSupported(field.NewPath("field[0].name"), "bar", nil),
field.NotSupported[string](field.NewPath("field[0].name"), "bar", nil),
&metav1.StatusDetails{
Kind: "Kind",
Name: "name",

View File

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

View File

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