test/e2e: check both beta and zone label for getting cluster zone

Signed-off-by: Andrew Sy Kim <kiman@vmware.com>
This commit is contained in:
Andrew Sy Kim 2019-08-28 13:14:02 -04:00
parent 07229d6c51
commit 349749644f
32 changed files with 201 additions and 1352 deletions

View File

@ -35,7 +35,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
utilfeature "k8s.io/apiserver/pkg/util/feature"
volumehelpers "k8s.io/cloud-provider/volume/helpers"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
@ -520,7 +519,7 @@ func (c *awsElasticBlockStoreProvisioner) Provision(selectedNode *v1.Node, allow
pv := &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: c.options.PVName,
Labels: labels,
Labels: map[string]string{},
Annotations: map[string]string{
util.VolumeDynamicallyCreatedByKey: "aws-ebs-dynamic-provisioner",
},
@ -548,9 +547,21 @@ func (c *awsElasticBlockStoreProvisioner) Provision(selectedNode *v1.Node, allow
pv.Spec.AccessModes = c.plugin.GetAccessModes()
}
requirements := make([]v1.NodeSelectorRequirement, 0)
if len(labels) != 0 {
if pv.Labels == nil {
pv.Labels = make(map[string]string)
}
for k, v := range labels {
pv.Labels[k] = v
requirements = append(requirements, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: []string{v}})
}
}
pv.Spec.NodeAffinity = new(v1.VolumeNodeAffinity)
pv.Spec.NodeAffinity.Required = new(v1.NodeSelector)
pv.Spec.NodeAffinity.Required.NodeSelectorTerms = volumehelpers.TranslateZoneRegionLabelsToNodeSelectorTerms(labels)
pv.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]v1.NodeSelectorTerm, 1)
pv.Spec.NodeAffinity.Required.NodeSelectorTerms[0].MatchExpressions = requirements
return pv, nil
}

View File

@ -207,7 +207,7 @@ func TestPlugin(t *testing.T) {
}
n := len(persistentSpec.Spec.NodeAffinity.Required.NodeSelectorTerms)
if n != 2 {
if n != 1 {
t.Errorf("Provision() returned unexpected number of NodeSelectorTerms %d. Expected %d", n, 1)
}
@ -228,25 +228,6 @@ func TestPlugin(t *testing.T) {
if len(req.Values) != 1 || req.Values[0] != "yes" {
t.Errorf("Provision() returned unexpected requirement value in NodeAffinity %v", req.Values)
}
n = len(persistentSpec.Spec.NodeAffinity.Required.NodeSelectorTerms[1].MatchExpressions)
if n != 1 {
t.Errorf("Provision() returned unexpected number of MatchExpressions %d. Expected %d", n, 1)
}
req = persistentSpec.Spec.NodeAffinity.Required.NodeSelectorTerms[1].MatchExpressions[0]
if req.Key != "fakepdmanager" {
t.Errorf("Provision() returned unexpected requirement key in NodeAffinity %v", req.Key)
}
if req.Operator != v1.NodeSelectorOpIn {
t.Errorf("Provision() returned unexpected requirement operator in NodeAffinity %v", req.Operator)
}
if len(req.Values) != 1 || req.Values[0] != "yes" {
t.Errorf("Provision() returned unexpected requirement value in NodeAffinity %v", req.Values)
}
// Test Deleter
volSpec := &volume.Spec{
PersistentVolume: persistentSpec,

View File

@ -322,16 +322,22 @@ func (p *azureDiskProvisioner) Provision(selectedNode *v1.Node, allowedTopologie
if zoned {
// Set node affinity labels based on availability zone labels.
if len(labels) > 0 {
nodeSelectorTerms = volumehelpers.TranslateZoneRegionLabelsToNodeSelectorTerms(labels)
}
requirements := make([]v1.NodeSelectorRequirement, 0)
for k, v := range labels {
requirements = append(requirements, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: []string{v}})
}
nodeSelectorTerms = append(nodeSelectorTerms, v1.NodeSelectorTerm{
MatchExpressions: requirements,
})
}
} else {
// Set node affinity labels based on fault domains.
// This is required because unzoned AzureDisk can't be attached to zoned nodes.
// There are at most 3 fault domains available in each region.
// Refer https://docs.microsoft.com/en-us/azure/virtual-machines/windows/manage-availability.
for i := 0; i < 3; i++ {
deprecatedTopologyReqs := []v1.NodeSelectorRequirement{
requirements := []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneRegion,
Operator: v1.NodeSelectorOpIn,
@ -343,25 +349,8 @@ func (p *azureDiskProvisioner) Provision(selectedNode *v1.Node, allowedTopologie
Values: []string{strconv.Itoa(i)},
},
}
topologyReqs := []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneRegionStable,
Operator: v1.NodeSelectorOpIn,
Values: []string{diskController.GetLocation()},
},
{
Key: v1.LabelZoneFailureDomainStable,
Operator: v1.NodeSelectorOpIn,
Values: []string{strconv.Itoa(i)},
},
}
nodeSelectorTerms = append(nodeSelectorTerms, v1.NodeSelectorTerm{
MatchExpressions: deprecatedTopologyReqs,
})
nodeSelectorTerms = append(nodeSelectorTerms, v1.NodeSelectorTerm{
MatchExpressions: topologyReqs,
MatchExpressions: requirements,
})
}
}

View File

@ -31,7 +31,6 @@ import (
"k8s.io/apimachinery/pkg/types"
utilfeature "k8s.io/apiserver/pkg/util/feature"
cloudprovider "k8s.io/cloud-provider"
volumehelpers "k8s.io/cloud-provider/volume/helpers"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/util/mount"
@ -619,9 +618,18 @@ func (c *cinderVolumeProvisioner) Provision(selectedNode *v1.Node, allowedTopolo
pv.Spec.AccessModes = c.plugin.GetAccessModes()
}
pv.Spec.NodeAffinity = new(v1.VolumeNodeAffinity)
pv.Spec.NodeAffinity.Required = new(v1.NodeSelector)
pv.Spec.NodeAffinity.Required.NodeSelectorTerms = volumehelpers.TranslateZoneRegionLabelsToNodeSelectorTerms(labels)
requirements := make([]v1.NodeSelectorRequirement, 0)
for k, v := range labels {
if v != "" {
requirements = append(requirements, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: []string{v}})
}
}
if len(requirements) > 0 {
pv.Spec.NodeAffinity = new(v1.VolumeNodeAffinity)
pv.Spec.NodeAffinity.Required = new(v1.NodeSelector)
pv.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]v1.NodeSelectorTerm, 1)
pv.Spec.NodeAffinity.Required.NodeSelectorTerms[0].MatchExpressions = requirements
}
return pv, nil
}

View File

@ -123,7 +123,6 @@ func (fake *fakePDManager) DetachDisk(c *cinderVolumeUnmounter) error {
func (fake *fakePDManager) CreateVolume(c *cinderVolumeProvisioner, node *v1.Node, allowedTopologies []v1.TopologySelectorTerm) (volumeID string, volumeSizeGB int, labels map[string]string, fstype string, err error) {
labels = make(map[string]string)
labels[v1.LabelZoneFailureDomain] = "nova"
labels[v1.LabelZoneFailureDomainStable] = "nova"
return "test-volume-name", 1, labels, "", nil
}
@ -230,7 +229,7 @@ func TestPlugin(t *testing.T) {
}
n := len(persistentSpec.Spec.NodeAffinity.Required.NodeSelectorTerms)
if n != 2 {
if n != 1 {
t.Errorf("Provision() returned unexpected number of NodeSelectorTerms %d. Expected %d", n, 1)
}
@ -253,25 +252,6 @@ func TestPlugin(t *testing.T) {
t.Errorf("Provision() returned unexpected requirement value in NodeAffinity %v", req.Values)
}
n = len(persistentSpec.Spec.NodeAffinity.Required.NodeSelectorTerms[1].MatchExpressions)
if n != 1 {
t.Errorf("Provision() returned unexpected number of MatchExpressions %d. Expected %d", n, 1)
}
req = persistentSpec.Spec.NodeAffinity.Required.NodeSelectorTerms[1].MatchExpressions[0]
if req.Key != v1.LabelZoneFailureDomainStable {
t.Errorf("Provision() returned unexpected requirement key in NodeAffinity %v", req.Key)
}
if req.Operator != v1.NodeSelectorOpIn {
t.Errorf("Provision() returned unexpected requirement operator in NodeAffinity %v", req.Operator)
}
if len(req.Values) != 1 || req.Values[0] != "nova" {
t.Errorf("Provision() returned unexpected requirement value in NodeAffinity %v", req.Values)
}
// Test Deleter
volSpec := &volume.Spec{
PersistentVolume: persistentSpec,

View File

@ -157,12 +157,6 @@ func getZonesFromNodes(kubeClient clientset.Interface) (sets.String, error) {
for _, node := range nodes.Items {
if zone, ok := node.Labels[v1.LabelZoneFailureDomain]; ok {
zones.Insert(zone)
// don't need to check GA label if beta label already exists
continue
}
if zone, ok := node.Labels[v1.LabelZoneFailureDomainStable]; ok {
zones.Insert(zone)
}
}
klog.V(4).Infof("zones found: %v", zones)
@ -235,12 +229,9 @@ func (util *DiskUtil) CreateVolume(c *cinderVolumeProvisioner, node *v1.Node, al
if IgnoreVolumeAZ == false {
if volumeAZ != "" {
volumeLabels[v1.LabelZoneFailureDomain] = volumeAZ
volumeLabels[v1.LabelZoneFailureDomainStable] = volumeAZ
}
if volumeRegion != "" {
volumeLabels[v1.LabelZoneRegion] = volumeRegion
volumeLabels[v1.LabelZoneRegionStable] = volumeRegion
}
}
return volumeID, volSizeGiB, volumeLabels, fstype, nil

View File

@ -457,8 +457,7 @@ func createPVSpec(name string, readOnly bool, zones []string) *volume.Spec {
if zones != nil {
zonesLabel := strings.Join(zones, cloudvolume.LabelMultiZoneDelimiter)
spec.PersistentVolume.ObjectMeta.Labels = map[string]string{
v1.LabelZoneFailureDomain: zonesLabel,
v1.LabelZoneFailureDomainStable: zonesLabel,
v1.LabelZoneFailureDomain: zonesLabel,
}
}

View File

@ -515,7 +515,7 @@ func (c *gcePersistentDiskProvisioner) Provision(selectedNode *v1.Node, allowedT
pv := &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: c.options.PVName,
Labels: labels,
Labels: map[string]string{},
Annotations: map[string]string{
util.VolumeDynamicallyCreatedByKey: "gce-pd-dynamic-provisioner",
},
@ -542,15 +542,32 @@ func (c *gcePersistentDiskProvisioner) Provision(selectedNode *v1.Node, allowedT
pv.Spec.AccessModes = c.plugin.GetAccessModes()
}
pv.Spec.NodeAffinity = new(v1.VolumeNodeAffinity)
pv.Spec.NodeAffinity.Required = new(v1.NodeSelector)
nodeSelectorTerms, err := volumehelpers.TranslateZoneLabelsToNodeSelectorTerms(labels)
if err != nil {
return nil, err
requirements := make([]v1.NodeSelectorRequirement, 0)
if len(labels) != 0 {
if pv.Labels == nil {
pv.Labels = make(map[string]string)
}
for k, v := range labels {
pv.Labels[k] = v
var values []string
if k == v1.LabelZoneFailureDomain {
values, err = volumehelpers.LabelZonesToList(v)
if err != nil {
return nil, fmt.Errorf("failed to convert label string for Zone: %s to a List: %v", v, err)
}
} else {
values = []string{v}
}
requirements = append(requirements, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: values})
}
}
pv.Spec.NodeAffinity.Required.NodeSelectorTerms = nodeSelectorTerms
if len(requirements) > 0 {
pv.Spec.NodeAffinity = new(v1.VolumeNodeAffinity)
pv.Spec.NodeAffinity.Required = new(v1.NodeSelector)
pv.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]v1.NodeSelectorTerm, 1)
pv.Spec.NodeAffinity.Required.NodeSelectorTerms[0].MatchExpressions = requirements
}
return pv, nil
}

View File

@ -86,7 +86,6 @@ func (fake *fakePDManager) CreateVolume(c *gcePersistentDiskProvisioner, node *v
labels = make(map[string]string)
labels["fakepdmanager"] = "yes"
labels[v1.LabelZoneFailureDomain] = "zone1__zone2"
labels[v1.LabelZoneFailureDomainStable] = "zone1__zone2"
return "test-gce-volume-name", 100, labels, "", nil
}
@ -204,14 +203,10 @@ func TestPlugin(t *testing.T) {
t.Errorf("Provision() returned unexpected value for %s: %v", v1.LabelZoneFailureDomain, persistentSpec.Labels[v1.LabelZoneFailureDomain])
}
if persistentSpec.Labels[v1.LabelZoneFailureDomainStable] != "zone1__zone2" {
t.Errorf("Provision() returned unexpected value for %s: %v", v1.LabelZoneFailureDomainStable, persistentSpec.Labels[v1.LabelZoneFailureDomainStable])
}
if persistentSpec.Spec.NodeAffinity == nil {
t.Errorf("Unexpected nil NodeAffinity found")
}
if len(persistentSpec.Spec.NodeAffinity.Required.NodeSelectorTerms) != 2 {
if len(persistentSpec.Spec.NodeAffinity.Required.NodeSelectorTerms) != 1 {
t.Errorf("Unexpected number of NodeSelectorTerms")
}
term := persistentSpec.Spec.NodeAffinity.Required.NodeSelectorTerms[0]
@ -232,24 +227,6 @@ func TestPlugin(t *testing.T) {
t.Errorf("ZoneFailureDomain elements %v does not match zone labels %v", r.Values, zones)
}
term = persistentSpec.Spec.NodeAffinity.Required.NodeSelectorTerms[1]
if len(term.MatchExpressions) != 2 {
t.Errorf("Unexpected number of NodeSelectorRequirements in volume NodeAffinity: %d", len(term.MatchExpressions))
}
r, _ = getNodeSelectorRequirementWithKey("fakepdmanager", term)
if r == nil || r.Values[0] != "yes" || r.Operator != v1.NodeSelectorOpIn {
t.Errorf("NodeSelectorRequirement fakepdmanager-in-yes not found in volume NodeAffinity")
}
zones, _ = volumehelpers.ZonesToSet("zone1,zone2")
r, _ = getNodeSelectorRequirementWithKey(v1.LabelZoneFailureDomainStable, term)
if r == nil {
t.Errorf("NodeSelectorRequirement %s-in-%v not found in volume NodeAffinity", v1.LabelZoneFailureDomainStable, zones)
}
sort.Strings(r.Values)
if !reflect.DeepEqual(r.Values, zones.List()) {
t.Errorf("ZoneFailureDomain elements %v does not match zone labels %v", r.Values, zones)
}
// Test Deleter
volSpec := &volume.Spec{
PersistentVolume: persistentSpec,

View File

@ -349,11 +349,7 @@ func udevadmChangeToDrive(drivePath string) error {
// Checks whether the given GCE PD volume spec is associated with a regional PD.
func isRegionalPD(spec *volume.Spec) bool {
if spec.PersistentVolume != nil {
zonesLabel, ok := spec.PersistentVolume.Labels[v1.LabelZoneFailureDomain]
if !ok {
zonesLabel = spec.PersistentVolume.Labels[v1.LabelZoneFailureDomainStable]
}
zonesLabel := spec.PersistentVolume.Labels[v1.LabelZoneFailureDomain]
zones := strings.Split(zonesLabel, cloudvolume.LabelMultiZoneDelimiter)
return len(zones) > 1
}

View File

@ -223,231 +223,6 @@ func TestCheckVolumeNodeAffinity(t *testing.T) {
}
}
func Test_CheckNodeAffinityWithTopology(t *testing.T) {
tests := []struct {
name string
pv *v1.PersistentVolume
nodeLabels map[string]string
expectSuccess bool
}{
{
name: "PV has only beta label, node has beta/GA label -- zone only",
pv: testVolumeWithNodeAffinity(t, &v1.VolumeNodeAffinity{
Required: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone"},
},
},
},
},
},
}),
nodeLabels: map[string]string{
v1.LabelZoneFailureDomain: "zone",
v1.LabelZoneFailureDomainStable: "zone",
},
expectSuccess: true,
},
{
name: "PV has only beta label, node has beta/GA label -- zone and region",
pv: testVolumeWithNodeAffinity(t, &v1.VolumeNodeAffinity{
Required: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone"},
},
{
Key: v1.LabelZoneRegion,
Operator: v1.NodeSelectorOpIn,
Values: []string{"region"},
},
},
},
},
},
}),
nodeLabels: map[string]string{
v1.LabelZoneFailureDomain: "zone",
v1.LabelZoneFailureDomainStable: "zone",
v1.LabelZoneRegion: "region",
v1.LabelZoneRegionStable: "region",
},
expectSuccess: true,
},
{
name: "PV has both beta/GA label, node has only beta -- zone only",
pv: testVolumeWithNodeAffinity(t, &v1.VolumeNodeAffinity{
Required: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone"},
},
},
},
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomainStable,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone"},
},
},
},
},
},
}),
nodeLabels: map[string]string{
v1.LabelZoneFailureDomain: "zone",
},
expectSuccess: true,
},
{
name: "PV has both beta/GA label, node has only beta -- zone and region",
pv: testVolumeWithNodeAffinity(t, &v1.VolumeNodeAffinity{
Required: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone"},
},
{
Key: v1.LabelZoneRegion,
Operator: v1.NodeSelectorOpIn,
Values: []string{"region"},
},
},
},
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomainStable,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone"},
},
{
Key: v1.LabelZoneRegionStable,
Operator: v1.NodeSelectorOpIn,
Values: []string{"region"},
},
},
},
},
},
}),
nodeLabels: map[string]string{
v1.LabelZoneFailureDomain: "zone",
v1.LabelZoneRegion: "region",
},
expectSuccess: true,
},
{
name: "PV has both beta/GA label, node has both beta/GA label -- zone only",
pv: testVolumeWithNodeAffinity(t, &v1.VolumeNodeAffinity{
Required: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone"},
},
},
},
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomainStable,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone"},
},
},
},
},
},
}),
nodeLabels: map[string]string{
v1.LabelZoneFailureDomain: "zone",
v1.LabelZoneFailureDomainStable: "zone",
},
expectSuccess: true,
},
{
name: "PV has both beta/GA label, node has both beta/GA label -- zone and region",
pv: testVolumeWithNodeAffinity(t, &v1.VolumeNodeAffinity{
Required: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone"},
},
{
Key: v1.LabelZoneRegion,
Operator: v1.NodeSelectorOpIn,
Values: []string{"region"},
},
},
},
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomainStable,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone"},
},
{
Key: v1.LabelZoneRegionStable,
Operator: v1.NodeSelectorOpIn,
Values: []string{"region"},
},
},
},
},
},
}),
nodeLabels: map[string]string{
v1.LabelZoneFailureDomain: "zone",
v1.LabelZoneRegion: "region",
v1.LabelZoneFailureDomainStable: "zone",
v1.LabelZoneRegionStable: "region",
},
expectSuccess: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := CheckNodeAffinity(test.pv, test.nodeLabels)
if err != nil && test.expectSuccess {
t.Errorf("CheckTopology returned error: %v", err)
}
if err == nil && !test.expectSuccess {
t.Error("CheckTopology returned success, expected error")
}
})
}
}
func testVolumeWithNodeAffinity(t *testing.T, affinity *v1.VolumeNodeAffinity) *v1.PersistentVolume {
objMeta := metav1.ObjectMeta{Name: "test-constraints"}
return &v1.PersistentVolume{

View File

@ -403,7 +403,7 @@ func (v *vsphereVolumeProvisioner) Provision(selectedNode *v1.Node, allowedTopol
pv := &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: v.options.PVName,
Labels: volSpec.Labels,
Labels: map[string]string{},
Annotations: map[string]string{
util.VolumeDynamicallyCreatedByKey: "vsphere-volume-dynamic-provisioner",
},
@ -430,15 +430,33 @@ func (v *vsphereVolumeProvisioner) Provision(selectedNode *v1.Node, allowedTopol
pv.Spec.AccessModes = v.plugin.GetAccessModes()
}
pv.Spec.NodeAffinity = new(v1.VolumeNodeAffinity)
pv.Spec.NodeAffinity.Required = new(v1.NodeSelector)
nodeSelectorTerms, err := volumehelpers.TranslateZoneLabelsToNodeSelectorTerms(volSpec.Labels)
if err != nil {
return nil, err
labels := volSpec.Labels
requirements := make([]v1.NodeSelectorRequirement, 0)
if len(labels) != 0 {
if pv.Labels == nil {
pv.Labels = make(map[string]string)
}
for k, v := range labels {
pv.Labels[k] = v
var values []string
if k == v1.LabelZoneFailureDomain {
values, err = volumehelpers.LabelZonesToList(v)
if err != nil {
return nil, fmt.Errorf("failed to convert label string for Zone: %s to a List: %v", v, err)
}
} else {
values = []string{v}
}
requirements = append(requirements, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: values})
}
}
pv.Spec.NodeAffinity.Required.NodeSelectorTerms = nodeSelectorTerms
if len(requirements) > 0 {
pv.Spec.NodeAffinity = new(v1.VolumeNodeAffinity)
pv.Spec.NodeAffinity.Required = new(v1.NodeSelector)
pv.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]v1.NodeSelectorTerm, 1)
pv.Spec.NodeAffinity.Required.NodeSelectorTerms[0].MatchExpressions = requirements
}
return pv, nil
}

View File

@ -22,7 +22,6 @@ import (
"errors"
"fmt"
"io"
"reflect"
"sync"
v1 "k8s.io/api/core/v1"
@ -118,13 +117,11 @@ func (l *persistentVolumeLabel) Admit(ctx context.Context, a admission.Attribute
return admission.NewForbidden(a, err)
}
requirements := make([]api.NodeSelectorRequirement, 0)
if len(volumeLabels) != 0 {
if volume.Labels == nil {
volume.Labels = make(map[string]string)
}
deprecatedTopologyReqs := make([]api.NodeSelectorRequirement, 0)
topologyReqs := make([]api.NodeSelectorRequirement, 0)
for k, v := range volumeLabels {
// We (silently) replace labels if they are provided.
// This should be OK because they are in the kubernetes.io namespace
@ -132,11 +129,8 @@ func (l *persistentVolumeLabel) Admit(ctx context.Context, a admission.Attribute
volume.Labels[k] = v
// Set NodeSelectorRequirements based on the labels
//
// we currently set both beta (failure-domain.beta.kubernetes.io/zone) and
// GA (topology.kubernetes.io/zone) topology labels for volumes
var values []string
if k == v1.LabelZoneFailureDomain || k == v1.LabelZoneFailureDomainStable {
if k == v1.LabelZoneFailureDomain {
zones, err := volumehelpers.LabelZonesToSet(v)
if err != nil {
return admission.NewForbidden(a, fmt.Errorf("failed to convert label string for Zone: %s to a Set", v))
@ -146,17 +140,7 @@ func (l *persistentVolumeLabel) Admit(ctx context.Context, a admission.Attribute
} else {
values = []string{v}
}
// separate topology requirements based on deprecated vs stable zone/region labels
// all other labels apply to both requirements
if k == v1.LabelZoneFailureDomain || k == v1.LabelZoneRegion {
deprecatedTopologyReqs = append(deprecatedTopologyReqs, api.NodeSelectorRequirement{Key: k, Operator: api.NodeSelectorOpIn, Values: values})
} else if k == v1.LabelZoneFailureDomainStable || k == v1.LabelZoneRegionStable {
topologyReqs = append(topologyReqs, api.NodeSelectorRequirement{Key: k, Operator: api.NodeSelectorOpIn, Values: values})
} else {
deprecatedTopologyReqs = append(deprecatedTopologyReqs, api.NodeSelectorRequirement{Key: k, Operator: api.NodeSelectorOpIn, Values: values})
topologyReqs = append(topologyReqs, api.NodeSelectorRequirement{Key: k, Operator: api.NodeSelectorOpIn, Values: values})
}
requirements = append(requirements, api.NodeSelectorRequirement{Key: k, Operator: api.NodeSelectorOpIn, Values: values})
}
if volume.Spec.NodeAffinity == nil {
@ -169,44 +153,16 @@ func (l *persistentVolumeLabel) Admit(ctx context.Context, a admission.Attribute
// Need at least one term pre-allocated whose MatchExpressions can be appended to
volume.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]api.NodeSelectorTerm, 1)
}
deprecatedNodeTerms := volume.DeepCopy().Spec.NodeAffinity.Required.NodeSelectorTerms
stableNodeTerms := volume.DeepCopy().Spec.NodeAffinity.Required.NodeSelectorTerms
// only attempt to rewrite beta/stable topology labels if there are no conflicting labels on the PV at all
if nodeSelectorRequirementKeysExistInNodeSelectorTerms(deprecatedTopologyReqs, volume.Spec.NodeAffinity.Required.NodeSelectorTerms) ||
nodeSelectorRequirementKeysExistInNodeSelectorTerms(topologyReqs, volume.Spec.NodeAffinity.Required.NodeSelectorTerms) {
klog.V(4).Infof("NodeSelectorRequirements for cloud labels %v conflict with existing NodeAffinity %v or %v. Skipping addition of NodeSelectorRequirements for cloud labels.",
deprecatedTopologyReqs, topologyReqs, volume.Spec.NodeAffinity)
return nil
}
for _, req := range deprecatedTopologyReqs {
for i := range deprecatedNodeTerms {
deprecatedNodeTerms[i].MatchExpressions = append(deprecatedNodeTerms[i].MatchExpressions, req)
if nodeSelectorRequirementKeysExistInNodeSelectorTerms(requirements, volume.Spec.NodeAffinity.Required.NodeSelectorTerms) {
klog.V(4).Infof("NodeSelectorRequirements for cloud labels %v conflict with existing NodeAffinity %v. Skipping addition of NodeSelectorRequirements for cloud labels.",
requirements, volume.Spec.NodeAffinity)
} else {
for _, req := range requirements {
for i := range volume.Spec.NodeAffinity.Required.NodeSelectorTerms {
volume.Spec.NodeAffinity.Required.NodeSelectorTerms[i].MatchExpressions = append(volume.Spec.NodeAffinity.Required.NodeSelectorTerms[i].MatchExpressions, req)
}
}
}
for _, req := range topologyReqs {
for i := range stableNodeTerms {
stableNodeTerms[i].MatchExpressions = append(stableNodeTerms[i].MatchExpressions, req)
}
}
// Deprecated and stable node selector terms are the same, i.e. the cloud provider
// didn't specify eithr zone/region labels. In the case set either one without
// expanding the set of selector terms
if reflect.DeepEqual(deprecatedTopologyReqs, topologyReqs) {
volume.Spec.NodeAffinity.Required.NodeSelectorTerms = stableNodeTerms
return nil
}
// for deprecated topology labels, we overwrite existing terms directly with the deprecated topology reqs appended
volume.Spec.NodeAffinity.Required.NodeSelectorTerms = deprecatedNodeTerms
// for new stable topology labels, we expand node selector requirements by copying existing selector terms but using stable topology labels
volume.Spec.NodeAffinity.Required.NodeSelectorTerms = append(volume.Spec.NodeAffinity.Required.NodeSelectorTerms, stableNodeTerms...)
}
return nil
@ -215,17 +171,15 @@ func (l *persistentVolumeLabel) Admit(ctx context.Context, a admission.Attribute
func (l *persistentVolumeLabel) findVolumeLabels(volume *api.PersistentVolume) (map[string]string, error) {
existingLabels := volume.Labels
// deprecated zone/region labels are still the source of truth
// All cloud providers set only these two labels.
domain, domainOK := existingLabels[v1.LabelZoneFailureDomain]
region, regionOK := existingLabels[v1.LabelZoneRegion]
isDynamicallyProvisioned := metav1.HasAnnotation(volume.ObjectMeta, persistentvolume.AnnDynamicallyProvisioned)
if isDynamicallyProvisioned && domainOK && regionOK {
// PV already has all the labels and we can trust the dynamic provisioning that it provided correct values.
return map[string]string{
v1.LabelZoneFailureDomain: domain,
v1.LabelZoneRegion: region,
v1.LabelZoneFailureDomainStable: domain,
v1.LabelZoneRegionStable: region,
v1.LabelZoneFailureDomain: domain,
v1.LabelZoneRegion: region,
}, nil
}

View File

@ -66,10 +66,9 @@ func Test_PVLAdmission(t *testing.T) {
name: "non-cloud PV ignored",
handler: newPersistentVolumeLabel(),
pvlabeler: mockVolumeLabels(map[string]string{
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
v1.LabelZoneFailureDomainStable: "1__2__3",
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
}),
preAdmissionPV: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "noncloud", Namespace: "myns"},
@ -175,10 +174,9 @@ func Test_PVLAdmission(t *testing.T) {
name: "AWS EBS PV labeled correctly",
handler: newPersistentVolumeLabel(),
pvlabeler: mockVolumeLabels(map[string]string{
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
v1.LabelZoneFailureDomainStable: "1__2__3",
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
}),
preAdmissionPV: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "awsebs", Namespace: "myns"},
@ -195,10 +193,9 @@ func Test_PVLAdmission(t *testing.T) {
Name: "awsebs",
Namespace: "myns",
Labels: map[string]string{
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
v1.LabelZoneFailureDomainStable: "1__2__3",
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
},
},
Spec: api.PersistentVolumeSpec{
@ -229,25 +226,6 @@ func Test_PVLAdmission(t *testing.T) {
},
},
},
{
MatchExpressions: []api.NodeSelectorRequirement{
{
Key: "a",
Operator: api.NodeSelectorOpIn,
Values: []string{"1"},
},
{
Key: "b",
Operator: api.NodeSelectorOpIn,
Values: []string{"2"},
},
{
Key: v1.LabelZoneFailureDomainStable,
Operator: api.NodeSelectorOpIn,
Values: []string{"1", "2", "3"},
},
},
},
},
},
},
@ -259,19 +237,15 @@ func Test_PVLAdmission(t *testing.T) {
name: "existing labels from dynamic provisioning are not changed",
handler: newPersistentVolumeLabel(),
pvlabeler: mockVolumeLabels(map[string]string{
v1.LabelZoneFailureDomain: "domain1",
v1.LabelZoneRegion: "region1",
v1.LabelZoneFailureDomainStable: "domain1",
v1.LabelZoneRegionStable: "region1",
v1.LabelZoneFailureDomain: "domain1",
v1.LabelZoneRegion: "region1",
}),
preAdmissionPV: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "awsebs", Namespace: "myns",
Labels: map[string]string{
v1.LabelZoneFailureDomain: "existingDomain",
v1.LabelZoneRegion: "existingRegion",
v1.LabelZoneFailureDomainStable: "existingDomain",
v1.LabelZoneRegionStable: "existingRegion",
v1.LabelZoneFailureDomain: "existingDomain",
v1.LabelZoneRegion: "existingRegion",
},
Annotations: map[string]string{
persistentvolume.AnnDynamicallyProvisioned: "kubernetes.io/aws-ebs",
@ -290,10 +264,8 @@ func Test_PVLAdmission(t *testing.T) {
Name: "awsebs",
Namespace: "myns",
Labels: map[string]string{
v1.LabelZoneFailureDomain: "existingDomain",
v1.LabelZoneRegion: "existingRegion",
v1.LabelZoneFailureDomainStable: "existingDomain",
v1.LabelZoneRegionStable: "existingRegion",
v1.LabelZoneFailureDomain: "existingDomain",
v1.LabelZoneRegion: "existingRegion",
},
Annotations: map[string]string{
persistentvolume.AnnDynamicallyProvisioned: "kubernetes.io/aws-ebs",
@ -322,20 +294,6 @@ func Test_PVLAdmission(t *testing.T) {
},
},
},
{
MatchExpressions: []api.NodeSelectorRequirement{
{
Key: v1.LabelZoneRegionStable,
Operator: api.NodeSelectorOpIn,
Values: []string{"existingRegion"},
},
{
Key: v1.LabelZoneFailureDomainStable,
Operator: api.NodeSelectorOpIn,
Values: []string{"existingDomain"},
},
},
},
},
},
},
@ -347,10 +305,8 @@ func Test_PVLAdmission(t *testing.T) {
name: "existing labels from user are changed",
handler: newPersistentVolumeLabel(),
pvlabeler: mockVolumeLabels(map[string]string{
v1.LabelZoneFailureDomain: "domain1",
v1.LabelZoneRegion: "region1",
v1.LabelZoneFailureDomainStable: "domain1",
v1.LabelZoneRegionStable: "region1",
v1.LabelZoneFailureDomain: "domain1",
v1.LabelZoneRegion: "region1",
}),
preAdmissionPV: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
@ -373,10 +329,8 @@ func Test_PVLAdmission(t *testing.T) {
Name: "awsebs",
Namespace: "myns",
Labels: map[string]string{
v1.LabelZoneFailureDomain: "domain1",
v1.LabelZoneRegion: "region1",
v1.LabelZoneFailureDomainStable: "domain1",
v1.LabelZoneRegionStable: "region1",
v1.LabelZoneFailureDomain: "domain1",
v1.LabelZoneRegion: "region1",
},
},
Spec: api.PersistentVolumeSpec{
@ -402,20 +356,6 @@ func Test_PVLAdmission(t *testing.T) {
},
},
},
{
MatchExpressions: []api.NodeSelectorRequirement{
{
Key: v1.LabelZoneRegionStable,
Operator: api.NodeSelectorOpIn,
Values: []string{"region1"},
},
{
Key: v1.LabelZoneFailureDomainStable,
Operator: api.NodeSelectorOpIn,
Values: []string{"domain1"},
},
},
},
},
},
},
@ -427,10 +367,9 @@ func Test_PVLAdmission(t *testing.T) {
name: "GCE PD PV labeled correctly",
handler: newPersistentVolumeLabel(),
pvlabeler: mockVolumeLabels(map[string]string{
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
v1.LabelZoneFailureDomainStable: "1__2__3",
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
}),
preAdmissionPV: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "gcepd", Namespace: "myns"},
@ -447,10 +386,9 @@ func Test_PVLAdmission(t *testing.T) {
Name: "gcepd",
Namespace: "myns",
Labels: map[string]string{
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
v1.LabelZoneFailureDomainStable: "1__2__3",
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
},
},
Spec: api.PersistentVolumeSpec{
@ -481,25 +419,6 @@ func Test_PVLAdmission(t *testing.T) {
},
},
},
{
MatchExpressions: []api.NodeSelectorRequirement{
{
Key: "a",
Operator: api.NodeSelectorOpIn,
Values: []string{"1"},
},
{
Key: "b",
Operator: api.NodeSelectorOpIn,
Values: []string{"2"},
},
{
Key: v1.LabelZoneFailureDomainStable,
Operator: api.NodeSelectorOpIn,
Values: []string{"1", "2", "3"},
},
},
},
},
},
},
@ -511,10 +430,9 @@ func Test_PVLAdmission(t *testing.T) {
name: "Azure Disk PV labeled correctly",
handler: newPersistentVolumeLabel(),
pvlabeler: mockVolumeLabels(map[string]string{
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
v1.LabelZoneFailureDomainStable: "1__2__3",
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
}),
preAdmissionPV: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
@ -534,10 +452,9 @@ func Test_PVLAdmission(t *testing.T) {
Name: "azurepd",
Namespace: "myns",
Labels: map[string]string{
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
v1.LabelZoneFailureDomainStable: "1__2__3",
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
},
},
Spec: api.PersistentVolumeSpec{
@ -568,25 +485,6 @@ func Test_PVLAdmission(t *testing.T) {
},
},
},
{
MatchExpressions: []api.NodeSelectorRequirement{
{
Key: "a",
Operator: api.NodeSelectorOpIn,
Values: []string{"1"},
},
{
Key: "b",
Operator: api.NodeSelectorOpIn,
Values: []string{"2"},
},
{
Key: v1.LabelZoneFailureDomainStable,
Operator: api.NodeSelectorOpIn,
Values: []string{"1", "2", "3"},
},
},
},
},
},
},
@ -598,10 +496,9 @@ func Test_PVLAdmission(t *testing.T) {
name: "Cinder Disk PV labeled correctly",
handler: newPersistentVolumeLabel(),
pvlabeler: mockVolumeLabels(map[string]string{
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
v1.LabelZoneFailureDomainStable: "1__2__3",
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
}),
preAdmissionPV: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
@ -621,10 +518,9 @@ func Test_PVLAdmission(t *testing.T) {
Name: "azurepd",
Namespace: "myns",
Labels: map[string]string{
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
v1.LabelZoneFailureDomainStable: "1__2__3",
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
},
},
Spec: api.PersistentVolumeSpec{
@ -655,25 +551,6 @@ func Test_PVLAdmission(t *testing.T) {
},
},
},
{
MatchExpressions: []api.NodeSelectorRequirement{
{
Key: "a",
Operator: api.NodeSelectorOpIn,
Values: []string{"1"},
},
{
Key: "b",
Operator: api.NodeSelectorOpIn,
Values: []string{"2"},
},
{
Key: v1.LabelZoneFailureDomainStable,
Operator: api.NodeSelectorOpIn,
Values: []string{"1", "2", "3"},
},
},
},
},
},
},
@ -685,10 +562,9 @@ func Test_PVLAdmission(t *testing.T) {
name: "AWS EBS PV overrides user applied labels",
handler: newPersistentVolumeLabel(),
pvlabeler: mockVolumeLabels(map[string]string{
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
v1.LabelZoneFailureDomainStable: "1__2__3",
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
}),
preAdmissionPV: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
@ -711,10 +587,9 @@ func Test_PVLAdmission(t *testing.T) {
Name: "awsebs",
Namespace: "myns",
Labels: map[string]string{
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
v1.LabelZoneFailureDomainStable: "1__2__3",
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
},
},
Spec: api.PersistentVolumeSpec{
@ -745,25 +620,6 @@ func Test_PVLAdmission(t *testing.T) {
},
},
},
{
MatchExpressions: []api.NodeSelectorRequirement{
{
Key: "a",
Operator: api.NodeSelectorOpIn,
Values: []string{"1"},
},
{
Key: "b",
Operator: api.NodeSelectorOpIn,
Values: []string{"2"},
},
{
Key: v1.LabelZoneFailureDomainStable,
Operator: api.NodeSelectorOpIn,
Values: []string{"1", "2", "3"},
},
},
},
},
},
},
@ -963,10 +819,9 @@ func Test_PVLAdmission(t *testing.T) {
name: "vSphere PV labeled correctly",
handler: newPersistentVolumeLabel(),
pvlabeler: mockVolumeLabels(map[string]string{
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
v1.LabelZoneFailureDomainStable: "1__2__3",
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
}),
preAdmissionPV: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
@ -986,10 +841,9 @@ func Test_PVLAdmission(t *testing.T) {
Name: "vSpherePV",
Namespace: "myns",
Labels: map[string]string{
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
v1.LabelZoneFailureDomainStable: "1__2__3",
"a": "1",
"b": "2",
v1.LabelZoneFailureDomain: "1__2__3",
},
},
Spec: api.PersistentVolumeSpec{
@ -1020,25 +874,6 @@ func Test_PVLAdmission(t *testing.T) {
},
},
},
{
MatchExpressions: []api.NodeSelectorRequirement{
{
Key: "a",
Operator: api.NodeSelectorOpIn,
Values: []string{"1"},
},
{
Key: "b",
Operator: api.NodeSelectorOpIn,
Values: []string{"2"},
},
{
Key: v1.LabelZoneFailureDomainStable,
Operator: api.NodeSelectorOpIn,
Values: []string{"1", "2", "3"},
},
},
},
},
},
},
@ -1065,8 +900,6 @@ func Test_PVLAdmission(t *testing.T) {
if !reflect.DeepEqual(testcase.preAdmissionPV, testcase.postAdmissionPV) {
t.Logf("expected PV: %+v", testcase.postAdmissionPV)
t.Logf("actual PV: %+v", testcase.preAdmissionPV)
t.Logf("expected PV node affinity: %+v", testcase.postAdmissionPV.Spec.NodeAffinity.Required)
t.Logf("actual PV node affinity: %+v", testcase.preAdmissionPV.Spec.NodeAffinity.Required)
t.Error("unexpected PV")
}
@ -1094,12 +927,10 @@ func sortMatchExpressions(pv *api.PersistentVolume) {
return
}
for t := range pv.Spec.NodeAffinity.Required.NodeSelectorTerms {
match := pv.Spec.NodeAffinity.Required.NodeSelectorTerms[t].MatchExpressions
sort.Slice(match, func(i, j int) bool {
return match[i].Key < match[j].Key
})
match := pv.Spec.NodeAffinity.Required.NodeSelectorTerms[0].MatchExpressions
sort.Slice(match, func(i, j int) bool {
return match[i].Key < match[j].Key
})
pv.Spec.NodeAffinity.Required.NodeSelectorTerms[t].MatchExpressions = match
}
pv.Spec.NodeAffinity.Required.NodeSelectorTerms[0].MatchExpressions = match
}

View File

@ -120,11 +120,7 @@ func SelectZonesForVolume(zoneParameterPresent, zonesParameterPresent bool, zone
var ok bool
zoneFromNode, ok = node.ObjectMeta.Labels[v1.LabelZoneFailureDomain]
if !ok {
zoneFromNode, ok = node.ObjectMeta.Labels[v1.LabelZoneFailureDomainStable]
}
if !ok {
return nil, fmt.Errorf("Label %q or %q for node is missing", v1.LabelZoneFailureDomain, v1.LabelZoneFailureDomainStable)
return nil, fmt.Errorf("%s Label for node missing", v1.LabelZoneFailureDomain)
}
// if single replica volume and node with zone found, return immediately
if numReplicas == 1 {
@ -139,8 +135,7 @@ func SelectZonesForVolume(zoneParameterPresent, zonesParameterPresent bool, zone
}
if (len(allowedTopologies) > 0) && (allowedZones.Len() == 0) {
return nil, fmt.Errorf("no matchLabelExpressions with keys %q,%q found in allowedTopologies. Please specify matchLabelExpressions with keys: %q,%q",
v1.LabelZoneFailureDomain, v1.LabelZoneFailureDomainStable, v1.LabelZoneFailureDomain, v1.LabelZoneFailureDomainStable)
return nil, fmt.Errorf("no matchLabelExpressions with %s key found in allowedTopologies. Please specify matchLabelExpressions with %s key", v1.LabelZoneFailureDomain, v1.LabelZoneFailureDomain)
}
if allowedZones.Len() > 0 {
@ -190,7 +185,7 @@ func ZonesFromAllowedTopologies(allowedTopologies []v1.TopologySelectorTerm) (se
zones := make(sets.String)
for _, term := range allowedTopologies {
for _, exp := range term.MatchLabelExpressions {
if exp.Key == v1.LabelZoneFailureDomain || exp.Key == v1.LabelZoneFailureDomainStable {
if exp.Key == v1.LabelZoneFailureDomain {
for _, value := range exp.Values {
zones.Insert(value)
}
@ -313,103 +308,3 @@ func getPVCNameHashAndIndexOffset(pvcName string) (hash uint32, index uint32) {
return hash, index
}
// TranslateZoneRegionLabelsToNodeSelectorTerms translates the set of provided labels as []v1.NodeSelectorTerms.
// For zone/region topologies, a node can have either only the beta label (failure-domain.beta.kubernetes.io/{zone,region})
// or both the beta and GA label (topology.kubernetes.io/{zone,region}). We have to put each topology label into
// separate node selector terms so PVs can be scheduled on nodes with either one or both labels
func TranslateZoneRegionLabelsToNodeSelectorTerms(labels map[string]string) []v1.NodeSelectorTerm {
nodeSelectorTerms := make([]v1.NodeSelectorTerm, 0)
deprecatedTopologyReqs := make([]v1.NodeSelectorRequirement, 0)
topologyReqs := make([]v1.NodeSelectorRequirement, 0)
if len(labels) == 0 {
return nodeSelectorTerms
}
for k, v := range labels {
if k == v1.LabelZoneFailureDomain || k == v1.LabelZoneRegion {
deprecatedTopologyReqs = append(deprecatedTopologyReqs, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: []string{v}})
continue
}
if k == v1.LabelZoneFailureDomainStable || k == v1.LabelZoneRegionStable {
topologyReqs = append(topologyReqs, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: []string{v}})
continue
}
// remaining labels outside known topology labels get added to both beta and GA node selectors
deprecatedTopologyReqs = append(deprecatedTopologyReqs, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: []string{v}})
topologyReqs = append(topologyReqs, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: []string{v}})
}
if len(deprecatedTopologyReqs) > 0 {
nodeSelectorTerms = append(nodeSelectorTerms, v1.NodeSelectorTerm{
MatchExpressions: deprecatedTopologyReqs,
})
}
if len(topologyReqs) > 0 {
nodeSelectorTerms = append(nodeSelectorTerms, v1.NodeSelectorTerm{
MatchExpressions: topologyReqs,
})
}
return nodeSelectorTerms
}
// TranslateZoneLabelsToNodeSelectorTerms translates the set of provided labels as []v1.NodeSelectorTerms.
// For zone topologies, a node can have either only the beta label (failure-domain.beta.kubernetes.io/zone)
// or both the beta and GA label (topology.kubernetes.io/zone). We have to put each topology label into
// separate node selector terms so PVs can be scheduled on nodes with either one or both labels
func TranslateZoneLabelsToNodeSelectorTerms(labels map[string]string) ([]v1.NodeSelectorTerm, error) {
nodeSelectorTerms := make([]v1.NodeSelectorTerm, 0)
deprecatedTopologyReqs := make([]v1.NodeSelectorRequirement, 0)
topologyReqs := make([]v1.NodeSelectorRequirement, 0)
if len(labels) == 0 {
return nodeSelectorTerms, nil
}
for k, v := range labels {
var values []string
if k == v1.LabelZoneFailureDomain {
values, err := LabelZonesToList(v)
if err != nil {
return nil, fmt.Errorf("failed to convert label string for Zone: %s to a List: %v", v, err)
}
deprecatedTopologyReqs = append(deprecatedTopologyReqs, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: values})
continue
}
if k == v1.LabelZoneFailureDomainStable {
values, err := LabelZonesToList(v)
if err != nil {
return nil, fmt.Errorf("failed to convert label string for Zone: %s to a List: %v", v, err)
}
topologyReqs = append(topologyReqs, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: values})
continue
}
// remaining labels outside known topology labels get added to both beta and GA node selectors
values = []string{v}
deprecatedTopologyReqs = append(deprecatedTopologyReqs, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: values})
topologyReqs = append(topologyReqs, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: values})
}
if len(deprecatedTopologyReqs) > 0 {
nodeSelectorTerms = append(nodeSelectorTerms, v1.NodeSelectorTerm{
MatchExpressions: deprecatedTopologyReqs,
})
}
if len(topologyReqs) > 0 {
nodeSelectorTerms = append(nodeSelectorTerms, v1.NodeSelectorTerm{
MatchExpressions: topologyReqs,
})
}
return nodeSelectorTerms, nil
}

View File

@ -17,10 +17,7 @@ limitations under the License.
package helpers
import (
"fmt"
"hash/fnv"
"reflect"
"sort"
"testing"
"k8s.io/api/core/v1"
@ -420,7 +417,7 @@ func TestChooseZonesForVolume(t *testing.T) {
func TestSelectZoneForVolume(t *testing.T) {
nodeWithZoneLabels := &v1.Node{}
nodeWithZoneLabels.Labels = map[string]string{v1.LabelZoneFailureDomain: "zoneX", v1.LabelZoneFailureDomainStable: "zoneX"}
nodeWithZoneLabels.Labels = map[string]string{v1.LabelZoneFailureDomain: "zoneX"}
nodeWithNoLabels := &v1.Node{}
@ -661,10 +658,6 @@ func TestSelectZoneForVolume(t *testing.T) {
Key: v1.LabelZoneFailureDomain,
Values: []string{"zoneX", "zoneY"},
},
{
Key: v1.LabelZoneFailureDomainStable,
Values: []string{"zoneX", "zoneY"},
},
},
},
},
@ -696,22 +689,6 @@ func TestSelectZoneForVolume(t *testing.T) {
},
},
},
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
{
Key: v1.LabelZoneFailureDomainStable,
Values: []string{"zoneX"},
},
},
},
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
{
Key: v1.LabelZoneFailureDomainStable,
Values: []string{"zoneY"},
},
},
},
},
Reject: false,
ExpectedZones: "zoneX,zoneY",
@ -1133,7 +1110,7 @@ func TestSelectZonesForVolume(t *testing.T) {
// Select zones from node label and AllowedTopologies [Pass]
// [1] Node with zone labels
// [2] no Zone/Zones parameters
// [3] AllowedTopologies with single term with multiple values specified, both beta and GA zone labels
// [3] AllowedTopologies with single term with multiple values specified
// [4] ReplicaCount specified
// [5] ZonesWithNodes irrelevant
// Note: the test Name suffix is used as the pvcname and it's suffix is important to influence ChooseZonesForVolume
@ -1149,10 +1126,6 @@ func TestSelectZonesForVolume(t *testing.T) {
Key: v1.LabelZoneFailureDomain,
Values: []string{"zoneV", "zoneW", "zoneX", "zoneY", "zoneZ"},
},
{
Key: v1.LabelZoneFailureDomainStable,
Values: []string{"zoneV", "zoneW", "zoneX", "zoneY", "zoneZ"},
},
},
},
},
@ -1165,35 +1138,7 @@ func TestSelectZonesForVolume(t *testing.T) {
// Select zones from node label and AllowedTopologies [Pass]
// [1] Node with zone labels
// [2] no Zone/Zones parameters
// [3] AllowedTopologies with single term with multiple values specified, only GA zone labels
// [4] ReplicaCount specified
// [5] ZonesWithNodes irrelevant
// Note: the test Name suffix is used as the pvcname and it's suffix is important to influence ChooseZonesForVolume
// to NOT pick zoneX from AllowedTopologies if zoneFromNode is incorrectly set or not set at all.
{
Name: "Node_with_Zone_labels_and_Multiple_Allowed_Topology_values_Superset-1",
Node: nodeWithZoneLabels,
ReplicaCount: 2,
AllowedTopologies: []v1.TopologySelectorTerm{
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
{
Key: v1.LabelZoneFailureDomainStable,
Values: []string{"zoneV", "zoneW", "zoneX", "zoneY", "zoneZ"},
},
},
},
},
Reject: false,
ExpectSpecificZone: true,
ExpectedZone: "zoneX",
ExpectedZones: "zoneV,zoneW,zoneX,zoneY,zoneZ",
},
// Select zones from node label and AllowedTopologies [Pass]
// [1] Node with zone labels
// [2] no Zone/Zones parameters
// [3] AllowedTopologies with single term with multiple values specified, has both beta/GA zone labels
// [3] AllowedTopologies with single term with multiple values specified
// [4] ReplicaCount specified
// [5] ZonesWithNodes irrelevant
{
@ -1207,10 +1152,6 @@ func TestSelectZonesForVolume(t *testing.T) {
Key: v1.LabelZoneFailureDomain,
Values: []string{"zoneX", "zoneY"},
},
{
Key: v1.LabelZoneFailureDomainStable,
Values: []string{"zoneX", "zoneY"},
},
},
},
},
@ -1334,7 +1275,7 @@ func TestSelectZonesForVolume(t *testing.T) {
// Select zones from node label and AllowedTopologies [Pass]
// [1] Node with zone labels
// [2] no Zone/Zones parametes specified
// [3] AllowedTopologies with multiple terms specified, has both beta/GA zone labels
// [3] AllowedTopologies with multiple terms specified
// [4] ReplicaCount specified
// [5] ZonesWithNodes irrelevant
{
@ -1358,22 +1299,6 @@ func TestSelectZonesForVolume(t *testing.T) {
},
},
},
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
{
Key: v1.LabelZoneFailureDomainStable,
Values: []string{"zoneX"},
},
},
},
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
{
Key: v1.LabelZoneFailureDomainStable,
Values: []string{"zoneY"},
},
},
},
},
Reject: false,
ExpectSpecificZone: true,
@ -1712,396 +1637,3 @@ func checkFnv32(t *testing.T, s string, expected uint32) {
t.Fatalf("hash of %q was %v, expected %v", s, h.Sum32(), expected)
}
}
func Test_TranslateZoneRegionLabelsToNodeSelectorTerms(t *testing.T) {
testcases := []struct {
name string
labels map[string]string
nodeSelectorTerm []v1.NodeSelectorTerm
}{
{
name: "empty label set",
labels: map[string]string{},
nodeSelectorTerm: []v1.NodeSelectorTerm{},
},
{
name: "nil label set",
labels: nil,
nodeSelectorTerm: []v1.NodeSelectorTerm{},
},
{
name: "with beta zone labels",
labels: map[string]string{
v1.LabelZoneFailureDomain: "zone1",
},
nodeSelectorTerm: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1"},
},
},
},
},
},
{
name: "with beta and stable zone labels",
labels: map[string]string{
v1.LabelZoneFailureDomain: "zone1",
v1.LabelZoneFailureDomainStable: "zone1",
},
nodeSelectorTerm: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1"},
},
},
},
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomainStable,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1"},
},
},
},
},
},
{
name: "with beta zone and region labels",
labels: map[string]string{
v1.LabelZoneFailureDomain: "zone1",
v1.LabelZoneRegion: "region1",
},
nodeSelectorTerm: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1"},
},
{
Key: v1.LabelZoneRegion,
Operator: v1.NodeSelectorOpIn,
Values: []string{"region1"},
},
},
},
},
},
{
name: "with stable zone and region labels",
labels: map[string]string{
v1.LabelZoneFailureDomain: "zone1",
v1.LabelZoneRegion: "region1",
},
nodeSelectorTerm: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1"},
},
{
Key: v1.LabelZoneRegion,
Operator: v1.NodeSelectorOpIn,
Values: []string{"region1"},
},
},
},
},
},
{
name: "with beta/stable and zone/region labels",
labels: map[string]string{
v1.LabelZoneFailureDomain: "zone1",
v1.LabelZoneFailureDomainStable: "zone1",
v1.LabelZoneRegion: "region1",
v1.LabelZoneRegionStable: "region1",
},
nodeSelectorTerm: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1"},
},
{
Key: v1.LabelZoneRegion,
Operator: v1.NodeSelectorOpIn,
Values: []string{"region1"},
},
},
},
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomainStable,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1"},
},
{
Key: v1.LabelZoneRegionStable,
Operator: v1.NodeSelectorOpIn,
Values: []string{"region1"},
},
},
},
},
},
{
name: "with beta/stable and zone/region and other labels",
labels: map[string]string{
v1.LabelZoneFailureDomain: "zone1",
v1.LabelZoneFailureDomainStable: "zone1",
v1.LabelZoneRegion: "region1",
v1.LabelZoneRegionStable: "region1",
"hello": "world",
},
nodeSelectorTerm: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1"},
},
{
Key: v1.LabelZoneRegion,
Operator: v1.NodeSelectorOpIn,
Values: []string{"region1"},
},
{
Key: "hello",
Operator: v1.NodeSelectorOpIn,
Values: []string{"world"},
},
},
},
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomainStable,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1"},
},
{
Key: v1.LabelZoneRegionStable,
Operator: v1.NodeSelectorOpIn,
Values: []string{"region1"},
},
{
Key: "hello",
Operator: v1.NodeSelectorOpIn,
Values: []string{"world"},
},
},
},
},
},
}
for _, testcase := range testcases {
t.Run(testcase.name, func(t *testing.T) {
nodeSelectorTerm := TranslateZoneRegionLabelsToNodeSelectorTerms(testcase.labels)
sortNodeSelectorTerm(nodeSelectorTerm)
sortNodeSelectorTerm(testcase.nodeSelectorTerm)
if !reflect.DeepEqual(nodeSelectorTerm, testcase.nodeSelectorTerm) {
t.Logf("actual node selector term: %v", nodeSelectorTerm)
t.Logf("expected node selector term: %v", testcase.nodeSelectorTerm)
t.Error("unexpected node selector term")
}
})
}
}
func Test_TranslateZoneLabelsToNodeSelectorTerms(t *testing.T) {
testcases := []struct {
name string
labels map[string]string
nodeSelectorTerm []v1.NodeSelectorTerm
expectedErr error
}{
{
name: "empty label set",
labels: map[string]string{},
nodeSelectorTerm: []v1.NodeSelectorTerm{},
},
{
name: "nil label set",
labels: nil,
nodeSelectorTerm: []v1.NodeSelectorTerm{},
},
{
name: "with beta zone labels",
labels: map[string]string{
v1.LabelZoneFailureDomain: "zone1",
},
nodeSelectorTerm: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1"},
},
},
},
},
},
{
name: "with beta multi-zone labels",
labels: map[string]string{
v1.LabelZoneFailureDomain: "zone1__zone2",
},
nodeSelectorTerm: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1", "zone2"},
},
},
},
},
},
{
name: "with beta and stable zone labels",
labels: map[string]string{
v1.LabelZoneFailureDomain: "zone1",
v1.LabelZoneFailureDomainStable: "zone1",
},
nodeSelectorTerm: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1"},
},
},
},
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomainStable,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1"},
},
},
},
},
},
{
name: "with beta and stable multi-zone labels",
labels: map[string]string{
v1.LabelZoneFailureDomain: "zone1__zone2",
v1.LabelZoneFailureDomainStable: "zone1__zone2",
},
nodeSelectorTerm: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1", "zone2"},
},
},
},
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomainStable,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1", "zone2"},
},
},
},
},
},
{
name: "with beta/stable zones and others",
labels: map[string]string{
v1.LabelZoneFailureDomain: "zone1__zone2",
v1.LabelZoneFailureDomainStable: "zone1__zone2",
"hello": "world",
},
nodeSelectorTerm: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomain,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1", "zone2"},
},
{
Key: "hello",
Operator: v1.NodeSelectorOpIn,
Values: []string{"world"},
},
},
},
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: v1.LabelZoneFailureDomainStable,
Operator: v1.NodeSelectorOpIn,
Values: []string{"zone1", "zone2"},
},
{
Key: "hello",
Operator: v1.NodeSelectorOpIn,
Values: []string{"world"},
},
},
},
},
},
{
name: "with invalid zone value",
labels: map[string]string{
v1.LabelZoneFailureDomain: "zone1__",
},
expectedErr: fmt.Errorf("failed to convert label string for Zone: zone1__ to a List: %q separated list (%q) must not contain an empty string", "__", "zone1__"),
},
}
for _, testcase := range testcases {
t.Run(testcase.name, func(t *testing.T) {
nodeSelectorTerm, err := TranslateZoneLabelsToNodeSelectorTerms(testcase.labels)
if !reflect.DeepEqual(err, testcase.expectedErr) {
t.Logf("actual err: %v", err)
t.Logf("expected err: %v", testcase.expectedErr)
t.Fatal("unexpected error")
}
sortNodeSelectorTerm(nodeSelectorTerm)
sortNodeSelectorTerm(testcase.nodeSelectorTerm)
if !reflect.DeepEqual(nodeSelectorTerm, testcase.nodeSelectorTerm) {
t.Logf("actual node selector term: %v", nodeSelectorTerm)
t.Logf("expected node selector term: %v", testcase.nodeSelectorTerm)
t.Error("unexpected node selector term")
}
})
}
}
func sortNodeSelectorTerm(nodeSelectorTerms []v1.NodeSelectorTerm) {
for _, nodeSelectorTerm := range nodeSelectorTerms {
sort.Slice(nodeSelectorTerm.MatchExpressions, func(i, j int) bool {
return nodeSelectorTerm.MatchExpressions[i].Key < nodeSelectorTerm.MatchExpressions[j].Key
})
}
}

View File

@ -73,16 +73,13 @@ func translateAllowedTopologies(terms []v1.TopologySelectorTerm) ([]v1.TopologyS
newTopologies := []v1.TopologySelectorTerm{}
for _, term := range terms {
newTerm := v1.TopologySelectorTerm{}
zoneFound := false
for _, exp := range term.MatchLabelExpressions {
var newExp v1.TopologySelectorLabelRequirement
if !zoneFound && (exp.Key == v1.LabelZoneFailureDomain || exp.Key == v1.LabelZoneFailureDomainStable) {
if exp.Key == v1.LabelZoneFailureDomain {
newExp = v1.TopologySelectorLabelRequirement{
Key: GCEPDTopologyKey,
Values: exp.Values,
}
zoneFound = true
} else if exp.Key == GCEPDTopologyKey {
newExp = exp
} else {
@ -243,11 +240,7 @@ func (g *gcePersistentDiskCSITranslator) TranslateInTreePVToCSI(pv *v1.Persisten
return nil, fmt.Errorf("pv is nil or GCE Persistent Disk source not defined on pv")
}
zonesLabel, ok := pv.Labels[v1.LabelZoneFailureDomain]
if !ok {
zonesLabel = pv.Labels[v1.LabelZoneFailureDomainStable]
}
zonesLabel := pv.Labels[v1.LabelZoneFailureDomain]
zones := strings.Split(zonesLabel, cloudvolume.LabelMultiZoneDelimiter)
if len(zones) == 1 && len(zones[0]) != 0 {
// Zonal

View File

@ -71,14 +71,9 @@ func TestTranslatePDInTreeStorageClassToCSI(t *testing.T) {
options: NewStorageClass(map[string]string{}, generateToplogySelectors(GCEPDTopologyKey, []string{"foo"})),
expOptions: NewStorageClass(map[string]string{}, generateToplogySelectors(GCEPDTopologyKey, []string{"foo"})),
},
{
name: "some translated topology using deprecated zone label",
options: NewStorageClass(map[string]string{}, generateToplogySelectors(v1.LabelZoneFailureDomain, []string{"foo"})),
expOptions: NewStorageClass(map[string]string{}, generateToplogySelectors(GCEPDTopologyKey, []string{"foo"})),
},
{
name: "some translated topology",
options: NewStorageClass(map[string]string{}, generateToplogySelectors(v1.LabelZoneFailureDomainStable, []string{"foo"})),
options: NewStorageClass(map[string]string{}, generateToplogySelectors(v1.LabelZoneFailureDomain, []string{"foo"})),
expOptions: NewStorageClass(map[string]string{}, generateToplogySelectors(GCEPDTopologyKey, []string{"foo"})),
},
{

View File

@ -2639,15 +2639,11 @@ func (c *Cloud) GetVolumeLabels(volumeName KubernetesVolumeID) (map[string]strin
}
labels[v1.LabelZoneFailureDomain] = az
labels[v1.LabelZoneFailureDomainStable] = az
region, err := azToRegion(az)
if err != nil {
return nil, err
}
labels[v1.LabelZoneRegion] = region
labels[v1.LabelZoneRegionStable] = region
return labels, nil
}

View File

@ -1262,11 +1262,8 @@ func TestGetVolumeLabels(t *testing.T) {
assert.Nil(t, err, "Error creating Volume %v", err)
assert.Equal(t, map[string]string{
v1.LabelZoneFailureDomain: "us-east-1a",
v1.LabelZoneRegion: "us-east-1",
v1.LabelZoneFailureDomainStable: "us-east-1a",
v1.LabelZoneRegionStable: "us-east-1",
}, labels)
v1.LabelZoneFailureDomain: "us-east-1a",
v1.LabelZoneRegion: "us-east-1"}, labels)
awsServices.ec2.(*MockedFakeEC2).AssertExpectations(t)
}
@ -1339,10 +1336,8 @@ func TestGetLabelsForVolume(t *testing.T) {
AvailabilityZone: aws.String("us-east-1a"),
}},
map[string]string{
v1.LabelZoneFailureDomain: "us-east-1a",
v1.LabelZoneRegion: "us-east-1",
v1.LabelZoneFailureDomainStable: "us-east-1a",
v1.LabelZoneRegionStable: "us-east-1",
v1.LabelZoneFailureDomain: "us-east-1a",
v1.LabelZoneRegion: "us-east-1",
},
nil,
},

View File

@ -636,9 +636,7 @@ func (az *Cloud) SetInformers(informerFactory informers.SharedInformerFactory) {
prevNode := prev.(*v1.Node)
newNode := obj.(*v1.Node)
if newNode.Labels[v1.LabelZoneFailureDomain] ==
prevNode.Labels[v1.LabelZoneFailureDomain] &&
newNode.Labels[v1.LabelZoneFailureDomainStable] ==
prevNode.Labels[v1.LabelZoneFailureDomainStable] {
prevNode.Labels[v1.LabelZoneFailureDomain] {
return
}
az.updateNodeCaches(prevNode, newNode)
@ -673,10 +671,6 @@ func (az *Cloud) updateNodeCaches(prevNode, newNode *v1.Node) {
if prevNode != nil {
// Remove from nodeZones cache.
prevZone, ok := prevNode.ObjectMeta.Labels[v1.LabelZoneFailureDomain]
if !ok {
prevZone, ok = prevNode.ObjectMeta.Labels[v1.LabelZoneFailureDomainStable]
}
if ok && az.isAvailabilityZone(prevZone) {
az.nodeZones[prevZone].Delete(prevNode.ObjectMeta.Name)
if az.nodeZones[prevZone].Len() == 0 {
@ -700,10 +694,6 @@ func (az *Cloud) updateNodeCaches(prevNode, newNode *v1.Node) {
if newNode != nil {
// Add to nodeZones cache.
newZone, ok := newNode.ObjectMeta.Labels[v1.LabelZoneFailureDomain]
if !ok {
newZone, ok = newNode.ObjectMeta.Labels[v1.LabelZoneFailureDomainStable]
}
if ok && az.isAvailabilityZone(newZone) {
if az.nodeZones[newZone] == nil {
az.nodeZones[newZone] = sets.NewString()

View File

@ -333,10 +333,8 @@ func (c *Cloud) GetAzureDiskLabels(diskURI string) (map[string]string, error) {
zone := c.makeZone(c.Location, zoneID)
klog.V(4).Infof("Got zone %q for Azure disk %q", zone, diskName)
labels := map[string]string{
v1.LabelZoneRegion: c.Location,
v1.LabelZoneFailureDomain: zone,
v1.LabelZoneRegionStable: c.Location,
v1.LabelZoneFailureDomainStable: zone,
v1.LabelZoneRegion: c.Location,
v1.LabelZoneFailureDomain: zone,
}
return labels, nil
}

View File

@ -694,9 +694,7 @@ func (g *Cloud) SetInformers(informerFactory informers.SharedInformerFactory) {
prevNode := prev.(*v1.Node)
newNode := obj.(*v1.Node)
if newNode.Labels[v1.LabelZoneFailureDomain] ==
prevNode.Labels[v1.LabelZoneFailureDomain] &&
newNode.Labels[v1.LabelZoneFailureDomainStable] ==
prevNode.Labels[v1.LabelZoneFailureDomainStable] {
prevNode.Labels[v1.LabelZoneFailureDomain] {
return
}
g.updateNodeZones(prevNode, newNode)
@ -728,10 +726,6 @@ func (g *Cloud) updateNodeZones(prevNode, newNode *v1.Node) {
defer g.nodeZonesLock.Unlock()
if prevNode != nil {
prevZone, ok := prevNode.ObjectMeta.Labels[v1.LabelZoneFailureDomain]
if !ok {
prevZone, ok = prevNode.ObjectMeta.Labels[v1.LabelZoneFailureDomainStable]
}
if ok {
g.nodeZones[prevZone].Delete(prevNode.ObjectMeta.Name)
if g.nodeZones[prevZone].Len() == 0 {
@ -741,10 +735,6 @@ func (g *Cloud) updateNodeZones(prevNode, newNode *v1.Node) {
}
if newNode != nil {
newZone, ok := newNode.ObjectMeta.Labels[v1.LabelZoneFailureDomain]
if !ok {
newZone, ok = newNode.ObjectMeta.Labels[v1.LabelZoneFailureDomainStable]
}
if ok {
if g.nodeZones[newZone] == nil {
g.nodeZones[newZone] = sets.NewString()

View File

@ -499,10 +499,7 @@ func (g *Cloud) GetLabelsForVolume(ctx context.Context, pv *v1.PersistentVolume)
}
// If the zone is already labeled, honor the hint
zone, ok := pv.Labels[v1.LabelZoneFailureDomain]
if !ok {
zone = pv.Labels[v1.LabelZoneFailureDomainStable]
}
zone := pv.Labels[v1.LabelZoneFailureDomain]
labels, err := g.GetAutoLabelsForPD(pv.Spec.GCEPersistentDisk.PDName, zone)
if err != nil {
@ -859,8 +856,6 @@ func (g *Cloud) GetAutoLabelsForPD(name string, zone string) (map[string]string,
}
labels[v1.LabelZoneFailureDomain] = zoneInfo.zone
labels[v1.LabelZoneRegion] = disk.Region
labels[v1.LabelZoneFailureDomainStable] = zoneInfo.zone
labels[v1.LabelZoneRegionStable] = disk.Region
case multiZone:
if zoneInfo.replicaZones == nil || zoneInfo.replicaZones.Len() <= 0 {
// Unexpected, but sanity-check
@ -869,9 +864,6 @@ func (g *Cloud) GetAutoLabelsForPD(name string, zone string) (map[string]string,
labels[v1.LabelZoneFailureDomain] =
volumehelpers.ZonesSetToLabelValue(zoneInfo.replicaZones)
labels[v1.LabelZoneRegion] = disk.Region
labels[v1.LabelZoneFailureDomainStable] =
volumehelpers.ZonesSetToLabelValue(zoneInfo.replicaZones)
labels[v1.LabelZoneRegionStable] = disk.Region
case nil:
// Unexpected, but sanity-check
return nil, fmt.Errorf("PD did not have ZoneInfo: %v", disk)

View File

@ -465,23 +465,13 @@ func TestGetAutoLabelsForPD_Basic(t *testing.T) {
if err != nil {
t.Error(err)
}
if labels[v1.LabelZoneFailureDomain] != zone {
t.Errorf("Failure domain is '%v', but zone is '%v'",
labels[v1.LabelZoneFailureDomain], zone)
}
if labels[v1.LabelZoneRegion] != gceRegion {
t.Errorf("Region is '%v', but region is 'us-central1'", labels[v1.LabelZoneRegion])
}
if labels[v1.LabelZoneFailureDomainStable] != zone {
t.Errorf("Failure domain is '%v', but zone is '%v'",
labels[v1.LabelZoneFailureDomainStable], zone)
}
if labels[v1.LabelZoneRegionStable] != gceRegion {
t.Errorf("Region is '%v', but region is 'us-central1'", labels[v1.LabelZoneRegionStable])
}
}
func TestGetAutoLabelsForPD_NoZone(t *testing.T) {
@ -518,14 +508,6 @@ func TestGetAutoLabelsForPD_NoZone(t *testing.T) {
if labels[v1.LabelZoneRegion] != gceRegion {
t.Errorf("Region is '%v', but region is 'europe-west1'", labels[v1.LabelZoneRegion])
}
if labels[v1.LabelZoneFailureDomainStable] != zone {
t.Errorf("Failure domain is '%v', but zone is '%v'",
labels[v1.LabelZoneFailureDomainStable], zone)
}
if labels[v1.LabelZoneRegionStable] != gceRegion {
t.Errorf("Region is '%v', but region is 'europe-west1'", labels[v1.LabelZoneRegionStable])
}
}
func TestGetAutoLabelsForPD_DiskNotFound(t *testing.T) {
@ -612,14 +594,6 @@ func TestGetAutoLabelsForPD_DupDisk(t *testing.T) {
if labels[v1.LabelZoneRegion] != gceRegion {
t.Errorf("Region is '%v', but region is 'us-west1'", labels[v1.LabelZoneRegion])
}
if labels[v1.LabelZoneFailureDomainStable] != zone {
t.Errorf("Failure domain is '%v', but zone is '%v'",
labels[v1.LabelZoneFailureDomainStable], zone)
}
if labels[v1.LabelZoneRegionStable] != gceRegion {
t.Errorf("Region is '%v', but region is 'us-west1'", labels[v1.LabelZoneRegionStable])
}
}
func TestGetAutoLabelsForPD_DupDiskNoZone(t *testing.T) {

View File

@ -60,20 +60,12 @@ func splitNodesByZone(nodes []*v1.Node) map[string][]*v1.Node {
return zones
}
// getZone checks the deprecated beta zone label first and falls back to GA label if the beta label does not exist
// if both don't exist, returns the default zone which is ""
func getZone(n *v1.Node) string {
zone, ok := n.Labels[v1.LabelZoneFailureDomain]
if ok {
return zone
if !ok {
return defaultZone
}
zone, ok = n.Labels[v1.LabelZoneFailureDomainStable]
if ok {
return zone
}
return defaultZone
return zone
}
func makeHostURL(projectsAPIEndpoint, projectID, zone, host string) string {

View File

@ -736,8 +736,6 @@ func (os *OpenStack) GetLabelsForVolume(ctx context.Context, pv *v1.PersistentVo
labels := make(map[string]string)
labels[v1.LabelZoneFailureDomain] = volume.AvailabilityZone
labels[v1.LabelZoneRegion] = os.region
labels[v1.LabelZoneFailureDomainStable] = volume.AvailabilityZone
labels[v1.LabelZoneRegionStable] = os.region
klog.V(4).Infof("The Volume %s has labels %v", pv.Spec.Cinder.VolumeID, labels)
return labels, nil

View File

@ -203,8 +203,8 @@ func (nm *NodeManager) DiscoverNode(node *v1.Node) error {
node.Name, vm, res.vc, res.datacenter.Name())
// Get the node zone information
nodeFd := getNodeZoneFailureDomain(node)
nodeRegion := getNodeRegion(node)
nodeFd := node.ObjectMeta.Labels[v1.LabelZoneFailureDomain]
nodeRegion := node.ObjectMeta.Labels[v1.LabelZoneRegion]
nodeZone := &cloudprovider.Zone{FailureDomain: nodeFd, Region: nodeRegion}
nodeInfo := &NodeInfo{dataCenter: res.datacenter, vm: vm, vcServer: res.vc, vmUUID: nodeUUID, zone: nodeZone}
nm.addNodeInfo(node.ObjectMeta.Name, nodeInfo)
@ -230,34 +230,6 @@ func (nm *NodeManager) DiscoverNode(node *v1.Node) error {
return vclib.ErrNoVMFound
}
func getNodeZoneFailureDomain(node *v1.Node) string {
zone, ok := node.Labels[v1.LabelZoneFailureDomain]
if ok {
return zone
}
zone, ok = node.Labels[v1.LabelZoneFailureDomainStable]
if ok {
return zone
}
return ""
}
func getNodeRegion(node *v1.Node) string {
region, ok := node.Labels[v1.LabelZoneRegion]
if ok {
return region
}
region, ok = node.Labels[v1.LabelZoneRegionStable]
if ok {
return region
}
return ""
}
func (nm *NodeManager) RegisterNode(node *v1.Node) error {
nm.addNode(node)
return nm.DiscoverNode(node)

View File

@ -1649,8 +1649,6 @@ func (vs *VSphere) GetVolumeLabels(volumePath string) (map[string]string, error)
if len(dsZones) > 0 {
labels[v1.LabelZoneRegion] = dsZones[0].Region
labels[v1.LabelZoneFailureDomain] = dsZones[0].FailureDomain
labels[v1.LabelZoneRegionStable] = dsZones[0].Region
labels[v1.LabelZoneFailureDomainStable] = dsZones[0].FailureDomain
}
return labels, nil
}

View File

@ -34,11 +34,19 @@ func RecreateNodes(c clientset.Interface, nodes []v1.Node) error {
nodeNamesByZone := make(map[string][]string)
for i := range nodes {
node := &nodes[i]
zone := framework.TestContext.CloudConfig.Zone
if z, ok := node.Labels[v1.LabelZoneFailureDomain]; ok {
zone = z
if zone, ok := node.Labels[v1.LabelZoneFailureDomain]; ok {
nodeNamesByZone[zone] = append(nodeNamesByZone[zone], node.Name)
continue
}
nodeNamesByZone[zone] = append(nodeNamesByZone[zone], node.Name)
if zone, ok := node.Labels[v1.LabelZoneFailureDomainStable]; ok {
nodeNamesByZone[zone] = append(nodeNamesByZone[zone], node.Name)
continue
}
defaultZone := framework.TestContext.CloudConfig.Zone
nodeNamesByZone[defaultZone] = append(nodeNamesByZone[defaultZone], node.Name)
}
// Find the sole managed instance group name

View File

@ -2587,6 +2587,10 @@ func GetClusterZones(c clientset.Interface) (sets.String, error) {
if zone, found := node.Labels[v1.LabelZoneFailureDomain]; found {
zones.Insert(zone)
}
if zone, found := node.Labels[v1.LabelZoneFailureDomainStable]; found {
zones.Insert(zone)
}
}
return zones, nil
}

View File

@ -497,7 +497,7 @@ func verifyPVZoneLabels(client clientset.Interface, namespace string, scParamete
ginkgo.By("Verify zone information is present in the volume labels")
for _, pv := range persistentvolumes {
// Multiple zones are separated with "__"
pvZoneLabels := strings.Split(pv.ObjectMeta.Labels[v1.LabelZoneFailureDomain], "__")
pvZoneLabels := strings.Split(pv.ObjectMeta.Labels["failure-domain.beta.kubernetes.io/zone"], "__")
for _, zone := range zones {
gomega.Expect(pvZoneLabels).Should(gomega.ContainElement(zone), "Incorrect or missing zone labels in pv.")
}