fix: Added the implementation to automatically enable bucket versioning when enabling object lock. Added error response when attempting to set bucket versioning status to Suspended when object lock is enabled

This commit is contained in:
jonaustin09
2024-10-01 16:59:04 -04:00
parent 8b9a5ee567
commit e502a15306
4 changed files with 73 additions and 2 deletions
+23 -2
View File
@@ -325,6 +325,15 @@ func (p *Posix) CreateBucket(ctx context.Context, input *s3.CreateBucketInput, a
}
if input.ObjectLockEnabledForBucket != nil && *input.ObjectLockEnabledForBucket {
// First enable bucket versioning
// Bucket versioning is enabled automatically with object lock
if p.versioningEnabled() {
err = p.PutBucketVersioning(ctx, bucket, types.BucketVersioningStatusEnabled)
if err != nil {
return err
}
}
now := time.Now()
defaultLock := auth.BucketLockConfig{
Enabled: true,
@@ -437,7 +446,7 @@ func (p *Posix) DeleteBucketOwnershipControls(_ context.Context, bucket string)
return nil
}
func (p *Posix) PutBucketVersioning(_ context.Context, bucket string, status types.BucketVersioningStatus) error {
func (p *Posix) PutBucketVersioning(ctx context.Context, bucket string, status types.BucketVersioningStatus) error {
if !p.versioningEnabled() {
//TODO: Maybe we need to return our custom error here?
return nil
@@ -457,6 +466,18 @@ func (p *Posix) PutBucketVersioning(_ context.Context, bucket string, status typ
// '1' maps to 'Enabled'
versioning = []byte{1}
case types.BucketVersioningStatusSuspended:
lockRaw, err := p.GetObjectLockConfiguration(ctx, bucket)
if err != nil {
return err
}
lockStatus, err := auth.ParseBucketLockConfigurationOutput(lockRaw)
if err != nil {
return err
}
if lockStatus.ObjectLockEnabled == types.ObjectLockEnabledEnabled {
return s3err.GetAPIError(s3err.ErrSuspendedVersioningNotAllowed)
}
// '0' maps to 'Suspended'
versioning = []byte{0}
}
@@ -3409,7 +3430,7 @@ func (p *Posix) DeleteBucketPolicy(ctx context.Context, bucket string) error {
return p.PutBucketPolicy(ctx, bucket, nil)
}
func (p *Posix) PutObjectLockConfiguration(_ context.Context, bucket string, config []byte) error {
func (p *Posix) PutObjectLockConfiguration(ctx context.Context, bucket string, config []byte) error {
_, err := os.Stat(bucket)
if errors.Is(err, fs.ErrNotExist) {
return s3err.GetAPIError(s3err.ErrNoSuchBucket)
+6
View File
@@ -134,6 +134,7 @@ const (
ErrKeyTooLong
ErrInvalidVersionId
ErrNoSuchVersion
ErrSuspendedVersioningNotAllowed
// Non-AWS errors
ErrExistingObjectIsDirectory
@@ -537,6 +538,11 @@ var errorCodeResponse = map[ErrorCode]APIError{
Description: "The specified version does not exist.",
HTTPStatusCode: http.StatusNotFound,
},
ErrSuspendedVersioningNotAllowed: {
Code: "InvalidBucketState",
Description: "An Object Lock configuration is present on this bucket, so the versioning state cannot be changed.",
HTTPStatusCode: http.StatusBadRequest,
},
// non aws errors
ErrExistingObjectIsDirectory: {
+5
View File
@@ -553,6 +553,9 @@ func TestVersioning(s *S3Conf) {
Versioning_Multipart_Upload_overwrite_an_object(s)
Versioning_UploadPartCopy_non_existing_versionId(s)
Versioning_UploadPartCopy_from_an_object_version(s)
// Object lock configuration
Versioning_Enable_object_lock(s)
Versioning_status_switch_to_suspended_with_object_lock(s)
// Object-Lock Retention
Versionsin_PutObjectRetention_invalid_versionId(s)
Versioning_GetObjectRetention_invalid_versionId(s)
@@ -912,6 +915,8 @@ func GetIntTests() IntTests {
"Versioning_Multipart_Upload_overwrite_an_object": Versioning_Multipart_Upload_overwrite_an_object,
"Versioning_UploadPartCopy_non_existing_versionId": Versioning_UploadPartCopy_non_existing_versionId,
"Versioning_UploadPartCopy_from_an_object_version": Versioning_UploadPartCopy_from_an_object_version,
"Versioning_Enable_object_lock": Versioning_Enable_object_lock,
"Versioning_status_switch_to_suspended_with_object_lock": Versioning_status_switch_to_suspended_with_object_lock,
"Versionsin_PutObjectRetention_invalid_versionId": Versionsin_PutObjectRetention_invalid_versionId,
"Versioning_GetObjectRetention_invalid_versionId": Versioning_GetObjectRetention_invalid_versionId,
"Versioning_Put_GetObjectRetention_success": Versioning_Put_GetObjectRetention_success,
+39
View File
@@ -11746,6 +11746,45 @@ func Versioning_UploadPartCopy_from_an_object_version(s *S3Conf) error {
}, withVersioning())
}
func Versioning_Enable_object_lock(s *S3Conf) error {
testName := "Versioning_Enable_object_lock"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
res, err := s3client.GetBucketVersioning(ctx, &s3.GetBucketVersioningInput{
Bucket: &bucket,
})
cancel()
if err != nil {
return err
}
if res.Status != types.BucketVersioningStatusEnabled {
return fmt.Errorf("expected the bucket versioning status to be %v, instead got %v", types.BucketVersioningStatusEnabled, res.Status)
}
return nil
}, withLock())
}
func Versioning_status_switch_to_suspended_with_object_lock(s *S3Conf) error {
testName := "Versioning_status_switch_to_suspended_with_object_lock"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := s3client.PutBucketVersioning(ctx, &s3.PutBucketVersioningInput{
Bucket: &bucket,
VersioningConfiguration: &types.VersioningConfiguration{
Status: types.BucketVersioningStatusSuspended,
},
})
cancel()
if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrSuspendedVersioningNotAllowed)); err != nil {
return err
}
return nil
}, withLock())
}
func Versionsin_PutObjectRetention_invalid_versionId(s *S3Conf) error {
testName := "Versionsin_PutObjectRetention_invalid_versionId"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {