feat: Add ListBucketsWithMetadata extension API (#13219)

This commit is contained in:
Harshavardhana 2021-09-16 09:52:41 -07:00 committed by GitHub
parent 78dc08bdc2
commit 45bcf73185
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 105 additions and 7 deletions

View File

@ -240,6 +240,16 @@ type CommonPrefix struct {
type Bucket struct {
Name string
CreationDate string // time string of format "2006-01-02T15:04:05.000Z"
// Usage size of the bucket not reflective of
// actual usage atomically, but an ever increasing
// value.
Usage *BucketUsageInfo `xml:"Usage,omitempty"`
// Provides information about various bucket features
// enabled such as versioning, object locking, tagging
// quota, replication config etc.
Details *BucketDetailsInfo `xml:"Details,omitempty"`
}
// ObjectVersion container for object version metadata
@ -263,7 +273,7 @@ func (o ObjectVersion) MarshalXML(e *xml.Encoder, start xml.StartElement) error
return e.EncodeElement(objectVersionWrapper(o), start)
}
// StringMap is a map[string]string.
// StringMap is a map[string]string
type StringMap map[string]string
// MarshalXML - StringMap marshals into XML.
@ -424,10 +434,12 @@ func generateListBucketsResponse(buckets []BucketInfo) ListBucketsResponse {
}
for _, bucket := range buckets {
var listbucket = Bucket{}
listbucket.Name = bucket.Name
listbucket.CreationDate = bucket.Created.UTC().Format(iso8601TimeFormat)
listbuckets = append(listbuckets, listbucket)
listbuckets = append(listbuckets, Bucket{
Name: bucket.Name,
CreationDate: bucket.Created.UTC().Format(iso8601TimeFormat),
Usage: bucket.Usage,
Details: bucket.Details,
})
}
data.Owner = owner

View File

@ -306,6 +306,8 @@ func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.R
return
}
metadata := r.Form.Get("metadata") == "true"
// If etcd, dns federation configured list buckets from etcd.
var bucketsInfo []BucketInfo
if globalDNSConfig != nil && globalBucketFederation {
@ -370,6 +372,49 @@ func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.R
}
}
if metadata && !globalIsGateway {
usageInfo, err := loadDataUsageFromBackend(ctx, objectAPI)
if err != nil {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
return
}
for i, bucket := range bucketsInfo {
if bu, ok := usageInfo.BucketsUsage[bucket.Name]; ok {
bucketsInfo[i].Usage = &BucketUsageInfo{
Size: bu.Size,
ObjectsCount: bu.ObjectsCount,
ObjectSizesHistogram: StringMap{},
}
for k, v := range bu.ObjectSizesHistogram {
bucketsInfo[i].Usage.ObjectSizesHistogram[k] = fmt.Sprint(v)
}
} else {
bucketsInfo[i].Usage = &BucketUsageInfo{
ObjectSizesHistogram: StringMap{},
}
}
lcfg, _ := globalBucketObjectLockSys.Get(bucket.Name)
quota, _ := globalBucketQuotaSys.Get(bucket.Name)
var bquota *BucketQuotaConfig
if quota != nil {
bquota = &BucketQuotaConfig{
Quota: quota.Quota,
Type: quota.Type,
}
}
rcfg, _ := globalBucketMetadataSys.GetReplicationConfig(ctx, bucket.Name)
tcfg, _ := globalBucketMetadataSys.GetTaggingConfig(bucket.Name)
bucketsInfo[i].Details = &BucketDetailsInfo{
Versioning: globalBucketVersioningSys.Enabled(bucket.Name),
VersioningSuspended: globalBucketVersioningSys.Suspended(bucket.Name),
Replication: rcfg != nil,
Locking: lcfg.LockEnabled,
Quota: bquota,
Tagging: tcfg,
}
}
}
// Generate response.
response := generateListBucketsResponse(bucketsInfo)
encodedSuccessResponse := encodeResponse(response)

View File

@ -104,7 +104,10 @@ func (er erasureObjects) getBucketInfo(ctx context.Context, bucketName string) (
if err != nil {
return err
}
bucketsInfo[index] = BucketInfo(volInfo)
bucketsInfo[index] = BucketInfo{
Name: volInfo.Name,
Created: volInfo.Created,
}
return nil
}, index)
}

View File

@ -859,7 +859,10 @@ func (s *erasureSets) ListBuckets(ctx context.Context) (buckets []BucketInfo, er
}
for _, v := range healBuckets {
listBuckets = append(listBuckets, BucketInfo(v))
listBuckets = append(listBuckets, BucketInfo{
Name: v.Name,
Created: v.Created,
})
}
sort.Slice(listBuckets, func(i, j int) bool {

View File

@ -24,6 +24,7 @@ import (
humanize "github.com/dustin/go-humanize"
"github.com/minio/madmin-go"
"github.com/minio/minio-go/v7/pkg/tags"
"github.com/minio/minio/internal/bucket/replication"
"github.com/minio/minio/internal/hash"
)
@ -70,6 +71,30 @@ var ObjectsHistogramIntervals = []objectHistogramInterval{
{"GREATER_THAN_512_MB", humanize.MiByte * 512, math.MaxInt64},
}
// BucketUsageInfo represents per bucket usage statistics
type BucketUsageInfo struct {
Size uint64
ObjectsCount uint64
ObjectSizesHistogram StringMap
}
// BucketQuotaConfig holds bucket quota restrictions
type BucketQuotaConfig struct {
Quota uint64
Type madmin.QuotaType
}
// BucketDetailsInfo provides information about features currently
// turned-on per bucket.
type BucketDetailsInfo struct {
Versioning bool
VersioningSuspended bool
Locking bool
Replication bool
Tagging *tags.Tags `xml:",omitempty"`
Quota *BucketQuotaConfig `xml:",omitempty"`
}
// BucketInfo - represents bucket metadata.
type BucketInfo struct {
// Name of the bucket.
@ -77,6 +102,16 @@ type BucketInfo struct {
// Date and time when the bucket was created.
Created time.Time
// Usage size of the bucket not reflective of
// actual usage atomically, but an ever increasing
// value.
Usage *BucketUsageInfo `xml:",omitempty"`
// Provides information about various bucket features
// enabled such as versioning, object locking, tagging
// quota, replication config etc.
Details *BucketDetailsInfo `xml:",omitempty"`
}
// ObjectInfo - represents object metadata.