diff --git a/quota-commands.go b/quota-commands.go index 553ba41..56b3efe 100644 --- a/quota-commands.go +++ b/quota-commands.go @@ -25,6 +25,8 @@ import ( "io/ioutil" "net/http" "net/url" + "strconv" + "strings" ) // QuotaType represents bucket quota type @@ -40,13 +42,34 @@ func (t QuotaType) IsValid() bool { return t == HardQuota } +// SetBucketQuotaOptions holds set bucket quota options +type SetBucketQuotaOptions struct { + CreateNewRule bool + Update bool +} + +func (o *SetBucketQuotaOptions) getURLValues() url.Values { + urlValues := make(url.Values) + urlValues.Set("createNewRule", strconv.FormatBool(o.CreateNewRule)) + urlValues.Set("update", strconv.FormatBool(o.Update)) + return urlValues +} + +// BucketThrottleRule holds a bucket throttle rule +type BucketThrottleRule struct { + ID string `json:"id"` // indicates unique id of rule + ConcurrentRequestsCount uint64 `json:"concurrentRequestsCount"` // indicates no of concurrent requests + APIs []string `json:"apis"` // indicates list of APIs +} + // BucketQuota holds bucket quota restrictions type BucketQuota struct { - Quota uint64 `json:"quota"` // Deprecated Aug 2023 - Size uint64 `json:"size"` // Indicates maximum size allowed per bucket - Rate uint64 `json:"rate"` // Indicates bandwidth rate allocated per bucket - Requests uint64 `json:"requests"` // Indicates number of requests allocated per bucket - Type QuotaType `json:"quotatype,omitempty"` + Quota uint64 `json:"quota"` // Deprecated Aug 2023 + Size uint64 `json:"size"` // Indicates maximum size allowed per bucket + Rate uint64 `json:"rate"` // Indicates bandwidth rate allocated per bucket + Requests uint64 `json:"requests"` // Indicates number of requests allocated per bucket + Type QuotaType `json:"quotatype,omitempty"` + ThrottleRules []BucketThrottleRule `json:"throttleRules"` // indicates list of throttle rules per bucket } // IsValid returns false if quota is invalid @@ -55,10 +78,56 @@ func (q BucketQuota) IsValid() bool { if q.Quota > 0 { return q.Type.IsValid() } + if len(q.ThrottleRules) > 0 { + // if any throttle rule invalid, return false + for _, rule := range q.ThrottleRules { + if rule.ConcurrentRequestsCount <= 0 || len(rule.APIs) <= 0 { + return false + } + } + } // Empty configs are valid. return true } +// IsBucketThrottled returns true if throttle rules set for the bucket +func (q BucketQuota) IsBucketThrottled() bool { + return len(q.ThrottleRules) > 0 +} + +// HasDuplicateThrottleRules returns true if throttle rules set more than once +// for same APIs +func (q BucketQuota) HasDuplicateThrottleRules() (bool, string, string) { + rulesMap := make(map[string]BucketThrottleRule) + for _, rule := range q.ThrottleRules { + for _, api := range rule.APIs { + if eRule, ok := rulesMap[strings.ToLower(api)]; ok { + return true, api, eRule.ID + } + rulesMap[strings.ToLower(api)] = rule + } + } + return false, "", "" +} + +// ThrottleRulesMap returns a map of APIs to applicable rule +func (q BucketQuota) ThrottleRulesMap() map[string]BucketThrottleRule { + rulesMap := make(map[string]BucketThrottleRule) + for _, rule := range q.ThrottleRules { + for _, api := range rule.APIs { + if eRule, ok := rulesMap[api]; ok { + // apply the smaller value for the concurrent request count for the API + if eRule.ConcurrentRequestsCount > rule.ConcurrentRequestsCount { + rulesMap[api] = rule + } + } else { + rulesMap[api] = rule + } + } + } + return rulesMap +} + // GetBucketQuota - get info on a user func (adm *AdminClient) GetBucketQuota(ctx context.Context, bucket string) (q BucketQuota, err error) { queryValues := url.Values{} @@ -94,13 +163,13 @@ func (adm *AdminClient) GetBucketQuota(ctx context.Context, bucket string) (q Bu // SetBucketQuota - sets a bucket's quota, if quota is set to '0' // quota is disabled. -func (adm *AdminClient) SetBucketQuota(ctx context.Context, bucket string, quota *BucketQuota) error { +func (adm *AdminClient) SetBucketQuota(ctx context.Context, bucket string, quota *BucketQuota, opts SetBucketQuotaOptions) error { data, err := json.Marshal(quota) if err != nil { return err } - queryValues := url.Values{} + queryValues := opts.getURLValues() queryValues.Set("bucket", bucket) reqData := requestData{