Merge pull request #99130 from ayberk/ebs_ga_labels

Use GA topology labels for EBS
This commit is contained in:
Kubernetes Prow Robot 2021-02-23 23:48:49 -08:00 committed by GitHub
commit 267e47f548
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 262 additions and 144 deletions

View File

@ -396,7 +396,7 @@ func TestGetCandidateZone(t *testing.T) {
node: &v1.Node{ node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{ Labels: map[string]string{
v1.LabelFailureDomainBetaZone: testZone, v1.LabelTopologyZone: testZone,
}, },
}, },
}, },

View File

@ -176,7 +176,7 @@ func Test_PVLAdmission(t *testing.T) {
pvlabeler: mockVolumeLabels(map[string]string{ pvlabeler: mockVolumeLabels(map[string]string{
"a": "1", "a": "1",
"b": "2", "b": "2",
v1.LabelFailureDomainBetaZone: "1__2__3", v1.LabelTopologyZone: "1__2__3",
}), }),
preAdmissionPV: &api.PersistentVolume{ preAdmissionPV: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{Name: "awsebs", Namespace: "myns"}, ObjectMeta: metav1.ObjectMeta{Name: "awsebs", Namespace: "myns"},
@ -195,7 +195,7 @@ func Test_PVLAdmission(t *testing.T) {
Labels: map[string]string{ Labels: map[string]string{
"a": "1", "a": "1",
"b": "2", "b": "2",
v1.LabelFailureDomainBetaZone: "1__2__3", v1.LabelTopologyZone: "1__2__3",
}, },
}, },
Spec: api.PersistentVolumeSpec{ Spec: api.PersistentVolumeSpec{
@ -220,7 +220,7 @@ func Test_PVLAdmission(t *testing.T) {
Values: []string{"2"}, Values: []string{"2"},
}, },
{ {
Key: v1.LabelFailureDomainBetaZone, Key: v1.LabelTopologyZone,
Operator: api.NodeSelectorOpIn, Operator: api.NodeSelectorOpIn,
Values: []string{"1", "2", "3"}, Values: []string{"1", "2", "3"},
}, },
@ -373,15 +373,15 @@ func Test_PVLAdmission(t *testing.T) {
name: "existing labels from user are changed", name: "existing labels from user are changed",
handler: newPersistentVolumeLabel(), handler: newPersistentVolumeLabel(),
pvlabeler: mockVolumeLabels(map[string]string{ pvlabeler: mockVolumeLabels(map[string]string{
v1.LabelFailureDomainBetaZone: "domain1", v1.LabelTopologyZone: "domain1",
v1.LabelFailureDomainBetaRegion: "region1", v1.LabelTopologyRegion: "region1",
}), }),
preAdmissionPV: &api.PersistentVolume{ preAdmissionPV: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "awsebs", Namespace: "myns", Name: "awsebs", Namespace: "myns",
Labels: map[string]string{ Labels: map[string]string{
v1.LabelFailureDomainBetaZone: "existingDomain", v1.LabelTopologyZone: "existingDomain",
v1.LabelFailureDomainBetaRegion: "existingRegion", v1.LabelTopologyRegion: "existingRegion",
}, },
}, },
Spec: api.PersistentVolumeSpec{ Spec: api.PersistentVolumeSpec{
@ -397,8 +397,8 @@ func Test_PVLAdmission(t *testing.T) {
Name: "awsebs", Name: "awsebs",
Namespace: "myns", Namespace: "myns",
Labels: map[string]string{ Labels: map[string]string{
v1.LabelFailureDomainBetaZone: "domain1", v1.LabelTopologyZone: "domain1",
v1.LabelFailureDomainBetaRegion: "region1", v1.LabelTopologyRegion: "region1",
}, },
}, },
Spec: api.PersistentVolumeSpec{ Spec: api.PersistentVolumeSpec{
@ -413,12 +413,12 @@ func Test_PVLAdmission(t *testing.T) {
{ {
MatchExpressions: []api.NodeSelectorRequirement{ MatchExpressions: []api.NodeSelectorRequirement{
{ {
Key: v1.LabelFailureDomainBetaRegion, Key: v1.LabelTopologyRegion,
Operator: api.NodeSelectorOpIn, Operator: api.NodeSelectorOpIn,
Values: []string{"region1"}, Values: []string{"region1"},
}, },
{ {
Key: v1.LabelFailureDomainBetaZone, Key: v1.LabelTopologyZone,
Operator: api.NodeSelectorOpIn, Operator: api.NodeSelectorOpIn,
Values: []string{"domain1"}, Values: []string{"domain1"},
}, },
@ -632,7 +632,7 @@ func Test_PVLAdmission(t *testing.T) {
pvlabeler: mockVolumeLabels(map[string]string{ pvlabeler: mockVolumeLabels(map[string]string{
"a": "1", "a": "1",
"b": "2", "b": "2",
v1.LabelFailureDomainBetaZone: "1__2__3", v1.LabelTopologyZone: "1__2__3",
}), }),
preAdmissionPV: &api.PersistentVolume{ preAdmissionPV: &api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
@ -657,7 +657,7 @@ func Test_PVLAdmission(t *testing.T) {
Labels: map[string]string{ Labels: map[string]string{
"a": "1", "a": "1",
"b": "2", "b": "2",
v1.LabelFailureDomainBetaZone: "1__2__3", v1.LabelTopologyZone: "1__2__3",
}, },
}, },
Spec: api.PersistentVolumeSpec{ Spec: api.PersistentVolumeSpec{
@ -682,7 +682,7 @@ func Test_PVLAdmission(t *testing.T) {
Values: []string{"2"}, Values: []string{"2"},
}, },
{ {
Key: v1.LabelFailureDomainBetaZone, Key: v1.LabelTopologyZone,
Operator: api.NodeSelectorOpIn, Operator: api.NodeSelectorOpIn,
Values: []string{"1", "2", "3"}, Values: []string{"1", "2", "3"},
}, },

View File

@ -26,6 +26,7 @@ import (
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
storage "k8s.io/api/storage/v1" storage "k8s.io/api/storage/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
) )
const ( const (
@ -174,6 +175,11 @@ func (t *awsElasticBlockStoreCSITranslator) TranslateCSIPVToInTree(pv *v1.Persis
ebsSource.Partition = int32(partValue) ebsSource.Partition = int32(partValue)
} }
// translate CSI topology to In-tree topology for rollback compatibility
if err := translateTopologyFromCSIToInTree(pv, AWSEBSTopologyKey, getAwsRegionFromZones); err != nil {
return nil, fmt.Errorf("failed to translate topology. PV:%+v. Error:%v", *pv, err)
}
pv.Spec.CSI = nil pv.Spec.CSI = nil
pv.Spec.AWSElasticBlockStore = ebsSource pv.Spec.AWSElasticBlockStore = ebsSource
return pv, nil return pv, nil
@ -253,3 +259,30 @@ func KubernetesVolumeIDToEBSVolumeID(kubernetesID string) (string, error) {
return awsID, nil return awsID, nil
} }
func getAwsRegionFromZones(zones []string) (string, error) {
regions := sets.String{}
if len(zones) < 1 {
return "", fmt.Errorf("no zones specified")
}
// AWS zones can be in four forms:
// us-west-2a, us-gov-east-1a, us-west-2-lax-1a (local zone) and us-east-1-wl1-bos-wlz-1 (wavelength).
for _, zone := range zones {
splitZone := strings.Split(zone, "-")
if (len(splitZone) == 3 || len(splitZone) == 4) && len(splitZone[len(splitZone)-1]) == 2 {
// this would break if we ever have a location with more than 9 regions, ie us-west-10.
splitZone[len(splitZone)-1] = splitZone[len(splitZone)-1][:1]
regions.Insert(strings.Join(splitZone, "-"))
} else if len(splitZone) == 5 || len(splitZone) == 7 {
// local zone or wavelength
regions.Insert(strings.Join(splitZone[:3], "-"))
} else {
return "", fmt.Errorf("Unexpected zone format: %v is not a valid AWS zone", zone)
}
}
if regions.Len() != 1 {
return "", fmt.Errorf("multiple or no regions gotten from zones, got: %v", regions)
}
return regions.UnsortedList()[0], nil
}

View File

@ -17,10 +17,11 @@ limitations under the License.
package plugins package plugins
import ( import (
v1 "k8s.io/api/core/v1"
"reflect" "reflect"
"testing" "testing"
v1 "k8s.io/api/core/v1"
storage "k8s.io/api/storage/v1" storage "k8s.io/api/storage/v1"
) )
@ -198,3 +199,77 @@ func TestTranslateInTreeInlineVolumeToCSI(t *testing.T) {
}) })
} }
} }
func TestGetAwsRegionFromZones(t *testing.T) {
cases := []struct {
name string
zones []string
expRegion string
expErr bool
}{
{
name: "Commercial zone",
zones: []string{"us-west-2a", "us-west-2b"},
expRegion: "us-west-2",
},
{
name: "Govcloud zone",
zones: []string{"us-gov-east-1a"},
expRegion: "us-gov-east-1",
},
{
name: "Wavelength zone",
zones: []string{"us-east-1-wl1-bos-wlz-1"},
expRegion: "us-east-1",
},
{
name: "Local zone",
zones: []string{"us-west-2-lax-1a"},
expRegion: "us-west-2",
},
{
name: "Invalid: empty zones",
zones: []string{},
expErr: true,
},
{
name: "Invalid: multiple regions",
zones: []string{"us-west-2a", "us-east-1a"},
expErr: true,
},
{
name: "Invalid: region name only",
zones: []string{"us-west-2"},
expErr: true,
},
{
name: "Invalid: invalid suffix",
zones: []string{"us-west-2ab"},
expErr: true,
},
{
name: "Invalid: not enough fields",
zones: []string{"us-west"},
expErr: true,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
t.Logf("Testing %v", tc.name)
got, err := getAwsRegionFromZones(tc.zones)
if err != nil && !tc.expErr {
t.Fatalf("Did not expect error but got: %v", err)
}
if err == nil && tc.expErr {
t.Fatalf("Expected error, but did not get one.")
}
if err == nil && !reflect.DeepEqual(got, tc.expRegion) {
t.Errorf("Got PV name: %v, expected :%v", got, tc.expRegion)
}
})
}
}

View File

@ -227,7 +227,7 @@ func (g *gcePersistentDiskCSITranslator) TranslateInTreePVToCSI(pv *v1.Persisten
volID = fmt.Sprintf(volIDZonalFmt, UnspecifiedValue, zones[0], pv.Spec.GCEPersistentDisk.PDName) volID = fmt.Sprintf(volIDZonalFmt, UnspecifiedValue, zones[0], pv.Spec.GCEPersistentDisk.PDName)
} else if len(zones) > 1 { } else if len(zones) > 1 {
// Regional // Regional
region, err := getRegionFromZones(zones) region, err := gceGetRegionFromZones(zones)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get region from zones: %v", err) return nil, fmt.Errorf("failed to get region from zones: %v", err)
} }
@ -292,7 +292,7 @@ func (g *gcePersistentDiskCSITranslator) TranslateCSIPVToInTree(pv *v1.Persisten
} }
// translate CSI topology to In-tree topology for rollback compatibility // translate CSI topology to In-tree topology for rollback compatibility
if err := translateTopologyFromCSIToInTree(pv, GCEPDTopologyKey, gceRegionTopologyHandler); err != nil { if err := translateTopologyFromCSIToInTree(pv, GCEPDTopologyKey, gceGetRegionFromZones); err != nil {
return nil, fmt.Errorf("failed to translate topology. PV:%+v. Error:%v", *pv, err) return nil, fmt.Errorf("failed to translate topology. PV:%+v. Error:%v", *pv, err)
} }
@ -356,7 +356,7 @@ func (g *gcePersistentDiskCSITranslator) RepairVolumeHandle(volumeHandle, nodeID
case "regions": case "regions":
region := "" region := ""
if tok[volIDZoneValue] == UnspecifiedValue { if tok[volIDZoneValue] == UnspecifiedValue {
region, err = getRegionFromZones([]string{nodeTok[volIDZoneValue]}) region, err = gceGetRegionFromZones([]string{nodeTok[volIDZoneValue]})
if err != nil { if err != nil {
return "", fmt.Errorf("failed to get region from zone %s: %v", nodeTok[volIDZoneValue], err) return "", fmt.Errorf("failed to get region from zone %s: %v", nodeTok[volIDZoneValue], err)
} }
@ -377,70 +377,9 @@ func pdNameFromVolumeID(id string) (string, error) {
return splitID[volIDDiskNameValue], nil return splitID[volIDDiskNameValue], nil
} }
// gceRegionTopologyHandler will process the PV and add region
// kubernetes topology label to its NodeAffinity and labels
// It assumes the Zone NodeAffinity already exists
func gceRegionTopologyHandler(pv *v1.PersistentVolume) error {
// Make sure the necessary fields exist
if pv == nil || pv.Spec.NodeAffinity == nil || pv.Spec.NodeAffinity.Required == nil ||
pv.Spec.NodeAffinity.Required.NodeSelectorTerms == nil || len(pv.Spec.NodeAffinity.Required.NodeSelectorTerms) == 0 {
return nil
}
zoneLabel, regionLabel := getTopologyLabel(pv)
// process each term
for index, nodeSelectorTerm := range pv.Spec.NodeAffinity.Required.NodeSelectorTerms {
// In the first loop, see if regionLabel already exist
regionExist := false
var zoneVals []string
for _, nsRequirement := range nodeSelectorTerm.MatchExpressions {
if nsRequirement.Key == regionLabel {
regionExist = true
break
} else if nsRequirement.Key == zoneLabel {
zoneVals = append(zoneVals, nsRequirement.Values...)
}
}
if regionExist {
// Regionlabel already exist in this term, skip it
continue
}
// If no regionLabel found, generate region label from the zoneLabel we collect from this term
regionVal, err := getRegionFromZones(zoneVals)
if err != nil {
return err
}
// Add the regionVal to this term
pv.Spec.NodeAffinity.Required.NodeSelectorTerms[index].MatchExpressions =
append(pv.Spec.NodeAffinity.Required.NodeSelectorTerms[index].MatchExpressions, v1.NodeSelectorRequirement{
Key: regionLabel,
Operator: v1.NodeSelectorOpIn,
Values: []string{regionVal},
})
}
// Add region label
regionVals := getTopologyValues(pv, regionLabel)
if len(regionVals) == 1 {
// We should only have exactly 1 region value
if pv.Labels == nil {
pv.Labels = make(map[string]string)
}
_, regionOK := pv.Labels[regionLabel]
if !regionOK {
pv.Labels[regionLabel] = regionVals[0]
}
}
return nil
}
// TODO: Replace this with the imported one from GCE PD CSI Driver when // TODO: Replace this with the imported one from GCE PD CSI Driver when
// the driver removes all k8s/k8s dependencies // the driver removes all k8s/k8s dependencies
func getRegionFromZones(zones []string) (string, error) { func gceGetRegionFromZones(zones []string) (string, error) {
regions := sets.String{} regions := sets.String{}
if len(zones) < 1 { if len(zones) < 1 {
return "", fmt.Errorf("no zones specified") return "", fmt.Errorf("no zones specified")

View File

@ -255,22 +255,22 @@ func TopologyKeyExist(key string, vna *v1.VolumeNodeAffinity) bool {
return false return false
} }
type regionTopologyHandler func(pv *v1.PersistentVolume) error type regionParserFn func([]string) (string, error)
// translateTopologyFromCSIToInTree translate a CSI topology to // translateTopologyFromCSIToInTree translate a CSI topology to
// Kubernetes topology and add topology labels to it. Note that this function // Kubernetes topology and add topology labels to it. Note that this function
// will only work for plugin with a single topologyKey that translates to // will only work for plugin with a single topologyKey that translates to
// Kubernetes zone(and region if regionTopologyHandler is passed in). // Kubernetes zone(and region if regionParser is passed in).
// If a plugin has more than one topologyKey, it will need to be processed // If a plugin has more than one topologyKey, it will need to be processed
// separately by the plugin. // separately by the plugin.
// regionTopologyHandler is a function to add region topology NodeAffinity // If regionParser is nil, no region NodeAffinity will be added. If not nil,
// and labels for the given PV. It assumes the Zone NodeAffinity already exists // it'll be passed to regionTopologyHandler, which will add region topology NodeAffinity
// If regionTopologyHandler is nil, no region NodeAffinity will be added // and labels for the given PV. It assumes the Zone NodeAffinity already exists.
// // In short this function will,
// 1. Replace all CSI topology to Kubernetes Zone topology label // 1. Replace all CSI topology to Kubernetes Zone topology label
// 2. Process and generate region topology if a regionTopologyHandler is passed // 2. Process and generate region topology if a regionParser is passed
// 3. Add Kubernetes Topology labels(zone) if they do not exist // 3. Add Kubernetes Topology labels(zone) if they do not exist
func translateTopologyFromCSIToInTree(pv *v1.PersistentVolume, csiTopologyKey string, regionTopologyHandler regionTopologyHandler) error { func translateTopologyFromCSIToInTree(pv *v1.PersistentVolume, csiTopologyKey string, regionParser regionParserFn) error {
zoneLabel, _ := getTopologyLabel(pv) zoneLabel, _ := getTopologyLabel(pv)
@ -280,10 +280,10 @@ func translateTopologyFromCSIToInTree(pv *v1.PersistentVolume, csiTopologyKey st
return fmt.Errorf("Failed to replace CSI topology to Kubernetes topology, error: %v", err) return fmt.Errorf("Failed to replace CSI topology to Kubernetes topology, error: %v", err)
} }
// 2. Take care of region topology if a regionTopologyHandler is passed // 2. Take care of region topology if a regionParser is passed
if regionTopologyHandler != nil { if regionParser != nil {
// let's make less strict on this one. Even if there is an error in the region processing, just ignore it // let's make less strict on this one. Even if there is an error in the region processing, just ignore it
err = regionTopologyHandler(pv) err = regionTopologyHandler(pv, regionParser)
if err != nil { if err != nil {
return fmt.Errorf("Failed to handle region topology. error: %v", err) return fmt.Errorf("Failed to handle region topology. error: %v", err)
} }
@ -333,3 +333,65 @@ func translateAllowedTopologies(terms []v1.TopologySelectorTerm, key string) ([]
} }
return newTopologies, nil return newTopologies, nil
} }
// regionTopologyHandler will process the PV and add region
// kubernetes topology label to its NodeAffinity and labels
// It assumes the Zone NodeAffinity already exists
// Each provider is responsible for providing their own regionParser
func regionTopologyHandler(pv *v1.PersistentVolume, regionParser regionParserFn) error {
// Make sure the necessary fields exist
if pv == nil || pv.Spec.NodeAffinity == nil || pv.Spec.NodeAffinity.Required == nil ||
pv.Spec.NodeAffinity.Required.NodeSelectorTerms == nil || len(pv.Spec.NodeAffinity.Required.NodeSelectorTerms) == 0 {
return nil
}
zoneLabel, regionLabel := getTopologyLabel(pv)
// process each term
for index, nodeSelectorTerm := range pv.Spec.NodeAffinity.Required.NodeSelectorTerms {
// In the first loop, see if regionLabel already exist
regionExist := false
var zoneVals []string
for _, nsRequirement := range nodeSelectorTerm.MatchExpressions {
if nsRequirement.Key == regionLabel {
regionExist = true
break
} else if nsRequirement.Key == zoneLabel {
zoneVals = append(zoneVals, nsRequirement.Values...)
}
}
if regionExist {
// Regionlabel already exist in this term, skip it
continue
}
// If no regionLabel found, generate region label from the zoneLabel we collect from this term
regionVal, err := regionParser(zoneVals)
if err != nil {
return err
}
// Add the regionVal to this term
pv.Spec.NodeAffinity.Required.NodeSelectorTerms[index].MatchExpressions =
append(pv.Spec.NodeAffinity.Required.NodeSelectorTerms[index].MatchExpressions, v1.NodeSelectorRequirement{
Key: regionLabel,
Operator: v1.NodeSelectorOpIn,
Values: []string{regionVal},
})
}
// Add region label
regionVals := getTopologyValues(pv, regionLabel)
if len(regionVals) == 1 {
// We should only have exactly 1 region value
if pv.Labels == nil {
pv.Labels = make(map[string]string)
}
_, regionOK := pv.Labels[regionLabel]
if !regionOK {
pv.Labels[regionLabel] = regionVals[0]
}
}
return nil
}

View File

@ -108,7 +108,7 @@ func TestTranslateTopologyFromCSIToInTree(t *testing.T) {
name string name string
key string key string
expErr bool expErr bool
regionTopologyHandler regionTopologyHandler regionParser regionParserFn
pv *v1.PersistentVolume pv *v1.PersistentVolume
expectedNodeSelectorTerms []v1.NodeSelectorTerm expectedNodeSelectorTerms []v1.NodeSelectorTerm
expectedLabels map[string]string expectedLabels map[string]string
@ -117,7 +117,7 @@ func TestTranslateTopologyFromCSIToInTree(t *testing.T) {
name: "Remove CSI Topology Key and do not change existing GA Kubernetes topology", name: "Remove CSI Topology Key and do not change existing GA Kubernetes topology",
key: GCEPDTopologyKey, key: GCEPDTopologyKey,
expErr: false, expErr: false,
regionTopologyHandler: gceRegionTopologyHandler, regionParser: gceGetRegionFromZones,
pv: &v1.PersistentVolume{ pv: &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "gcepd", Namespace: "myns", Name: "gcepd", Namespace: "myns",
@ -153,7 +153,7 @@ func TestTranslateTopologyFromCSIToInTree(t *testing.T) {
name: "Remove CSI Topology Key and do not change existing Beta Kubernetes topology", name: "Remove CSI Topology Key and do not change existing Beta Kubernetes topology",
key: GCEPDTopologyKey, key: GCEPDTopologyKey,
expErr: false, expErr: false,
regionTopologyHandler: gceRegionTopologyHandler, regionParser: gceGetRegionFromZones,
pv: &v1.PersistentVolume{ pv: &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "gcepd", Namespace: "myns", Name: "gcepd", Namespace: "myns",
@ -189,7 +189,7 @@ func TestTranslateTopologyFromCSIToInTree(t *testing.T) {
name: "Remove CSI Topology Key and add Kubernetes topology from NodeAffinity, ignore labels", name: "Remove CSI Topology Key and add Kubernetes topology from NodeAffinity, ignore labels",
key: GCEPDTopologyKey, key: GCEPDTopologyKey,
expErr: false, expErr: false,
regionTopologyHandler: gceRegionTopologyHandler, regionParser: gceGetRegionFromZones,
pv: &v1.PersistentVolume{ pv: &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "gcepd", Namespace: "myns", Name: "gcepd", Namespace: "myns",
@ -226,7 +226,7 @@ func TestTranslateTopologyFromCSIToInTree(t *testing.T) {
name: "No CSI topology label exists and no change to the NodeAffinity", name: "No CSI topology label exists and no change to the NodeAffinity",
key: GCEPDTopologyKey, key: GCEPDTopologyKey,
expErr: false, expErr: false,
regionTopologyHandler: gceRegionTopologyHandler, regionParser: gceGetRegionFromZones,
pv: &v1.PersistentVolume{ pv: &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "gcepd", Namespace: "myns", Name: "gcepd", Namespace: "myns",
@ -253,7 +253,7 @@ func TestTranslateTopologyFromCSIToInTree(t *testing.T) {
name: "Generate GA labels and kubernetes topology only from CSI topology", name: "Generate GA labels and kubernetes topology only from CSI topology",
key: GCEPDTopologyKey, key: GCEPDTopologyKey,
expErr: false, expErr: false,
regionTopologyHandler: gceRegionTopologyHandler, regionParser: gceGetRegionFromZones,
pv: &v1.PersistentVolume{ pv: &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "gcepd", Namespace: "myns", Name: "gcepd", Namespace: "myns",
@ -283,7 +283,7 @@ func TestTranslateTopologyFromCSIToInTree(t *testing.T) {
name: "Generate Beta labels and kubernetes topology from Beta NodeAffinity", name: "Generate Beta labels and kubernetes topology from Beta NodeAffinity",
key: GCEPDTopologyKey, key: GCEPDTopologyKey,
expErr: false, expErr: false,
regionTopologyHandler: gceRegionTopologyHandler, regionParser: gceGetRegionFromZones,
pv: &v1.PersistentVolume{ pv: &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "gcepd", Namespace: "myns", Name: "gcepd", Namespace: "myns",
@ -313,7 +313,6 @@ func TestTranslateTopologyFromCSIToInTree(t *testing.T) {
name: "regionParser is missing and only zone labels get generated", name: "regionParser is missing and only zone labels get generated",
key: GCEPDTopologyKey, key: GCEPDTopologyKey,
expErr: false, expErr: false,
regionTopologyHandler: nil,
pv: &v1.PersistentVolume{ pv: &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "gcepd", Namespace: "myns", Name: "gcepd", Namespace: "myns",
@ -355,7 +354,7 @@ func TestTranslateTopologyFromCSIToInTree(t *testing.T) {
name: "Replace multi-term CSI Topology Key and add Region Kubernetes topology for both", name: "Replace multi-term CSI Topology Key and add Region Kubernetes topology for both",
key: GCEPDTopologyKey, key: GCEPDTopologyKey,
expErr: false, expErr: false,
regionTopologyHandler: gceRegionTopologyHandler, regionParser: gceGetRegionFromZones,
pv: &v1.PersistentVolume{ pv: &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "gcepd", Namespace: "myns", Name: "gcepd", Namespace: "myns",
@ -426,7 +425,7 @@ func TestTranslateTopologyFromCSIToInTree(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
t.Logf("Running test: %v", tc.name) t.Logf("Running test: %v", tc.name)
err := translateTopologyFromCSIToInTree(tc.pv, tc.key, tc.regionTopologyHandler) err := translateTopologyFromCSIToInTree(tc.pv, tc.key, tc.regionParser)
if err != nil && !tc.expErr { if err != nil && !tc.expErr {
t.Errorf("Did not expect an error, got: %v", err) t.Errorf("Did not expect an error, got: %v", err)
} }

View File

@ -170,15 +170,25 @@ func TestTopologyTranslation(t *testing.T) {
}, },
// EBS test cases: test mostly topology key, i.e., don't repeat testing done with GCE // EBS test cases: test mostly topology key, i.e., don't repeat testing done with GCE
{ {
name: "AWS EBS with zone labels", name: "AWS EBS with beta zone labels",
pv: makeAWSEBSPV(kubernetesBetaTopologyLabels, nil /*topology*/), pv: makeAWSEBSPV(kubernetesBetaTopologyLabels, nil /*topology*/),
expectedNodeAffinity: makeNodeAffinity(false /*multiTerms*/, plugins.AWSEBSTopologyKey, "us-east-1a"), expectedNodeAffinity: makeNodeAffinity(false /*multiTerms*/, plugins.AWSEBSTopologyKey, "us-east-1a"),
}, },
{ {
name: "AWS EBS with zone labels and topology", name: "AWS EBS with beta zone labels and topology",
pv: makeAWSEBSPV(kubernetesBetaTopologyLabels, makeTopology(v1.LabelFailureDomainBetaZone, "us-east-2a")), pv: makeAWSEBSPV(kubernetesBetaTopologyLabels, makeTopology(v1.LabelFailureDomainBetaZone, "us-east-2a")),
expectedNodeAffinity: makeNodeAffinity(false /*multiTerms*/, plugins.AWSEBSTopologyKey, "us-east-2a"), expectedNodeAffinity: makeNodeAffinity(false /*multiTerms*/, plugins.AWSEBSTopologyKey, "us-east-2a"),
}, },
{
name: "AWS EBS with GA zone labels",
pv: makeAWSEBSPV(kubernetesGATopologyLabels, nil /*topology*/),
expectedNodeAffinity: makeNodeAffinity(false /*multiTerms*/, plugins.AWSEBSTopologyKey, "us-east-1a"),
},
{
name: "AWS EBS with GA zone labels and topology",
pv: makeAWSEBSPV(kubernetesGATopologyLabels, makeTopology(v1.LabelTopologyZone, "us-east-2a")),
expectedNodeAffinity: makeNodeAffinity(false /*multiTerms*/, plugins.AWSEBSTopologyKey, "us-east-2a"),
},
// Cinder test cases: test mosty topology key, i.e., don't repeat testing done with GCE // Cinder test cases: test mosty topology key, i.e., don't repeat testing done with GCE
{ {
name: "OpenStack Cinder with zone labels", name: "OpenStack Cinder with zone labels",

View File

@ -2749,12 +2749,12 @@ func (c *Cloud) GetVolumeLabels(volumeName KubernetesVolumeID) (map[string]strin
return nil, fmt.Errorf("volume did not have AZ information: %q", aws.StringValue(info.VolumeId)) return nil, fmt.Errorf("volume did not have AZ information: %q", aws.StringValue(info.VolumeId))
} }
labels[v1.LabelFailureDomainBetaZone] = az labels[v1.LabelTopologyZone] = az
region, err := azToRegion(az) region, err := azToRegion(az)
if err != nil { if err != nil {
return nil, err return nil, err
} }
labels[v1.LabelFailureDomainBetaRegion] = region labels[v1.LabelTopologyRegion] = region
return labels, nil return labels, nil
} }

View File

@ -1576,8 +1576,8 @@ func TestGetVolumeLabels(t *testing.T) {
assert.Nil(t, err, "Error creating Volume %v", err) assert.Nil(t, err, "Error creating Volume %v", err)
assert.Equal(t, map[string]string{ assert.Equal(t, map[string]string{
v1.LabelFailureDomainBetaZone: "us-east-1a", v1.LabelTopologyZone: "us-east-1a",
v1.LabelFailureDomainBetaRegion: "us-east-1"}, labels) v1.LabelTopologyRegion: "us-east-1"}, labels)
awsServices.ec2.(*MockedFakeEC2).AssertExpectations(t) awsServices.ec2.(*MockedFakeEC2).AssertExpectations(t)
} }
@ -1650,8 +1650,8 @@ func TestGetLabelsForVolume(t *testing.T) {
AvailabilityZone: aws.String("us-east-1a"), AvailabilityZone: aws.String("us-east-1a"),
}}, }},
map[string]string{ map[string]string{
v1.LabelFailureDomainBetaZone: "us-east-1a", v1.LabelTopologyZone: "us-east-1a",
v1.LabelFailureDomainBetaRegion: "us-east-1", v1.LabelTopologyRegion: "us-east-1",
}, },
nil, nil,
}, },

View File

@ -1683,7 +1683,7 @@ func InitAwsDriver() storageframework.TestDriver {
"ntfs", "ntfs",
), ),
SupportedMountOption: sets.NewString("debug", "nouid32"), SupportedMountOption: sets.NewString("debug", "nouid32"),
TopologyKeys: []string{v1.LabelFailureDomainBetaZone}, TopologyKeys: []string{v1.LabelTopologyZone},
Capabilities: map[storageframework.Capability]bool{ Capabilities: map[storageframework.Capability]bool{
storageframework.CapPersistence: true, storageframework.CapPersistence: true,
storageframework.CapFsGroup: true, storageframework.CapFsGroup: true,
@ -1775,7 +1775,7 @@ func (a *awsDriver) CreateVolume(config *storageframework.PerTestConfig, volType
// so pods should be also scheduled there. // so pods should be also scheduled there.
config.ClientNodeSelection = e2epod.NodeSelection{ config.ClientNodeSelection = e2epod.NodeSelection{
Selector: map[string]string{ Selector: map[string]string{
v1.LabelFailureDomainBetaZone: zone, v1.LabelTopologyZone: zone,
}, },
} }
} }