mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 20:53:33 +00:00
allow to mutate pv nodeaffinity label key
This commit is contained in:
parent
8e642d3d0d
commit
c8d10dcaeb
@ -26,6 +26,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
@ -36,6 +37,7 @@ import (
|
|||||||
apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
|
apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
unversionedvalidation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
|
unversionedvalidation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
|
||||||
|
"k8s.io/apimachinery/pkg/conversion"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
@ -43,6 +45,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
schedulinghelper "k8s.io/component-helpers/scheduling/corev1"
|
schedulinghelper "k8s.io/component-helpers/scheduling/corev1"
|
||||||
|
kubeletapis "k8s.io/kubelet/pkg/apis"
|
||||||
apiservice "k8s.io/kubernetes/pkg/api/service"
|
apiservice "k8s.io/kubernetes/pkg/api/service"
|
||||||
"k8s.io/kubernetes/pkg/apis/core"
|
"k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/helper"
|
"k8s.io/kubernetes/pkg/apis/core/helper"
|
||||||
@ -1990,7 +1993,7 @@ func ValidatePersistentVolumeUpdate(newPv, oldPv *core.PersistentVolume, opts Pe
|
|||||||
|
|
||||||
// Allow setting NodeAffinity if oldPv NodeAffinity was not set
|
// Allow setting NodeAffinity if oldPv NodeAffinity was not set
|
||||||
if oldPv.Spec.NodeAffinity != nil {
|
if oldPv.Spec.NodeAffinity != nil {
|
||||||
allErrs = append(allErrs, ValidateImmutableField(newPv.Spec.NodeAffinity, oldPv.Spec.NodeAffinity, field.NewPath("nodeAffinity"))...)
|
allErrs = append(allErrs, validatePvNodeAffinity(newPv.Spec.NodeAffinity, oldPv.Spec.NodeAffinity, field.NewPath("nodeAffinity"))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
@ -7165,3 +7168,44 @@ func ValidatePodAffinityTermSelector(podAffinityTerm core.PodAffinityTerm, allow
|
|||||||
allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(podAffinityTerm.NamespaceSelector, labelSelectorValidationOptions, fldPath.Child("namespaceSelector"))...)
|
allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(podAffinityTerm.NamespaceSelector, labelSelectorValidationOptions, fldPath.Child("namespaceSelector"))...)
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var betaToGALabel = map[string]string{
|
||||||
|
v1.LabelFailureDomainBetaZone: v1.LabelTopologyZone,
|
||||||
|
v1.LabelFailureDomainBetaRegion: v1.LabelTopologyRegion,
|
||||||
|
kubeletapis.LabelOS: v1.LabelOSStable,
|
||||||
|
kubeletapis.LabelArch: v1.LabelArchStable,
|
||||||
|
v1.LabelInstanceType: v1.LabelInstanceTypeStable,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
maskNodeSelectorLabelChangeEqualities conversion.Equalities
|
||||||
|
initMaskNodeSelectorLabelChangeEqualities sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
func getMaskNodeSelectorLabelChangeEqualities() conversion.Equalities {
|
||||||
|
initMaskNodeSelectorLabelChangeEqualities.Do(func() {
|
||||||
|
var eqs = apiequality.Semantic.Copy()
|
||||||
|
err := eqs.AddFunc(
|
||||||
|
func(newReq, oldReq core.NodeSelectorRequirement) bool {
|
||||||
|
// allow newReq to change to a GA key
|
||||||
|
if oldReq.Key != newReq.Key && betaToGALabel[oldReq.Key] == newReq.Key {
|
||||||
|
oldReq.Key = newReq.Key // +k8s:verify-mutation:reason=clone
|
||||||
|
}
|
||||||
|
return apiequality.Semantic.DeepEqual(newReq, oldReq)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("failed to instantiate semantic equalities: %w", err))
|
||||||
|
}
|
||||||
|
maskNodeSelectorLabelChangeEqualities = eqs
|
||||||
|
})
|
||||||
|
return maskNodeSelectorLabelChangeEqualities
|
||||||
|
}
|
||||||
|
|
||||||
|
func validatePvNodeAffinity(newPvNodeAffinity, oldPvNodeAffinity *core.VolumeNodeAffinity, fldPath *field.Path) field.ErrorList {
|
||||||
|
var allErrs field.ErrorList
|
||||||
|
if !getMaskNodeSelectorLabelChangeEqualities().DeepEqual(newPvNodeAffinity, oldPvNodeAffinity) {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath, newPvNodeAffinity, fieldImmutableErrorMsg+", except for updating from beta label to GA"))
|
||||||
|
}
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
@ -41,6 +41,7 @@ import (
|
|||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
"k8s.io/component-base/featuregate"
|
"k8s.io/component-base/featuregate"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
|
kubeletapis "k8s.io/kubelet/pkg/apis"
|
||||||
"k8s.io/kubernetes/pkg/apis/core"
|
"k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/capabilities"
|
"k8s.io/kubernetes/pkg/capabilities"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
@ -53,6 +54,11 @@ const (
|
|||||||
envVarNameErrMsg = "a valid environment variable name must consist of"
|
envVarNameErrMsg = "a valid environment variable name must consist of"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type topologyPair struct {
|
||||||
|
key string
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
func line() string {
|
func line() string {
|
||||||
_, _, line, ok := runtime.Caller(1)
|
_, _, line, ok := runtime.Caller(1)
|
||||||
var s string
|
var s string
|
||||||
@ -1088,6 +1094,29 @@ func simpleVolumeNodeAffinity(key, value string) *core.VolumeNodeAffinity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func multipleVolumeNodeAffinity(terms [][]topologyPair) *core.VolumeNodeAffinity {
|
||||||
|
nodeSelectorTerms := []core.NodeSelectorTerm{}
|
||||||
|
for _, term := range terms {
|
||||||
|
matchExpressions := []core.NodeSelectorRequirement{}
|
||||||
|
for _, topology := range term {
|
||||||
|
matchExpressions = append(matchExpressions, core.NodeSelectorRequirement{
|
||||||
|
Key: topology.key,
|
||||||
|
Operator: core.NodeSelectorOpIn,
|
||||||
|
Values: []string{topology.value},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
nodeSelectorTerms = append(nodeSelectorTerms, core.NodeSelectorTerm{
|
||||||
|
MatchExpressions: matchExpressions,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &core.VolumeNodeAffinity{
|
||||||
|
Required: &core.NodeSelector{
|
||||||
|
NodeSelectorTerms: nodeSelectorTerms,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestValidateVolumeNodeAffinityUpdate(t *testing.T) {
|
func TestValidateVolumeNodeAffinityUpdate(t *testing.T) {
|
||||||
scenarios := map[string]struct {
|
scenarios := map[string]struct {
|
||||||
isExpectedFailure bool
|
isExpectedFailure bool
|
||||||
@ -1109,6 +1138,268 @@ func TestValidateVolumeNodeAffinityUpdate(t *testing.T) {
|
|||||||
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity("foo", "bar")),
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity("foo", "bar")),
|
||||||
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity("foo", "bar2")),
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity("foo", "bar2")),
|
||||||
},
|
},
|
||||||
|
"affinity-non-beta-label-changed": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity("foo", "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity("foo2", "bar")),
|
||||||
|
},
|
||||||
|
"affinity-zone-beta-unchanged": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelFailureDomainBetaZone, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelFailureDomainBetaZone, "bar")),
|
||||||
|
},
|
||||||
|
"affinity-zone-beta-label-to-GA": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelFailureDomainBetaZone, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelTopologyZone, "bar")),
|
||||||
|
},
|
||||||
|
"affinity-zone-beta-label-to-non-GA": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelFailureDomainBetaZone, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity("foo", "bar")),
|
||||||
|
},
|
||||||
|
"affinity-zone-GA-label-changed": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelTopologyZone, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelFailureDomainBetaZone, "bar")),
|
||||||
|
},
|
||||||
|
"affinity-region-beta-unchanged": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelFailureDomainBetaRegion, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelFailureDomainBetaRegion, "bar")),
|
||||||
|
},
|
||||||
|
"affinity-region-beta-label-to-GA": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelFailureDomainBetaRegion, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelTopologyRegion, "bar")),
|
||||||
|
},
|
||||||
|
"affinity-region-beta-label-to-non-GA": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelFailureDomainBetaRegion, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity("foo", "bar")),
|
||||||
|
},
|
||||||
|
"affinity-region-GA-label-changed": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelTopologyRegion, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelFailureDomainBetaRegion, "bar")),
|
||||||
|
},
|
||||||
|
"affinity-os-beta-label-unchanged": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(kubeletapis.LabelOS, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(kubeletapis.LabelOS, "bar")),
|
||||||
|
},
|
||||||
|
"affinity-os-beta-label-to-GA": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(kubeletapis.LabelOS, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelOSStable, "bar")),
|
||||||
|
},
|
||||||
|
"affinity-os-beta-label-to-non-GA": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(kubeletapis.LabelOS, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity("foo", "bar")),
|
||||||
|
},
|
||||||
|
"affinity-os-GA-label-changed": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelOSStable, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(kubeletapis.LabelOS, "bar")),
|
||||||
|
},
|
||||||
|
"affinity-arch-beta-label-unchanged": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(kubeletapis.LabelArch, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(kubeletapis.LabelArch, "bar")),
|
||||||
|
},
|
||||||
|
"affinity-arch-beta-label-to-GA": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(kubeletapis.LabelArch, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelArchStable, "bar")),
|
||||||
|
},
|
||||||
|
"affinity-arch-beta-label-to-non-GA": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(kubeletapis.LabelArch, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity("foo", "bar")),
|
||||||
|
},
|
||||||
|
"affinity-arch-GA-label-changed": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelArchStable, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(kubeletapis.LabelArch, "bar")),
|
||||||
|
},
|
||||||
|
"affinity-instanceType-beta-label-unchanged": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelInstanceType, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelInstanceType, "bar")),
|
||||||
|
},
|
||||||
|
"affinity-instanceType-beta-label-to-GA": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelInstanceType, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelInstanceTypeStable, "bar")),
|
||||||
|
},
|
||||||
|
"affinity-instanceType-beta-label-to-non-GA": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelInstanceType, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity("foo", "bar")),
|
||||||
|
},
|
||||||
|
"affinity-instanceType-GA-label-changed": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelInstanceTypeStable, "bar")),
|
||||||
|
newPV: testVolumeWithNodeAffinity(simpleVolumeNodeAffinity(v1.LabelInstanceType, "bar")),
|
||||||
|
},
|
||||||
|
"affinity-same-terms-expressions-length-beta-to-GA-partially-changed": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(multipleVolumeNodeAffinity([][]topologyPair{
|
||||||
|
{
|
||||||
|
topologyPair{"foo", "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topologyPair{v1.LabelFailureDomainBetaZone, "bar"},
|
||||||
|
topologyPair{v1.LabelFailureDomainBetaRegion, "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topologyPair{kubeletapis.LabelOS, "bar"},
|
||||||
|
topologyPair{kubeletapis.LabelArch, "bar"},
|
||||||
|
topologyPair{v1.LabelInstanceType, "bar"},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
newPV: testVolumeWithNodeAffinity(multipleVolumeNodeAffinity([][]topologyPair{
|
||||||
|
{
|
||||||
|
topologyPair{"foo", "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topologyPair{v1.LabelTopologyZone, "bar"},
|
||||||
|
topologyPair{v1.LabelFailureDomainBetaRegion, "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topologyPair{kubeletapis.LabelOS, "bar"},
|
||||||
|
topologyPair{v1.LabelArchStable, "bar"},
|
||||||
|
topologyPair{v1.LabelInstanceTypeStable, "bar"},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
"affinity-same-terms-expressions-length-beta-to-non-GA-partially-changed": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(multipleVolumeNodeAffinity([][]topologyPair{
|
||||||
|
{
|
||||||
|
topologyPair{"foo", "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topologyPair{v1.LabelFailureDomainBetaZone, "bar"},
|
||||||
|
topologyPair{v1.LabelFailureDomainBetaRegion, "bar"},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
newPV: testVolumeWithNodeAffinity(multipleVolumeNodeAffinity([][]topologyPair{
|
||||||
|
{
|
||||||
|
topologyPair{"foo", "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topologyPair{v1.LabelFailureDomainBetaZone, "bar"},
|
||||||
|
topologyPair{"foo", "bar"},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
"affinity-same-terms-expressions-length-GA-partially-changed": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(multipleVolumeNodeAffinity([][]topologyPair{
|
||||||
|
{
|
||||||
|
topologyPair{"foo", "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topologyPair{v1.LabelTopologyZone, "bar"},
|
||||||
|
topologyPair{v1.LabelFailureDomainBetaZone, "bar"},
|
||||||
|
topologyPair{v1.LabelOSStable, "bar"},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
newPV: testVolumeWithNodeAffinity(multipleVolumeNodeAffinity([][]topologyPair{
|
||||||
|
{
|
||||||
|
topologyPair{"foo", "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topologyPair{v1.LabelFailureDomainBetaZone, "bar"},
|
||||||
|
topologyPair{v1.LabelFailureDomainBetaZone, "bar"},
|
||||||
|
topologyPair{v1.LabelOSStable, "bar"},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
"affinity-same-terms-expressions-length-beta-fully-changed": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(multipleVolumeNodeAffinity([][]topologyPair{
|
||||||
|
{
|
||||||
|
topologyPair{"foo", "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topologyPair{v1.LabelFailureDomainBetaZone, "bar"},
|
||||||
|
topologyPair{v1.LabelFailureDomainBetaRegion, "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topologyPair{kubeletapis.LabelOS, "bar"},
|
||||||
|
topologyPair{kubeletapis.LabelArch, "bar"},
|
||||||
|
topologyPair{v1.LabelInstanceType, "bar"},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
newPV: testVolumeWithNodeAffinity(multipleVolumeNodeAffinity([][]topologyPair{
|
||||||
|
{
|
||||||
|
topologyPair{"foo", "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topologyPair{v1.LabelTopologyZone, "bar"},
|
||||||
|
topologyPair{v1.LabelTopologyRegion, "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topologyPair{v1.LabelOSStable, "bar"},
|
||||||
|
topologyPair{v1.LabelArchStable, "bar"},
|
||||||
|
topologyPair{v1.LabelInstanceTypeStable, "bar"},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
"affinity-same-terms-expressions-length-beta-GA-mixed-fully-changed": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(multipleVolumeNodeAffinity([][]topologyPair{
|
||||||
|
{
|
||||||
|
topologyPair{"foo", "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topologyPair{v1.LabelFailureDomainBetaZone, "bar"},
|
||||||
|
topologyPair{v1.LabelTopologyZone, "bar"},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
newPV: testVolumeWithNodeAffinity(multipleVolumeNodeAffinity([][]topologyPair{
|
||||||
|
{
|
||||||
|
topologyPair{"foo", "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topologyPair{v1.LabelTopologyZone, "bar"},
|
||||||
|
topologyPair{v1.LabelFailureDomainBetaZone, "bar2"},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
"affinity-same-terms-length-different-expressions-length-beta-changed": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(multipleVolumeNodeAffinity([][]topologyPair{
|
||||||
|
{
|
||||||
|
topologyPair{v1.LabelFailureDomainBetaZone, "bar"},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
newPV: testVolumeWithNodeAffinity(multipleVolumeNodeAffinity([][]topologyPair{
|
||||||
|
{
|
||||||
|
topologyPair{v1.LabelTopologyZone, "bar"},
|
||||||
|
topologyPair{v1.LabelFailureDomainBetaRegion, "bar"},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
"affinity-different-terms-expressions-length-beta-changed": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldPV: testVolumeWithNodeAffinity(multipleVolumeNodeAffinity([][]topologyPair{
|
||||||
|
{
|
||||||
|
topologyPair{v1.LabelFailureDomainBetaZone, "bar"},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
newPV: testVolumeWithNodeAffinity(multipleVolumeNodeAffinity([][]topologyPair{
|
||||||
|
{
|
||||||
|
topologyPair{v1.LabelTopologyZone, "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topologyPair{v1.LabelArchStable, "bar"},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
"nil-to-obj": {
|
"nil-to-obj": {
|
||||||
isExpectedFailure: false,
|
isExpectedFailure: false,
|
||||||
oldPV: testVolumeWithNodeAffinity(nil),
|
oldPV: testVolumeWithNodeAffinity(nil),
|
||||||
@ -1122,6 +1413,8 @@ func TestValidateVolumeNodeAffinityUpdate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for name, scenario := range scenarios {
|
for name, scenario := range scenarios {
|
||||||
|
originalNewPV := scenario.newPV.DeepCopy()
|
||||||
|
originalOldPV := scenario.oldPV.DeepCopy()
|
||||||
opts := ValidationOptionsForPersistentVolume(scenario.newPV, scenario.oldPV)
|
opts := ValidationOptionsForPersistentVolume(scenario.newPV, scenario.oldPV)
|
||||||
errs := ValidatePersistentVolumeUpdate(scenario.newPV, scenario.oldPV, opts)
|
errs := ValidatePersistentVolumeUpdate(scenario.newPV, scenario.oldPV, opts)
|
||||||
if len(errs) == 0 && scenario.isExpectedFailure {
|
if len(errs) == 0 && scenario.isExpectedFailure {
|
||||||
@ -1130,6 +1423,12 @@ func TestValidateVolumeNodeAffinityUpdate(t *testing.T) {
|
|||||||
if len(errs) > 0 && !scenario.isExpectedFailure {
|
if len(errs) > 0 && !scenario.isExpectedFailure {
|
||||||
t.Errorf("Unexpected failure for scenario: %s - %+v", name, errs)
|
t.Errorf("Unexpected failure for scenario: %s - %+v", name, errs)
|
||||||
}
|
}
|
||||||
|
if diff := cmp.Diff(originalNewPV, scenario.newPV); len(diff) > 0 {
|
||||||
|
t.Errorf("newPV was modified: %s", diff)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(originalOldPV, scenario.oldPV); len(diff) > 0 {
|
||||||
|
t.Errorf("oldPV was modified: %s", diff)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user