Skip to content

Commit eef4950

Browse files
authored
Add support for EBS CSI Driver (#2677)
* Add support for EBS CSI Driver
1 parent e7cc4f9 commit eef4950

File tree

7 files changed

+160
-4
lines changed

7 files changed

+160
-4
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,5 @@ e2e/tls
104104
mocks
105105

106106
ui/.npm/
107+
108+
.DS_Store

charts/postgres-operator/templates/clusterrole.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ rules:
141141
- get
142142
- list
143143
- patch
144-
{{- if toString .Values.configKubernetes.storage_resize_mode | eq "pvc" }}
144+
{{- if or (toString .Values.configKubernetes.storage_resize_mode | eq "pvc") (toString .Values.configKubernetes.storage_resize_mode | eq "mixed") }}
145145
- update
146146
{{- end }}
147147
# to read existing PVs. Creation should be done via dynamic provisioning

pkg/cluster/volumes.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ func (c *Cluster) populateVolumeMetaData() error {
151151
volumeIds := []string{}
152152
var volumeID string
153153
for _, pv := range pvs {
154-
volumeID, err = c.VolumeResizer.ExtractVolumeID(pv.Spec.AWSElasticBlockStore.VolumeID)
154+
volumeID, err = c.VolumeResizer.GetProviderVolumeID(pv)
155155
if err != nil {
156156
continue
157157
}

pkg/cluster/volumes_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,12 @@ func TestMigrateEBS(t *testing.T) {
216216
resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-1")).Return("ebs-volume-1", nil)
217217
resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-2")).Return("ebs-volume-2", nil)
218218

219+
resizer.EXPECT().GetProviderVolumeID(gomock.Any()).
220+
DoAndReturn(func(pv *v1.PersistentVolume) (string, error) {
221+
return resizer.ExtractVolumeID(pv.Spec.AWSElasticBlockStore.VolumeID)
222+
}).
223+
Times(2)
224+
219225
resizer.EXPECT().DescribeVolumes(gomock.Eq([]string{"ebs-volume-1", "ebs-volume-2"})).Return(
220226
[]volumes.VolumeProperties{
221227
{VolumeID: "ebs-volume-1", VolumeType: "gp2", Size: 100},
@@ -322,6 +328,12 @@ func TestMigrateGp3Support(t *testing.T) {
322328
resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-2")).Return("ebs-volume-2", nil)
323329
resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-3")).Return("ebs-volume-3", nil)
324330

331+
resizer.EXPECT().GetProviderVolumeID(gomock.Any()).
332+
DoAndReturn(func(pv *v1.PersistentVolume) (string, error) {
333+
return resizer.ExtractVolumeID(pv.Spec.AWSElasticBlockStore.VolumeID)
334+
}).
335+
Times(3)
336+
325337
resizer.EXPECT().DescribeVolumes(gomock.Eq([]string{"ebs-volume-1", "ebs-volume-2", "ebs-volume-3"})).Return(
326338
[]volumes.VolumeProperties{
327339
{VolumeID: "ebs-volume-1", VolumeType: "gp3", Size: 100, Iops: 3000},
@@ -377,6 +389,12 @@ func TestManualGp2Gp3Support(t *testing.T) {
377389
resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-1")).Return("ebs-volume-1", nil)
378390
resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-2")).Return("ebs-volume-2", nil)
379391

392+
resizer.EXPECT().GetProviderVolumeID(gomock.Any()).
393+
DoAndReturn(func(pv *v1.PersistentVolume) (string, error) {
394+
return resizer.ExtractVolumeID(pv.Spec.AWSElasticBlockStore.VolumeID)
395+
}).
396+
Times(2)
397+
380398
resizer.EXPECT().DescribeVolumes(gomock.Eq([]string{"ebs-volume-1", "ebs-volume-2"})).Return(
381399
[]volumes.VolumeProperties{
382400
{VolumeID: "ebs-volume-1", VolumeType: "gp2", Size: 150, Iops: 3000},
@@ -436,6 +454,12 @@ func TestDontTouchType(t *testing.T) {
436454
resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-1")).Return("ebs-volume-1", nil)
437455
resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-2")).Return("ebs-volume-2", nil)
438456

457+
resizer.EXPECT().GetProviderVolumeID(gomock.Any()).
458+
DoAndReturn(func(pv *v1.PersistentVolume) (string, error) {
459+
return resizer.ExtractVolumeID(pv.Spec.AWSElasticBlockStore.VolumeID)
460+
}).
461+
Times(2)
462+
439463
resizer.EXPECT().DescribeVolumes(gomock.Eq([]string{"ebs-volume-1", "ebs-volume-2"})).Return(
440464
[]volumes.VolumeProperties{
441465
{VolumeID: "ebs-volume-1", VolumeType: "gp2", Size: 150, Iops: 3000},

pkg/util/constants/aws.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const (
77
// EBS related constants
88
EBSVolumeIDStart = "/vol-"
99
EBSProvisioner = "kubernetes.io/aws-ebs"
10+
EBSDriver = "ebs.csi.aws.com"
1011
//https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_VolumeModification.html
1112
EBSVolumeStateModifying = "modifying"
1213
EBSVolumeStateOptimizing = "optimizing"

pkg/util/volumes/ebs.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ func (r *EBSVolumeResizer) IsConnectedToProvider() bool {
3636

3737
// VolumeBelongsToProvider checks if the given persistent volume is backed by EBS.
3838
func (r *EBSVolumeResizer) VolumeBelongsToProvider(pv *v1.PersistentVolume) bool {
39-
return pv.Spec.AWSElasticBlockStore != nil && pv.Annotations[constants.VolumeStorateProvisionerAnnotation] == constants.EBSProvisioner
39+
return (pv.Spec.AWSElasticBlockStore != nil && pv.Annotations[constants.VolumeStorateProvisionerAnnotation] == constants.EBSProvisioner) ||
40+
(pv.Spec.CSI != nil && pv.Spec.CSI.Driver == constants.EBSDriver)
4041
}
4142

4243
// ExtractVolumeID extracts volumeID from "aws://eu-central-1a/vol-075ddfc4a127d0bd4"
@@ -54,7 +55,12 @@ func (r *EBSVolumeResizer) ExtractVolumeID(volumeID string) (string, error) {
5455

5556
// GetProviderVolumeID converts aws://eu-central-1b/vol-00f93d4827217c629 to vol-00f93d4827217c629 for EBS volumes
5657
func (r *EBSVolumeResizer) GetProviderVolumeID(pv *v1.PersistentVolume) (string, error) {
57-
volumeID := pv.Spec.AWSElasticBlockStore.VolumeID
58+
var volumeID string = ""
59+
if pv.Spec.CSI != nil {
60+
volumeID = pv.Spec.CSI.VolumeHandle
61+
} else if pv.Spec.AWSElasticBlockStore != nil {
62+
volumeID = pv.Spec.AWSElasticBlockStore.VolumeID
63+
}
5864
if volumeID == "" {
5965
return "", fmt.Errorf("got empty volume id for volume %v", pv)
6066
}

pkg/util/volumes/ebs_test.go

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package volumes
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
v1 "k8s.io/api/core/v1"
7+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
)
9+
10+
func TestGetProviderVolumeID(t *testing.T) {
11+
tests := []struct {
12+
name string
13+
pv *v1.PersistentVolume
14+
expected string
15+
err error
16+
}{
17+
{
18+
name: "CSI volume handle",
19+
pv: &v1.PersistentVolume{
20+
Spec: v1.PersistentVolumeSpec{
21+
PersistentVolumeSource: v1.PersistentVolumeSource{
22+
CSI: &v1.CSIPersistentVolumeSource{
23+
VolumeHandle: "vol-075ddfc4a127d0bd5",
24+
},
25+
},
26+
},
27+
},
28+
expected: "vol-075ddfc4a127d0bd5",
29+
err: nil,
30+
},
31+
{
32+
name: "AWS EBS volume handle",
33+
pv: &v1.PersistentVolume{
34+
Spec: v1.PersistentVolumeSpec{
35+
PersistentVolumeSource: v1.PersistentVolumeSource{
36+
AWSElasticBlockStore: &v1.AWSElasticBlockStoreVolumeSource{
37+
VolumeID: "aws://eu-central-1a/vol-075ddfc4a127d0bd4",
38+
},
39+
},
40+
},
41+
},
42+
expected: "vol-075ddfc4a127d0bd4",
43+
err: nil,
44+
},
45+
{
46+
name: "Empty volume handle",
47+
pv: &v1.PersistentVolume{
48+
Spec: v1.PersistentVolumeSpec{},
49+
},
50+
expected: "",
51+
err: fmt.Errorf("got empty volume id for volume %v", &v1.PersistentVolume{}),
52+
},
53+
}
54+
55+
resizer := EBSVolumeResizer{}
56+
57+
for _, tt := range tests {
58+
t.Run(tt.name, func(t *testing.T) {
59+
volumeID, err := resizer.GetProviderVolumeID(tt.pv)
60+
if volumeID != tt.expected || (err != nil && err.Error() != tt.err.Error()) {
61+
t.Errorf("expected %v, got %v, expected err %v, got %v", tt.expected, volumeID, tt.err, err)
62+
}
63+
})
64+
}
65+
}
66+
67+
func TestVolumeBelongsToProvider(t *testing.T) {
68+
tests := []struct {
69+
name string
70+
pv *v1.PersistentVolume
71+
expected bool
72+
}{
73+
{
74+
name: "CSI volume handle",
75+
pv: &v1.PersistentVolume{
76+
Spec: v1.PersistentVolumeSpec{
77+
PersistentVolumeSource: v1.PersistentVolumeSource{
78+
CSI: &v1.CSIPersistentVolumeSource{
79+
Driver: "ebs.csi.aws.com",
80+
VolumeHandle: "vol-075ddfc4a127d0bd5",
81+
},
82+
},
83+
},
84+
},
85+
expected: true,
86+
},
87+
{
88+
name: "AWS EBS volume handle",
89+
pv: &v1.PersistentVolume{
90+
ObjectMeta: metav1.ObjectMeta{
91+
Annotations: map[string]string {
92+
"pv.kubernetes.io/provisioned-by": "kubernetes.io/aws-ebs",
93+
},
94+
},
95+
Spec: v1.PersistentVolumeSpec{
96+
PersistentVolumeSource: v1.PersistentVolumeSource{
97+
AWSElasticBlockStore: &v1.AWSElasticBlockStoreVolumeSource{
98+
VolumeID: "aws://eu-central-1a/vol-075ddfc4a127d0bd4",
99+
},
100+
},
101+
},
102+
},
103+
expected: true,
104+
},
105+
{
106+
name: "Empty volume source",
107+
pv: &v1.PersistentVolume{
108+
Spec: v1.PersistentVolumeSpec{},
109+
},
110+
expected: false,
111+
},
112+
}
113+
114+
for _, tt := range tests {
115+
t.Run(tt.name, func(t *testing.T) {
116+
resizer := EBSVolumeResizer{}
117+
isProvider := resizer.VolumeBelongsToProvider(tt.pv)
118+
if isProvider != tt.expected {
119+
t.Errorf("expected %v, got %v", tt.expected, isProvider)
120+
}
121+
})
122+
}
123+
}

0 commit comments

Comments
 (0)