Skip to content

Commit 2c284d4

Browse files
committed
Regional PD Implementation, added unit tests for common utilities. When
picking random zones just pick 1 zone randomly and the others are picked consecutively
1 parent 14ab26f commit 2c284d4

22 files changed

+1329
-397
lines changed

cmd/main.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ func init() {
3535
var (
3636
endpoint = flag.String("endpoint", "unix:/tmp/csi.sock", "CSI endpoint")
3737
driverName = flag.String("drivername", "com.google.csi.gcepd", "name of the driver")
38-
nodeID = flag.String("nodeid", "", "node id")
3938
vendorVersion string
4039
)
4140

@@ -50,7 +49,7 @@ func handle() {
5049
if vendorVersion == "" {
5150
glog.Fatalf("vendorVersion must be set at compile time")
5251
}
53-
glog.Infof("Driver vendor version %v", vendorVersion)
52+
glog.V(4).Infof("Driver vendor version %v", vendorVersion)
5453

5554
gceDriver := driver.GetGCEDriver()
5655

@@ -68,7 +67,7 @@ func handle() {
6867
glog.Fatalf("Failed to set up metadata service: %v", err)
6968
}
7069

71-
err = gceDriver.SetupGCEDriver(cloudProvider, mounter, deviceUtils, ms, *driverName, *nodeID, vendorVersion)
70+
err = gceDriver.SetupGCEDriver(cloudProvider, mounter, deviceUtils, ms, *driverName, vendorVersion)
7271
if err != nil {
7372
glog.Fatalf("Failed to initialize GCE CSI Driver: %v", err)
7473
}

pkg/common/constants.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ package common
1818

1919
const (
2020
// Keys for Storage Class Parameters
21-
ParameterKeyZone = "zone"
22-
ParameterKeyType = "type"
21+
ParameterKeyType = "type"
22+
ParameterKeyReplicationType = "replication-type"
2323

2424
// Keys for Topology. This key will be shared amonst drivers from GCP
2525
TopologyKeyZone = "com.google.topology/zone"

pkg/common/utils.go

+54-6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,25 @@ package common
1919
import (
2020
"fmt"
2121
"strings"
22+
23+
"k8s.io/apimachinery/pkg/util/sets"
24+
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta"
25+
)
26+
27+
const (
28+
// Volume ID Expected Format
29+
// "projects/{projectName}/zones/{zoneName}/disks/{diskName}"
30+
// "projects/{projectName}/regions/{regionName}/disks/{diskName}"
31+
volIDToplogyKey = 2
32+
volIDToplogyValue = 3
33+
volIDDiskNameValue = 5
34+
volIDTotalElements = 6
35+
36+
// Node ID Expected Format
37+
// "{zoneName}/{instanceName}"
38+
nodeIDZoneValue = 0
39+
nodeIDNameValue = 1
40+
nodeIDTotalElements = 2
2241
)
2342

2443
func BytesToGb(bytes int64) int64 {
@@ -31,14 +50,43 @@ func GbToBytes(Gb int64) int64 {
3150
return Gb * 1024 * 1024 * 1024
3251
}
3352

34-
func SplitZoneNameId(id string) (string, string, error) {
53+
func VolumeIDToKey(id string) (*meta.Key, error) {
54+
splitId := strings.Split(id, "/")
55+
if len(splitId) != volIDTotalElements {
56+
return nil, fmt.Errorf("failed to get id components. Expected projects/{project}/zones/{zone}/disks/{name}. Got: %s", id)
57+
}
58+
if splitId[volIDToplogyKey] == "zones" {
59+
return meta.ZonalKey(splitId[volIDDiskNameValue], splitId[volIDToplogyValue]), nil
60+
} else if splitId[volIDToplogyKey] == "regions" {
61+
return meta.RegionalKey(splitId[volIDDiskNameValue], splitId[volIDToplogyValue]), nil
62+
} else {
63+
return nil, fmt.Errorf("could not get id components, expected either zones or regions, got: %v", splitId[volIDToplogyKey])
64+
}
65+
}
66+
67+
func NodeIDToZoneAndName(id string) (string, string, error) {
3568
splitId := strings.Split(id, "/")
36-
if len(splitId) != 2 {
37-
return "", "", fmt.Errorf("Failed to get id components. Expected {zone}/{name}. Got: %s", id)
69+
if len(splitId) != nodeIDTotalElements {
70+
return "", "", fmt.Errorf("failed to get id components. expected {zone}/{name}. Got: %s", id)
3871
}
39-
return splitId[0], splitId[1], nil
72+
return splitId[nodeIDZoneValue], splitId[nodeIDNameValue], nil
4073
}
4174

42-
func CombineVolumeId(zone, name string) string {
43-
return fmt.Sprintf("%s/%s", zone, name)
75+
func GetRegionFromZones(zones []string) (string, error) {
76+
regions := sets.String{}
77+
if len(zones) < 1 {
78+
return "", fmt.Errorf("no zones specified")
79+
}
80+
for _, zone := range zones {
81+
// Zone expected format {locale}-{region}-{zone}
82+
splitZone := strings.Split(zone, "-")
83+
if len(splitZone) != 3 {
84+
return "", fmt.Errorf("zone in unexpected format, expected: {locale}-{region}-{zone}, got: %v", zone)
85+
}
86+
regions.Insert(strings.Join(splitZone[0:2], "-"))
87+
}
88+
if regions.Len() != 1 {
89+
return "", fmt.Errorf("multiple or no regions gotten from zones, got: %v", regions)
90+
}
91+
return regions.UnsortedList()[0], nil
4492
}

pkg/common/utils_test.go

+249
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
/*
2+
Copyright 2018 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package common
18+
19+
import (
20+
"fmt"
21+
"reflect"
22+
"testing"
23+
24+
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta"
25+
)
26+
27+
const (
28+
volIDZoneFmt = "projects/%s/zones/%s/disks/%s"
29+
volIDRegionFmt = "projects/%s/regions/%s/disks/%s"
30+
nodeIDFmt = "%s/%s"
31+
)
32+
33+
func TestBytesToGb(t *testing.T) {
34+
testCases := []struct {
35+
name string
36+
bytes int64
37+
expGB int64
38+
}{
39+
{
40+
name: "normal 5gb",
41+
bytes: 5368709120,
42+
expGB: 5,
43+
},
44+
{
45+
name: "slightly less than 5gb",
46+
bytes: 5368709119,
47+
expGB: 4,
48+
},
49+
{
50+
name: "slightly more than 5gb",
51+
bytes: 5368709121,
52+
expGB: 5,
53+
},
54+
{
55+
name: "zero",
56+
bytes: 0,
57+
expGB: 0,
58+
},
59+
}
60+
for _, tc := range testCases {
61+
t.Logf("test case: %s", tc.name)
62+
gotGB := BytesToGb(tc.bytes)
63+
64+
if gotGB != tc.expGB {
65+
t.Errorf("got GB %v, expected %v", gotGB, tc.expGB)
66+
}
67+
68+
}
69+
}
70+
71+
func TestGbToBytes(t *testing.T) {
72+
testCases := []struct {
73+
name string
74+
gb int64
75+
expBytes int64
76+
}{
77+
{
78+
name: "5Gb",
79+
gb: 5,
80+
expBytes: 5368709120,
81+
},
82+
{
83+
name: "0gb",
84+
gb: 0,
85+
expBytes: 0,
86+
},
87+
{
88+
name: "1gb",
89+
gb: 1,
90+
expBytes: 1024 * 1024 * 1024,
91+
},
92+
}
93+
for _, tc := range testCases {
94+
t.Logf("test case: %s", tc.name)
95+
gotBytes := GbToBytes(tc.gb)
96+
if gotBytes != tc.expBytes {
97+
t.Errorf("got bytes: %v, expected: %v", gotBytes, tc.expBytes)
98+
}
99+
100+
}
101+
}
102+
103+
func TestVolumeIDToKey(t *testing.T) {
104+
testName := "test-name"
105+
testZone := "test-zone"
106+
testProject := "test-project"
107+
testRegion := "test-region"
108+
109+
testCases := []struct {
110+
name string
111+
volID string
112+
expKey *meta.Key
113+
expErr bool
114+
}{
115+
{
116+
name: "normal zonal",
117+
volID: fmt.Sprintf(volIDZoneFmt, testProject, testZone, testName),
118+
expKey: meta.ZonalKey(testName, testZone),
119+
},
120+
{
121+
name: "normal regional",
122+
volID: fmt.Sprintf(volIDRegionFmt, testProject, testRegion, testName),
123+
expKey: meta.RegionalKey(testName, testRegion),
124+
},
125+
{
126+
name: "malformed",
127+
volID: "wrong",
128+
expErr: true,
129+
},
130+
{
131+
name: "malformed but right length",
132+
volID: "this/is/wrong/but/right/num",
133+
expErr: true,
134+
},
135+
}
136+
for _, tc := range testCases {
137+
t.Logf("test case: %s", tc.name)
138+
gotKey, err := VolumeIDToKey(tc.volID)
139+
if err == nil && tc.expErr {
140+
t.Errorf("Expected error but got none")
141+
}
142+
if err != nil {
143+
if !tc.expErr {
144+
t.Errorf("Did not expect error but got: %v", err)
145+
}
146+
continue
147+
}
148+
149+
if !reflect.DeepEqual(gotKey, tc.expKey) {
150+
t.Errorf("Got key %v, but expected %v, from volume ID %v", gotKey, tc.expKey, tc.volID)
151+
}
152+
}
153+
154+
}
155+
156+
func TestNodeIDToZoneAndName(t *testing.T) {
157+
testName := "test-name"
158+
testZone := "test-zone"
159+
160+
testCases := []struct {
161+
name string
162+
nodeID string
163+
expZone string
164+
expName string
165+
expErr bool
166+
}{
167+
{
168+
name: "normal",
169+
nodeID: fmt.Sprintf(nodeIDFmt, testZone, testName),
170+
expZone: testZone,
171+
expName: testName,
172+
},
173+
{
174+
name: "malformed",
175+
nodeID: "wrong",
176+
expErr: true,
177+
},
178+
}
179+
for _, tc := range testCases {
180+
t.Logf("test case: %s", tc.name)
181+
zone, name, err := NodeIDToZoneAndName(tc.nodeID)
182+
if err == nil && tc.expErr {
183+
t.Errorf("Expected error but got none")
184+
}
185+
if err != nil {
186+
if !tc.expErr {
187+
t.Errorf("Did not expect error but got: %v", err)
188+
}
189+
continue
190+
}
191+
192+
if !(zone == tc.expZone && name == tc.expName) {
193+
t.Errorf("got wrong zone/name %s/%s, expected %s/%s", zone, name, tc.expZone, tc.expName)
194+
}
195+
196+
}
197+
}
198+
199+
func TestGetRegionFromZones(t *testing.T) {
200+
testCases := []struct {
201+
name string
202+
zones []string
203+
expRegion string
204+
expErr bool
205+
}{
206+
{
207+
name: "single zone success",
208+
zones: []string{"us-central1-c"},
209+
expRegion: "us-central1",
210+
},
211+
{
212+
name: "multi zone success",
213+
zones: []string{"us-central1-b", "us-central1-c"},
214+
expRegion: "us-central1",
215+
},
216+
{
217+
name: "multi different zone fail",
218+
zones: []string{"us-central1-c", "us-asia1-b"},
219+
expErr: true,
220+
},
221+
{
222+
name: "empty zones",
223+
expErr: true,
224+
},
225+
{
226+
name: "malformed zone",
227+
zones: []string{"blah/blooh"},
228+
expErr: true,
229+
},
230+
}
231+
for _, tc := range testCases {
232+
t.Logf("test case: %s", tc.name)
233+
region, err := GetRegionFromZones(tc.zones)
234+
if err == nil && tc.expErr {
235+
t.Errorf("Expected error but got none")
236+
}
237+
if err != nil {
238+
if !tc.expErr {
239+
t.Errorf("Did not expect error but got: %v", err)
240+
}
241+
continue
242+
}
243+
244+
if region != tc.expRegion {
245+
t.Errorf("Got region: %v, expected: %v", region, tc.expRegion)
246+
}
247+
248+
}
249+
}

0 commit comments

Comments
 (0)