Skip to content

Commit d362b42

Browse files
authored
Merge pull request kubernetes#85251 from leakingtapan/ebs-migraiton-zone
Add CSI migration logic for EBS storageclass zone/zones/topology
2 parents e052900 + 3a7e0c2 commit d362b42

File tree

6 files changed

+202
-145
lines changed

6 files changed

+202
-145
lines changed

staging/src/k8s.io/csi-translation-lib/plugins/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ go_test(
4343
"azure_disk_test.go",
4444
"azure_file_test.go",
4545
"gce_pd_test.go",
46+
"in_tree_volume_test.go",
4647
],
4748
embed = [":go_default_library"],
4849
deps = [

staging/src/k8s.io/csi-translation-lib/plugins/aws_ebs.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ import (
3131
const (
3232
// AWSEBSDriverName is the name of the CSI driver for EBS
3333
AWSEBSDriverName = "ebs.csi.aws.com"
34-
// AWSEBSTopologyKey is the zonal topology key for AWS EBS CSI Driver
35-
AWSEBSTopologyKey = "topology.ebs.csi.aws.com/zone"
3634
// AWSEBSInTreePluginName is the name of the intree plugin for EBS
3735
AWSEBSInTreePluginName = "kubernetes.io/aws-ebs"
36+
// AWSEBSTopologyKey is the zonal topology key for AWS EBS CSI driver
37+
AWSEBSTopologyKey = "topology." + AWSEBSDriverName + "/zone"
3838
)
3939

4040
var _ InTreePlugin = &awsElasticBlockStoreCSITranslator{}
@@ -49,17 +49,35 @@ func NewAWSElasticBlockStoreCSITranslator() InTreePlugin {
4949

5050
// TranslateInTreeStorageClassToCSI translates InTree EBS storage class parameters to CSI storage class
5151
func (t *awsElasticBlockStoreCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) {
52-
params := map[string]string{}
53-
52+
var (
53+
generatedTopologies []v1.TopologySelectorTerm
54+
params = map[string]string{}
55+
)
5456
for k, v := range sc.Parameters {
5557
switch strings.ToLower(k) {
56-
case "fstype":
57-
params["csi.storage.k8s.io/fstype"] = v
58+
case fsTypeKey:
59+
params[csiFsTypeKey] = v
60+
case zoneKey:
61+
generatedTopologies = generateToplogySelectors(AWSEBSTopologyKey, []string{v})
62+
case zonesKey:
63+
generatedTopologies = generateToplogySelectors(AWSEBSTopologyKey, strings.Split(v, ","))
5864
default:
5965
params[k] = v
6066
}
6167
}
6268

69+
if len(generatedTopologies) > 0 && len(sc.AllowedTopologies) > 0 {
70+
return nil, fmt.Errorf("cannot simultaneously set allowed topologies and zone/zones parameters")
71+
} else if len(generatedTopologies) > 0 {
72+
sc.AllowedTopologies = generatedTopologies
73+
} else if len(sc.AllowedTopologies) > 0 {
74+
newTopologies, err := translateAllowedTopologies(sc.AllowedTopologies, AWSEBSTopologyKey)
75+
if err != nil {
76+
return nil, fmt.Errorf("failed translating allowed topologies: %v", err)
77+
}
78+
sc.AllowedTopologies = newTopologies
79+
}
80+
6381
sc.Parameters = params
6482

6583
return sc, nil

staging/src/k8s.io/csi-translation-lib/plugins/gce_pd.go

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -65,33 +65,6 @@ func NewGCEPersistentDiskCSITranslator() InTreePlugin {
6565
return &gcePersistentDiskCSITranslator{}
6666
}
6767

68-
func translateAllowedTopologies(terms []v1.TopologySelectorTerm) ([]v1.TopologySelectorTerm, error) {
69-
if terms == nil {
70-
return nil, nil
71-
}
72-
73-
newTopologies := []v1.TopologySelectorTerm{}
74-
for _, term := range terms {
75-
newTerm := v1.TopologySelectorTerm{}
76-
for _, exp := range term.MatchLabelExpressions {
77-
var newExp v1.TopologySelectorLabelRequirement
78-
if exp.Key == v1.LabelZoneFailureDomain {
79-
newExp = v1.TopologySelectorLabelRequirement{
80-
Key: GCEPDTopologyKey,
81-
Values: exp.Values,
82-
}
83-
} else if exp.Key == GCEPDTopologyKey {
84-
newExp = exp
85-
} else {
86-
return nil, fmt.Errorf("unknown topology key: %v", exp.Key)
87-
}
88-
newTerm.MatchLabelExpressions = append(newTerm.MatchLabelExpressions, newExp)
89-
}
90-
newTopologies = append(newTopologies, newTerm)
91-
}
92-
return newTopologies, nil
93-
}
94-
9568
func generateToplogySelectors(key string, values []string) []v1.TopologySelectorTerm {
9669
return []v1.TopologySelectorTerm{
9770
{
@@ -112,13 +85,13 @@ func (g *gcePersistentDiskCSITranslator) TranslateInTreeStorageClassToCSI(sc *st
11285
np := map[string]string{}
11386
for k, v := range sc.Parameters {
11487
switch strings.ToLower(k) {
115-
case "fstype":
88+
case fsTypeKey:
11689
// prefixed fstype parameter is stripped out by external provisioner
117-
np["csi.storage.k8s.io/fstype"] = v
90+
np[csiFsTypeKey] = v
11891
// Strip out zone and zones parameters and translate them into topologies instead
119-
case "zone":
92+
case zoneKey:
12093
generatedTopologies = generateToplogySelectors(GCEPDTopologyKey, []string{v})
121-
case "zones":
94+
case zonesKey:
12295
generatedTopologies = generateToplogySelectors(GCEPDTopologyKey, strings.Split(v, ","))
12396
default:
12497
np[k] = v
@@ -130,7 +103,7 @@ func (g *gcePersistentDiskCSITranslator) TranslateInTreeStorageClassToCSI(sc *st
130103
} else if len(generatedTopologies) > 0 {
131104
sc.AllowedTopologies = generatedTopologies
132105
} else if len(sc.AllowedTopologies) > 0 {
133-
newTopologies, err := translateAllowedTopologies(sc.AllowedTopologies)
106+
newTopologies, err := translateAllowedTopologies(sc.AllowedTopologies, GCEPDTopologyKey)
134107
if err != nil {
135108
return nil, fmt.Errorf("failed translating allowed topologies: %v", err)
136109
}

staging/src/k8s.io/csi-translation-lib/plugins/gce_pd_test.go

Lines changed: 0 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -98,113 +98,6 @@ func TestTranslatePDInTreeStorageClassToCSI(t *testing.T) {
9898
}
9999
}
100100

101-
func TestTranslateAllowedTopologies(t *testing.T) {
102-
testCases := []struct {
103-
name string
104-
topology []v1.TopologySelectorTerm
105-
expectedToplogy []v1.TopologySelectorTerm
106-
expErr bool
107-
}{
108-
{
109-
name: "no translation",
110-
topology: generateToplogySelectors(GCEPDTopologyKey, []string{"foo", "bar"}),
111-
expectedToplogy: []v1.TopologySelectorTerm{
112-
{
113-
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
114-
{
115-
Key: GCEPDTopologyKey,
116-
Values: []string{"foo", "bar"},
117-
},
118-
},
119-
},
120-
},
121-
},
122-
{
123-
name: "translate",
124-
topology: []v1.TopologySelectorTerm{
125-
{
126-
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
127-
{
128-
Key: "failure-domain.beta.kubernetes.io/zone",
129-
Values: []string{"foo", "bar"},
130-
},
131-
},
132-
},
133-
},
134-
expectedToplogy: []v1.TopologySelectorTerm{
135-
{
136-
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
137-
{
138-
Key: GCEPDTopologyKey,
139-
Values: []string{"foo", "bar"},
140-
},
141-
},
142-
},
143-
},
144-
},
145-
{
146-
name: "combo",
147-
topology: []v1.TopologySelectorTerm{
148-
{
149-
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
150-
{
151-
Key: "failure-domain.beta.kubernetes.io/zone",
152-
Values: []string{"foo", "bar"},
153-
},
154-
{
155-
Key: GCEPDTopologyKey,
156-
Values: []string{"boo", "baz"},
157-
},
158-
},
159-
},
160-
},
161-
expectedToplogy: []v1.TopologySelectorTerm{
162-
{
163-
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
164-
{
165-
Key: GCEPDTopologyKey,
166-
Values: []string{"foo", "bar"},
167-
},
168-
{
169-
Key: GCEPDTopologyKey,
170-
Values: []string{"boo", "baz"},
171-
},
172-
},
173-
},
174-
},
175-
},
176-
{
177-
name: "some other key",
178-
topology: []v1.TopologySelectorTerm{
179-
{
180-
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
181-
{
182-
Key: "test",
183-
Values: []string{"foo", "bar"},
184-
},
185-
},
186-
},
187-
},
188-
expErr: true,
189-
},
190-
}
191-
192-
for _, tc := range testCases {
193-
t.Logf("Running test: %v", tc.name)
194-
gotTop, err := translateAllowedTopologies(tc.topology)
195-
if err != nil && !tc.expErr {
196-
t.Errorf("Did not expect an error, got: %v", err)
197-
}
198-
if err == nil && tc.expErr {
199-
t.Errorf("Expected an error but did not get one")
200-
}
201-
202-
if !reflect.DeepEqual(gotTop, tc.expectedToplogy) {
203-
t.Errorf("Expected topology: %v, but got: %v", tc.expectedToplogy, gotTop)
204-
}
205-
}
206-
}
207-
208101
func TestRepairVolumeHandle(t *testing.T) {
209102
testCases := []struct {
210103
name string

staging/src/k8s.io/csi-translation-lib/plugins/in_tree_volume.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package plugins
1818

1919
import (
2020
"errors"
21+
"fmt"
2122
"strings"
2223

2324
v1 "k8s.io/api/core/v1"
@@ -65,6 +66,17 @@ type InTreePlugin interface {
6566
RepairVolumeHandle(volumeHandle, nodeID string) (string, error)
6667
}
6768

69+
const (
70+
// fsTypeKey is the deprecated storage class parameter key for fstype
71+
fsTypeKey = "fstype"
72+
// csiFsTypeKey is the storage class parameter key for CSI fstype
73+
csiFsTypeKey = "csi.storage.k8s.io/fstype"
74+
// zoneKey is the deprecated storage class parameter key for zone
75+
zoneKey = "zone"
76+
// zonesKey is the deprecated storage class parameter key for zones
77+
zonesKey = "zones"
78+
)
79+
6880
// replaceTopology overwrites an existing topology key by a new one.
6981
func replaceTopology(pv *v1.PersistentVolume, oldKey, newKey string) error {
7082
for i := range pv.Spec.NodeAffinity.Required.NodeSelectorTerms {
@@ -153,3 +165,32 @@ func translateTopology(pv *v1.PersistentVolume, topologyKey string) error {
153165

154166
return nil
155167
}
168+
169+
// translateAllowedTopologies translates allowed topologies within storage class
170+
// from legacy failure domain to given CSI topology key
171+
func translateAllowedTopologies(terms []v1.TopologySelectorTerm, key string) ([]v1.TopologySelectorTerm, error) {
172+
if terms == nil {
173+
return nil, nil
174+
}
175+
176+
newTopologies := []v1.TopologySelectorTerm{}
177+
for _, term := range terms {
178+
newTerm := v1.TopologySelectorTerm{}
179+
for _, exp := range term.MatchLabelExpressions {
180+
var newExp v1.TopologySelectorLabelRequirement
181+
if exp.Key == v1.LabelZoneFailureDomain {
182+
newExp = v1.TopologySelectorLabelRequirement{
183+
Key: key,
184+
Values: exp.Values,
185+
}
186+
} else if exp.Key == key {
187+
newExp = exp
188+
} else {
189+
return nil, fmt.Errorf("unknown topology key: %v", exp.Key)
190+
}
191+
newTerm.MatchLabelExpressions = append(newTerm.MatchLabelExpressions, newExp)
192+
}
193+
newTopologies = append(newTopologies, newTerm)
194+
}
195+
return newTopologies, nil
196+
}

0 commit comments

Comments
 (0)