2021-04-18 15:41:13 -04: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/>.
2020-04-30 18:55:54 -04:00
package cmd
import (
"context"
"encoding/json"
2022-02-17 15:49:46 -05:00
"errors"
2020-04-30 18:55:54 -04:00
"fmt"
"time"
2021-05-06 11:52:02 -04:00
"github.com/minio/madmin-go"
2022-02-17 15:49:46 -05:00
"github.com/minio/minio/internal/logger"
2020-04-30 18:55:54 -04:00
)
// BucketQuotaSys - map of bucket and quota configuration.
2020-05-27 09:45:43 -04:00
type BucketQuotaSys struct {
bucketStorageCache timedValue
}
2020-04-30 18:55:54 -04:00
// Get - Get quota configuration.
2022-01-31 20:27:43 -05:00
func ( sys * BucketQuotaSys ) Get ( ctx context . Context , bucketName string ) ( * madmin . BucketQuota , error ) {
2020-05-19 16:53:54 -04:00
if globalIsGateway {
objAPI := newObjectLayerFn ( )
if objAPI == nil {
2020-05-20 13:18:15 -04:00
return nil , errServerNotInitialized
2020-05-19 16:53:54 -04:00
}
2020-05-20 13:18:15 -04:00
return & madmin . BucketQuota { } , nil
2020-05-19 16:53:54 -04:00
}
2022-04-24 05:36:31 -04:00
qCfg , _ , err := globalBucketMetadataSys . GetQuotaConfig ( ctx , bucketName )
return qCfg , err
2020-04-30 18:55:54 -04:00
}
// NewBucketQuotaSys returns initialized BucketQuotaSys
func NewBucketQuotaSys ( ) * BucketQuotaSys {
2020-05-20 13:18:15 -04:00
return & BucketQuotaSys { }
2020-04-30 18:55:54 -04:00
}
2022-01-31 14:07:04 -05:00
// Init initialize bucket quota.
func ( sys * BucketQuotaSys ) Init ( objAPI ObjectLayer ) {
sys . bucketStorageCache . Once . Do ( func ( ) {
sys . bucketStorageCache . TTL = 1 * time . Second
sys . bucketStorageCache . Update = func ( ) ( interface { } , error ) {
ctx , done := context . WithTimeout ( context . Background ( ) , 5 * time . Second )
defer done ( )
return loadDataUsageFromBackend ( ctx , objAPI )
}
} )
}
// GetBucketUsageInfo return bucket usage info for a given bucket
func ( sys * BucketQuotaSys ) GetBucketUsageInfo ( bucket string ) ( BucketUsageInfo , error ) {
v , err := sys . bucketStorageCache . Get ( )
if err != nil {
return BucketUsageInfo { } , err
}
dui , ok := v . ( DataUsageInfo )
if ! ok {
return BucketUsageInfo { } , fmt . Errorf ( "internal error: Unexpected DUI data type: %T" , v )
}
bui := dui . BucketsUsage [ bucket ]
return bui , nil
}
2020-04-30 18:55:54 -04:00
// parseBucketQuota parses BucketQuota from json
2020-05-20 13:18:15 -04:00
func parseBucketQuota ( bucket string , data [ ] byte ) ( quotaCfg * madmin . BucketQuota , err error ) {
quotaCfg = & madmin . BucketQuota { }
if err = json . Unmarshal ( data , quotaCfg ) ; err != nil {
2020-05-19 16:53:54 -04:00
return quotaCfg , err
2020-04-30 18:55:54 -04:00
}
2020-05-20 13:18:15 -04:00
if ! quotaCfg . IsValid ( ) {
2022-02-17 15:49:46 -05:00
if quotaCfg . Type == "fifo" {
logger . LogIf ( GlobalContext , errors . New ( "Detected older 'fifo' quota config, 'fifo' feature is removed and not supported anymore. Please clear your quota configs using 'mc admin bucket quota alias/bucket --clear' and use 'mc ilm add' for expiration of objects" ) )
return quotaCfg , nil
}
2020-05-20 13:18:15 -04:00
return quotaCfg , fmt . Errorf ( "Invalid quota config %#v" , quotaCfg )
2020-04-30 18:55:54 -04:00
}
return
}
2022-01-31 14:07:04 -05:00
func ( sys * BucketQuotaSys ) enforceQuotaHard ( ctx context . Context , bucket string , size int64 ) error {
if size < 0 {
return nil
2020-05-27 09:45:43 -04:00
}
2022-01-31 20:27:43 -05:00
q , err := sys . Get ( ctx , bucket )
2020-05-27 09:45:43 -04:00
if err != nil {
return err
}
2020-07-24 15:24:21 -04:00
if q != nil && q . Type == madmin . HardQuota && q . Quota > 0 {
2022-01-31 14:07:04 -05:00
bui , err := sys . GetBucketUsageInfo ( bucket )
2020-07-24 15:24:21 -04:00
if err != nil {
return err
}
2020-05-27 09:45:43 -04:00
2022-01-31 14:07:04 -05:00
if bui . Size > 0 && ( ( bui . Size + uint64 ( size ) ) >= q . Quota ) {
2020-07-24 15:24:21 -04:00
return BucketQuotaExceeded { Bucket : bucket }
}
2020-04-30 18:55:54 -04:00
}
2020-05-27 09:45:43 -04:00
2020-04-30 18:55:54 -04:00
return nil
}
2020-05-27 09:45:43 -04:00
2022-01-31 14:07:04 -05:00
func enforceBucketQuotaHard ( ctx context . Context , bucket string , size int64 ) error {
if globalBucketQuotaSys == nil {
2020-04-30 18:55:54 -04:00
return nil
}
2022-01-31 14:07:04 -05:00
return globalBucketQuotaSys . enforceQuotaHard ( ctx , bucket , size )
2020-04-30 18:55:54 -04:00
}