| 
									
										
										
										
											2021-04-19 03:41:13 +08:00
										 |  |  | // Copyright (c) 2015-2021 MinIO, Inc.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This file is part of MinIO Object Storage stack
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU Affero General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or
 | 
					
						
							|  |  |  | // (at your option) any later version.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU Affero General Public License for more details.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU Affero General Public License
 | 
					
						
							|  |  |  | // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2016-06-02 07:43:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 07:23:42 +08:00
										 |  |  | package cmd | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2018-03-15 03:01:47 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2020-10-14 09:28:42 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2017-11-26 03:58:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-15 00:38:05 +08:00
										 |  |  | 	"github.com/minio/minio-go/v7/pkg/s3utils" | 
					
						
							| 
									
										
										
										
											2021-06-02 05:59:40 +08:00
										 |  |  | 	"github.com/minio/minio/internal/logger" | 
					
						
							|  |  |  | 	"github.com/minio/minio/internal/sync/errgroup" | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-24 12:05:04 +08:00
										 |  |  | // list all errors that can be ignore in a bucket operation.
 | 
					
						
							| 
									
										
										
										
											2020-07-25 04:16:11 +08:00
										 |  |  | var bucketOpIgnoredErrs = append(baseIgnoredErrs, errDiskAccessDenied, errUnformattedDisk) | 
					
						
							| 
									
										
										
										
											2016-11-24 12:05:04 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-21 08:57:12 +08:00
										 |  |  | // list all errors that can be ignored in a bucket metadata operation.
 | 
					
						
							|  |  |  | var bucketMetadataOpIgnoredErrs = append(bucketOpIgnoredErrs, errVolumeNotFound) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-17 01:28:29 +08:00
										 |  |  | // Bucket operations
 | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // MakeBucket - make a bucket.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | func (er erasureObjects) MakeBucketWithLocation(ctx context.Context, bucket string, opts BucketOptions) error { | 
					
						
							| 
									
										
										
										
											2021-05-17 23:25:48 +08:00
										 |  |  | 	defer NSUpdated(bucket, slashSeparator) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | 	// Verify if bucket is valid.
 | 
					
						
							| 
									
										
										
										
											2019-03-06 02:42:32 +08:00
										 |  |  | 	if err := s3utils.CheckValidBucketNameStrict(bucket); err != nil { | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 		return BucketNameInvalid{Bucket: bucket} | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	storageDisks := er.getDisks() | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-15 00:44:51 +08:00
										 |  |  | 	g := errgroup.WithNErrs(len(storageDisks)) | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Make a volume entry on all underlying storage disks.
 | 
					
						
							| 
									
										
										
										
											2019-10-15 00:44:51 +08:00
										 |  |  | 	for index := range storageDisks { | 
					
						
							|  |  |  | 		index := index | 
					
						
							|  |  |  | 		g.Go(func() error { | 
					
						
							|  |  |  | 			if storageDisks[index] != nil { | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 				if err := storageDisks[index].MakeVol(ctx, bucket); err != nil { | 
					
						
							| 
									
										
										
										
											2020-10-14 09:28:42 +08:00
										 |  |  | 					if !errors.Is(err, errVolumeExists) { | 
					
						
							| 
									
										
										
										
											2019-10-15 00:44:51 +08:00
										 |  |  | 						logger.LogIf(ctx, err) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					return err | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2019-10-15 00:44:51 +08:00
										 |  |  | 				return nil | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-10-15 00:44:51 +08:00
										 |  |  | 			return errDiskNotFound | 
					
						
							|  |  |  | 		}, index) | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 00:32:16 +08:00
										 |  |  | 	writeQuorum := getWriteQuorum(len(storageDisks)) | 
					
						
							| 
									
										
										
										
											2019-10-15 00:44:51 +08:00
										 |  |  | 	err := reduceWriteQuorumErrs(ctx, g.Wait(), bucketOpIgnoredErrs, writeQuorum) | 
					
						
							| 
									
										
										
										
											2017-02-02 03:16:17 +08:00
										 |  |  | 	return toObjectErr(err, bucket) | 
					
						
							| 
									
										
										
										
											2016-06-18 02:57:51 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-15 00:44:51 +08:00
										 |  |  | func undoDeleteBucket(storageDisks []StorageAPI, bucket string) { | 
					
						
							|  |  |  | 	g := errgroup.WithNErrs(len(storageDisks)) | 
					
						
							| 
									
										
										
										
											2016-07-21 15:27:08 +08:00
										 |  |  | 	// Undo previous make bucket entry on all underlying storage disks.
 | 
					
						
							| 
									
										
										
										
											2019-10-15 00:44:51 +08:00
										 |  |  | 	for index := range storageDisks { | 
					
						
							|  |  |  | 		if storageDisks[index] == nil { | 
					
						
							| 
									
										
										
										
											2016-07-21 15:27:08 +08:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-10-15 00:44:51 +08:00
										 |  |  | 		index := index | 
					
						
							|  |  |  | 		g.Go(func() error { | 
					
						
							| 
									
										
										
										
											2020-09-05 00:45:06 +08:00
										 |  |  | 			_ = storageDisks[index].MakeVol(context.Background(), bucket) | 
					
						
							| 
									
										
										
										
											2019-10-15 00:44:51 +08:00
										 |  |  | 			return nil | 
					
						
							|  |  |  | 		}, index) | 
					
						
							| 
									
										
										
										
											2016-07-21 15:27:08 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Wait for all make vol to finish.
 | 
					
						
							| 
									
										
										
										
											2019-10-15 00:44:51 +08:00
										 |  |  | 	g.Wait() | 
					
						
							| 
									
										
										
										
											2016-07-21 15:27:08 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 07:43:31 +08:00
										 |  |  | // getBucketInfo - returns the BucketInfo from one of the load balanced disks.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | func (er erasureObjects) getBucketInfo(ctx context.Context, bucketName string) (bucketInfo BucketInfo, err error) { | 
					
						
							| 
									
										
										
										
											2020-09-29 10:39:32 +08:00
										 |  |  | 	storageDisks := er.getDisks() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	g := errgroup.WithNErrs(len(storageDisks)) | 
					
						
							|  |  |  | 	var bucketsInfo = make([]BucketInfo, len(storageDisks)) | 
					
						
							|  |  |  | 	// Undo previous make bucket entry on all underlying storage disks.
 | 
					
						
							|  |  |  | 	for index := range storageDisks { | 
					
						
							|  |  |  | 		index := index | 
					
						
							|  |  |  | 		g.Go(func() error { | 
					
						
							|  |  |  | 			if storageDisks[index] == nil { | 
					
						
							|  |  |  | 				return errDiskNotFound | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			volInfo, err := storageDisks[index].StatVol(ctx, bucketName) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-09-18 06:02:21 +08:00
										 |  |  | 			bucketsInfo[index] = BucketInfo(volInfo) | 
					
						
							| 
									
										
										
										
											2020-09-29 10:39:32 +08:00
										 |  |  | 			return nil | 
					
						
							|  |  |  | 		}, index) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	errs := g.Wait() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, err := range errs { | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			return bucketsInfo[i], nil | 
					
						
							| 
									
										
										
										
											2016-06-02 07:43:31 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-09-29 10:39:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 06:38:35 +08:00
										 |  |  | 	// If all our errors were ignored, then we try to
 | 
					
						
							|  |  |  | 	// reduce to one error based on read quorum.
 | 
					
						
							|  |  |  | 	// `nil` is deliberately passed for ignoredErrs
 | 
					
						
							|  |  |  | 	// because these errors were already ignored.
 | 
					
						
							| 
									
										
										
										
											2020-09-29 10:39:32 +08:00
										 |  |  | 	readQuorum := getReadQuorum(len(storageDisks)) | 
					
						
							|  |  |  | 	return BucketInfo{}, reduceReadQuorumErrs(ctx, errs, nil, readQuorum) | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-26 18:15:01 +08:00
										 |  |  | // GetBucketInfo - returns BucketInfo for a bucket.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | func (er erasureObjects) GetBucketInfo(ctx context.Context, bucket string) (bi BucketInfo, e error) { | 
					
						
							|  |  |  | 	bucketInfo, err := er.getBucketInfo(ctx, bucket) | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:53:09 +08:00
										 |  |  | 		return bi, toObjectErr(err, bucket) | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-05-26 18:15:01 +08:00
										 |  |  | 	return bucketInfo, nil | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-26 18:15:01 +08:00
										 |  |  | // DeleteBucket - deletes a bucket.
 | 
					
						
							| 
									
										
										
										
											2021-10-07 01:24:40 +08:00
										 |  |  | func (er erasureObjects) DeleteBucket(ctx context.Context, bucket string, opts DeleteBucketOptions) error { | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | 	// Collect if all disks report volume not found.
 | 
					
						
							| 
									
										
										
										
											2021-05-17 23:25:48 +08:00
										 |  |  | 	defer NSUpdated(bucket, slashSeparator) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	storageDisks := er.getDisks() | 
					
						
							| 
									
										
										
										
											2019-02-06 09:58:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-15 00:44:51 +08:00
										 |  |  | 	g := errgroup.WithNErrs(len(storageDisks)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for index := range storageDisks { | 
					
						
							|  |  |  | 		index := index | 
					
						
							|  |  |  | 		g.Go(func() error { | 
					
						
							|  |  |  | 			if storageDisks[index] != nil { | 
					
						
							| 
									
										
										
										
											2021-10-07 01:24:40 +08:00
										 |  |  | 				return storageDisks[index].DeleteVol(ctx, bucket, opts.Force) | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-10-15 00:44:51 +08:00
										 |  |  | 			return errDiskNotFound | 
					
						
							|  |  |  | 		}, index) | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Wait for all the delete vols to finish.
 | 
					
						
							| 
									
										
										
										
											2019-10-15 00:44:51 +08:00
										 |  |  | 	dErrs := g.Wait() | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 01:24:40 +08:00
										 |  |  | 	if opts.Force { | 
					
						
							| 
									
										
										
										
											2020-03-28 12:52:59 +08:00
										 |  |  | 		for _, err := range dErrs { | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				undoDeleteBucket(storageDisks, bucket) | 
					
						
							|  |  |  | 				return toObjectErr(err, bucket) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 00:32:16 +08:00
										 |  |  | 	writeQuorum := getWriteQuorum(len(storageDisks)) | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	err := reduceWriteQuorumErrs(ctx, dErrs, bucketOpIgnoredErrs, writeQuorum) | 
					
						
							| 
									
										
										
										
											2021-10-07 01:24:40 +08:00
										 |  |  | 	if err == errErasureWriteQuorum && !opts.NoRecreate { | 
					
						
							| 
									
										
										
										
											2019-10-15 00:44:51 +08:00
										 |  |  | 		undoDeleteBucket(storageDisks, bucket) | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-10 07:19:30 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-02 12:52:45 +08:00
										 |  |  | 	if err == nil || errors.Is(err, errVolumeNotFound) { | 
					
						
							|  |  |  | 		var purgedDangling bool | 
					
						
							|  |  |  | 		// At this point we have `err == nil` but some errors might be `errVolumeNotEmpty`
 | 
					
						
							|  |  |  | 		// we should proceed to attempt a force delete of such buckets.
 | 
					
						
							|  |  |  | 		for index, err := range dErrs { | 
					
						
							|  |  |  | 			if err == errVolumeNotEmpty && storageDisks[index] != nil { | 
					
						
							|  |  |  | 				storageDisks[index].RenameFile(ctx, bucket, "", minioMetaTmpDeletedBucket, mustGetUUID()) | 
					
						
							|  |  |  | 				purgedDangling = true | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-10-07 00:20:25 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-11-02 12:52:45 +08:00
										 |  |  | 		// if we purged dangling buckets, ignore errVolumeNotFound error.
 | 
					
						
							|  |  |  | 		if purgedDangling { | 
					
						
							|  |  |  | 			err = nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 00:20:25 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-02-06 09:58:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-02 12:52:45 +08:00
										 |  |  | 	return toObjectErr(err, bucket) | 
					
						
							| 
									
										
										
										
											2018-02-10 07:19:30 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // IsNotificationSupported returns whether bucket notification is applicable for this layer.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | func (er erasureObjects) IsNotificationSupported() bool { | 
					
						
							| 
									
										
										
										
											2018-02-10 07:19:30 +08:00
										 |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-21 03:52:49 +08:00
										 |  |  | // IsListenSupported returns whether listen bucket notification is applicable for this layer.
 | 
					
						
							|  |  |  | func (er erasureObjects) IsListenSupported() bool { | 
					
						
							| 
									
										
										
										
											2018-12-06 06:03:42 +08:00
										 |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-06 06:16:43 +08:00
										 |  |  | // IsEncryptionSupported returns whether server side encryption is implemented for this layer.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | func (er erasureObjects) IsEncryptionSupported() bool { | 
					
						
							| 
									
										
										
										
											2018-02-10 07:19:30 +08:00
										 |  |  | 	return true | 
					
						
							| 
									
										
										
										
											2016-05-21 11:48:47 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-09-28 11:36:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // IsCompressionSupported returns whether compression is applicable for this layer.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | func (er erasureObjects) IsCompressionSupported() bool { | 
					
						
							| 
									
										
										
										
											2018-09-28 11:36:17 +08:00
										 |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-05-24 02:09:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | // IsTaggingSupported indicates whether erasureObjects implements tagging support.
 | 
					
						
							|  |  |  | func (er erasureObjects) IsTaggingSupported() bool { | 
					
						
							| 
									
										
										
										
											2020-05-24 02:09:35 +08:00
										 |  |  | 	return true | 
					
						
							|  |  |  | } |