mirror of
https://github.com/minio/minio.git
synced 2025-04-04 03:40:30 -04:00
cleanup object-lock/bucket tagging for gateways (#9548)
This PR is to ensure that we call the relevant object layer APIs for necessary S3 API level functionalities allowing gateway implementations to return proper errors as NotImplemented{} This allows for all our tests in mint to behave appropriately and can be handled appropriately as well.
This commit is contained in:
parent
6885c72f32
commit
a1de9cec58
@ -1808,6 +1808,10 @@ func toAPIErrorCode(ctx context.Context, err error) (apiErr APIErrorCode) {
|
|||||||
apiErr = ErrNoSuchLifecycleConfiguration
|
apiErr = ErrNoSuchLifecycleConfiguration
|
||||||
case BucketSSEConfigNotFound:
|
case BucketSSEConfigNotFound:
|
||||||
apiErr = ErrNoSuchBucketSSEConfig
|
apiErr = ErrNoSuchBucketSSEConfig
|
||||||
|
case BucketTaggingNotFound:
|
||||||
|
apiErr = ErrBucketTaggingNotFound
|
||||||
|
case BucketObjectLockConfigNotFound:
|
||||||
|
apiErr = ErrObjectLockConfigurationNotFound
|
||||||
case BucketQuotaConfigNotFound:
|
case BucketQuotaConfigNotFound:
|
||||||
apiErr = ErrAdminNoSuchQuotaConfiguration
|
apiErr = ErrAdminNoSuchQuotaConfiguration
|
||||||
case BucketQuotaExceeded:
|
case BucketQuotaExceeded:
|
||||||
|
@ -35,7 +35,7 @@ func runPutObjectBenchmark(b *testing.B, obj ObjectLayer, objSize int) {
|
|||||||
// obtains random bucket name.
|
// obtains random bucket name.
|
||||||
bucket := getRandomBucketName()
|
bucket := getRandomBucketName()
|
||||||
// create bucket.
|
// create bucket.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucket, "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -76,7 +76,7 @@ func runPutObjectPartBenchmark(b *testing.B, obj ObjectLayer, partSize int) {
|
|||||||
object := getRandomObjectName()
|
object := getRandomObjectName()
|
||||||
|
|
||||||
// create bucket.
|
// create bucket.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucket, "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -181,7 +181,7 @@ func runGetObjectBenchmark(b *testing.B, obj ObjectLayer, objSize int) {
|
|||||||
// obtains random bucket name.
|
// obtains random bucket name.
|
||||||
bucket := getRandomBucketName()
|
bucket := getRandomBucketName()
|
||||||
// create bucket.
|
// create bucket.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucket, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -278,7 +278,7 @@ func runPutObjectBenchmarkParallel(b *testing.B, obj ObjectLayer, objSize int) {
|
|||||||
// obtains random bucket name.
|
// obtains random bucket name.
|
||||||
bucket := getRandomBucketName()
|
bucket := getRandomBucketName()
|
||||||
// create bucket.
|
// create bucket.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucket, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -322,7 +322,7 @@ func runGetObjectBenchmarkParallel(b *testing.B, obj ObjectLayer, objSize int) {
|
|||||||
// obtains random bucket name.
|
// obtains random bucket name.
|
||||||
bucket := getRandomBucketName()
|
bucket := getRandomBucketName()
|
||||||
// create bucket.
|
// create bucket.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucket, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -292,16 +292,6 @@ func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.R
|
|||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range bucketsInfo {
|
|
||||||
meta, err := loadBucketMetadata(ctx, objectAPI, bucketsInfo[i].Name)
|
|
||||||
if err == nil {
|
|
||||||
bucketsInfo[i].Created = meta.Created
|
|
||||||
}
|
|
||||||
if err != errMetaDataConverted {
|
|
||||||
logger.LogIf(ctx, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if s3Error == ErrAccessDenied {
|
if s3Error == ErrAccessDenied {
|
||||||
@ -409,7 +399,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := globalBucketObjectLockConfig.Get(bucket); ok {
|
if _, ok := globalBucketObjectLockSys.Get(bucket); ok {
|
||||||
if err := enforceRetentionBypassForDelete(ctx, r, bucket, object.ObjectName, getObjectInfoFn); err != ErrNone {
|
if err := enforceRetentionBypassForDelete(ctx, r, bucket, object.ObjectName, getObjectInfoFn); err != ErrNone {
|
||||||
dErrs[index] = err
|
dErrs[index] = err
|
||||||
continue
|
continue
|
||||||
@ -537,14 +527,7 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if err == dns.ErrNoEntriesFound {
|
if err == dns.ErrNoEntriesFound {
|
||||||
// Proceed to creating a bucket.
|
// Proceed to creating a bucket.
|
||||||
if err = objectAPI.MakeBucketWithLocation(ctx, bucket, location); err != nil {
|
if err = objectAPI.MakeBucketWithLocation(ctx, bucket, location, objectLockEnabled); err != nil {
|
||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
meta := newBucketMetadata(bucket)
|
|
||||||
meta.LockEnabled = objectLockEnabled
|
|
||||||
if err := meta.save(ctx, objectAPI); err != nil {
|
|
||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -579,24 +562,16 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Proceed to creating a bucket.
|
// Proceed to creating a bucket.
|
||||||
err := objectAPI.MakeBucketWithLocation(ctx, bucket, location)
|
err := objectAPI.MakeBucketWithLocation(ctx, bucket, location, objectLockEnabled)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !globalIsGateway {
|
if objectLockEnabled && !globalIsGateway {
|
||||||
meta := newBucketMetadata(bucket)
|
ret := &objectlock.Retention{}
|
||||||
meta.LockEnabled = objectLockEnabled
|
globalBucketObjectLockSys.Set(bucket, ret)
|
||||||
if err := meta.save(ctx, objectAPI); err != nil {
|
globalNotificationSys.PutBucketObjectLockConfig(ctx, bucket, ret)
|
||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if objectLockEnabled {
|
|
||||||
ret := &objectlock.Retention{}
|
|
||||||
globalBucketObjectLockConfig.Set(bucket, ret)
|
|
||||||
globalNotificationSys.PutBucketObjectLockConfig(ctx, bucket, ret)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure to add Location information here only for bucket
|
// Make sure to add Location information here only for bucket
|
||||||
@ -933,7 +908,7 @@ func (api objectAPIHandlers) DeleteBucketHandler(w http.ResponseWriter, r *http.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := globalBucketObjectLockConfig.Get(bucket); ok && forceDelete {
|
if _, ok := globalBucketObjectLockSys.Get(bucket); ok && forceDelete {
|
||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -949,15 +924,12 @@ func (api objectAPIHandlers) DeleteBucketHandler(w http.ResponseWriter, r *http.
|
|||||||
if globalDNSConfig != nil {
|
if globalDNSConfig != nil {
|
||||||
if err := globalDNSConfig.Delete(bucket); err != nil {
|
if err := globalDNSConfig.Delete(bucket); err != nil {
|
||||||
// Deleting DNS entry failed, attempt to create the bucket again.
|
// Deleting DNS entry failed, attempt to create the bucket again.
|
||||||
objectAPI.MakeBucketWithLocation(ctx, bucket, "")
|
objectAPI.MakeBucketWithLocation(ctx, bucket, "", false)
|
||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete metadata, only log errors.
|
|
||||||
logger.LogIf(ctx, newBucketMetadata(bucket).delete(ctx, objectAPI))
|
|
||||||
|
|
||||||
globalNotificationSys.DeleteBucket(ctx, bucket)
|
globalNotificationSys.DeleteBucket(ctx, bucket)
|
||||||
|
|
||||||
// Write success response.
|
// Write success response.
|
||||||
@ -1041,6 +1013,7 @@ func (api objectAPIHandlers) PutBucketObjectLockConfigHandler(w http.ResponseWri
|
|||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config, err := objectlock.ParseObjectLockConfig(r.Body)
|
config, err := objectlock.ParseObjectLockConfig(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiErr := errorCodes.ToAPIErr(ErrMalformedXML)
|
apiErr := errorCodes.ToAPIErr(ErrMalformedXML)
|
||||||
@ -1049,32 +1022,17 @@ func (api objectAPIHandlers) PutBucketObjectLockConfigHandler(w http.ResponseWri
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := loadBucketMetadata(ctx, objectAPI, bucket)
|
if err = objectAPI.SetBucketObjectLockConfig(ctx, bucket, config); err != nil {
|
||||||
if err != nil {
|
|
||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !meta.LockEnabled {
|
|
||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrObjectLockConfigurationNotAllowed), r.URL, guessIsBrowserReq(r))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := xml.Marshal(config)
|
|
||||||
if err != nil {
|
|
||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
configFile := path.Join(bucketConfigPrefix, bucket, objectLockConfig)
|
|
||||||
if err = saveConfig(ctx, objectAPI, configFile, data); err != nil {
|
|
||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if config.Rule != nil {
|
if config.Rule != nil {
|
||||||
retention := config.ToRetention()
|
retention := config.ToRetention()
|
||||||
globalBucketObjectLockConfig.Set(bucket, retention)
|
globalBucketObjectLockSys.Set(bucket, retention)
|
||||||
globalNotificationSys.PutBucketObjectLockConfig(ctx, bucket, retention)
|
globalNotificationSys.PutBucketObjectLockConfig(ctx, bucket, retention)
|
||||||
} else {
|
} else {
|
||||||
globalBucketObjectLockConfig.Set(bucket, &objectlock.Retention{})
|
globalBucketObjectLockSys.Set(bucket, &objectlock.Retention{})
|
||||||
globalNotificationSys.PutBucketObjectLockConfig(ctx, bucket, &objectlock.Retention{})
|
globalNotificationSys.PutBucketObjectLockConfig(ctx, bucket, &objectlock.Retention{})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1106,28 +1064,16 @@ func (api objectAPIHandlers) GetBucketObjectLockConfigHandler(w http.ResponseWri
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := loadBucketMetadata(ctx, objectAPI, bucket)
|
lkCfg, err := objectAPI.GetBucketObjectLockConfig(ctx, bucket)
|
||||||
if err != nil && err != errMetaDataConverted {
|
if err != nil {
|
||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !meta.LockEnabled {
|
|
||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrObjectLockConfigurationNotAllowed), r.URL, guessIsBrowserReq(r))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
configFile := path.Join(bucketConfigPrefix, bucket, objectLockConfig)
|
configData, err := xml.Marshal(lkCfg)
|
||||||
configData, err := readConfig(ctx, objectAPI, configFile)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != errConfigNotFound {
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if configData, err = xml.Marshal(objectlock.NewObjectLockConfig()); err != nil {
|
|
||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write success response.
|
// Write success response.
|
||||||
@ -1154,6 +1100,7 @@ func (api objectAPIHandlers) PutBucketTaggingHandler(w http.ResponseWriter, r *h
|
|||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tags, err := tags.ParseBucketXML(io.LimitReader(r.Body, r.ContentLength))
|
tags, err := tags.ParseBucketXML(io.LimitReader(r.Body, r.ContentLength))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiErr := errorCodes.ToAPIErr(ErrMalformedXML)
|
apiErr := errorCodes.ToAPIErr(ErrMalformedXML)
|
||||||
@ -1161,13 +1108,8 @@ func (api objectAPIHandlers) PutBucketTaggingHandler(w http.ResponseWriter, r *h
|
|||||||
writeErrorResponse(ctx, w, apiErr, r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, apiErr, r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data, err := xml.Marshal(tags)
|
|
||||||
if err != nil {
|
if err = objectAPI.SetBucketTagging(ctx, bucket, tags); err != nil {
|
||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
configFile := path.Join(bucketConfigPrefix, bucket, bucketTaggingConfigFile)
|
|
||||||
if err = saveConfig(ctx, objectAPI, configFile, data); err != nil {
|
|
||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1191,21 +1133,22 @@ func (api objectAPIHandlers) GetBucketTaggingHandler(w http.ResponseWriter, r *h
|
|||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if user has permissions to perform this operation
|
// check if user has permissions to perform this operation
|
||||||
if s3Error := checkRequestAuthType(ctx, r, policy.GetBucketTaggingAction, bucket, ""); s3Error != ErrNone {
|
if s3Error := checkRequestAuthType(ctx, r, policy.GetBucketTaggingAction, bucket, ""); s3Error != ErrNone {
|
||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
configFile := path.Join(bucketConfigPrefix, bucket, bucketTaggingConfigFile)
|
|
||||||
configData, err := readConfig(ctx, objectAPI, configFile)
|
t, err := objectAPI.GetBucketTagging(ctx, bucket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var aerr APIError
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
||||||
if err == errConfigNotFound {
|
return
|
||||||
aerr = errorCodes.ToAPIErr(ErrBucketTaggingNotFound)
|
}
|
||||||
} else {
|
|
||||||
aerr = toAPIError(ctx, err)
|
configData, err := xml.Marshal(t)
|
||||||
}
|
if err != nil {
|
||||||
writeErrorResponse(ctx, w, aerr, r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1234,8 +1177,7 @@ func (api objectAPIHandlers) DeleteBucketTaggingHandler(w http.ResponseWriter, r
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
configFile := path.Join(bucketConfigPrefix, bucket, bucketTaggingConfigFile)
|
if err := objectAPI.DeleteBucketTagging(ctx, bucket); err != nil {
|
||||||
if err := deleteConfig(ctx, objectAPI, configFile); err != nil && err != errConfigNotFound {
|
|
||||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -154,14 +154,12 @@ func (b *bucketMetadata) save(ctx context.Context, o ObjectLayer) error {
|
|||||||
return saveConfig(ctx, o, configFile, data)
|
return saveConfig(ctx, o, configFile, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete the config metadata.
|
// removeBucketMeta bucket metadata.
|
||||||
// If config does not exist no error is returned.
|
// If config does not exist no error is returned.
|
||||||
func (b bucketMetadata) delete(ctx context.Context, o ObjectLayer) error {
|
func removeBucketMeta(ctx context.Context, obj ObjectLayer, bucket string) error {
|
||||||
configFile := path.Join(bucketConfigPrefix, b.Name, bucketMetadataFile)
|
configFile := path.Join(bucketConfigPrefix, bucket, bucketMetadataFile)
|
||||||
err := deleteConfig(ctx, o, configFile)
|
if err := deleteConfig(ctx, obj, configFile); err != nil && err != errConfigNotFound {
|
||||||
if err == errConfigNotFound {
|
return err
|
||||||
// We don't care
|
|
||||||
err = nil
|
|
||||||
}
|
}
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,12 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/xml"
|
||||||
"errors"
|
"errors"
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
"github.com/minio/minio/pkg/auth"
|
"github.com/minio/minio/pkg/auth"
|
||||||
@ -30,6 +32,54 @@ import (
|
|||||||
"github.com/minio/minio/pkg/bucket/policy"
|
"github.com/minio/minio/pkg/bucket/policy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// BucketObjectLockSys - map of bucket and retention configuration.
|
||||||
|
type BucketObjectLockSys struct {
|
||||||
|
sync.RWMutex
|
||||||
|
retentionMap map[string]*objectlock.Retention
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set - set retention configuration.
|
||||||
|
func (sys *BucketObjectLockSys) Set(bucketName string, retention *objectlock.Retention) {
|
||||||
|
if globalIsGateway {
|
||||||
|
// no-op
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sys.Lock()
|
||||||
|
sys.retentionMap[bucketName] = retention
|
||||||
|
sys.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get - Get retention configuration.
|
||||||
|
func (sys *BucketObjectLockSys) Get(bucketName string) (r *objectlock.Retention, ok bool) {
|
||||||
|
if globalIsGateway {
|
||||||
|
// When gateway is enabled, no cached value
|
||||||
|
// is used to validate bucket object lock configuration
|
||||||
|
objAPI := newObjectLayerWithoutSafeModeFn()
|
||||||
|
if objAPI == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lc, err := objAPI.GetBucketObjectLockConfig(GlobalContext, bucketName)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return lc.ToRetention(), true
|
||||||
|
}
|
||||||
|
|
||||||
|
sys.RLock()
|
||||||
|
defer sys.RUnlock()
|
||||||
|
r, ok = sys.retentionMap[bucketName]
|
||||||
|
return r, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove - removes retention sysuration.
|
||||||
|
func (sys *BucketObjectLockSys) Remove(bucketName string) {
|
||||||
|
sys.Lock()
|
||||||
|
delete(sys.retentionMap, bucketName)
|
||||||
|
sys.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
// Similar to enforceRetentionBypassForDelete but for WebUI
|
// Similar to enforceRetentionBypassForDelete but for WebUI
|
||||||
func enforceRetentionBypassForDeleteWeb(ctx context.Context, r *http.Request, bucket, object string, getObjectInfoFn GetObjectInfoFn, govBypassPerms bool) APIErrorCode {
|
func enforceRetentionBypassForDeleteWeb(ctx context.Context, r *http.Request, bucket, object string, getObjectInfoFn GetObjectInfoFn, govBypassPerms bool) APIErrorCode {
|
||||||
opts, err := getOpts(ctx, r, bucket, object)
|
opts, err := getOpts(ctx, r, bucket, object)
|
||||||
@ -295,7 +345,7 @@ func checkPutObjectLockAllowed(ctx context.Context, r *http.Request, bucket, obj
|
|||||||
retentionRequested := objectlock.IsObjectLockRetentionRequested(r.Header)
|
retentionRequested := objectlock.IsObjectLockRetentionRequested(r.Header)
|
||||||
legalHoldRequested := objectlock.IsObjectLockLegalHoldRequested(r.Header)
|
legalHoldRequested := objectlock.IsObjectLockLegalHoldRequested(r.Header)
|
||||||
|
|
||||||
retentionCfg, isWORMBucket := globalBucketObjectLockConfig.Get(bucket)
|
retentionCfg, isWORMBucket := globalBucketObjectLockSys.Get(bucket)
|
||||||
if !isWORMBucket {
|
if !isWORMBucket {
|
||||||
if legalHoldRequested || retentionRequested {
|
if legalHoldRequested || retentionRequested {
|
||||||
return mode, retainDate, legalHold, ErrInvalidBucketObjectLockConfiguration
|
return mode, retainDate, legalHold, ErrInvalidBucketObjectLockConfiguration
|
||||||
@ -378,7 +428,74 @@ func checkPutObjectLockAllowed(ctx context.Context, r *http.Request, bucket, obj
|
|||||||
return mode, retainDate, legalHold, ErrNone
|
return mode, retainDate, legalHold, ErrNone
|
||||||
}
|
}
|
||||||
|
|
||||||
func initBucketObjectLockConfig(buckets []BucketInfo, objAPI ObjectLayer) error {
|
func readBucketObjectLockConfig(ctx context.Context, objAPI ObjectLayer, bucket string) (*objectlock.Config, error) {
|
||||||
|
meta, err := loadBucketMetadata(ctx, objAPI, bucket)
|
||||||
|
if err != nil && err != errMetaDataConverted {
|
||||||
|
return nil, toObjectErr(err, bucket)
|
||||||
|
}
|
||||||
|
if !meta.LockEnabled {
|
||||||
|
return nil, BucketObjectLockConfigNotFound{Bucket: bucket}
|
||||||
|
}
|
||||||
|
configFile := path.Join(bucketConfigPrefix, bucket, objectLockConfig)
|
||||||
|
configData, err := readConfig(ctx, objAPI, configFile)
|
||||||
|
if err != nil {
|
||||||
|
if err != errConfigNotFound {
|
||||||
|
return nil, toObjectErr(err, bucket)
|
||||||
|
}
|
||||||
|
return objectlock.NewObjectLockConfig(), nil
|
||||||
|
}
|
||||||
|
cfg, err := objectlock.ParseObjectLockConfig(bytes.NewReader(configData))
|
||||||
|
if err != nil {
|
||||||
|
return nil, toObjectErr(err, bucket)
|
||||||
|
}
|
||||||
|
return cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveBucketObjectLockConfig(ctx context.Context, objAPI ObjectLayer, bucket string, config *objectlock.Config) error {
|
||||||
|
meta, err := loadBucketMetadata(ctx, objAPI, bucket)
|
||||||
|
if err != nil && err != errMetaDataConverted {
|
||||||
|
return toObjectErr(err, bucket)
|
||||||
|
}
|
||||||
|
if !meta.LockEnabled {
|
||||||
|
return BucketObjectLockConfigNotFound{Bucket: bucket}
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := xml.Marshal(config)
|
||||||
|
if err != nil {
|
||||||
|
return toObjectErr(err, bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
configFile := path.Join(bucketConfigPrefix, bucket, objectLockConfig)
|
||||||
|
if err = saveConfig(ctx, objAPI, configFile, data); err != nil {
|
||||||
|
return toObjectErr(err, bucket)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBucketObjectLockSys returns initialized BucketObjectLockSys
|
||||||
|
func NewBucketObjectLockSys() *BucketObjectLockSys {
|
||||||
|
return &BucketObjectLockSys{
|
||||||
|
retentionMap: make(map[string]*objectlock.Retention),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init - initializes bucket object lock config system for all buckets
|
||||||
|
func (sys *BucketObjectLockSys) Init(buckets []BucketInfo, objAPI ObjectLayer) error {
|
||||||
|
if objAPI == nil {
|
||||||
|
return errServerNotInitialized
|
||||||
|
}
|
||||||
|
|
||||||
|
// In gateway mode, we always fetch the bucket object lock configuration from the gateway backend.
|
||||||
|
// So, this is a no-op for gateway servers.
|
||||||
|
if globalIsGateway {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load BucketObjectLockSys once during boot.
|
||||||
|
return sys.load(buckets, objAPI)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sys *BucketObjectLockSys) load(buckets []BucketInfo, objAPI ObjectLayer) error {
|
||||||
for _, bucket := range buckets {
|
for _, bucket := range buckets {
|
||||||
ctx := logger.SetReqInfo(GlobalContext, &logger.ReqInfo{BucketName: bucket.Name})
|
ctx := logger.SetReqInfo(GlobalContext, &logger.ReqInfo{BucketName: bucket.Name})
|
||||||
meta, err := loadBucketMetadata(ctx, objAPI, bucket.Name)
|
meta, err := loadBucketMetadata(ctx, objAPI, bucket.Name)
|
||||||
@ -398,7 +515,7 @@ func initBucketObjectLockConfig(buckets []BucketInfo, objAPI ObjectLayer) error
|
|||||||
configData, err := readConfig(ctx, objAPI, configFile)
|
configData, err := readConfig(ctx, objAPI, configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, errConfigNotFound) {
|
if errors.Is(err, errConfigNotFound) {
|
||||||
globalBucketObjectLockConfig.Set(bucket.Name, &objectlock.Retention{})
|
globalBucketObjectLockSys.Set(bucket.Name, &objectlock.Retention{})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
@ -412,7 +529,7 @@ func initBucketObjectLockConfig(buckets []BucketInfo, objAPI ObjectLayer) error
|
|||||||
if config.Rule != nil {
|
if config.Rule != nil {
|
||||||
retention = config.ToRetention()
|
retention = config.ToRetention()
|
||||||
}
|
}
|
||||||
globalBucketObjectLockConfig.Set(bucket.Name, retention)
|
globalBucketObjectLockSys.Set(bucket.Name, retention)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ func testPutBucketPolicyHandler(obj ObjectLayer, instanceType, bucketName string
|
|||||||
credentials auth.Credentials, t *testing.T) {
|
credentials auth.Credentials, t *testing.T) {
|
||||||
|
|
||||||
bucketName1 := fmt.Sprintf("%s-1", bucketName)
|
bucketName1 := fmt.Sprintf("%s-1", bucketName)
|
||||||
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName1, ""); err != nil {
|
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName1, "", false); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +198,7 @@ func enforceFIFOQuota(ctx context.Context, objectAPI ObjectLayer) error {
|
|||||||
if cfg.Type != madmin.FIFOQuota {
|
if cfg.Type != madmin.FIFOQuota {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, bucketHasLockConfig := globalBucketObjectLockConfig.Get(bucket)
|
_, bucketHasLockConfig := globalBucketObjectLockSys.Get(bucket)
|
||||||
|
|
||||||
dataUsageInfo, err := loadDataUsageFromBackend(ctx, objectAPI)
|
dataUsageInfo, err := loadDataUsageFromBackend(ctx, objectAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
61
cmd/bucket-tagging.go
Normal file
61
cmd/bucket-tagging.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* MinIO Cloud Storage, (C) 2020 MinIO, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/xml"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/minio/minio-go/v6/pkg/tags"
|
||||||
|
)
|
||||||
|
|
||||||
|
func saveBucketTagging(ctx context.Context, objAPI ObjectLayer, bucket string, t *tags.Tags) error {
|
||||||
|
data, err := xml.Marshal(t)
|
||||||
|
if err != nil {
|
||||||
|
return toObjectErr(err, bucket)
|
||||||
|
}
|
||||||
|
configFile := path.Join(bucketConfigPrefix, bucket, bucketTaggingConfigFile)
|
||||||
|
if err := saveConfig(ctx, objAPI, configFile, data); err != nil {
|
||||||
|
return toObjectErr(err, bucket)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteBucketTagging(ctx context.Context, objAPI ObjectLayer, bucket string) error {
|
||||||
|
configFile := path.Join(bucketConfigPrefix, bucket, bucketTaggingConfigFile)
|
||||||
|
if err := deleteConfig(ctx, objAPI, configFile); err != nil && err != errConfigNotFound {
|
||||||
|
return toObjectErr(err, bucket)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readBucketTagging(ctx context.Context, objAPI ObjectLayer, bucket string) (*tags.Tags, error) {
|
||||||
|
configFile := path.Join(bucketConfigPrefix, bucket, bucketTaggingConfigFile)
|
||||||
|
configData, err := readConfig(ctx, objAPI, configFile)
|
||||||
|
if err != nil {
|
||||||
|
if err == errConfigNotFound {
|
||||||
|
return nil, BucketTaggingNotFound{Bucket: bucket}
|
||||||
|
}
|
||||||
|
return nil, toObjectErr(err, bucket)
|
||||||
|
}
|
||||||
|
t := &tags.Tags{}
|
||||||
|
if err = xml.Unmarshal(configData, t); err != nil {
|
||||||
|
return nil, toObjectErr(err, bucket)
|
||||||
|
}
|
||||||
|
return t, nil
|
||||||
|
}
|
@ -63,7 +63,7 @@ func lifecycleRound(ctx context.Context, objAPI ObjectLayer) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
_, bucketHasLockConfig := globalBucketObjectLockConfig.Get(bucket.Name)
|
_, bucketHasLockConfig := globalBucketObjectLockSys.Get(bucket.Name)
|
||||||
|
|
||||||
// Calculate the common prefix of all lifecycle rules
|
// Calculate the common prefix of all lifecycle rules
|
||||||
var prefixes []string
|
var prefixes []string
|
||||||
|
@ -53,7 +53,7 @@ func TestReadFSMetadata(t *testing.T) {
|
|||||||
bucketName := "bucket"
|
bucketName := "bucket"
|
||||||
objectName := "object"
|
objectName := "object"
|
||||||
|
|
||||||
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, ""); err != nil {
|
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false); err != nil {
|
||||||
t.Fatal("Unexpected err: ", err)
|
t.Fatal("Unexpected err: ", err)
|
||||||
}
|
}
|
||||||
if _, err := obj.PutObject(GlobalContext, bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{}); err != nil {
|
if _, err := obj.PutObject(GlobalContext, bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{}); err != nil {
|
||||||
@ -88,7 +88,7 @@ func TestWriteFSMetadata(t *testing.T) {
|
|||||||
bucketName := "bucket"
|
bucketName := "bucket"
|
||||||
objectName := "object"
|
objectName := "object"
|
||||||
|
|
||||||
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, ""); err != nil {
|
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false); err != nil {
|
||||||
t.Fatal("Unexpected err: ", err)
|
t.Fatal("Unexpected err: ", err)
|
||||||
}
|
}
|
||||||
if _, err := obj.PutObject(GlobalContext, bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{}); err != nil {
|
if _, err := obj.PutObject(GlobalContext, bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{}); err != nil {
|
||||||
|
@ -40,7 +40,7 @@ func TestFSCleanupMultipartUploadsInRoutine(t *testing.T) {
|
|||||||
|
|
||||||
// Create a context we can cancel.
|
// Create a context we can cancel.
|
||||||
ctx, cancel := context.WithCancel(GlobalContext)
|
ctx, cancel := context.WithCancel(GlobalContext)
|
||||||
obj.MakeBucketWithLocation(ctx, bucketName, "")
|
obj.MakeBucketWithLocation(ctx, bucketName, "", false)
|
||||||
|
|
||||||
uploadID, err := obj.NewMultipartUpload(ctx, bucketName, objectName, ObjectOptions{})
|
uploadID, err := obj.NewMultipartUpload(ctx, bucketName, objectName, ObjectOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -81,7 +81,7 @@ func TestNewMultipartUploadFaultyDisk(t *testing.T) {
|
|||||||
bucketName := "bucket"
|
bucketName := "bucket"
|
||||||
objectName := "object"
|
objectName := "object"
|
||||||
|
|
||||||
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, ""); err != nil {
|
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false); err != nil {
|
||||||
t.Fatal("Cannot create bucket, err: ", err)
|
t.Fatal("Cannot create bucket, err: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ func TestPutObjectPartFaultyDisk(t *testing.T) {
|
|||||||
data := []byte("12345")
|
data := []byte("12345")
|
||||||
dataLen := int64(len(data))
|
dataLen := int64(len(data))
|
||||||
|
|
||||||
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, ""); err != nil {
|
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false); err != nil {
|
||||||
t.Fatal("Cannot create bucket, err: ", err)
|
t.Fatal("Cannot create bucket, err: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +139,7 @@ func TestCompleteMultipartUploadFaultyDisk(t *testing.T) {
|
|||||||
objectName := "object"
|
objectName := "object"
|
||||||
data := []byte("12345")
|
data := []byte("12345")
|
||||||
|
|
||||||
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, ""); err != nil {
|
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false); err != nil {
|
||||||
t.Fatal("Cannot create bucket, err: ", err)
|
t.Fatal("Cannot create bucket, err: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ func TestCompleteMultipartUpload(t *testing.T) {
|
|||||||
objectName := "object"
|
objectName := "object"
|
||||||
data := []byte("12345")
|
data := []byte("12345")
|
||||||
|
|
||||||
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, ""); err != nil {
|
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false); err != nil {
|
||||||
t.Fatal("Cannot create bucket, err: ", err)
|
t.Fatal("Cannot create bucket, err: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ func TestAbortMultipartUpload(t *testing.T) {
|
|||||||
objectName := "object"
|
objectName := "object"
|
||||||
data := []byte("12345")
|
data := []byte("12345")
|
||||||
|
|
||||||
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, ""); err != nil {
|
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false); err != nil {
|
||||||
t.Fatal("Cannot create bucket, err: ", err)
|
t.Fatal("Cannot create bucket, err: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,7 +235,7 @@ func TestListMultipartUploadsFaultyDisk(t *testing.T) {
|
|||||||
bucketName := "bucket"
|
bucketName := "bucket"
|
||||||
objectName := "object"
|
objectName := "object"
|
||||||
|
|
||||||
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, ""); err != nil {
|
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false); err != nil {
|
||||||
t.Fatal("Cannot create bucket, err: ", err)
|
t.Fatal("Cannot create bucket, err: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
84
cmd/fs-v1.go
84
cmd/fs-v1.go
@ -41,6 +41,7 @@ import (
|
|||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
bucketsse "github.com/minio/minio/pkg/bucket/encryption"
|
bucketsse "github.com/minio/minio/pkg/bucket/encryption"
|
||||||
"github.com/minio/minio/pkg/bucket/lifecycle"
|
"github.com/minio/minio/pkg/bucket/lifecycle"
|
||||||
|
objectlock "github.com/minio/minio/pkg/bucket/object/lock"
|
||||||
"github.com/minio/minio/pkg/bucket/policy"
|
"github.com/minio/minio/pkg/bucket/policy"
|
||||||
"github.com/minio/minio/pkg/color"
|
"github.com/minio/minio/pkg/color"
|
||||||
"github.com/minio/minio/pkg/lock"
|
"github.com/minio/minio/pkg/lock"
|
||||||
@ -314,12 +315,17 @@ func (fs *FSObjects) statBucketDir(ctx context.Context, bucket string) (os.FileI
|
|||||||
|
|
||||||
// MakeBucketWithLocation - create a new bucket, returns if it
|
// MakeBucketWithLocation - create a new bucket, returns if it
|
||||||
// already exists.
|
// already exists.
|
||||||
func (fs *FSObjects) MakeBucketWithLocation(ctx context.Context, bucket, location string) error {
|
func (fs *FSObjects) MakeBucketWithLocation(ctx context.Context, bucket, location string, lockEnabled bool) error {
|
||||||
|
if lockEnabled {
|
||||||
|
return NotImplemented{}
|
||||||
|
}
|
||||||
|
|
||||||
bucketLock := fs.NewNSLock(ctx, bucket, "")
|
bucketLock := fs.NewNSLock(ctx, bucket, "")
|
||||||
if err := bucketLock.GetLock(globalObjectTimeout); err != nil {
|
if err := bucketLock.GetLock(globalObjectTimeout); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer bucketLock.Unlock()
|
defer bucketLock.Unlock()
|
||||||
|
|
||||||
// Verify if bucket is valid.
|
// Verify if bucket is valid.
|
||||||
if s3utils.CheckValidBucketNameStrict(bucket) != nil {
|
if s3utils.CheckValidBucketNameStrict(bucket) != nil {
|
||||||
return BucketNameInvalid{Bucket: bucket}
|
return BucketNameInvalid{Bucket: bucket}
|
||||||
@ -339,6 +345,12 @@ func (fs *FSObjects) MakeBucketWithLocation(ctx context.Context, bucket, locatio
|
|||||||
return toObjectErr(err, bucket)
|
return toObjectErr(err, bucket)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
meta := newBucketMetadata(bucket)
|
||||||
|
meta.LockEnabled = false
|
||||||
|
if err := meta.save(ctx, fs); err != nil {
|
||||||
|
return toObjectErr(err, bucket)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,7 +393,7 @@ func (fs *FSObjects) ListBuckets(ctx context.Context) ([]BucketInfo, error) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
var bucketInfos []BucketInfo
|
var bucketInfos []BucketInfo
|
||||||
entries, err := readDir((fs.fsPath))
|
entries, err := readDir(fs.fsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.LogIf(ctx, errDiskNotFound)
|
logger.LogIf(ctx, errDiskNotFound)
|
||||||
return nil, toObjectErr(errDiskNotFound)
|
return nil, toObjectErr(errDiskNotFound)
|
||||||
@ -402,10 +414,17 @@ func (fs *FSObjects) ListBuckets(ctx context.Context) ([]BucketInfo, error) {
|
|||||||
// Ignore any errors returned here.
|
// Ignore any errors returned here.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
var created = fi.ModTime()
|
||||||
|
meta, err := loadBucketMetadata(ctx, fs, fi.Name())
|
||||||
|
if err == nil {
|
||||||
|
created = meta.Created
|
||||||
|
}
|
||||||
|
if err != errMetaDataConverted {
|
||||||
|
logger.LogIf(ctx, err)
|
||||||
|
}
|
||||||
bucketInfos = append(bucketInfos, BucketInfo{
|
bucketInfos = append(bucketInfos, BucketInfo{
|
||||||
Name: fi.Name(),
|
Name: fi.Name(),
|
||||||
// As os.Stat() doesnt carry CreatedTime, use ModTime() as CreatedTime.
|
Created: created,
|
||||||
Created: fi.ModTime(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -644,12 +663,12 @@ func (fs *FSObjects) GetObject(ctx context.Context, bucket, object string, offse
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lock the object before reading.
|
// Lock the object before reading.
|
||||||
objectLock := fs.NewNSLock(ctx, bucket, object)
|
lk := fs.NewNSLock(ctx, bucket, object)
|
||||||
if err := objectLock.GetRLock(globalObjectTimeout); err != nil {
|
if err := lk.GetRLock(globalObjectTimeout); err != nil {
|
||||||
logger.LogIf(ctx, err)
|
logger.LogIf(ctx, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer objectLock.RUnlock()
|
defer lk.RUnlock()
|
||||||
|
|
||||||
atomic.AddInt64(&fs.activeIOCount, 1)
|
atomic.AddInt64(&fs.activeIOCount, 1)
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -818,11 +837,11 @@ func (fs *FSObjects) getObjectInfo(ctx context.Context, bucket, object string) (
|
|||||||
// getObjectInfoWithLock - reads object metadata and replies back ObjectInfo.
|
// getObjectInfoWithLock - reads object metadata and replies back ObjectInfo.
|
||||||
func (fs *FSObjects) getObjectInfoWithLock(ctx context.Context, bucket, object string) (oi ObjectInfo, e error) {
|
func (fs *FSObjects) getObjectInfoWithLock(ctx context.Context, bucket, object string) (oi ObjectInfo, e error) {
|
||||||
// Lock the object before reading.
|
// Lock the object before reading.
|
||||||
objectLock := fs.NewNSLock(ctx, bucket, object)
|
lk := fs.NewNSLock(ctx, bucket, object)
|
||||||
if err := objectLock.GetRLock(globalObjectTimeout); err != nil {
|
if err := lk.GetRLock(globalObjectTimeout); err != nil {
|
||||||
return oi, err
|
return oi, err
|
||||||
}
|
}
|
||||||
defer objectLock.RUnlock()
|
defer lk.RUnlock()
|
||||||
|
|
||||||
if err := checkGetObjArgs(ctx, bucket, object); err != nil {
|
if err := checkGetObjArgs(ctx, bucket, object); err != nil {
|
||||||
return oi, err
|
return oi, err
|
||||||
@ -849,14 +868,14 @@ func (fs *FSObjects) GetObjectInfo(ctx context.Context, bucket, object string, o
|
|||||||
|
|
||||||
oi, err := fs.getObjectInfoWithLock(ctx, bucket, object)
|
oi, err := fs.getObjectInfoWithLock(ctx, bucket, object)
|
||||||
if err == errCorruptedFormat || err == io.EOF {
|
if err == errCorruptedFormat || err == io.EOF {
|
||||||
objectLock := fs.NewNSLock(ctx, bucket, object)
|
lk := fs.NewNSLock(ctx, bucket, object)
|
||||||
if err = objectLock.GetLock(globalObjectTimeout); err != nil {
|
if err = lk.GetLock(globalObjectTimeout); err != nil {
|
||||||
return oi, toObjectErr(err, bucket, object)
|
return oi, toObjectErr(err, bucket, object)
|
||||||
}
|
}
|
||||||
|
|
||||||
fsMetaPath := pathJoin(fs.fsPath, minioMetaBucket, bucketMetaPrefix, bucket, object, fs.metaJSONFile)
|
fsMetaPath := pathJoin(fs.fsPath, minioMetaBucket, bucketMetaPrefix, bucket, object, fs.metaJSONFile)
|
||||||
err = fs.createFsJSON(object, fsMetaPath)
|
err = fs.createFsJSON(object, fsMetaPath)
|
||||||
objectLock.Unlock()
|
lk.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return oi, toObjectErr(err, bucket, object)
|
return oi, toObjectErr(err, bucket, object)
|
||||||
}
|
}
|
||||||
@ -896,12 +915,12 @@ func (fs *FSObjects) PutObject(ctx context.Context, bucket string, object string
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lock the object.
|
// Lock the object.
|
||||||
objectLock := fs.NewNSLock(ctx, bucket, object)
|
lk := fs.NewNSLock(ctx, bucket, object)
|
||||||
if err := objectLock.GetLock(globalObjectTimeout); err != nil {
|
if err := lk.GetLock(globalObjectTimeout); err != nil {
|
||||||
logger.LogIf(ctx, err)
|
logger.LogIf(ctx, err)
|
||||||
return objInfo, err
|
return objInfo, err
|
||||||
}
|
}
|
||||||
defer objectLock.Unlock()
|
defer lk.Unlock()
|
||||||
defer ObjectPathUpdated(path.Join(bucket, object))
|
defer ObjectPathUpdated(path.Join(bucket, object))
|
||||||
|
|
||||||
atomic.AddInt64(&fs.activeIOCount, 1)
|
atomic.AddInt64(&fs.activeIOCount, 1)
|
||||||
@ -1051,11 +1070,11 @@ func (fs *FSObjects) DeleteObjects(ctx context.Context, bucket string, objects [
|
|||||||
// and there are no rollbacks supported.
|
// and there are no rollbacks supported.
|
||||||
func (fs *FSObjects) DeleteObject(ctx context.Context, bucket, object string) error {
|
func (fs *FSObjects) DeleteObject(ctx context.Context, bucket, object string) error {
|
||||||
// Acquire a write lock before deleting the object.
|
// Acquire a write lock before deleting the object.
|
||||||
objectLock := fs.NewNSLock(ctx, bucket, object)
|
lk := fs.NewNSLock(ctx, bucket, object)
|
||||||
if err := objectLock.GetLock(globalOperationTimeout); err != nil {
|
if err := lk.GetLock(globalOperationTimeout); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer objectLock.Unlock()
|
defer lk.Unlock()
|
||||||
|
|
||||||
if err := checkDelObjArgs(ctx, bucket, object); err != nil {
|
if err := checkDelObjArgs(ctx, bucket, object); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -1364,6 +1383,31 @@ func (fs *FSObjects) DeleteBucketSSEConfig(ctx context.Context, bucket string) e
|
|||||||
return removeBucketSSEConfig(ctx, fs, bucket)
|
return removeBucketSSEConfig(ctx, fs, bucket)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetBucketObjectLockConfig enables/clears default object lock configuration
|
||||||
|
func (fs *FSObjects) SetBucketObjectLockConfig(ctx context.Context, bucket string, config *objectlock.Config) error {
|
||||||
|
return saveBucketObjectLockConfig(ctx, fs, bucket, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBucketObjectLockConfig - returns current defaults for object lock configuration
|
||||||
|
func (fs *FSObjects) GetBucketObjectLockConfig(ctx context.Context, bucket string) (*objectlock.Config, error) {
|
||||||
|
return readBucketObjectLockConfig(ctx, fs, bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBucketTagging sets bucket tags on given bucket
|
||||||
|
func (fs *FSObjects) SetBucketTagging(ctx context.Context, bucket string, t *tags.Tags) error {
|
||||||
|
return saveBucketTagging(ctx, fs, bucket, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBucketTagging get bucket tags set on given bucket
|
||||||
|
func (fs *FSObjects) GetBucketTagging(ctx context.Context, bucket string) (*tags.Tags, error) {
|
||||||
|
return readBucketTagging(ctx, fs, bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBucketTagging delete bucket tags set if any.
|
||||||
|
func (fs *FSObjects) DeleteBucketTagging(ctx context.Context, bucket string) error {
|
||||||
|
return deleteBucketTagging(ctx, fs, bucket)
|
||||||
|
}
|
||||||
|
|
||||||
// ListObjectsV2 lists all blobs in bucket filtered by prefix
|
// ListObjectsV2 lists all blobs in bucket filtered by prefix
|
||||||
func (fs *FSObjects) ListObjectsV2(ctx context.Context, bucket, prefix, continuationToken, delimiter string, maxKeys int, fetchOwner bool, startAfter string) (result ListObjectsV2Info, err error) {
|
func (fs *FSObjects) ListObjectsV2(ctx context.Context, bucket, prefix, continuationToken, delimiter string, maxKeys int, fetchOwner bool, startAfter string) (result ListObjectsV2Info, err error) {
|
||||||
marker := continuationToken
|
marker := continuationToken
|
||||||
|
@ -36,7 +36,7 @@ func TestFSParentDirIsObject(t *testing.T) {
|
|||||||
bucketName := "testbucket"
|
bucketName := "testbucket"
|
||||||
objectName := "object"
|
objectName := "object"
|
||||||
|
|
||||||
if err = obj.MakeBucketWithLocation(GlobalContext, bucketName, ""); err != nil {
|
if err = obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
objectContent := "12345"
|
objectContent := "12345"
|
||||||
@ -124,7 +124,7 @@ func TestFSShutdown(t *testing.T) {
|
|||||||
fs := obj.(*FSObjects)
|
fs := obj.(*FSObjects)
|
||||||
|
|
||||||
objectContent := "12345"
|
objectContent := "12345"
|
||||||
obj.MakeBucketWithLocation(GlobalContext, bucketName, "")
|
obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false)
|
||||||
obj.PutObject(GlobalContext, bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte(objectContent)), int64(len(objectContent)), "", ""), ObjectOptions{})
|
obj.PutObject(GlobalContext, bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte(objectContent)), int64(len(objectContent)), "", ""), ObjectOptions{})
|
||||||
return fs, disk
|
return fs, disk
|
||||||
}
|
}
|
||||||
@ -155,12 +155,12 @@ func TestFSGetBucketInfo(t *testing.T) {
|
|||||||
fs := obj.(*FSObjects)
|
fs := obj.(*FSObjects)
|
||||||
bucketName := "bucket"
|
bucketName := "bucket"
|
||||||
|
|
||||||
err := obj.MakeBucketWithLocation(GlobalContext, "a", "")
|
err := obj.MakeBucketWithLocation(GlobalContext, "a", "", false)
|
||||||
if !isSameType(err, BucketNameInvalid{}) {
|
if !isSameType(err, BucketNameInvalid{}) {
|
||||||
t.Fatal("BucketNameInvalid error not returned")
|
t.Fatal("BucketNameInvalid error not returned")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = obj.MakeBucketWithLocation(GlobalContext, bucketName, "")
|
err = obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -199,7 +199,7 @@ func TestFSPutObject(t *testing.T) {
|
|||||||
bucketName := "bucket"
|
bucketName := "bucket"
|
||||||
objectName := "1/2/3/4/object"
|
objectName := "1/2/3/4/object"
|
||||||
|
|
||||||
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, ""); err != nil {
|
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,7 +267,7 @@ func TestFSDeleteObject(t *testing.T) {
|
|||||||
bucketName := "bucket"
|
bucketName := "bucket"
|
||||||
objectName := "object"
|
objectName := "object"
|
||||||
|
|
||||||
obj.MakeBucketWithLocation(GlobalContext, bucketName, "")
|
obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false)
|
||||||
obj.PutObject(GlobalContext, bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{})
|
obj.PutObject(GlobalContext, bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{})
|
||||||
|
|
||||||
// Test with invalid bucket name
|
// Test with invalid bucket name
|
||||||
@ -311,7 +311,7 @@ func TestFSDeleteBucket(t *testing.T) {
|
|||||||
fs := obj.(*FSObjects)
|
fs := obj.(*FSObjects)
|
||||||
bucketName := "bucket"
|
bucketName := "bucket"
|
||||||
|
|
||||||
err := obj.MakeBucketWithLocation(GlobalContext, bucketName, "")
|
err := obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Unexpected error: ", err)
|
t.Fatal("Unexpected error: ", err)
|
||||||
}
|
}
|
||||||
@ -330,7 +330,7 @@ func TestFSDeleteBucket(t *testing.T) {
|
|||||||
t.Fatal("Unexpected error: ", err)
|
t.Fatal("Unexpected error: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.MakeBucketWithLocation(GlobalContext, bucketName, "")
|
obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false)
|
||||||
|
|
||||||
// Delete bucket should get error disk not found.
|
// Delete bucket should get error disk not found.
|
||||||
os.RemoveAll(disk)
|
os.RemoveAll(disk)
|
||||||
@ -351,7 +351,7 @@ func TestFSListBuckets(t *testing.T) {
|
|||||||
fs := obj.(*FSObjects)
|
fs := obj.(*FSObjects)
|
||||||
|
|
||||||
bucketName := "bucket"
|
bucketName := "bucket"
|
||||||
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, ""); err != nil {
|
if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false); err != nil {
|
||||||
t.Fatal("Unexpected error: ", err)
|
t.Fatal("Unexpected error: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/minio/minio-go/v6/pkg/tags"
|
"github.com/minio/minio-go/v6/pkg/tags"
|
||||||
bucketsse "github.com/minio/minio/pkg/bucket/encryption"
|
bucketsse "github.com/minio/minio/pkg/bucket/encryption"
|
||||||
"github.com/minio/minio/pkg/bucket/lifecycle"
|
"github.com/minio/minio/pkg/bucket/lifecycle"
|
||||||
|
objectlock "github.com/minio/minio/pkg/bucket/object/lock"
|
||||||
"github.com/minio/minio/pkg/bucket/policy"
|
"github.com/minio/minio/pkg/bucket/policy"
|
||||||
|
|
||||||
"github.com/minio/minio/pkg/madmin"
|
"github.com/minio/minio/pkg/madmin"
|
||||||
@ -198,6 +199,35 @@ func (a GatewayUnsupported) GetMetrics(ctx context.Context) (*Metrics, error) {
|
|||||||
return &Metrics{}, NotImplemented{}
|
return &Metrics{}, NotImplemented{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetBucketTagging - not implemented
|
||||||
|
func (a GatewayUnsupported) SetBucketTagging(ctx context.Context, bucket string, t *tags.Tags) error {
|
||||||
|
logger.LogIf(ctx, NotImplemented{})
|
||||||
|
return NotImplemented{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBucketObjectLockConfig - not implemented
|
||||||
|
func (a GatewayUnsupported) GetBucketObjectLockConfig(ctx context.Context, bucket string) (*objectlock.Config, error) {
|
||||||
|
logger.LogIf(ctx, NotImplemented{})
|
||||||
|
return nil, NotImplemented{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBucketObjectLockConfig - not implemented
|
||||||
|
func (a GatewayUnsupported) SetBucketObjectLockConfig(ctx context.Context, bucket string, _ *objectlock.Config) error {
|
||||||
|
logger.LogIf(ctx, NotImplemented{})
|
||||||
|
return NotImplemented{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBucketTagging - not implemented
|
||||||
|
func (a GatewayUnsupported) GetBucketTagging(ctx context.Context, bucket string) (*tags.Tags, error) {
|
||||||
|
return nil, NotImplemented{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBucketTagging - not implemented.
|
||||||
|
func (a GatewayUnsupported) DeleteBucketTagging(ctx context.Context, bucket string) error {
|
||||||
|
logger.LogIf(ctx, NotImplemented{})
|
||||||
|
return NotImplemented{}
|
||||||
|
}
|
||||||
|
|
||||||
// PutObjectTag - not implemented.
|
// PutObjectTag - not implemented.
|
||||||
func (a GatewayUnsupported) PutObjectTag(ctx context.Context, bucket, object string, tags string) error {
|
func (a GatewayUnsupported) PutObjectTag(ctx context.Context, bucket, object string, tags string) error {
|
||||||
logger.LogIf(ctx, NotImplemented{})
|
logger.LogIf(ctx, NotImplemented{})
|
||||||
|
@ -544,7 +544,11 @@ func (a *azureObjects) StorageInfo(ctx context.Context, _ bool) (si minio.Storag
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MakeBucketWithLocation - Create a new container on azure backend.
|
// MakeBucketWithLocation - Create a new container on azure backend.
|
||||||
func (a *azureObjects) MakeBucketWithLocation(ctx context.Context, bucket, location string) error {
|
func (a *azureObjects) MakeBucketWithLocation(ctx context.Context, bucket, location string, lockEnabled bool) error {
|
||||||
|
if lockEnabled {
|
||||||
|
return minio.NotImplemented{}
|
||||||
|
}
|
||||||
|
|
||||||
// Verify if bucket (container-name) is valid.
|
// Verify if bucket (container-name) is valid.
|
||||||
// IsValidBucketName has same restrictions as container names mentioned
|
// IsValidBucketName has same restrictions as container names mentioned
|
||||||
// in azure documentation, so we will simply use the same function here.
|
// in azure documentation, so we will simply use the same function here.
|
||||||
|
@ -19,13 +19,14 @@ package azure
|
|||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dustin/go-humanize"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/dustin/go-humanize"
|
||||||
|
|
||||||
"github.com/Azure/azure-storage-blob-go/azblob"
|
"github.com/Azure/azure-storage-blob-go/azblob"
|
||||||
minio "github.com/minio/minio/cmd"
|
minio "github.com/minio/minio/cmd"
|
||||||
)
|
)
|
||||||
|
@ -421,7 +421,11 @@ func (l *gcsGateway) StorageInfo(ctx context.Context, _ bool) (si minio.StorageI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MakeBucketWithLocation - Create a new container on GCS backend.
|
// MakeBucketWithLocation - Create a new container on GCS backend.
|
||||||
func (l *gcsGateway) MakeBucketWithLocation(ctx context.Context, bucket, location string) error {
|
func (l *gcsGateway) MakeBucketWithLocation(ctx context.Context, bucket, location string, lockEnabled bool) error {
|
||||||
|
if lockEnabled {
|
||||||
|
return minio.NotImplemented{}
|
||||||
|
}
|
||||||
|
|
||||||
bkt := l.client.Bucket(bucket)
|
bkt := l.client.Bucket(bucket)
|
||||||
|
|
||||||
// we'll default to the us multi-region in case of us-east-1
|
// we'll default to the us multi-region in case of us-east-1
|
||||||
|
@ -281,7 +281,11 @@ func (n *hdfsObjects) DeleteBucket(ctx context.Context, bucket string, forceDele
|
|||||||
return hdfsToObjectErr(ctx, n.clnt.Remove(minio.PathJoin(hdfsSeparator, bucket)), bucket)
|
return hdfsToObjectErr(ctx, n.clnt.Remove(minio.PathJoin(hdfsSeparator, bucket)), bucket)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *hdfsObjects) MakeBucketWithLocation(ctx context.Context, bucket, location string) error {
|
func (n *hdfsObjects) MakeBucketWithLocation(ctx context.Context, bucket, location string, lockEnabled bool) error {
|
||||||
|
if lockEnabled {
|
||||||
|
return minio.NotImplemented{}
|
||||||
|
}
|
||||||
|
|
||||||
if !hdfsIsValidBucketName(bucket) {
|
if !hdfsIsValidBucketName(bucket) {
|
||||||
return minio.BucketNameInvalid{Bucket: bucket}
|
return minio.BucketNameInvalid{Bucket: bucket}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/minio/cli"
|
"github.com/minio/cli"
|
||||||
minio "github.com/minio/minio/cmd"
|
minio "github.com/minio/minio/cmd"
|
||||||
"github.com/minio/minio/pkg/auth"
|
"github.com/minio/minio/pkg/auth"
|
||||||
|
objectlock "github.com/minio/minio/pkg/bucket/object/lock"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -121,6 +122,16 @@ type nasObjects struct {
|
|||||||
minio.ObjectLayer
|
minio.ObjectLayer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBucketObjectLockConfig - not implemented
|
||||||
|
func (n *nasObjects) GetBucketObjectLockConfig(ctx context.Context, bucket string) (*objectlock.Config, error) {
|
||||||
|
return nil, minio.NotImplemented{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBucketObjectLockConfig - not implemented
|
||||||
|
func (n *nasObjects) SetBucketObjectLockConfig(ctx context.Context, bucket string, _ *objectlock.Config) error {
|
||||||
|
return minio.NotImplemented{}
|
||||||
|
}
|
||||||
|
|
||||||
// IsReady returns whether the layer is ready to take requests.
|
// IsReady returns whether the layer is ready to take requests.
|
||||||
func (n *nasObjects) IsReady(ctx context.Context) bool {
|
func (n *nasObjects) IsReady(ctx context.Context) bool {
|
||||||
sinfo := n.ObjectLayer.StorageInfo(ctx, false)
|
sinfo := n.ObjectLayer.StorageInfo(ctx, false)
|
||||||
|
@ -281,7 +281,11 @@ func (l *s3Objects) StorageInfo(ctx context.Context, _ bool) (si minio.StorageIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MakeBucket creates a new container on S3 backend.
|
// MakeBucket creates a new container on S3 backend.
|
||||||
func (l *s3Objects) MakeBucketWithLocation(ctx context.Context, bucket, location string) error {
|
func (l *s3Objects) MakeBucketWithLocation(ctx context.Context, bucket, location string, lockEnabled bool) error {
|
||||||
|
if lockEnabled {
|
||||||
|
return minio.NotImplemented{}
|
||||||
|
}
|
||||||
|
|
||||||
// Verify if bucket name is valid.
|
// Verify if bucket name is valid.
|
||||||
// We are using a separate helper function here to validate bucket
|
// We are using a separate helper function here to validate bucket
|
||||||
// names instead of IsValidBucketName() because there is a possibility
|
// names instead of IsValidBucketName() because there is a possibility
|
||||||
|
@ -35,7 +35,6 @@ import (
|
|||||||
"github.com/minio/minio/cmd/crypto"
|
"github.com/minio/minio/cmd/crypto"
|
||||||
xhttp "github.com/minio/minio/cmd/http"
|
xhttp "github.com/minio/minio/cmd/http"
|
||||||
"github.com/minio/minio/pkg/auth"
|
"github.com/minio/minio/pkg/auth"
|
||||||
objectlock "github.com/minio/minio/pkg/bucket/object/lock"
|
|
||||||
|
|
||||||
"github.com/minio/minio/pkg/certs"
|
"github.com/minio/minio/pkg/certs"
|
||||||
"github.com/minio/minio/pkg/event"
|
"github.com/minio/minio/pkg/event"
|
||||||
@ -216,10 +215,9 @@ var (
|
|||||||
globalOperationTimeout = newDynamicTimeout(10*time.Minute /*30*/, 600*time.Second) // default timeout for general ops
|
globalOperationTimeout = newDynamicTimeout(10*time.Minute /*30*/, 600*time.Second) // default timeout for general ops
|
||||||
globalHealingTimeout = newDynamicTimeout(30*time.Minute /*1*/, 30*time.Minute) // timeout for healing related ops
|
globalHealingTimeout = newDynamicTimeout(30*time.Minute /*1*/, 30*time.Minute) // timeout for healing related ops
|
||||||
|
|
||||||
globalBucketObjectLockConfig = objectlock.NewBucketObjectLockConfig()
|
globalBucketObjectLockSys *BucketObjectLockSys
|
||||||
|
globalBucketQuotaSys *BucketQuotaSys
|
||||||
globalBucketQuotaSys *BucketQuotaSys
|
globalBucketStorageCache bucketStorageCache
|
||||||
globalBucketStorageCache bucketStorageCache
|
|
||||||
|
|
||||||
// Disk cache drives
|
// Disk cache drives
|
||||||
globalCacheConfig cache.Config
|
globalCacheConfig cache.Config
|
||||||
|
@ -566,7 +566,7 @@ func (sys *NotificationSys) SetBucketPolicy(ctx context.Context, bucketName stri
|
|||||||
// DeleteBucket - calls DeleteBucket RPC call on all peers.
|
// DeleteBucket - calls DeleteBucket RPC call on all peers.
|
||||||
func (sys *NotificationSys) DeleteBucket(ctx context.Context, bucketName string) {
|
func (sys *NotificationSys) DeleteBucket(ctx context.Context, bucketName string) {
|
||||||
globalNotificationSys.RemoveNotification(bucketName)
|
globalNotificationSys.RemoveNotification(bucketName)
|
||||||
globalBucketObjectLockConfig.Remove(bucketName)
|
globalBucketObjectLockSys.Remove(bucketName)
|
||||||
globalBucketQuotaSys.Remove(bucketName)
|
globalBucketQuotaSys.Remove(bucketName)
|
||||||
globalPolicySys.Remove(bucketName)
|
globalPolicySys.Remove(bucketName)
|
||||||
globalLifecycleSys.Remove(bucketName)
|
globalLifecycleSys.Remove(bucketName)
|
||||||
|
@ -85,7 +85,10 @@ func deleteBucketMetadata(ctx context.Context, bucket string, objAPI ObjectLayer
|
|||||||
removePolicyConfig(ctx, objAPI, bucket)
|
removePolicyConfig(ctx, objAPI, bucket)
|
||||||
|
|
||||||
// Delete notification config, if present - ignore any errors.
|
// Delete notification config, if present - ignore any errors.
|
||||||
removeNotificationConfig(ctx, objAPI, bucket)
|
logger.LogIf(ctx, removeNotificationConfig(ctx, objAPI, bucket))
|
||||||
|
|
||||||
|
// Delete bucket meta config, if present - ignore any errors.
|
||||||
|
logger.LogIf(ctx, removeBucketMeta(ctx, objAPI, bucket))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depending on the disk type network or local, initialize storage API.
|
// Depending on the disk type network or local, initialize storage API.
|
||||||
@ -144,13 +147,11 @@ func cleanupDir(ctx context.Context, storage StorageAPI, volume, dirPath string)
|
|||||||
|
|
||||||
// Removes notification.xml for a given bucket, only used during DeleteBucket.
|
// Removes notification.xml for a given bucket, only used during DeleteBucket.
|
||||||
func removeNotificationConfig(ctx context.Context, objAPI ObjectLayer, bucket string) error {
|
func removeNotificationConfig(ctx context.Context, objAPI ObjectLayer, bucket string) error {
|
||||||
// Verify bucket is valid.
|
|
||||||
if !IsValidBucketName(bucket) {
|
|
||||||
return BucketNameInvalid{Bucket: bucket}
|
|
||||||
}
|
|
||||||
|
|
||||||
ncPath := path.Join(bucketConfigPrefix, bucket, bucketNotificationConfig)
|
ncPath := path.Join(bucketConfigPrefix, bucket, bucketNotificationConfig)
|
||||||
return objAPI.DeleteObject(ctx, minioMetaBucket, ncPath)
|
if err := deleteConfig(ctx, objAPI, ncPath); err != nil && err != errConfigNotFound {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func listObjectsNonSlash(ctx context.Context, bucket, prefix, marker, delimiter string, maxKeys int, tpool *TreeWalkPool, listDir ListDirFunc, getObjInfo func(context.Context, string, string) (ObjectInfo, error), getObjectInfoDirs ...func(context.Context, string, string) (ObjectInfo, error)) (loi ListObjectsInfo, err error) {
|
func listObjectsNonSlash(ctx context.Context, bucket, prefix, marker, delimiter string, maxKeys int, tpool *TreeWalkPool, listDir ListDirFunc, getObjInfo func(context.Context, string, string) (ObjectInfo, error), getObjectInfoDirs ...func(context.Context, string, string) (ObjectInfo, error)) (loi ListObjectsInfo, err error) {
|
||||||
|
@ -85,7 +85,7 @@ func testDeleteObject(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
|||||||
|
|
||||||
for i, testCase := range testCases {
|
for i, testCase := range testCases {
|
||||||
|
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), testCase.bucketName, "")
|
err := obj.MakeBucketWithLocation(context.Background(), testCase.bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
}
|
}
|
||||||
|
@ -255,21 +255,35 @@ func (e InvalidMarkerPrefixCombination) Error() string {
|
|||||||
type BucketPolicyNotFound GenericError
|
type BucketPolicyNotFound GenericError
|
||||||
|
|
||||||
func (e BucketPolicyNotFound) Error() string {
|
func (e BucketPolicyNotFound) Error() string {
|
||||||
return "No bucket policy found for bucket: " + e.Bucket
|
return "No bucket policy configuration found for bucket: " + e.Bucket
|
||||||
}
|
}
|
||||||
|
|
||||||
// BucketLifecycleNotFound - no bucket lifecycle found.
|
// BucketLifecycleNotFound - no bucket lifecycle found.
|
||||||
type BucketLifecycleNotFound GenericError
|
type BucketLifecycleNotFound GenericError
|
||||||
|
|
||||||
func (e BucketLifecycleNotFound) Error() string {
|
func (e BucketLifecycleNotFound) Error() string {
|
||||||
return "No bucket life cycle found for bucket : " + e.Bucket
|
return "No bucket lifecycle configuration found for bucket : " + e.Bucket
|
||||||
}
|
}
|
||||||
|
|
||||||
// BucketSSEConfigNotFound - no bucket encryption config found
|
// BucketSSEConfigNotFound - no bucket encryption found
|
||||||
type BucketSSEConfigNotFound GenericError
|
type BucketSSEConfigNotFound GenericError
|
||||||
|
|
||||||
func (e BucketSSEConfigNotFound) Error() string {
|
func (e BucketSSEConfigNotFound) Error() string {
|
||||||
return "No bucket encryption found for bucket: " + e.Bucket
|
return "No bucket encryption configuration found for bucket: " + e.Bucket
|
||||||
|
}
|
||||||
|
|
||||||
|
// BucketTaggingNotFound - no bucket tags found
|
||||||
|
type BucketTaggingNotFound GenericError
|
||||||
|
|
||||||
|
func (e BucketTaggingNotFound) Error() string {
|
||||||
|
return "No bucket tags found for bucket: " + e.Bucket
|
||||||
|
}
|
||||||
|
|
||||||
|
// BucketObjectLockConfigNotFound - no bucket object lock config found
|
||||||
|
type BucketObjectLockConfigNotFound GenericError
|
||||||
|
|
||||||
|
func (e BucketObjectLockConfigNotFound) Error() string {
|
||||||
|
return "No bucket object lock configuration found for bucket: " + e.Bucket
|
||||||
}
|
}
|
||||||
|
|
||||||
// BucketQuotaConfigNotFound - no bucket quota config found.
|
// BucketQuotaConfigNotFound - no bucket quota config found.
|
||||||
|
@ -42,7 +42,7 @@ func testGetObject(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
|||||||
emptyDirName := "test-empty-dir/"
|
emptyDirName := "test-empty-dir/"
|
||||||
|
|
||||||
// create bucket.
|
// create bucket.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucketName, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucketName, "", false)
|
||||||
// Stop the test if creation of the bucket fails.
|
// Stop the test if creation of the bucket fails.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
@ -194,7 +194,7 @@ func testGetObjectPermissionDenied(obj ObjectLayer, instanceType string, disks [
|
|||||||
// Setup for the tests.
|
// Setup for the tests.
|
||||||
bucketName := getRandomBucketName()
|
bucketName := getRandomBucketName()
|
||||||
// create bucket.
|
// create bucket.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucketName, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucketName, "", false)
|
||||||
// Stop the test if creation of the bucket fails.
|
// Stop the test if creation of the bucket fails.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
@ -304,7 +304,7 @@ func testGetObjectDiskNotFound(obj ObjectLayer, instanceType string, disks []str
|
|||||||
bucketName := getRandomBucketName()
|
bucketName := getRandomBucketName()
|
||||||
objectName := "test-object"
|
objectName := "test-object"
|
||||||
// create bucket.
|
// create bucket.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucketName, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucketName, "", false)
|
||||||
// Stop the test if creation of the bucket fails.
|
// Stop the test if creation of the bucket fails.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
|
@ -30,7 +30,7 @@ func TestGetObjectInfo(t *testing.T) {
|
|||||||
// Testing GetObjectInfo().
|
// Testing GetObjectInfo().
|
||||||
func testGetObjectInfo(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
func testGetObjectInfo(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
||||||
// This bucket is used for testing getObjectInfo operations.
|
// This bucket is used for testing getObjectInfo operations.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), "test-getobjectinfo", "")
|
err := obj.MakeBucketWithLocation(context.Background(), "test-getobjectinfo", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* MinIO Cloud Storage, (C) 2016 MinIO, Inc.
|
* MinIO Cloud Storage, (C) 2016-2020 MinIO, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/minio/minio-go/v6/pkg/tags"
|
"github.com/minio/minio-go/v6/pkg/tags"
|
||||||
bucketsse "github.com/minio/minio/pkg/bucket/encryption"
|
bucketsse "github.com/minio/minio/pkg/bucket/encryption"
|
||||||
"github.com/minio/minio/pkg/bucket/lifecycle"
|
"github.com/minio/minio/pkg/bucket/lifecycle"
|
||||||
|
objectlock "github.com/minio/minio/pkg/bucket/object/lock"
|
||||||
"github.com/minio/minio/pkg/bucket/policy"
|
"github.com/minio/minio/pkg/bucket/policy"
|
||||||
|
|
||||||
"github.com/minio/minio/pkg/madmin"
|
"github.com/minio/minio/pkg/madmin"
|
||||||
@ -64,7 +65,7 @@ type ObjectLayer interface {
|
|||||||
StorageInfo(ctx context.Context, local bool) StorageInfo // local queries only local disks
|
StorageInfo(ctx context.Context, local bool) StorageInfo // local queries only local disks
|
||||||
|
|
||||||
// Bucket operations.
|
// Bucket operations.
|
||||||
MakeBucketWithLocation(ctx context.Context, bucket string, location string) error
|
MakeBucketWithLocation(ctx context.Context, bucket string, location string, lockEnabled bool) error
|
||||||
GetBucketInfo(ctx context.Context, bucket string) (bucketInfo BucketInfo, err error)
|
GetBucketInfo(ctx context.Context, bucket string) (bucketInfo BucketInfo, err error)
|
||||||
ListBuckets(ctx context.Context) (buckets []BucketInfo, err error)
|
ListBuckets(ctx context.Context) (buckets []BucketInfo, err error)
|
||||||
DeleteBucket(ctx context.Context, bucket string, forceDelete bool) error
|
DeleteBucket(ctx context.Context, bucket string, forceDelete bool) error
|
||||||
@ -130,6 +131,15 @@ type ObjectLayer interface {
|
|||||||
GetBucketSSEConfig(context.Context, string) (*bucketsse.BucketSSEConfig, error)
|
GetBucketSSEConfig(context.Context, string) (*bucketsse.BucketSSEConfig, error)
|
||||||
DeleteBucketSSEConfig(context.Context, string) error
|
DeleteBucketSSEConfig(context.Context, string) error
|
||||||
|
|
||||||
|
// Bucket locking configuration operations
|
||||||
|
SetBucketObjectLockConfig(context.Context, string, *objectlock.Config) error
|
||||||
|
GetBucketObjectLockConfig(context.Context, string) (*objectlock.Config, error)
|
||||||
|
|
||||||
|
// Bucket tagging operations
|
||||||
|
SetBucketTagging(context.Context, string, *tags.Tags) error
|
||||||
|
GetBucketTagging(context.Context, string) (*tags.Tags, error)
|
||||||
|
DeleteBucketTagging(context.Context, string) error
|
||||||
|
|
||||||
// Backend related metrics
|
// Backend related metrics
|
||||||
GetMetrics(ctx context.Context) (*Metrics, error)
|
GetMetrics(ctx context.Context) (*Metrics, error)
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ func testListObjects(obj ObjectLayer, instanceType string, t1 TestErrHandler) {
|
|||||||
"test-bucket-single-object",
|
"test-bucket-single-object",
|
||||||
}
|
}
|
||||||
for _, bucket := range testBuckets {
|
for _, bucket := range testBuckets {
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucket, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
}
|
}
|
||||||
@ -669,7 +669,7 @@ func BenchmarkListObjects(b *testing.B) {
|
|||||||
|
|
||||||
bucket := "ls-benchmark-bucket"
|
bucket := "ls-benchmark-bucket"
|
||||||
// Create a bucket.
|
// Create a bucket.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucket, "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ func testObjectNewMultipartUpload(obj ObjectLayer, instanceType string, t TestEr
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create bucket before intiating NewMultipartUpload.
|
// Create bucket before intiating NewMultipartUpload.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucket, "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// failed to create newbucket, abort.
|
// failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
@ -89,7 +89,7 @@ func testObjectAbortMultipartUpload(obj ObjectLayer, instanceType string, t Test
|
|||||||
object := "minio-object"
|
object := "minio-object"
|
||||||
opts := ObjectOptions{}
|
opts := ObjectOptions{}
|
||||||
// Create bucket before intiating NewMultipartUpload.
|
// Create bucket before intiating NewMultipartUpload.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucket, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// failed to create newbucket, abort.
|
// failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
@ -135,7 +135,7 @@ func testObjectAPIIsUploadIDExists(obj ObjectLayer, instanceType string, t TestE
|
|||||||
object := "minio-object"
|
object := "minio-object"
|
||||||
|
|
||||||
// Create bucket before intiating NewMultipartUpload.
|
// Create bucket before intiating NewMultipartUpload.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucket, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
@ -166,7 +166,7 @@ func testObjectAPIPutObjectPart(obj ObjectLayer, instanceType string, t TestErrH
|
|||||||
object := "minio-object"
|
object := "minio-object"
|
||||||
opts := ObjectOptions{}
|
opts := ObjectOptions{}
|
||||||
// Create bucket before intiating NewMultipartUpload.
|
// Create bucket before intiating NewMultipartUpload.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucket, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
@ -178,7 +178,7 @@ func testObjectAPIPutObjectPart(obj ObjectLayer, instanceType string, t TestErrH
|
|||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
}
|
}
|
||||||
// Creating a dummy bucket for tests.
|
// Creating a dummy bucket for tests.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), "unused-bucket", "")
|
err = obj.MakeBucketWithLocation(context.Background(), "unused-bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
@ -302,7 +302,7 @@ func testListMultipartUploads(obj ObjectLayer, instanceType string, t TestErrHan
|
|||||||
// objectNames[0].
|
// objectNames[0].
|
||||||
// uploadIds [0].
|
// uploadIds [0].
|
||||||
// Create bucket before initiating NewMultipartUpload.
|
// Create bucket before initiating NewMultipartUpload.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucketNames[0], "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucketNames[0], "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
@ -320,7 +320,7 @@ func testListMultipartUploads(obj ObjectLayer, instanceType string, t TestErrHan
|
|||||||
// objectNames[0].
|
// objectNames[0].
|
||||||
// uploadIds [1-3].
|
// uploadIds [1-3].
|
||||||
// Bucket to test for mutiple upload Id's for a given object.
|
// Bucket to test for mutiple upload Id's for a given object.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucketNames[1], "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucketNames[1], "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
@ -341,7 +341,7 @@ func testListMultipartUploads(obj ObjectLayer, instanceType string, t TestErrHan
|
|||||||
// bucketnames[2].
|
// bucketnames[2].
|
||||||
// objectNames[0-2].
|
// objectNames[0-2].
|
||||||
// uploadIds [4-9].
|
// uploadIds [4-9].
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucketNames[2], "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucketNames[2], "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
@ -1166,7 +1166,7 @@ func testListObjectPartsDiskNotFound(obj ObjectLayer, instanceType string, disks
|
|||||||
// objectNames[0].
|
// objectNames[0].
|
||||||
// uploadIds [0].
|
// uploadIds [0].
|
||||||
// Create bucket before intiating NewMultipartUpload.
|
// Create bucket before intiating NewMultipartUpload.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucketNames[0], "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucketNames[0], "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
@ -1411,7 +1411,7 @@ func testListObjectParts(obj ObjectLayer, instanceType string, t TestErrHandler)
|
|||||||
// objectNames[0].
|
// objectNames[0].
|
||||||
// uploadIds [0].
|
// uploadIds [0].
|
||||||
// Create bucket before intiating NewMultipartUpload.
|
// Create bucket before intiating NewMultipartUpload.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucketNames[0], "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucketNames[0], "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
@ -1657,7 +1657,7 @@ func testObjectCompleteMultipartUpload(obj ObjectLayer, instanceType string, t T
|
|||||||
// objectNames[0].
|
// objectNames[0].
|
||||||
// uploadIds [0].
|
// uploadIds [0].
|
||||||
// Create bucket before intiating NewMultipartUpload.
|
// Create bucket before intiating NewMultipartUpload.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucketNames[0], "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucketNames[0], "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err)
|
t.Fatalf("%s : %s", instanceType, err)
|
||||||
|
@ -46,14 +46,14 @@ func testObjectAPIPutObject(obj ObjectLayer, instanceType string, t TestErrHandl
|
|||||||
object := "minio-object"
|
object := "minio-object"
|
||||||
|
|
||||||
// Create bucket.
|
// Create bucket.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucket, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating a dummy bucket for tests.
|
// Creating a dummy bucket for tests.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), "unused-bucket", "")
|
err = obj.MakeBucketWithLocation(context.Background(), "unused-bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
@ -206,14 +206,14 @@ func testObjectAPIPutObjectDiskNotFound(obj ObjectLayer, instanceType string, di
|
|||||||
object := "minio-object"
|
object := "minio-object"
|
||||||
|
|
||||||
// Create bucket.
|
// Create bucket.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucket, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating a dummy bucket for tests.
|
// Creating a dummy bucket for tests.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), "unused-bucket", "")
|
err = obj.MakeBucketWithLocation(context.Background(), "unused-bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
@ -318,7 +318,7 @@ func testObjectAPIPutObjectStaleFiles(obj ObjectLayer, instanceType string, disk
|
|||||||
object := "minio-object"
|
object := "minio-object"
|
||||||
|
|
||||||
// Create bucket.
|
// Create bucket.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucket, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
@ -352,7 +352,7 @@ func testObjectAPIMultipartPutObjectStaleFiles(obj ObjectLayer, instanceType str
|
|||||||
object := "minio-object"
|
object := "minio-object"
|
||||||
|
|
||||||
// Create bucket.
|
// Create bucket.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucket, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
|
@ -2593,7 +2593,7 @@ func (api objectAPIHandlers) DeleteObjectHandler(w http.ResponseWriter, r *http.
|
|||||||
}
|
}
|
||||||
|
|
||||||
apiErr := ErrNone
|
apiErr := ErrNone
|
||||||
if _, ok := globalBucketObjectLockConfig.Get(bucket); ok {
|
if _, ok := globalBucketObjectLockSys.Get(bucket); ok {
|
||||||
apiErr = enforceRetentionBypassForDelete(ctx, r, bucket, object, getObjectInfo)
|
apiErr = enforceRetentionBypassForDelete(ctx, r, bucket, object, getObjectInfo)
|
||||||
if apiErr != ErrNone && apiErr != ErrNoSuchKey {
|
if apiErr != ErrNone && apiErr != ErrNoSuchKey {
|
||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(apiErr), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(apiErr), r.URL, guessIsBrowserReq(r))
|
||||||
@ -2657,7 +2657,7 @@ func (api objectAPIHandlers) PutObjectLegalHoldHandler(w http.ResponseWriter, r
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := globalBucketObjectLockConfig.Get(bucket); !ok {
|
if _, ok := globalBucketObjectLockSys.Get(bucket); !ok {
|
||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidBucketObjectLockConfiguration), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidBucketObjectLockConfiguration), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2739,7 +2739,7 @@ func (api objectAPIHandlers) GetObjectLegalHoldHandler(w http.ResponseWriter, r
|
|||||||
getObjectInfo = api.CacheAPI().GetObjectInfo
|
getObjectInfo = api.CacheAPI().GetObjectInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := globalBucketObjectLockConfig.Get(bucket); !ok {
|
if _, ok := globalBucketObjectLockSys.Get(bucket); !ok {
|
||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidBucketObjectLockConfiguration), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidBucketObjectLockConfiguration), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2816,7 +2816,7 @@ func (api objectAPIHandlers) PutObjectRetentionHandler(w http.ResponseWriter, r
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := globalBucketObjectLockConfig.Get(bucket); !ok {
|
if _, ok := globalBucketObjectLockSys.Get(bucket); !ok {
|
||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidBucketObjectLockConfiguration), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidBucketObjectLockConfiguration), r.URL, guessIsBrowserReq(r))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ func (s *ObjectLayerAPISuite) TestMakeBucket(t *testing.T) {
|
|||||||
|
|
||||||
// Tests validate bucket creation.
|
// Tests validate bucket creation.
|
||||||
func testMakeBucket(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
func testMakeBucket(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), "bucket-unknown", "")
|
err := obj.MakeBucketWithLocation(context.Background(), "bucket-unknown", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
}
|
}
|
||||||
@ -91,7 +91,7 @@ func (s *ObjectLayerAPISuite) TestMultipartObjectCreation(t *testing.T) {
|
|||||||
// Tests validate creation of part files during Multipart operation.
|
// Tests validate creation of part files during Multipart operation.
|
||||||
func testMultipartObjectCreation(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
func testMultipartObjectCreation(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
||||||
var opts ObjectOptions
|
var opts ObjectOptions
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), "bucket", "")
|
err := obj.MakeBucketWithLocation(context.Background(), "bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ func (s *ObjectLayerAPISuite) TestMultipartObjectAbort(t *testing.T) {
|
|||||||
// Tests validate abortion of Multipart operation.
|
// Tests validate abortion of Multipart operation.
|
||||||
func testMultipartObjectAbort(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
func testMultipartObjectAbort(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
||||||
var opts ObjectOptions
|
var opts ObjectOptions
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), "bucket", "")
|
err := obj.MakeBucketWithLocation(context.Background(), "bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
}
|
}
|
||||||
@ -181,7 +181,7 @@ func (s *ObjectLayerAPISuite) TestMultipleObjectCreation(t *testing.T) {
|
|||||||
func testMultipleObjectCreation(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
func testMultipleObjectCreation(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
||||||
objects := make(map[string][]byte)
|
objects := make(map[string][]byte)
|
||||||
var opts ObjectOptions
|
var opts ObjectOptions
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), "bucket", "")
|
err := obj.MakeBucketWithLocation(context.Background(), "bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
}
|
}
|
||||||
@ -236,7 +236,7 @@ func (s *ObjectLayerAPISuite) TestPaging(t *testing.T) {
|
|||||||
|
|
||||||
// Tests validate creation of objects and the order of listing using various filters for ListObjects operation.
|
// Tests validate creation of objects and the order of listing using various filters for ListObjects operation.
|
||||||
func testPaging(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
func testPaging(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
||||||
obj.MakeBucketWithLocation(context.Background(), "bucket", "")
|
obj.MakeBucketWithLocation(context.Background(), "bucket", "", false)
|
||||||
result, err := obj.ListObjects(context.Background(), "bucket", "", "", "", 0)
|
result, err := obj.ListObjects(context.Background(), "bucket", "", "", "", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
@ -440,7 +440,7 @@ func (s *ObjectLayerAPISuite) TestObjectOverwriteWorks(t *testing.T) {
|
|||||||
|
|
||||||
// Tests validate overwriting of an existing object.
|
// Tests validate overwriting of an existing object.
|
||||||
func testObjectOverwriteWorks(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
func testObjectOverwriteWorks(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), "bucket", "")
|
err := obj.MakeBucketWithLocation(context.Background(), "bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
}
|
}
|
||||||
@ -494,11 +494,11 @@ func (s *ObjectLayerAPISuite) TestBucketRecreateFails(t *testing.T) {
|
|||||||
|
|
||||||
// Tests validate that recreation of the bucket fails.
|
// Tests validate that recreation of the bucket fails.
|
||||||
func testBucketRecreateFails(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
func testBucketRecreateFails(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), "string", "")
|
err := obj.MakeBucketWithLocation(context.Background(), "string", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
}
|
}
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), "string", "")
|
err = obj.MakeBucketWithLocation(context.Background(), "string", "", false)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("%s: Expected error but found nil.", instanceType)
|
t.Fatalf("%s: Expected error but found nil.", instanceType)
|
||||||
}
|
}
|
||||||
@ -519,7 +519,7 @@ func testPutObject(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
|||||||
length := int64(len(content))
|
length := int64(len(content))
|
||||||
readerEOF := newTestReaderEOF(content)
|
readerEOF := newTestReaderEOF(content)
|
||||||
readerNoEOF := newTestReaderNoEOF(content)
|
readerNoEOF := newTestReaderNoEOF(content)
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), "bucket", "")
|
err := obj.MakeBucketWithLocation(context.Background(), "bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
}
|
}
|
||||||
@ -559,7 +559,7 @@ func (s *ObjectLayerAPISuite) TestPutObjectInSubdir(t *testing.T) {
|
|||||||
|
|
||||||
// Tests validate PutObject with subdirectory prefix.
|
// Tests validate PutObject with subdirectory prefix.
|
||||||
func testPutObjectInSubdir(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
func testPutObjectInSubdir(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), "bucket", "")
|
err := obj.MakeBucketWithLocation(context.Background(), "bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
}
|
}
|
||||||
@ -601,7 +601,7 @@ func testListBuckets(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add one and test exists.
|
// add one and test exists.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), "bucket1", "")
|
err = obj.MakeBucketWithLocation(context.Background(), "bucket1", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
}
|
}
|
||||||
@ -615,7 +615,7 @@ func testListBuckets(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add two and test exists.
|
// add two and test exists.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), "bucket2", "")
|
err = obj.MakeBucketWithLocation(context.Background(), "bucket2", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
}
|
}
|
||||||
@ -629,7 +629,7 @@ func testListBuckets(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add three and test exists + prefix.
|
// add three and test exists + prefix.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), "bucket22", "")
|
err = obj.MakeBucketWithLocation(context.Background(), "bucket22", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
}
|
}
|
||||||
@ -653,11 +653,11 @@ func testListBucketsOrder(obj ObjectLayer, instanceType string, t TestErrHandler
|
|||||||
// if implementation contains a map, order of map keys will vary.
|
// if implementation contains a map, order of map keys will vary.
|
||||||
// this ensures they return in the same order each time.
|
// this ensures they return in the same order each time.
|
||||||
// add one and test exists.
|
// add one and test exists.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), "bucket1", "")
|
err := obj.MakeBucketWithLocation(context.Background(), "bucket1", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
}
|
}
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), "bucket2", "")
|
err = obj.MakeBucketWithLocation(context.Background(), "bucket2", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
}
|
}
|
||||||
@ -706,7 +706,7 @@ func (s *ObjectLayerAPISuite) TestNonExistantObjectInBucket(t *testing.T) {
|
|||||||
|
|
||||||
// Tests validate that GetObject fails on a non-existent bucket as expected.
|
// Tests validate that GetObject fails on a non-existent bucket as expected.
|
||||||
func testNonExistantObjectInBucket(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
func testNonExistantObjectInBucket(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), "bucket", "")
|
err := obj.MakeBucketWithLocation(context.Background(), "bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
}
|
}
|
||||||
@ -734,7 +734,7 @@ func (s *ObjectLayerAPISuite) TestGetDirectoryReturnsObjectNotFound(t *testing.T
|
|||||||
// Tests validate that GetObject on an existing directory fails as expected.
|
// Tests validate that GetObject on an existing directory fails as expected.
|
||||||
func testGetDirectoryReturnsObjectNotFound(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
func testGetDirectoryReturnsObjectNotFound(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
||||||
bucketName := "bucket"
|
bucketName := "bucket"
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucketName, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
}
|
}
|
||||||
@ -776,7 +776,7 @@ func (s *ObjectLayerAPISuite) TestContentType(t *testing.T) {
|
|||||||
|
|
||||||
// Test content-type.
|
// Test content-type.
|
||||||
func testContentType(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
func testContentType(obj ObjectLayer, instanceType string, t TestErrHandler) {
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), "bucket", "")
|
err := obj.MakeBucketWithLocation(context.Background(), "bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
t.Fatalf("%s: <ERROR> %s", instanceType, err)
|
||||||
}
|
}
|
||||||
|
@ -598,7 +598,7 @@ func (s *peerRESTServer) DeleteBucketHandler(w http.ResponseWriter, r *http.Requ
|
|||||||
|
|
||||||
globalNotificationSys.RemoveNotification(bucketName)
|
globalNotificationSys.RemoveNotification(bucketName)
|
||||||
globalPolicySys.Remove(bucketName)
|
globalPolicySys.Remove(bucketName)
|
||||||
globalBucketObjectLockConfig.Remove(bucketName)
|
globalBucketObjectLockSys.Remove(bucketName)
|
||||||
globalBucketQuotaSys.Remove(bucketName)
|
globalBucketQuotaSys.Remove(bucketName)
|
||||||
globalLifecycleSys.Remove(bucketName)
|
globalLifecycleSys.Remove(bucketName)
|
||||||
|
|
||||||
@ -843,7 +843,7 @@ func (s *peerRESTServer) RemoveBucketObjectLockConfigHandler(w http.ResponseWrit
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
globalBucketObjectLockConfig.Remove(bucketName)
|
globalBucketObjectLockSys.Remove(bucketName)
|
||||||
w.(http.Flusher).Flush()
|
w.(http.Flusher).Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -873,7 +873,7 @@ func (s *peerRESTServer) PutBucketObjectLockConfigHandler(w http.ResponseWriter,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
globalBucketObjectLockConfig.Set(bucketName, retention)
|
globalBucketObjectLockSys.Set(bucketName, retention)
|
||||||
w.(http.Flusher).Flush()
|
w.(http.Flusher).Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ func testPostPolicyBucketHandler(obj ObjectLayer, instanceType string, t TestErr
|
|||||||
// objectNames[0].
|
// objectNames[0].
|
||||||
// uploadIds [0].
|
// uploadIds [0].
|
||||||
// Create bucket before initiating NewMultipartUpload.
|
// Create bucket before initiating NewMultipartUpload.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucketName, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
@ -451,7 +451,7 @@ func testPostPolicyBucketHandlerRedirect(obj ObjectLayer, instanceType string, t
|
|||||||
curTime := UTCNow()
|
curTime := UTCNow()
|
||||||
curTimePlus5Min := curTime.Add(time.Minute * 5)
|
curTimePlus5Min := curTime.Add(time.Minute * 5)
|
||||||
|
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Failed to create newbucket, abort.
|
// Failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err.Error())
|
t.Fatalf("%s : %s", instanceType, err.Error())
|
||||||
|
@ -156,6 +156,9 @@ func newAllSubsystems() {
|
|||||||
// Create new bucket encryption subsystem
|
// Create new bucket encryption subsystem
|
||||||
globalBucketSSEConfigSys = NewBucketSSEConfigSys()
|
globalBucketSSEConfigSys = NewBucketSSEConfigSys()
|
||||||
|
|
||||||
|
// Create new bucket object lock subsystem
|
||||||
|
globalBucketObjectLockSys = NewBucketObjectLockSys()
|
||||||
|
|
||||||
// Create new bucket quota subsystem
|
// Create new bucket quota subsystem
|
||||||
globalBucketQuotaSys = NewBucketQuotaSys()
|
globalBucketQuotaSys = NewBucketQuotaSys()
|
||||||
}
|
}
|
||||||
@ -281,7 +284,7 @@ func initAllSubsystems(newObject ObjectLayer) (err error) {
|
|||||||
wquorum := &InsufficientWriteQuorum{}
|
wquorum := &InsufficientWriteQuorum{}
|
||||||
rquorum := &InsufficientReadQuorum{}
|
rquorum := &InsufficientReadQuorum{}
|
||||||
for _, bucket := range buckets {
|
for _, bucket := range buckets {
|
||||||
if err = newObject.MakeBucketWithLocation(GlobalContext, bucket.Name, ""); err != nil {
|
if err = newObject.MakeBucketWithLocation(GlobalContext, bucket.Name, "", false); err != nil {
|
||||||
if errors.As(err, &wquorum) || errors.As(err, &rquorum) {
|
if errors.As(err, &wquorum) || errors.As(err, &rquorum) {
|
||||||
// Retrun the error upwards for the caller to retry.
|
// Retrun the error upwards for the caller to retry.
|
||||||
return fmt.Errorf("Unable to heal bucket: %w", err)
|
return fmt.Errorf("Unable to heal bucket: %w", err)
|
||||||
@ -329,11 +332,6 @@ func initAllSubsystems(newObject ObjectLayer) (err error) {
|
|||||||
return fmt.Errorf("Unable to initialize policy system: %w", err)
|
return fmt.Errorf("Unable to initialize policy system: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize bucket object lock.
|
|
||||||
if err = initBucketObjectLockConfig(buckets, newObject); err != nil {
|
|
||||||
return fmt.Errorf("Unable to initialize object lock system: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize lifecycle system.
|
// Initialize lifecycle system.
|
||||||
if err = globalLifecycleSys.Init(buckets, newObject); err != nil {
|
if err = globalLifecycleSys.Init(buckets, newObject); err != nil {
|
||||||
return fmt.Errorf("Unable to initialize lifecycle system: %w", err)
|
return fmt.Errorf("Unable to initialize lifecycle system: %w", err)
|
||||||
@ -344,6 +342,11 @@ func initAllSubsystems(newObject ObjectLayer) (err error) {
|
|||||||
return fmt.Errorf("Unable to initialize bucket encryption subsystem: %w", err)
|
return fmt.Errorf("Unable to initialize bucket encryption subsystem: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize bucket object lock.
|
||||||
|
if err = globalBucketObjectLockSys.Init(buckets, newObject); err != nil {
|
||||||
|
return fmt.Errorf("Unable to initialize object lock system: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize bucket quota system.
|
// Initialize bucket quota system.
|
||||||
if err = globalBucketQuotaSys.Init(buckets, newObject); err != nil {
|
if err = globalBucketQuotaSys.Init(buckets, newObject); err != nil {
|
||||||
return fmt.Errorf("Unable to initialize bucket quota system: %w", err)
|
return fmt.Errorf("Unable to initialize bucket quota system: %w", err)
|
||||||
|
@ -1640,7 +1640,7 @@ func initAPIHandlerTest(obj ObjectLayer, endpoints []string) (string, http.Handl
|
|||||||
bucketName := getRandomBucketName()
|
bucketName := getRandomBucketName()
|
||||||
|
|
||||||
// Create bucket.
|
// Create bucket.
|
||||||
err := obj.MakeBucketWithLocation(context.Background(), bucketName, "")
|
err := obj.MakeBucketWithLocation(context.Background(), bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// failed to create newbucket, return err.
|
// failed to create newbucket, return err.
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
|
@ -172,7 +172,7 @@ func (web *webAPIHandlers) MakeBucket(r *http.Request, args *MakeBucketArgs, rep
|
|||||||
if _, err := globalDNSConfig.Get(args.BucketName); err != nil {
|
if _, err := globalDNSConfig.Get(args.BucketName); err != nil {
|
||||||
if err == dns.ErrNoEntriesFound {
|
if err == dns.ErrNoEntriesFound {
|
||||||
// Proceed to creating a bucket.
|
// Proceed to creating a bucket.
|
||||||
if err = objectAPI.MakeBucketWithLocation(ctx, args.BucketName, globalServerRegion); err != nil {
|
if err = objectAPI.MakeBucketWithLocation(ctx, args.BucketName, globalServerRegion, false); err != nil {
|
||||||
return toJSONError(ctx, err)
|
return toJSONError(ctx, err)
|
||||||
}
|
}
|
||||||
if err = globalDNSConfig.Put(args.BucketName); err != nil {
|
if err = globalDNSConfig.Put(args.BucketName); err != nil {
|
||||||
@ -188,7 +188,7 @@ func (web *webAPIHandlers) MakeBucket(r *http.Request, args *MakeBucketArgs, rep
|
|||||||
return toJSONError(ctx, errBucketAlreadyExists)
|
return toJSONError(ctx, errBucketAlreadyExists)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := objectAPI.MakeBucketWithLocation(ctx, args.BucketName, globalServerRegion); err != nil {
|
if err := objectAPI.MakeBucketWithLocation(ctx, args.BucketName, globalServerRegion, false); err != nil {
|
||||||
return toJSONError(ctx, err, args.BucketName)
|
return toJSONError(ctx, err, args.BucketName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +261,7 @@ func (web *webAPIHandlers) DeleteBucket(r *http.Request, args *RemoveBucketArgs,
|
|||||||
if globalDNSConfig != nil {
|
if globalDNSConfig != nil {
|
||||||
if err := globalDNSConfig.Delete(args.BucketName); err != nil {
|
if err := globalDNSConfig.Delete(args.BucketName); err != nil {
|
||||||
// Deleting DNS entry failed, attempt to create the bucket again.
|
// Deleting DNS entry failed, attempt to create the bucket again.
|
||||||
objectAPI.MakeBucketWithLocation(ctx, args.BucketName, "")
|
objectAPI.MakeBucketWithLocation(ctx, args.BucketName, "", false)
|
||||||
return toJSONError(ctx, err)
|
return toJSONError(ctx, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -320,7 +320,7 @@ func testDeleteBucketWebHandler(obj ObjectLayer, instanceType string, t TestErrH
|
|||||||
bucketName := getRandomBucketName()
|
bucketName := getRandomBucketName()
|
||||||
var opts ObjectOptions
|
var opts ObjectOptions
|
||||||
|
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create bucket: %s (%s)", err.Error(), instanceType)
|
t.Fatalf("failed to create bucket: %s (%s)", err.Error(), instanceType)
|
||||||
}
|
}
|
||||||
@ -398,7 +398,7 @@ func testDeleteBucketWebHandler(obj ObjectLayer, instanceType string, t TestErrH
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// failed to create new bucket, abort.
|
// failed to create new bucket, abort.
|
||||||
t.Fatalf("failed to create new bucket (%s): %s", instanceType, err.Error())
|
t.Fatalf("failed to create new bucket (%s): %s", instanceType, err.Error())
|
||||||
@ -426,7 +426,7 @@ func testListBucketsWebHandler(obj ObjectLayer, instanceType string, t TestErrHa
|
|||||||
|
|
||||||
bucketName := getRandomBucketName()
|
bucketName := getRandomBucketName()
|
||||||
// Create bucket.
|
// Create bucket.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// failed to create newbucket, abort.
|
// failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err)
|
t.Fatalf("%s : %s", instanceType, err)
|
||||||
@ -477,7 +477,7 @@ func testListObjectsWebHandler(obj ObjectLayer, instanceType string, t TestErrHa
|
|||||||
objectSize := 1 * humanize.KiByte
|
objectSize := 1 * humanize.KiByte
|
||||||
|
|
||||||
// Create bucket.
|
// Create bucket.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// failed to create newbucket, abort.
|
// failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err)
|
t.Fatalf("%s : %s", instanceType, err)
|
||||||
@ -581,7 +581,7 @@ func testRemoveObjectWebHandler(obj ObjectLayer, instanceType string, t TestErrH
|
|||||||
objectSize := 1 * humanize.KiByte
|
objectSize := 1 * humanize.KiByte
|
||||||
|
|
||||||
// Create bucket.
|
// Create bucket.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// failed to create newbucket, abort.
|
// failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err)
|
t.Fatalf("%s : %s", instanceType, err)
|
||||||
@ -858,7 +858,7 @@ func testUploadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler
|
|||||||
return rec.Code
|
return rec.Code
|
||||||
}
|
}
|
||||||
// Create bucket.
|
// Create bucket.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// failed to create newbucket, abort.
|
// failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err)
|
t.Fatalf("%s : %s", instanceType, err)
|
||||||
@ -955,7 +955,7 @@ func testDownloadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create bucket.
|
// Create bucket.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// failed to create newbucket, abort.
|
// failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err)
|
t.Fatalf("%s : %s", instanceType, err)
|
||||||
@ -1060,7 +1060,7 @@ func testWebHandlerDownloadZip(obj ObjectLayer, instanceType string, t TestErrHa
|
|||||||
fileThree := "cccccccccccccc"
|
fileThree := "cccccccccccccc"
|
||||||
|
|
||||||
// Create bucket.
|
// Create bucket.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucket, "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// failed to create newbucket, abort.
|
// failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err)
|
t.Fatalf("%s : %s", instanceType, err)
|
||||||
@ -1147,7 +1147,7 @@ func testWebPresignedGetHandler(obj ObjectLayer, instanceType string, t TestErrH
|
|||||||
objectSize := 1 * humanize.KiByte
|
objectSize := 1 * humanize.KiByte
|
||||||
|
|
||||||
// Create bucket.
|
// Create bucket.
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// failed to create newbucket, abort.
|
// failed to create newbucket, abort.
|
||||||
t.Fatalf("%s : %s", instanceType, err)
|
t.Fatalf("%s : %s", instanceType, err)
|
||||||
@ -1248,7 +1248,7 @@ func testWebGetBucketPolicyHandler(obj ObjectLayer, instanceType string, t TestE
|
|||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
|
|
||||||
bucketName := getRandomBucketName()
|
bucketName := getRandomBucketName()
|
||||||
if err = obj.MakeBucketWithLocation(context.Background(), bucketName, ""); err != nil {
|
if err = obj.MakeBucketWithLocation(context.Background(), bucketName, "", false); err != nil {
|
||||||
t.Fatal("Unexpected error: ", err)
|
t.Fatal("Unexpected error: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1323,7 +1323,7 @@ func testWebListAllBucketPoliciesHandler(obj ObjectLayer, instanceType string, t
|
|||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
|
|
||||||
bucketName := getRandomBucketName()
|
bucketName := getRandomBucketName()
|
||||||
if err = obj.MakeBucketWithLocation(context.Background(), bucketName, ""); err != nil {
|
if err = obj.MakeBucketWithLocation(context.Background(), bucketName, "", false); err != nil {
|
||||||
t.Fatal("Unexpected error: ", err)
|
t.Fatal("Unexpected error: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1428,7 +1428,7 @@ func testWebSetBucketPolicyHandler(obj ObjectLayer, instanceType string, t TestE
|
|||||||
|
|
||||||
// Create a bucket
|
// Create a bucket
|
||||||
bucketName := getRandomBucketName()
|
bucketName := getRandomBucketName()
|
||||||
if err = obj.MakeBucketWithLocation(context.Background(), bucketName, ""); err != nil {
|
if err = obj.MakeBucketWithLocation(context.Background(), bucketName, "", false); err != nil {
|
||||||
t.Fatal("Unexpected error: ", err)
|
t.Fatal("Unexpected error: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1587,7 +1587,7 @@ func TestWebObjectLayerFaultyDisks(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bucketName := "mybucket"
|
bucketName := "mybucket"
|
||||||
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "")
|
err = obj.MakeBucketWithLocation(context.Background(), bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Cannot make bucket:", err)
|
t.Fatal("Cannot make bucket:", err)
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ import (
|
|||||||
"github.com/minio/minio/pkg/bpool"
|
"github.com/minio/minio/pkg/bpool"
|
||||||
bucketsse "github.com/minio/minio/pkg/bucket/encryption"
|
bucketsse "github.com/minio/minio/pkg/bucket/encryption"
|
||||||
"github.com/minio/minio/pkg/bucket/lifecycle"
|
"github.com/minio/minio/pkg/bucket/lifecycle"
|
||||||
|
objectlock "github.com/minio/minio/pkg/bucket/object/lock"
|
||||||
"github.com/minio/minio/pkg/bucket/policy"
|
"github.com/minio/minio/pkg/bucket/policy"
|
||||||
"github.com/minio/minio/pkg/dsync"
|
"github.com/minio/minio/pkg/dsync"
|
||||||
"github.com/minio/minio/pkg/madmin"
|
"github.com/minio/minio/pkg/madmin"
|
||||||
@ -509,14 +510,14 @@ func (s *xlSets) Shutdown(ctx context.Context) error {
|
|||||||
// MakeBucketLocation - creates a new bucket across all sets simultaneously
|
// MakeBucketLocation - creates a new bucket across all sets simultaneously
|
||||||
// even if one of the sets fail to create buckets, we proceed to undo a
|
// even if one of the sets fail to create buckets, we proceed to undo a
|
||||||
// successful operation.
|
// successful operation.
|
||||||
func (s *xlSets) MakeBucketWithLocation(ctx context.Context, bucket, location string) error {
|
func (s *xlSets) MakeBucketWithLocation(ctx context.Context, bucket, location string, lockEnabled bool) error {
|
||||||
g := errgroup.WithNErrs(len(s.sets))
|
g := errgroup.WithNErrs(len(s.sets))
|
||||||
|
|
||||||
// Create buckets in parallel across all sets.
|
// Create buckets in parallel across all sets.
|
||||||
for index := range s.sets {
|
for index := range s.sets {
|
||||||
index := index
|
index := index
|
||||||
g.Go(func() error {
|
g.Go(func() error {
|
||||||
return s.sets[index].MakeBucketWithLocation(ctx, bucket, location)
|
return s.sets[index].MakeBucketWithLocation(ctx, bucket, location, lockEnabled)
|
||||||
}, index)
|
}, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -657,6 +658,31 @@ func (s *xlSets) DeleteBucketSSEConfig(ctx context.Context, bucket string) error
|
|||||||
return removeBucketSSEConfig(ctx, s, bucket)
|
return removeBucketSSEConfig(ctx, s, bucket)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetBucketObjectLockConfig enables/clears default object lock configuration
|
||||||
|
func (s *xlSets) SetBucketObjectLockConfig(ctx context.Context, bucket string, config *objectlock.Config) error {
|
||||||
|
return saveBucketObjectLockConfig(ctx, s, bucket, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBucketObjectLockConfig - returns current defaults for object lock configuration
|
||||||
|
func (s *xlSets) GetBucketObjectLockConfig(ctx context.Context, bucket string) (*objectlock.Config, error) {
|
||||||
|
return readBucketObjectLockConfig(ctx, s, bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBucketTagging sets bucket tags on given bucket
|
||||||
|
func (s *xlSets) SetBucketTagging(ctx context.Context, bucket string, t *tags.Tags) error {
|
||||||
|
return saveBucketTagging(ctx, s, bucket, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBucketTagging get bucket tags set on given bucket
|
||||||
|
func (s *xlSets) GetBucketTagging(ctx context.Context, bucket string) (*tags.Tags, error) {
|
||||||
|
return readBucketTagging(ctx, s, bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBucketTagging delete bucket tags set if any.
|
||||||
|
func (s *xlSets) DeleteBucketTagging(ctx context.Context, bucket string) error {
|
||||||
|
return deleteBucketTagging(ctx, s, bucket)
|
||||||
|
}
|
||||||
|
|
||||||
// IsNotificationSupported returns whether bucket notification is applicable for this layer.
|
// IsNotificationSupported returns whether bucket notification is applicable for this layer.
|
||||||
func (s *xlSets) IsNotificationSupported() bool {
|
func (s *xlSets) IsNotificationSupported() bool {
|
||||||
return s.getHashedSet("").IsNotificationSupported()
|
return s.getHashedSet("").IsNotificationSupported()
|
||||||
@ -717,7 +743,7 @@ func undoDeleteBucketSets(bucket string, sets []*xlObjects, errs []error) {
|
|||||||
index := index
|
index := index
|
||||||
g.Go(func() error {
|
g.Go(func() error {
|
||||||
if errs[index] == nil {
|
if errs[index] == nil {
|
||||||
return sets[index].MakeBucketWithLocation(GlobalContext, bucket, "")
|
return sets[index].MakeBucketWithLocation(GlobalContext, bucket, "", false)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}, index)
|
}, index)
|
||||||
|
@ -21,9 +21,11 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/minio/minio-go/v6/pkg/s3utils"
|
"github.com/minio/minio-go/v6/pkg/s3utils"
|
||||||
|
"github.com/minio/minio-go/v6/pkg/tags"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
bucketsse "github.com/minio/minio/pkg/bucket/encryption"
|
bucketsse "github.com/minio/minio/pkg/bucket/encryption"
|
||||||
"github.com/minio/minio/pkg/bucket/lifecycle"
|
"github.com/minio/minio/pkg/bucket/lifecycle"
|
||||||
|
objectlock "github.com/minio/minio/pkg/bucket/object/lock"
|
||||||
"github.com/minio/minio/pkg/bucket/policy"
|
"github.com/minio/minio/pkg/bucket/policy"
|
||||||
|
|
||||||
"github.com/minio/minio/pkg/sync/errgroup"
|
"github.com/minio/minio/pkg/sync/errgroup"
|
||||||
@ -38,7 +40,7 @@ var bucketMetadataOpIgnoredErrs = append(bucketOpIgnoredErrs, errVolumeNotFound)
|
|||||||
/// Bucket operations
|
/// Bucket operations
|
||||||
|
|
||||||
// MakeBucket - make a bucket.
|
// MakeBucket - make a bucket.
|
||||||
func (xl xlObjects) MakeBucketWithLocation(ctx context.Context, bucket, location string) error {
|
func (xl xlObjects) MakeBucketWithLocation(ctx context.Context, bucket, location string, lockEnabled bool) error {
|
||||||
// Verify if bucket is valid.
|
// Verify if bucket is valid.
|
||||||
if err := s3utils.CheckValidBucketNameStrict(bucket); err != nil {
|
if err := s3utils.CheckValidBucketNameStrict(bucket); err != nil {
|
||||||
return BucketNameInvalid{Bucket: bucket}
|
return BucketNameInvalid{Bucket: bucket}
|
||||||
@ -321,6 +323,31 @@ func (xl xlObjects) DeleteBucketSSEConfig(ctx context.Context, bucket string) er
|
|||||||
return removeBucketSSEConfig(ctx, xl, bucket)
|
return removeBucketSSEConfig(ctx, xl, bucket)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetBucketObjectLockConfig enables/clears default object lock configuration
|
||||||
|
func (xl xlObjects) SetBucketObjectLockConfig(ctx context.Context, bucket string, config *objectlock.Config) error {
|
||||||
|
return saveBucketObjectLockConfig(ctx, xl, bucket, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBucketObjectLockConfig - returns current defaults for object lock configuration
|
||||||
|
func (xl xlObjects) GetBucketObjectLockConfig(ctx context.Context, bucket string) (*objectlock.Config, error) {
|
||||||
|
return readBucketObjectLockConfig(ctx, xl, bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBucketTagging sets bucket tags on given bucket
|
||||||
|
func (xl xlObjects) SetBucketTagging(ctx context.Context, bucket string, t *tags.Tags) error {
|
||||||
|
return saveBucketTagging(ctx, xl, bucket, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBucketTagging get bucket tags set on given bucket
|
||||||
|
func (xl xlObjects) GetBucketTagging(ctx context.Context, bucket string) (*tags.Tags, error) {
|
||||||
|
return readBucketTagging(ctx, xl, bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBucketTagging delete bucket tags set if any.
|
||||||
|
func (xl xlObjects) DeleteBucketTagging(ctx context.Context, bucket string) error {
|
||||||
|
return deleteBucketTagging(ctx, xl, bucket)
|
||||||
|
}
|
||||||
|
|
||||||
// IsNotificationSupported returns whether bucket notification is applicable for this layer.
|
// IsNotificationSupported returns whether bucket notification is applicable for this layer.
|
||||||
func (xl xlObjects) IsNotificationSupported() bool {
|
func (xl xlObjects) IsNotificationSupported() bool {
|
||||||
return true
|
return true
|
||||||
|
@ -41,7 +41,7 @@ func TestXLParentDirIsObject(t *testing.T) {
|
|||||||
bucketName := "testbucket"
|
bucketName := "testbucket"
|
||||||
objectName := "object"
|
objectName := "object"
|
||||||
|
|
||||||
if err = obj.MakeBucketWithLocation(GlobalContext, bucketName, ""); err != nil {
|
if err = obj.MakeBucketWithLocation(GlobalContext, bucketName, "", false); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
objectContent := "12345"
|
objectContent := "12345"
|
||||||
|
@ -181,7 +181,7 @@ func TestListOnlineDisks(t *testing.T) {
|
|||||||
obj.DeleteObject(GlobalContext, bucket, object)
|
obj.DeleteObject(GlobalContext, bucket, object)
|
||||||
obj.DeleteBucket(GlobalContext, bucket, false)
|
obj.DeleteBucket(GlobalContext, bucket, false)
|
||||||
|
|
||||||
err = obj.MakeBucketWithLocation(GlobalContext, "bucket", "")
|
err = obj.MakeBucketWithLocation(GlobalContext, "bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to make a bucket %v", err)
|
t.Fatalf("Failed to make a bucket %v", err)
|
||||||
}
|
}
|
||||||
@ -276,7 +276,7 @@ func TestDisksWithAllParts(t *testing.T) {
|
|||||||
z := obj.(*xlZones)
|
z := obj.(*xlZones)
|
||||||
xl := z.zones[0].sets[0]
|
xl := z.zones[0].sets[0]
|
||||||
xlDisks := xl.getDisks()
|
xlDisks := xl.getDisks()
|
||||||
err = obj.MakeBucketWithLocation(ctx, "bucket", "")
|
err = obj.MakeBucketWithLocation(ctx, "bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to make a bucket %v", err)
|
t.Fatalf("Failed to make a bucket %v", err)
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ func TestUndoMakeBucket(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bucketName := getRandomBucketName()
|
bucketName := getRandomBucketName()
|
||||||
if err = obj.MakeBucketWithLocation(ctx, bucketName, ""); err != nil {
|
if err = obj.MakeBucketWithLocation(ctx, bucketName, "", false); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
z := obj.(*xlZones)
|
z := obj.(*xlZones)
|
||||||
@ -88,7 +88,7 @@ func TestHealObjectCorrupted(t *testing.T) {
|
|||||||
data := bytes.Repeat([]byte("a"), 5*1024*1024)
|
data := bytes.Repeat([]byte("a"), 5*1024*1024)
|
||||||
var opts ObjectOptions
|
var opts ObjectOptions
|
||||||
|
|
||||||
err = objLayer.MakeBucketWithLocation(ctx, bucket, "")
|
err = objLayer.MakeBucketWithLocation(ctx, bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to make a bucket - %v", err)
|
t.Fatalf("Failed to make a bucket - %v", err)
|
||||||
}
|
}
|
||||||
@ -233,7 +233,7 @@ func TestHealObjectXL(t *testing.T) {
|
|||||||
data := bytes.Repeat([]byte("a"), 5*1024*1024)
|
data := bytes.Repeat([]byte("a"), 5*1024*1024)
|
||||||
var opts ObjectOptions
|
var opts ObjectOptions
|
||||||
|
|
||||||
err = obj.MakeBucketWithLocation(ctx, bucket, "")
|
err = obj.MakeBucketWithLocation(ctx, bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to make a bucket - %v", err)
|
t.Fatalf("Failed to make a bucket - %v", err)
|
||||||
}
|
}
|
||||||
@ -322,7 +322,7 @@ func TestHealEmptyDirectoryXL(t *testing.T) {
|
|||||||
object := "empty-dir/"
|
object := "empty-dir/"
|
||||||
var opts ObjectOptions
|
var opts ObjectOptions
|
||||||
|
|
||||||
err = obj.MakeBucketWithLocation(ctx, bucket, "")
|
err = obj.MakeBucketWithLocation(ctx, bucket, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to make a bucket - %v", err)
|
t.Fatalf("Failed to make a bucket - %v", err)
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ func TestXLCleanupStaleMultipartUploads(t *testing.T) {
|
|||||||
objectName := "object"
|
objectName := "object"
|
||||||
var opts ObjectOptions
|
var opts ObjectOptions
|
||||||
|
|
||||||
obj.MakeBucketWithLocation(ctx, bucketName, "")
|
obj.MakeBucketWithLocation(ctx, bucketName, "", false)
|
||||||
uploadID, err := obj.NewMultipartUpload(GlobalContext, bucketName, objectName, opts)
|
uploadID, err := obj.NewMultipartUpload(GlobalContext, bucketName, objectName, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Unexpected err: ", err)
|
t.Fatal("Unexpected err: ", err)
|
||||||
|
@ -49,7 +49,7 @@ func TestRepeatPutObjectPart(t *testing.T) {
|
|||||||
// cleaning up of temporary test directories
|
// cleaning up of temporary test directories
|
||||||
defer removeRoots(disks)
|
defer removeRoots(disks)
|
||||||
|
|
||||||
err = objLayer.MakeBucketWithLocation(ctx, "bucket1", "")
|
err = objLayer.MakeBucketWithLocation(ctx, "bucket1", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ func TestXLDeleteObjectBasic(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = xl.MakeBucketWithLocation(ctx, "bucket", "")
|
err = xl.MakeBucketWithLocation(ctx, "bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -152,7 +152,7 @@ func TestXLDeleteObjectsXLSet(t *testing.T) {
|
|||||||
{bucketName, "obj_4"},
|
{bucketName, "obj_4"},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := xlSets.MakeBucketWithLocation(GlobalContext, bucketName, "")
|
err := xlSets.MakeBucketWithLocation(GlobalContext, bucketName, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -211,7 +211,7 @@ func TestXLDeleteObjectDiskNotFound(t *testing.T) {
|
|||||||
xl := z.zones[0].sets[0]
|
xl := z.zones[0].sets[0]
|
||||||
|
|
||||||
// Create "bucket"
|
// Create "bucket"
|
||||||
err = obj.MakeBucketWithLocation(ctx, "bucket", "")
|
err = obj.MakeBucketWithLocation(ctx, "bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -278,7 +278,7 @@ func TestGetObjectNoQuorum(t *testing.T) {
|
|||||||
xl := z.zones[0].sets[0]
|
xl := z.zones[0].sets[0]
|
||||||
|
|
||||||
// Create "bucket"
|
// Create "bucket"
|
||||||
err = obj.MakeBucketWithLocation(ctx, "bucket", "")
|
err = obj.MakeBucketWithLocation(ctx, "bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -340,7 +340,7 @@ func TestPutObjectNoQuorum(t *testing.T) {
|
|||||||
xl := z.zones[0].sets[0]
|
xl := z.zones[0].sets[0]
|
||||||
|
|
||||||
// Create "bucket"
|
// Create "bucket"
|
||||||
err = obj.MakeBucketWithLocation(ctx, "bucket", "")
|
err = obj.MakeBucketWithLocation(ctx, "bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -400,7 +400,7 @@ func TestHealing(t *testing.T) {
|
|||||||
xl := z.zones[0].sets[0]
|
xl := z.zones[0].sets[0]
|
||||||
|
|
||||||
// Create "bucket"
|
// Create "bucket"
|
||||||
err = obj.MakeBucketWithLocation(ctx, "bucket", "")
|
err = obj.MakeBucketWithLocation(ctx, "bucket", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -511,7 +511,7 @@ func testObjectQuorumFromMeta(obj ObjectLayer, instanceType string, dirs []strin
|
|||||||
xl := z.zones[0].sets[0]
|
xl := z.zones[0].sets[0]
|
||||||
xlDisks := xl.getDisks()
|
xlDisks := xl.getDisks()
|
||||||
|
|
||||||
err := obj.MakeBucketWithLocation(GlobalContext, bucket, globalMinioDefaultRegion)
|
err := obj.MakeBucketWithLocation(GlobalContext, bucket, globalMinioDefaultRegion, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to make a bucket %v", err)
|
t.Fatalf("Failed to make a bucket %v", err)
|
||||||
}
|
}
|
||||||
|
144
cmd/xl-zones.go
144
cmd/xl-zones.go
@ -31,6 +31,7 @@ import (
|
|||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
bucketsse "github.com/minio/minio/pkg/bucket/encryption"
|
bucketsse "github.com/minio/minio/pkg/bucket/encryption"
|
||||||
"github.com/minio/minio/pkg/bucket/lifecycle"
|
"github.com/minio/minio/pkg/bucket/lifecycle"
|
||||||
|
objectlock "github.com/minio/minio/pkg/bucket/object/lock"
|
||||||
"github.com/minio/minio/pkg/bucket/policy"
|
"github.com/minio/minio/pkg/bucket/policy"
|
||||||
"github.com/minio/minio/pkg/madmin"
|
"github.com/minio/minio/pkg/madmin"
|
||||||
"github.com/minio/minio/pkg/sync/errgroup"
|
"github.com/minio/minio/pkg/sync/errgroup"
|
||||||
@ -336,9 +337,19 @@ func undoMakeBucketZones(bucket string, zones []*xlSets, errs []error) {
|
|||||||
// MakeBucketWithLocation - creates a new bucket across all zones simultaneously
|
// MakeBucketWithLocation - creates a new bucket across all zones simultaneously
|
||||||
// even if one of the sets fail to create buckets, we proceed all the successful
|
// even if one of the sets fail to create buckets, we proceed all the successful
|
||||||
// operations.
|
// operations.
|
||||||
func (z *xlZones) MakeBucketWithLocation(ctx context.Context, bucket, location string) error {
|
func (z *xlZones) MakeBucketWithLocation(ctx context.Context, bucket, location string, lockEnabled bool) error {
|
||||||
if z.SingleZone() {
|
if z.SingleZone() {
|
||||||
return z.zones[0].MakeBucketWithLocation(ctx, bucket, location)
|
if err := z.zones[0].MakeBucketWithLocation(ctx, bucket, location, lockEnabled); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if lockEnabled {
|
||||||
|
meta := newBucketMetadata(bucket)
|
||||||
|
meta.LockEnabled = lockEnabled
|
||||||
|
if err := meta.save(ctx, z); err != nil {
|
||||||
|
return toObjectErr(err, bucket)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
g := errgroup.WithNErrs(len(z.zones))
|
g := errgroup.WithNErrs(len(z.zones))
|
||||||
@ -347,7 +358,7 @@ func (z *xlZones) MakeBucketWithLocation(ctx context.Context, bucket, location s
|
|||||||
for index := range z.zones {
|
for index := range z.zones {
|
||||||
index := index
|
index := index
|
||||||
g.Go(func() error {
|
g.Go(func() error {
|
||||||
return z.zones[index].MakeBucketWithLocation(ctx, bucket, location)
|
return z.zones[index].MakeBucketWithLocation(ctx, bucket, location, lockEnabled)
|
||||||
}, index)
|
}, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,6 +373,14 @@ func (z *xlZones) MakeBucketWithLocation(ctx context.Context, bucket, location s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if lockEnabled {
|
||||||
|
meta := newBucketMetadata(bucket)
|
||||||
|
meta.LockEnabled = lockEnabled
|
||||||
|
if err := meta.save(ctx, z); err != nil {
|
||||||
|
return toObjectErr(err, bucket)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Success.
|
// Success.
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
@ -405,11 +424,11 @@ func (z *xlZones) GetObjectNInfo(ctx context.Context, bucket, object string, rs
|
|||||||
|
|
||||||
func (z *xlZones) GetObject(ctx context.Context, bucket, object string, startOffset int64, length int64, writer io.Writer, etag string, opts ObjectOptions) error {
|
func (z *xlZones) GetObject(ctx context.Context, bucket, object string, startOffset int64, length int64, writer io.Writer, etag string, opts ObjectOptions) error {
|
||||||
// Lock the object before reading.
|
// Lock the object before reading.
|
||||||
objectLock := z.NewNSLock(ctx, bucket, object)
|
lk := z.NewNSLock(ctx, bucket, object)
|
||||||
if err := objectLock.GetRLock(globalObjectTimeout); err != nil {
|
if err := lk.GetRLock(globalObjectTimeout); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer objectLock.RUnlock()
|
defer lk.RUnlock()
|
||||||
|
|
||||||
if z.SingleZone() {
|
if z.SingleZone() {
|
||||||
return z.zones[0].GetObject(ctx, bucket, object, startOffset, length, writer, etag, opts)
|
return z.zones[0].GetObject(ctx, bucket, object, startOffset, length, writer, etag, opts)
|
||||||
@ -428,11 +447,11 @@ func (z *xlZones) GetObject(ctx context.Context, bucket, object string, startOff
|
|||||||
|
|
||||||
func (z *xlZones) GetObjectInfo(ctx context.Context, bucket, object string, opts ObjectOptions) (ObjectInfo, error) {
|
func (z *xlZones) GetObjectInfo(ctx context.Context, bucket, object string, opts ObjectOptions) (ObjectInfo, error) {
|
||||||
// Lock the object before reading.
|
// Lock the object before reading.
|
||||||
objectLock := z.NewNSLock(ctx, bucket, object)
|
lk := z.NewNSLock(ctx, bucket, object)
|
||||||
if err := objectLock.GetRLock(globalObjectTimeout); err != nil {
|
if err := lk.GetRLock(globalObjectTimeout); err != nil {
|
||||||
return ObjectInfo{}, err
|
return ObjectInfo{}, err
|
||||||
}
|
}
|
||||||
defer objectLock.RUnlock()
|
defer lk.RUnlock()
|
||||||
|
|
||||||
if z.SingleZone() {
|
if z.SingleZone() {
|
||||||
return z.zones[0].GetObjectInfo(ctx, bucket, object, opts)
|
return z.zones[0].GetObjectInfo(ctx, bucket, object, opts)
|
||||||
@ -453,11 +472,11 @@ func (z *xlZones) GetObjectInfo(ctx context.Context, bucket, object string, opts
|
|||||||
// PutObject - writes an object to least used erasure zone.
|
// PutObject - writes an object to least used erasure zone.
|
||||||
func (z *xlZones) PutObject(ctx context.Context, bucket string, object string, data *PutObjReader, opts ObjectOptions) (ObjectInfo, error) {
|
func (z *xlZones) PutObject(ctx context.Context, bucket string, object string, data *PutObjReader, opts ObjectOptions) (ObjectInfo, error) {
|
||||||
// Lock the object.
|
// Lock the object.
|
||||||
objectLock := z.NewNSLock(ctx, bucket, object)
|
lk := z.NewNSLock(ctx, bucket, object)
|
||||||
if err := objectLock.GetLock(globalObjectTimeout); err != nil {
|
if err := lk.GetLock(globalObjectTimeout); err != nil {
|
||||||
return ObjectInfo{}, err
|
return ObjectInfo{}, err
|
||||||
}
|
}
|
||||||
defer objectLock.Unlock()
|
defer lk.Unlock()
|
||||||
|
|
||||||
if z.SingleZone() {
|
if z.SingleZone() {
|
||||||
return z.zones[0].PutObject(ctx, bucket, object, data, opts)
|
return z.zones[0].PutObject(ctx, bucket, object, data, opts)
|
||||||
@ -480,11 +499,11 @@ func (z *xlZones) PutObject(ctx context.Context, bucket string, object string, d
|
|||||||
|
|
||||||
func (z *xlZones) DeleteObject(ctx context.Context, bucket string, object string) error {
|
func (z *xlZones) DeleteObject(ctx context.Context, bucket string, object string) error {
|
||||||
// Acquire a write lock before deleting the object.
|
// Acquire a write lock before deleting the object.
|
||||||
objectLock := z.NewNSLock(ctx, bucket, object)
|
lk := z.NewNSLock(ctx, bucket, object)
|
||||||
if err := objectLock.GetLock(globalOperationTimeout); err != nil {
|
if err := lk.GetLock(globalOperationTimeout); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer objectLock.Unlock()
|
defer lk.Unlock()
|
||||||
|
|
||||||
if z.SingleZone() {
|
if z.SingleZone() {
|
||||||
return z.zones[0].DeleteObject(ctx, bucket, object)
|
return z.zones[0].DeleteObject(ctx, bucket, object)
|
||||||
@ -531,11 +550,11 @@ func (z *xlZones) CopyObject(ctx context.Context, srcBucket, srcObject, destBuck
|
|||||||
// Check if this request is only metadata update.
|
// Check if this request is only metadata update.
|
||||||
cpSrcDstSame := isStringEqual(pathJoin(srcBucket, srcObject), pathJoin(destBucket, destObject))
|
cpSrcDstSame := isStringEqual(pathJoin(srcBucket, srcObject), pathJoin(destBucket, destObject))
|
||||||
if !cpSrcDstSame {
|
if !cpSrcDstSame {
|
||||||
objectLock := z.NewNSLock(ctx, destBucket, destObject)
|
lk := z.NewNSLock(ctx, destBucket, destObject)
|
||||||
if err := objectLock.GetLock(globalObjectTimeout); err != nil {
|
if err := lk.GetLock(globalObjectTimeout); err != nil {
|
||||||
return objInfo, err
|
return objInfo, err
|
||||||
}
|
}
|
||||||
defer objectLock.Unlock()
|
defer lk.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
if z.SingleZone() {
|
if z.SingleZone() {
|
||||||
@ -1110,11 +1129,11 @@ func (z *xlZones) CompleteMultipartUpload(ctx context.Context, bucket, object, u
|
|||||||
|
|
||||||
// Hold namespace to complete the transaction, only hold
|
// Hold namespace to complete the transaction, only hold
|
||||||
// if uploadID can be held exclusively.
|
// if uploadID can be held exclusively.
|
||||||
objectLock := z.NewNSLock(ctx, bucket, object)
|
lk := z.NewNSLock(ctx, bucket, object)
|
||||||
if err = objectLock.GetLock(globalOperationTimeout); err != nil {
|
if err = lk.GetLock(globalOperationTimeout); err != nil {
|
||||||
return objInfo, err
|
return objInfo, err
|
||||||
}
|
}
|
||||||
defer objectLock.Unlock()
|
defer lk.Unlock()
|
||||||
|
|
||||||
if z.SingleZone() {
|
if z.SingleZone() {
|
||||||
return z.zones[0].CompleteMultipartUpload(ctx, bucket, object, uploadID, uploadedParts, opts)
|
return z.zones[0].CompleteMultipartUpload(ctx, bucket, object, uploadID, uploadedParts, opts)
|
||||||
@ -1201,6 +1220,31 @@ func (z *xlZones) SetBucketSSEConfig(ctx context.Context, bucket string, config
|
|||||||
return saveBucketSSEConfig(ctx, z, bucket, config)
|
return saveBucketSSEConfig(ctx, z, bucket, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetBucketObjectLockConfig enables/clears default object lock configuration
|
||||||
|
func (z *xlZones) SetBucketObjectLockConfig(ctx context.Context, bucket string, config *objectlock.Config) error {
|
||||||
|
return saveBucketObjectLockConfig(ctx, z, bucket, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBucketObjectLockConfig - returns current defaults for object lock configuration
|
||||||
|
func (z *xlZones) GetBucketObjectLockConfig(ctx context.Context, bucket string) (*objectlock.Config, error) {
|
||||||
|
return readBucketObjectLockConfig(ctx, z, bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBucketTagging sets bucket tags on given bucket
|
||||||
|
func (z *xlZones) SetBucketTagging(ctx context.Context, bucket string, t *tags.Tags) error {
|
||||||
|
return saveBucketTagging(ctx, z, bucket, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBucketTagging get bucket tags set on given bucket
|
||||||
|
func (z *xlZones) GetBucketTagging(ctx context.Context, bucket string) (*tags.Tags, error) {
|
||||||
|
return readBucketTagging(ctx, z, bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBucketTagging delete bucket tags set if any.
|
||||||
|
func (z *xlZones) DeleteBucketTagging(ctx context.Context, bucket string) error {
|
||||||
|
return deleteBucketTagging(ctx, z, bucket)
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteBucketSSEConfig deletes bucket encryption config on given bucket
|
// DeleteBucketSSEConfig deletes bucket encryption config on given bucket
|
||||||
func (z *xlZones) DeleteBucketSSEConfig(ctx context.Context, bucket string) error {
|
func (z *xlZones) DeleteBucketSSEConfig(ctx context.Context, bucket string) error {
|
||||||
return removeBucketSSEConfig(ctx, z, bucket)
|
return removeBucketSSEConfig(ctx, z, bucket)
|
||||||
@ -1245,27 +1289,14 @@ func (z *xlZones) DeleteBucket(ctx context.Context, bucket string, forceDelete b
|
|||||||
|
|
||||||
errs := g.Wait()
|
errs := g.Wait()
|
||||||
|
|
||||||
if forceDelete {
|
// For any write quorum failure, we undo all the delete
|
||||||
for _, err := range errs {
|
// buckets operation by creating all the buckets again.
|
||||||
if err != nil {
|
|
||||||
if _, ok := err.(InsufficientWriteQuorum); ok {
|
|
||||||
undoDeleteBucketZones(bucket, z.zones, errs)
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// For any write quorum failure, we undo all the delete buckets operation
|
|
||||||
// by creating all the buckets again.
|
|
||||||
for _, err := range errs {
|
for _, err := range errs {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(InsufficientWriteQuorum); ok {
|
if _, ok := err.(InsufficientWriteQuorum); ok {
|
||||||
undoDeleteBucketZones(bucket, z.zones, errs)
|
undoDeleteBucketZones(bucket, z.zones, errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1283,7 +1314,7 @@ func undoDeleteBucketZones(bucket string, zones []*xlSets, errs []error) {
|
|||||||
index := index
|
index := index
|
||||||
g.Go(func() error {
|
g.Go(func() error {
|
||||||
if errs[index] == nil {
|
if errs[index] == nil {
|
||||||
return zones[index].MakeBucketWithLocation(GlobalContext, bucket, "")
|
return zones[index].MakeBucketWithLocation(GlobalContext, bucket, "", false)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}, index)
|
}, index)
|
||||||
@ -1297,17 +1328,30 @@ func undoDeleteBucketZones(bucket string, zones []*xlSets, errs []error) {
|
|||||||
// that all buckets are present on all zones.
|
// that all buckets are present on all zones.
|
||||||
func (z *xlZones) ListBuckets(ctx context.Context) (buckets []BucketInfo, err error) {
|
func (z *xlZones) ListBuckets(ctx context.Context) (buckets []BucketInfo, err error) {
|
||||||
if z.SingleZone() {
|
if z.SingleZone() {
|
||||||
return z.zones[0].ListBuckets(ctx)
|
buckets, err = z.zones[0].ListBuckets(ctx)
|
||||||
}
|
} else {
|
||||||
for _, zone := range z.zones {
|
for _, zone := range z.zones {
|
||||||
buckets, err := zone.ListBuckets(ctx)
|
buckets, err = zone.ListBuckets(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.LogIf(ctx, err)
|
logger.LogIf(ctx, err)
|
||||||
continue
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
return buckets, nil
|
|
||||||
}
|
}
|
||||||
return buckets, InsufficientReadQuorum{}
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for i := range buckets {
|
||||||
|
meta, err := loadBucketMetadata(ctx, z, buckets[i].Name)
|
||||||
|
if err == nil {
|
||||||
|
buckets[i].Created = meta.Created
|
||||||
|
}
|
||||||
|
if err != errMetaDataConverted {
|
||||||
|
logger.LogIf(ctx, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buckets, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *xlZones) ReloadFormat(ctx context.Context, dryRun bool) error {
|
func (z *xlZones) ReloadFormat(ctx context.Context, dryRun bool) error {
|
||||||
@ -1488,11 +1532,11 @@ func (z *xlZones) HealObjects(ctx context.Context, bucket, prefix string, opts m
|
|||||||
func (z *xlZones) HealObject(ctx context.Context, bucket, object string, opts madmin.HealOpts) (madmin.HealResultItem, error) {
|
func (z *xlZones) HealObject(ctx context.Context, bucket, object string, opts madmin.HealOpts) (madmin.HealResultItem, error) {
|
||||||
// Lock the object before healing. Use read lock since healing
|
// Lock the object before healing. Use read lock since healing
|
||||||
// will only regenerate parts & xl.json of outdated disks.
|
// will only regenerate parts & xl.json of outdated disks.
|
||||||
objectLock := z.NewNSLock(ctx, bucket, object)
|
lk := z.NewNSLock(ctx, bucket, object)
|
||||||
if err := objectLock.GetRLock(globalHealingTimeout); err != nil {
|
if err := lk.GetRLock(globalHealingTimeout); err != nil {
|
||||||
return madmin.HealResultItem{}, err
|
return madmin.HealResultItem{}, err
|
||||||
}
|
}
|
||||||
defer objectLock.RUnlock()
|
defer lk.RUnlock()
|
||||||
|
|
||||||
if z.SingleZone() {
|
if z.SingleZone() {
|
||||||
return z.zones[0].HealObject(ctx, bucket, object, opts)
|
return z.zones[0].HealObject(ctx, bucket, object, opts)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
#
|
#
|
||||||
# Mint (C) 2017, 2018 Minio, Inc.
|
# Mint (C) 2017-2020 Minio, Inc.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@ -69,24 +69,6 @@ function make_bucket() {
|
|||||||
return $rv
|
return $rv
|
||||||
}
|
}
|
||||||
|
|
||||||
function make_bucket_with_lock() {
|
|
||||||
# Make bucket
|
|
||||||
bucket_name="awscli-mint-test-bucket-$RANDOM"
|
|
||||||
function="${AWS} s3api create-bucket --bucket ${bucket_name} --object-lock-enabled-for-bucket"
|
|
||||||
|
|
||||||
# execute the test
|
|
||||||
out=$($function 2>&1)
|
|
||||||
rv=$?
|
|
||||||
|
|
||||||
# if command is successful print bucket_name or print error
|
|
||||||
if [ $rv -eq 0 ]; then
|
|
||||||
echo "${bucket_name}"
|
|
||||||
else
|
|
||||||
echo "${out}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
return $rv
|
|
||||||
}
|
|
||||||
function delete_bucket() {
|
function delete_bucket() {
|
||||||
# Delete bucket
|
# Delete bucket
|
||||||
function="${AWS} s3 rb s3://${1} --force"
|
function="${AWS} s3 rb s3://${1} --force"
|
||||||
@ -688,7 +670,7 @@ function test_copy_object_storage_class() {
|
|||||||
out=$($function 2>&1)
|
out=$($function 2>&1)
|
||||||
rv=$?
|
rv=$?
|
||||||
# if this functionality is not implemented return right away.
|
# if this functionality is not implemented return right away.
|
||||||
if [ $rv -eq 255 ]; then
|
if [ $rv -ne 0 ]; then
|
||||||
if echo "$out" | greq -q "NotImplemented"; then
|
if echo "$out" | greq -q "NotImplemented"; then
|
||||||
${AWS} s3 rb s3://"${bucket_name}" --force > /dev/null 2>&1
|
${AWS} s3 rb s3://"${bucket_name}" --force > /dev/null 2>&1
|
||||||
return 0
|
return 0
|
||||||
@ -758,7 +740,7 @@ function test_copy_object_storage_class_same() {
|
|||||||
out=$($function 2>&1)
|
out=$($function 2>&1)
|
||||||
rv=$?
|
rv=$?
|
||||||
# if this functionality is not implemented return right away.
|
# if this functionality is not implemented return right away.
|
||||||
if [ $rv -eq 255 ]; then
|
if [ $rv -ne 0 ]; then
|
||||||
if echo "$out" | greq -q "NotImplemented"; then
|
if echo "$out" | greq -q "NotImplemented"; then
|
||||||
${AWS} s3 rb s3://"${bucket_name}" --force > /dev/null 2>&1
|
${AWS} s3 rb s3://"${bucket_name}" --force > /dev/null 2>&1
|
||||||
return 0
|
return 0
|
||||||
@ -1591,9 +1573,22 @@ function test_legal_hold() {
|
|||||||
# log start time
|
# log start time
|
||||||
start_time=$(get_time)
|
start_time=$(get_time)
|
||||||
|
|
||||||
function="make_bucket_with_lock"
|
# Make bucket
|
||||||
bucket_name=$(make_bucket_with_lock)
|
bucket_name="awscli-mint-test-bucket-$RANDOM"
|
||||||
|
function="${AWS} s3api create-bucket --bucket ${bucket_name} --object-lock-enabled-for-bucket"
|
||||||
|
|
||||||
|
# execute the test
|
||||||
|
out=$($function 2>&1)
|
||||||
rv=$?
|
rv=$?
|
||||||
|
|
||||||
|
if [ $rv -ne 0 ]; then
|
||||||
|
# if this functionality is not implemented return right away.
|
||||||
|
if echo "$out" | greq -q "NotImplemented"; then
|
||||||
|
${AWS} s3 rb s3://"${bucket_name}" --force > /dev/null 2>&1
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# if make bucket succeeds upload a file
|
# if make bucket succeeds upload a file
|
||||||
if [ $rv -eq 0 ]; then
|
if [ $rv -eq 0 ]; then
|
||||||
function="${AWS} s3api put-object --body ${MINT_DATA_DIR}/datafile-1-kB --bucket ${bucket_name} --key datafile-1-kB --object-lock-legal-hold-status ON"
|
function="${AWS} s3api put-object --body ${MINT_DATA_DIR}/datafile-1-kB --bucket ${bucket_name} --key datafile-1-kB --object-lock-legal-hold-status ON"
|
||||||
|
@ -24,7 +24,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/beevik/ntp"
|
"github.com/beevik/ntp"
|
||||||
@ -158,41 +157,6 @@ func (r Retention) Retain(created time.Time) bool {
|
|||||||
return created.Add(r.Validity).After(t)
|
return created.Add(r.Validity).After(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BucketObjectLockConfig - map of bucket and retention configuration.
|
|
||||||
type BucketObjectLockConfig struct {
|
|
||||||
sync.RWMutex
|
|
||||||
retentionMap map[string]*Retention
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set - set retention configuration.
|
|
||||||
func (config *BucketObjectLockConfig) Set(bucketName string, retention *Retention) {
|
|
||||||
config.Lock()
|
|
||||||
config.retentionMap[bucketName] = retention
|
|
||||||
config.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get - Get retention configuration.
|
|
||||||
func (config *BucketObjectLockConfig) Get(bucketName string) (r *Retention, ok bool) {
|
|
||||||
config.RLock()
|
|
||||||
defer config.RUnlock()
|
|
||||||
r, ok = config.retentionMap[bucketName]
|
|
||||||
return r, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove - removes retention configuration.
|
|
||||||
func (config *BucketObjectLockConfig) Remove(bucketName string) {
|
|
||||||
config.Lock()
|
|
||||||
delete(config.retentionMap, bucketName)
|
|
||||||
config.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBucketObjectLockConfig returns initialized BucketObjectLockConfig
|
|
||||||
func NewBucketObjectLockConfig() *BucketObjectLockConfig {
|
|
||||||
return &BucketObjectLockConfig{
|
|
||||||
retentionMap: make(map[string]*Retention),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultRetention - default retention configuration.
|
// DefaultRetention - default retention configuration.
|
||||||
type DefaultRetention struct {
|
type DefaultRetention struct {
|
||||||
XMLName xml.Name `xml:"DefaultRetention"`
|
XMLName xml.Name `xml:"DefaultRetention"`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user