mirror of
https://github.com/minio/minio.git
synced 2025-04-22 03:24:38 -04:00
Add prefixes usage in Accounting Usage Info (#12687)
This commit is contained in:
parent
e316873f84
commit
aa78505181
@ -344,6 +344,40 @@ func (a adminAPIHandlers) DataUsageInfoHandler(w http.ResponseWriter, r *http.Re
|
|||||||
writeSuccessResponseJSON(w, dataUsageInfoJSON)
|
writeSuccessResponseJSON(w, dataUsageInfoJSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PrefixUsageInfoHandler - GET /minio/admin/v3/prefixusage
|
||||||
|
// ----------
|
||||||
|
// Get server/cluster data usage info
|
||||||
|
func (a adminAPIHandlers) PrefixUsageInfoHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := newContext(r, w, "PrefixUsageInfo")
|
||||||
|
|
||||||
|
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
|
||||||
|
|
||||||
|
objectAPI, _ := validateAdminReq(ctx, w, r, iampolicy.DataUsageInfoAdminAction)
|
||||||
|
if objectAPI == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bucket := r.URL.Query().Get("bucket")
|
||||||
|
if isReservedOrInvalidBucket(bucket, false) {
|
||||||
|
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidBucketName), r.URL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixUsageInfo, err := loadPrefixUsageFromBackend(ctx, objectAPI, bucket)
|
||||||
|
if err != nil {
|
||||||
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixUsageInfoJSON, err := json.Marshal(prefixUsageInfo)
|
||||||
|
if err != nil {
|
||||||
|
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
writeSuccessResponseJSON(w, prefixUsageInfoJSON)
|
||||||
|
}
|
||||||
|
|
||||||
func lriToLockEntry(l lockRequesterInfo, resource, server string) *madmin.LockEntry {
|
func lriToLockEntry(l lockRequesterInfo, resource, server string) *madmin.LockEntry {
|
||||||
entry := &madmin.LockEntry{
|
entry := &madmin.LockEntry{
|
||||||
Timestamp: l.Timestamp,
|
Timestamp: l.Timestamp,
|
||||||
|
@ -72,6 +72,8 @@ func registerAdminRouter(router *mux.Router, enableConfigOps bool) {
|
|||||||
adminRouter.Methods(http.MethodGet).Path(adminVersion + "/storageinfo").HandlerFunc(gz(httpTraceAll(adminAPI.StorageInfoHandler)))
|
adminRouter.Methods(http.MethodGet).Path(adminVersion + "/storageinfo").HandlerFunc(gz(httpTraceAll(adminAPI.StorageInfoHandler)))
|
||||||
// DataUsageInfo operations
|
// DataUsageInfo operations
|
||||||
adminRouter.Methods(http.MethodGet).Path(adminVersion + "/datausageinfo").HandlerFunc(gz(httpTraceAll(adminAPI.DataUsageInfoHandler)))
|
adminRouter.Methods(http.MethodGet).Path(adminVersion + "/datausageinfo").HandlerFunc(gz(httpTraceAll(adminAPI.DataUsageInfoHandler)))
|
||||||
|
// PrefixUsageInfo operations
|
||||||
|
adminRouter.Methods(http.MethodGet).Path(adminVersion + "/prefixusageinfo").HandlerFunc(gz(httpTraceAll(adminAPI.PrefixUsageInfoHandler)))
|
||||||
|
|
||||||
if globalIsDistErasure || globalIsErasure {
|
if globalIsDistErasure || globalIsErasure {
|
||||||
/// Heal operations
|
/// Heal operations
|
||||||
|
@ -530,6 +530,18 @@ func (h dataUsageHash) Key() string {
|
|||||||
return string(h)
|
return string(h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *dataUsageCache) flattenChildrens(root dataUsageEntry) (m map[string]dataUsageEntry) {
|
||||||
|
m = make(map[string]dataUsageEntry)
|
||||||
|
for id := range root.Children {
|
||||||
|
e := d.Cache[id]
|
||||||
|
if len(e.Children) > 0 {
|
||||||
|
e = d.flatten(e)
|
||||||
|
}
|
||||||
|
m[id] = e
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
// flatten all children of the root into the root element and return it.
|
// flatten all children of the root into the root element and return it.
|
||||||
func (d *dataUsageCache) flatten(root dataUsageEntry) dataUsageEntry {
|
func (d *dataUsageCache) flatten(root dataUsageEntry) dataUsageEntry {
|
||||||
for id := range root.Children {
|
for id := range root.Children {
|
||||||
|
@ -20,7 +20,9 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
"github.com/minio/madmin-go"
|
"github.com/minio/madmin-go"
|
||||||
@ -59,6 +61,39 @@ func storeDataUsageInBackend(ctx context.Context, objAPI ObjectLayer, dui <-chan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// loadPrefixUsageFromBackend returns prefix usages found in passed buckets
|
||||||
|
// e.g.: /testbucket/prefix => 355601334
|
||||||
|
func loadPrefixUsageFromBackend(ctx context.Context, objAPI ObjectLayer, bucket string) (map[string]uint64, error) {
|
||||||
|
z, ok := objAPI.(*erasureServerPools)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("prefix usage is not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
cache := dataUsageCache{}
|
||||||
|
|
||||||
|
m := make(map[string]uint64)
|
||||||
|
for _, pool := range z.serverPools {
|
||||||
|
for _, er := range pool.sets {
|
||||||
|
// Load bucket usage prefixes
|
||||||
|
if err := cache.load(ctx, er, bucket+slashSeparator+dataUsageCacheName); err == nil {
|
||||||
|
root := cache.find(bucket)
|
||||||
|
if root == nil {
|
||||||
|
// We dont have usage information for this bucket in this
|
||||||
|
// set, go to the next set
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for id, usageInfo := range cache.flattenChildrens(*root) {
|
||||||
|
prefix := strings.TrimPrefix(id, bucket+slashSeparator)
|
||||||
|
m[prefix] += uint64(usageInfo.Size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
func loadDataUsageFromBackend(ctx context.Context, objAPI ObjectLayer) (madmin.DataUsageInfo, error) {
|
func loadDataUsageFromBackend(ctx context.Context, objAPI ObjectLayer) (madmin.DataUsageInfo, error) {
|
||||||
r, err := objAPI.GetObjectNInfo(ctx, dataUsageBucket, dataUsageObjName, nil, http.Header{}, readLock, ObjectOptions{})
|
r, err := objAPI.GetObjectNInfo(ctx, dataUsageBucket, dataUsageObjName, nil, http.Header{}, readLock, ObjectOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user