Skip to content

Commit dc0d466

Browse files
authored
Merge branch 'main' into ashima-server
2 parents 256f12d + 6dccbd8 commit dc0d466

File tree

5 files changed

+130
-10
lines changed

5 files changed

+130
-10
lines changed

pkg/driver/controllerserver.go

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func (cs *controllerServer) CreateVolume(_ context.Context, req *csi.CreateVolum
4949
kpRootKeyCrn string
5050
pvcName string
5151
pvcNamespace string
52+
bucketVersioning string
5253
)
5354
secretMapCustom := make(map[string]string)
5455

@@ -85,6 +86,7 @@ func (cs *controllerServer) CreateVolume(_ context.Context, req *csi.CreateVolum
8586
secretMap := req.GetSecrets()
8687
klog.Info("req.GetSecrets() length:\t", len(secretMap))
8788

89+
var customSecretName string
8890
if len(secretMap) == 0 {
8991
klog.Info("Did not find the secret that matches pvc name. Fetching custom secret from PVC annotations")
9092

@@ -108,10 +110,10 @@ func (cs *controllerServer) CreateVolume(_ context.Context, req *csi.CreateVolum
108110

109111
pvcAnnotations := pvcRes.Annotations
110112

111-
secretName := pvcAnnotations["cos.csi.driver/secret"]
113+
customSecretName = pvcAnnotations["cos.csi.driver/secret"]
112114
secretNamespace := pvcAnnotations["cos.csi.driver/secret-namespace"]
113115

114-
if secretName == "" {
116+
if customSecretName == "" {
115117
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("secretName annotation 'cos.csi.driver/secret' not specified in the PVC annotations, could not fetch the secret %v", err))
116118
}
117119

@@ -120,7 +122,7 @@ func (cs *controllerServer) CreateVolume(_ context.Context, req *csi.CreateVolum
120122
secretNamespace = constants.DefaultNamespace
121123
}
122124

123-
secret, err := utils.GetSecret(secretName, secretNamespace)
125+
secret, err := utils.GetSecret(customSecretName, secretNamespace)
124126
if err != nil {
125127
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Secret resource not found %v", err))
126128
}
@@ -165,6 +167,24 @@ func (cs *controllerServer) CreateVolume(_ context.Context, req *csi.CreateVolum
165167
bucketName = secretMapCustom["bucketName"]
166168
}
167169

170+
// Check for bucketVersioning parameter
171+
if val, ok := secretMap["bucketVersioning"]; ok && val != "" {
172+
enable := strings.ToLower(strings.TrimSpace(val))
173+
if enable != "true" && enable != "false" {
174+
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Invalid BucketVersioning value in secret: %s. Value set %s. Must be 'true' or 'false'", customSecretName, val))
175+
}
176+
bucketVersioning = enable
177+
klog.Infof("BucketVersioning value that will be set via secret: %s", bucketVersioning)
178+
} else if val, ok := params["bucketVersioning"]; ok && val != "" {
179+
enable := strings.ToLower(strings.TrimSpace(val))
180+
if enable != "true" && enable != "false" {
181+
return nil, status.Error(codes.InvalidArgument,
182+
fmt.Sprintf("Invalid bucketVersioning value in storage class: %s. Must be 'true' or 'false'", val))
183+
}
184+
bucketVersioning = enable
185+
klog.Infof("BucketVersioning value that will be set via storage class params: %s", bucketVersioning)
186+
}
187+
168188
creds, err := getCredentials(secretMap)
169189
if err != nil {
170190
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Error in getting credentials %v", err))
@@ -185,6 +205,24 @@ func (cs *controllerServer) CreateVolume(_ context.Context, req *csi.CreateVolum
185205
params["userProvidedBucket"] = "false"
186206
klog.Infof("Created bucket: %s", bucketName)
187207
}
208+
209+
if bucketVersioning != "" {
210+
enable := strings.ToLower(strings.TrimSpace(bucketVersioning)) == "true"
211+
klog.Infof("Bucket versioning value evaluated to: %t", enable)
212+
213+
err := sess.SetBucketVersioning(bucketName, enable)
214+
if err != nil {
215+
if params["userProvidedBucket"] == "false" {
216+
err1 := sess.DeleteBucket(bucketName)
217+
if err1 != nil {
218+
return nil, status.Error(codes.Internal, fmt.Sprintf("cannot set versioning: %v and cannot delete bucket %s: %v", err, bucketName, err1))
219+
}
220+
}
221+
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to set versioning %t for bucket %s: %v", enable, bucketName, err))
222+
}
223+
klog.Infof("Bucket versioning set to %t for bucket %s", enable, bucketName)
224+
}
225+
188226
params["bucketName"] = bucketName
189227
} else {
190228
// Generate random temp bucket name based on volume id
@@ -198,6 +236,21 @@ func (cs *controllerServer) CreateVolume(_ context.Context, req *csi.CreateVolum
198236
if err != nil {
199237
return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("%v: %v", err, tempBucketName))
200238
}
239+
240+
if bucketVersioning != "" {
241+
enable := strings.ToLower(strings.TrimSpace(bucketVersioning)) == "true"
242+
klog.Infof("Temp bucket versioning value evaluated to: %t", enable)
243+
244+
err := sess.SetBucketVersioning(tempBucketName, enable)
245+
if err != nil {
246+
err1 := sess.DeleteBucket(tempBucketName)
247+
if err1 != nil {
248+
return nil, status.Error(codes.Internal, fmt.Sprintf("cannot set versioning: %v and cannot delete temp bucket %s: %v", err, tempBucketName, err1))
249+
}
250+
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to set versioning %t for temp bucket %s: %v", enable, tempBucketName, err))
251+
}
252+
klog.Infof("Bucket versioning set to %t for temp bucket %s", enable, tempBucketName)
253+
}
201254
klog.Infof("Created temp bucket: %s", tempBucketName)
202255
params["userProvidedBucket"] = "false"
203256
params["bucketName"] = tempBucketName
@@ -442,6 +495,7 @@ func parseCustomSecret(secret *v1.Secret) map[string]string {
442495
iamEndpoint string
443496
cosEndpoint string
444497
locationConstraint string
498+
bucketVersioning string
445499
)
446500

447501
if bytesVal, ok := secret.Data["accessKey"]; ok {
@@ -480,6 +534,10 @@ func parseCustomSecret(secret *v1.Secret) map[string]string {
480534
locationConstraint = string(bytesVal)
481535
}
482536

537+
if bytesVal, ok := secret.Data["bucketVersioning"]; ok {
538+
bucketVersioning = string(bytesVal)
539+
}
540+
483541
secretMapCustom["accessKey"] = accessKey
484542
secretMapCustom["secretKey"] = secretKey
485543
secretMapCustom["apiKey"] = apiKey
@@ -489,6 +547,7 @@ func parseCustomSecret(secret *v1.Secret) map[string]string {
489547
secretMapCustom["iamEndpoint"] = iamEndpoint
490548
secretMapCustom["cosEndpoint"] = cosEndpoint
491549
secretMapCustom["locationConstraint"] = locationConstraint
550+
secretMapCustom["bucketVersioning"] = bucketVersioning
492551

493552
return secretMapCustom
494553
}

pkg/s3client/fake_s3client.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ type FakeCOSSessionFactory struct {
1111
FailCheckBucketAccess bool
1212
FailCreateBucket bool
1313
FailDeleteBucket bool
14+
FailBucketVersioning bool
1415
}
1516

1617
type fakeCOSSession struct {
@@ -31,6 +32,13 @@ func (s *fakeCOSSession) CheckBucketAccess(bucket string) error {
3132
return nil
3233
}
3334

35+
func (s *fakeCOSSession) SetBucketVersioning(bucket string, enable bool) error {
36+
if s.factory.FailBucketVersioning {
37+
return errors.New("failed to set bucket versioning")
38+
}
39+
return nil
40+
}
41+
3442
func (s *fakeCOSSession) CheckObjectPathExistence(bucket, objectpath string) (bool, error) {
3543
return true, nil
3644
}

pkg/s3client/s3client.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ type ObjectStorageSession interface {
6161

6262
// DeleteBucket methods deletes a bucket (with all of its objects)
6363
DeleteBucket(bucket string) error
64+
65+
SetBucketVersioning(bucket string, enable bool) error
6466
}
6567

6668
// COSSessionFactory represents a COS (S3) session factory
@@ -91,6 +93,7 @@ type s3API interface {
9193
ListObjectsV2(input *s3.ListObjectsV2Input) (*s3.ListObjectsV2Output, error)
9294
DeleteObject(input *s3.DeleteObjectInput) (*s3.DeleteObjectOutput, error)
9395
DeleteBucket(input *s3.DeleteBucketInput) (*s3.DeleteBucketOutput, error)
96+
PutBucketVersioning(input *s3.PutBucketVersioningInput) (*s3.PutBucketVersioningOutput, error)
9497
}
9598

9699
func (s *COSSession) CheckBucketAccess(bucket string) error {
@@ -182,6 +185,26 @@ func (s *COSSession) DeleteBucket(bucket string) error {
182185
return err
183186
}
184187

188+
func (s *COSSession) SetBucketVersioning(bucket string, enable bool) error {
189+
status := s3.BucketVersioningStatusSuspended
190+
if enable {
191+
status = s3.BucketVersioningStatusEnabled
192+
}
193+
s.logger.Info("Setting versioning for bucket", zap.String("bucket", bucket), zap.Bool("enable", enable))
194+
_, err := s.svc.PutBucketVersioning(&s3.PutBucketVersioningInput{
195+
Bucket: aws.String(bucket),
196+
VersioningConfiguration: &s3.VersioningConfiguration{
197+
Status: aws.String(status),
198+
},
199+
})
200+
if err != nil {
201+
s.logger.Error("Failed to set versioning", zap.String("bucket", bucket), zap.Bool("enable", enable), zap.Error(err))
202+
return fmt.Errorf("failed to set versioning to %v for bucket '%s': %v", enable, bucket, err)
203+
}
204+
s.logger.Info("Versioning set successfully for bucket", zap.String("bucket", bucket), zap.Bool("enable", enable))
205+
return nil
206+
}
207+
185208
func NewS3Client(lgr *zap.Logger) (ObjectStorageSession, error) {
186209
cosSession := new(COSSession)
187210
cosSession.logger = lgr

pkg/s3client/s3client_test.go

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ import (
1212
)
1313

1414
type fakeS3API struct {
15-
ErrHeadBucket error
16-
ErrCreateBucket error
17-
ErrListObjects error
18-
ErrListObjectsV2 error
19-
ErrDeleteObject error
20-
ErrDeleteBucket error
21-
ObjectPath string
15+
ErrHeadBucket error
16+
ErrCreateBucket error
17+
ErrListObjects error
18+
ErrListObjectsV2 error
19+
ErrDeleteObject error
20+
ErrDeleteBucket error
21+
ObjectPath string
22+
ErrPutBucketVersioning error
2223
}
2324

2425
const (
@@ -49,6 +50,10 @@ func (a *fakeS3API) CreateBucket(input *s3.CreateBucketInput) (*s3.CreateBucketO
4950
return nil, a.ErrCreateBucket
5051
}
5152

53+
func (a *fakeS3API) PutBucketVersioning(input *s3.PutBucketVersioningInput) (*s3.PutBucketVersioningOutput, error) {
54+
return &s3.PutBucketVersioningOutput{}, a.ErrPutBucketVersioning
55+
}
56+
5257
func (a *fakeS3API) ListObjects(input *s3.ListObjectsInput) (*s3.ListObjectsOutput, error) {
5358
return &s3.ListObjectsOutput{
5459
Contents: []*s3.Object{{Key: &testObject}},
@@ -156,6 +161,26 @@ func Test_CreateBucket_Positive(t *testing.T) {
156161
assert.NoError(t, err)
157162
}
158163

164+
func Test_SetBucketVersioning_True_Positive(t *testing.T) {
165+
sess := getSession(&fakeS3API{})
166+
err := sess.SetBucketVersioning(testBucket, true)
167+
assert.NoError(t, err)
168+
}
169+
170+
func Test_SetBucketVersioning_False_Positive(t *testing.T) {
171+
sess := getSession(&fakeS3API{})
172+
err := sess.SetBucketVersioning(testBucket, false)
173+
assert.NoError(t, err)
174+
}
175+
176+
func Test_SetBucketVersioning_Error(t *testing.T) {
177+
sess := getSession(&fakeS3API{ErrPutBucketVersioning: errFoo})
178+
err := sess.SetBucketVersioning(testBucket, true)
179+
if assert.Error(t, err) {
180+
assert.EqualError(t, err, "failed to set versioning to true for bucket 'test-bucket': foo")
181+
}
182+
}
183+
159184
func Test_DeleteBucket_BucketAlreadyDeleted_Positive(t *testing.T) {
160185
sess := getSession(&fakeS3API{ErrListObjects: awserr.New("NoSuchBucket", "", errFoo)})
161186
err := sess.DeleteBucket(testBucket)

tests/sanity/sanity_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,11 @@ func (s *fakeObjectStorageSession) CheckBucketAccess(bucket string) error {
151151
return nil
152152
}
153153

154+
func (s *fakeObjectStorageSession) SetBucketVersioning(bucketName string, enable bool) error {
155+
s.logger.Info(fmt.Sprintf("Fake SetBucketVersioning called for bucket %s with enable=%t", bucketName, enable))
156+
return nil
157+
}
158+
154159
func (s *fakeObjectStorageSession) CheckObjectPathExistence(bucket, objectpath string) (bool, error) {
155160
return true, nil
156161
}

0 commit comments

Comments
 (0)