@ -19,19 +19,23 @@ package cmd
import (
import (
"bytes"
"bytes"
"context"
"context"
"errors"
"fmt"
"fmt"
"sync"
"sync"
"github.com/minio/minio-go/v6/pkg/tags"
bucketsse "github.com/minio/minio/pkg/bucket/encryption"
"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/event"
"github.com/minio/minio/pkg/madmin"
)
)
// BucketMetadataSys captures all bucket metadata for a given cluster.
// BucketMetadataSys captures all bucket metadata for a given cluster.
type BucketMetadataSys struct {
type BucketMetadataSys struct {
sync . RWMutex
sync . RWMutex
metadataMap map [ string ] BucketMetadata
metadataMap map [ string ] BucketMetadata
// Do fallback to old config when unable to find a bucket config
fallback bool
}
}
// Remove bucket metadata from memory.
// Remove bucket metadata from memory.
@ -84,13 +88,9 @@ func (sys *BucketMetadataSys) Update(bucket string, configFile string, configDat
return errInvalidArgument
return errInvalidArgument
}
}
defer globalNotificationSys . LoadBucketMetadata ( GlobalContext , bucket )
meta , err := loadBucketMetadata ( GlobalContext , objAPI , bucket )
if err != nil {
sys . Lock ( )
return err
meta , ok := sys . metadataMap [ bucket ]
sys . Unlock ( )
if ! ok {
return BucketNotFound { Bucket : bucket }
}
}
switch configFile {
switch configFile {
@ -116,9 +116,8 @@ func (sys *BucketMetadataSys) Update(bucket string, configFile string, configDat
return err
return err
}
}
sys . Lock ( )
sys . Set ( bucket , meta )
sys . metadataMap [ bucket ] = meta
globalNotificationSys . LoadBucketMetadata ( GlobalContext , bucket )
sys . Unlock ( )
return nil
return nil
}
}
@ -143,62 +142,134 @@ func (sys *BucketMetadataSys) Get(bucket string) (BucketMetadata, error) {
return meta , nil
return meta , nil
}
}
// GetConfig returns a specific configuration from the bucket metadata.
// GetTaggingConfig returns configured tagging config
// The returned data should be copied before being modified.
// The returned object may not be modified.
func ( sys * BucketMetadataSys ) GetConfig ( bucket string , configFile string ) ( [ ] byte , error ) {
func ( sys * BucketMetadataSys ) GetTaggingConfig ( bucket string ) ( * tags . Tags , error ) {
if globalIsGateway {
meta , err := sys . GetConfig ( bucket )
return nil , NotImplemented { }
if err != nil {
if errors . Is ( err , errConfigNotFound ) {
return nil , BucketTaggingNotFound { Bucket : bucket }
}
return nil , err
}
}
if meta . taggingConfig == nil {
if bucket == minioMetaBucket {
return nil , BucketTaggingNotFound { Bucket : bucket }
return nil , errInvalidArgument
}
}
return meta . taggingConfig , nil
}
sys . RLock ( )
// GetObjectLockConfig returns configured object lock config
defer sys . RUnlock ( )
// The returned object may not be modified.
func ( sys * BucketMetadataSys ) GetObjectLockConfig ( bucket string ) ( * objectlock . Config , error ) {
meta , err := sys . GetConfig ( bucket )
if err != nil {
if errors . Is ( err , errConfigNotFound ) {
return nil , BucketObjectLockConfigNotFound { Bucket : bucket }
}
return nil , err
}
if meta . objectLockConfig == nil {
return nil , BucketObjectLockConfigNotFound { Bucket : bucket }
}
return meta . objectLockConfig , nil
}
meta , ok := sys . metadataMap [ bucket ]
// GetLifecycleConfig returns configured lifecycle config
if ! ok {
// The returned object may not be modified.
if ! sys . fallback {
func ( sys * BucketMetadataSys ) GetLifecycleConfig ( bucket string ) ( * lifecycle . Lifecycle , error ) {
return nil , errConfigNotFound
meta , err := sys . GetConfig ( bucket )
if err != nil {
if errors . Is ( err , errConfigNotFound ) {
return nil , BucketLifecycleNotFound { Bucket : bucket }
}
}
objAPI := newObjectLayerWithoutSafeModeFn ( )
return nil , err
if objAPI == nil {
}
return nil , errServerNotInitialized
if meta . lifecycleConfig == nil {
return nil , BucketLifecycleNotFound { Bucket : bucket }
}
return meta . lifecycleConfig , nil
}
// GetNotificationConfig returns configured notification config
// The returned object may not be modified.
func ( sys * BucketMetadataSys ) GetNotificationConfig ( bucket string ) ( * event . Config , error ) {
meta , err := sys . GetConfig ( bucket )
if err != nil {
return nil , err
}
return meta . notificationConfig , nil
}
// GetSSEConfig returns configured SSE config
// The returned object may not be modified.
func ( sys * BucketMetadataSys ) GetSSEConfig ( bucket string ) ( * bucketsse . BucketSSEConfig , error ) {
meta , err := sys . GetConfig ( bucket )
if err != nil {
if errors . Is ( err , errConfigNotFound ) {
return nil , BucketSSEConfigNotFound { Bucket : bucket }
}
}
var err error
return nil , err
meta , err = loadBucketMetadata ( GlobalContext , objAPI , bucket )
}
if err != nil {
if meta . sseConfig == nil {
return nil , err
return nil , BucketSSEConfigNotFound { Bucket : bucket }
}
return meta . sseConfig , nil
}
// GetPolicyConfig returns configured bucket policy
// The returned object may not be modified.
func ( sys * BucketMetadataSys ) GetPolicyConfig ( bucket string ) ( * policy . Policy , error ) {
meta , err := sys . GetConfig ( bucket )
if err != nil {
if errors . Is ( err , errConfigNotFound ) {
return nil , BucketPolicyNotFound { Bucket : bucket }
}
}
sys . metadataMap [ bucket ] = meta
return nil , err
}
if meta . policyConfig == nil {
return nil , BucketPolicyNotFound { Bucket : bucket }
}
}
return meta . policyConfig , nil
}
var configData [ ] byte
// GetQuotaConfig returns configured bucket quota
switch configFile {
// The returned object may not be modified.
case bucketPolicyConfig :
func ( sys * BucketMetadataSys ) GetQuotaConfig ( bucket string ) ( * madmin . BucketQuota , error ) {
configData = meta . PolicyConfigJSON
meta , err := sys . GetConfig ( bucket )
case bucketNotificationConfig :
if err != nil {
configData = meta . NotificationXML
return nil , err
case bucketLifecycleConfig :
configData = meta . LifecycleConfigXML
case bucketSSEConfig :
configData = meta . EncryptionConfigXML
case bucketTaggingConfigFile :
configData = meta . TaggingConfigXML
case objectLockConfig :
configData = meta . ObjectLockConfigurationXML
case bucketQuotaConfigFile :
configData = meta . QuotaConfigJSON
default :
return nil , fmt . Errorf ( "Unknown bucket %s metadata update requested %s" , bucket , configFile )
}
}
return meta . quotaConfig , nil
}
if len ( configData ) == 0 {
// GetConfig returns a specific configuration from the bucket metadata.
return nil , errConfigNotFound
// The returned object may not be modified.
func ( sys * BucketMetadataSys ) GetConfig ( bucket string ) ( BucketMetadata , error ) {
objAPI := newObjectLayerWithoutSafeModeFn ( )
if objAPI == nil {
return newBucketMetadata ( bucket ) , errServerNotInitialized
}
if globalIsGateway {
return newBucketMetadata ( bucket ) , NotImplemented { }
}
if bucket == minioMetaBucket {
return newBucketMetadata ( bucket ) , errInvalidArgument
}
}
return configData , nil
sys . Lock ( )
defer sys . Unlock ( )
meta , ok := sys . metadataMap [ bucket ]
if ok {
return meta , nil
}
meta , err := loadBucketMetadata ( GlobalContext , objAPI , bucket )
if err != nil {
return meta , err
}
sys . metadataMap [ bucket ] = meta
return meta , nil
}
}
// Init - initializes bucket metadata system for all buckets.
// Init - initializes bucket metadata system for all buckets.
@ -218,7 +289,6 @@ func (sys *BucketMetadataSys) Init(ctx context.Context, buckets []BucketInfo, ob
}
}
// Loads bucket metadata for all buckets into BucketMetadataSys.
// Loads bucket metadata for all buckets into BucketMetadataSys.
// When if done successfully fallback will be disabled.
func ( sys * BucketMetadataSys ) load ( ctx context . Context , buckets [ ] BucketInfo , objAPI ObjectLayer ) error {
func ( sys * BucketMetadataSys ) load ( ctx context . Context , buckets [ ] BucketInfo , objAPI ObjectLayer ) error {
sys . Lock ( )
sys . Lock ( )
defer sys . Unlock ( )
defer sys . Unlock ( )
@ -230,7 +300,6 @@ func (sys *BucketMetadataSys) load(ctx context.Context, buckets []BucketInfo, ob
}
}
sys . metadataMap [ bucket . Name ] = meta
sys . metadataMap [ bucket . Name ] = meta
}
}
sys . fallback = false
return nil
return nil
}
}
@ -238,8 +307,5 @@ func (sys *BucketMetadataSys) load(ctx context.Context, buckets []BucketInfo, ob
func NewBucketMetadataSys ( ) * BucketMetadataSys {
func NewBucketMetadataSys ( ) * BucketMetadataSys {
return & BucketMetadataSys {
return & BucketMetadataSys {
metadataMap : make ( map [ string ] BucketMetadata ) ,
metadataMap : make ( map [ string ] BucketMetadata ) ,
// Do fallback until all buckets have been loaded.
fallback : true ,
}
}
}
}